From 80cb8fc5995939ba5f5f1cd4366dae7efda6f49a Mon Sep 17 00:00:00 2001
From: prr <3099672575@qq.com>
Date: Fri, 22 Nov 2024 18:08:57 +0800
Subject: [PATCH] =?UTF-8?q?add=EF=BC=9AAI=E5=86=99=E4=BD=9C?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
packages/word/index.html | 59 ++++++++
packages/word/src/assets/images/article.svg | 1 +
packages/word/src/assets/images/outline.svg | 1 +
.../word/src/editor/core/command/Command.ts | 2 +
.../src/editor/core/command/CommandAdapt.ts | 85 +++++++++++-
packages/word/src/main.ts | 82 +++++++++++-
.../src/plugins/floatingToolbar/icons/Svgs.ts | 4 +-
.../word/src/plugins/floatingToolbar/index.ts | 31 -----
packages/word/src/style.css | 126 ++++++++++++++++++
9 files changed, 346 insertions(+), 45 deletions(-)
create mode 100644 packages/word/src/assets/images/article.svg
create mode 100644 packages/word/src/assets/images/outline.svg
diff --git a/packages/word/index.html b/packages/word/index.html
index f821ec6..5b73c0a 100644
--- a/packages/word/index.html
+++ b/packages/word/index.html
@@ -337,6 +337,65 @@
+
diff --git a/packages/word/src/assets/images/article.svg b/packages/word/src/assets/images/article.svg
new file mode 100644
index 0000000..5a9b23b
--- /dev/null
+++ b/packages/word/src/assets/images/article.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/packages/word/src/assets/images/outline.svg b/packages/word/src/assets/images/outline.svg
new file mode 100644
index 0000000..c537630
--- /dev/null
+++ b/packages/word/src/assets/images/outline.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/packages/word/src/editor/core/command/Command.ts b/packages/word/src/editor/core/command/Command.ts
index f63c19a..c2a85e9 100644
--- a/packages/word/src/editor/core/command/Command.ts
+++ b/packages/word/src/editor/core/command/Command.ts
@@ -30,6 +30,7 @@ export class Command {
public executeSubscript: CommandAdapt['subscript']
public excuteAiResult: CommandAdapt['aiResult']
public executeAiEdit: CommandAdapt['aiEdit']
+ public executeAiArticle: CommandAdapt['aiArticle']
public executeColor: CommandAdapt['color']
public executeHighlight: CommandAdapt['highlight']
public executeTitle: CommandAdapt['title']
@@ -156,6 +157,7 @@ export class Command {
this.executeSubscript = adapt.subscript.bind(adapt)
this.excuteAiResult = adapt.aiResult.bind(adapt)
this.executeAiEdit = adapt.aiEdit.bind(adapt)
+ this.executeAiArticle = adapt.aiArticle.bind(adapt)
this.executeColor = adapt.color.bind(adapt)
this.executeHighlight = adapt.highlight.bind(adapt)
// 标题、对齐方式、列表
diff --git a/packages/word/src/editor/core/command/CommandAdapt.ts b/packages/word/src/editor/core/command/CommandAdapt.ts
index 3d2c69b..9ce810a 100644
--- a/packages/word/src/editor/core/command/CommandAdapt.ts
+++ b/packages/word/src/editor/core/command/CommandAdapt.ts
@@ -477,7 +477,7 @@ export class CommandAdapt {
const isDisabled = this.draw.isReadonly() || this.draw.isDisabled()
if (isDisabled) return
const selection = this.range.getSelectionElementList()
-
+
if (selection?.length) {
const noBoldIndex = selection.findIndex(s => !s.bold)
selection.forEach(el => {
@@ -635,10 +635,75 @@ export class CommandAdapt {
})
this.draw.render({ isSetCursor: false })
}
- public aiResult (result?: string) {
- result ? this.aiContent = result : ''
+ public aiResult(result?: string) {
+ result ? (this.aiContent = result) : ''
return this.aiContent
}
+ public aiArticle(payload: string) {
+ // const isDisabled = this.draw.isReadonly() || this.draw.isDisabled()
+ // if (isDisabled) return
+ // const activeControl = this.control.getActiveControl()
+ // if (activeControl) return
+ // let { startIndex, endIndex } = this.range.getRange()
+ // console.log('range:', startIndex, endIndex)
+
+ // if (!~startIndex && !~endIndex) {
+ // startIndex = 0
+ // endIndex = 0
+ // }
+ // const elementList = this.draw.getElementList()
+ // console.log('hyperlink temp: ', payload, elementList)
+
+ // const { valueList, url } = payload
+ // const hyperlinkId = getUUID()
+ // const newElementList = valueList?.map(v => ({
+ // url,
+ // hyperlinkId,
+ // value: v.value,
+ // type: ElementType.HYPERLINK
+ // }))
+ // if (!newElementList) return
+ // const start = startIndex + 1
+ // formatElementContext(elementList, newElementList, startIndex, {
+ // editorOptions: this.options
+ // })
+ // this.draw.spliceElementList(
+ // elementList,
+ // start,
+ // startIndex === endIndex ? 0 : endIndex - startIndex,
+ // ...newElementList
+ // )
+ // const articalLength = newElementList?.length || 0
+ // const curIndex = start + articalLength - 1
+ // this.range.setRange(curIndex, curIndex)
+ // this.draw.render({ curIndex })
+
+ // console.log('ai article:')
+ this.selectAll()
+ const isDisabled = this.draw.isReadonly() || this.draw.isDisabled()
+ // console.log('isDisables:', isDisabled);
+
+ if (isDisabled) return
+ const selection = this.range.getSelectionElementList()
+ // if (!selection) return
+ let content = ''
+ selection?.forEach(el => {
+ content += el.value
+ })
+ this.search(content)
+ this.replace(content + payload)
+ // if (operate && content) {
+ // window.parent.postMessage(
+ // {
+ // type: 'aiCreater',
+ // data: content,
+ // action: operate
+ // },
+ // '*'
+ // )
+ // }
+ return content
+ }
public aiEdit(operate: string | null) {
console.log('ai edit:', operate)
const isDisabled = this.draw.isReadonly() || this.draw.isDisabled()
@@ -648,9 +713,9 @@ export class CommandAdapt {
let content = ''
selection.forEach(el => {
content += el.value
- })
+ })
// const eventBus = this.draw.getEventBus()
-
+
this.search(content)
if (operate && content) {
window.parent.postMessage(
@@ -905,10 +970,12 @@ export class CommandAdapt {
const isDisabled = this.draw.isReadonly() || this.draw.isDisabled()
if (isDisabled) return
const activeControl = this.control.getActiveControl()
+ //console.log(' hyperlink:', activeControl)
if (activeControl) return
const { startIndex, endIndex } = this.range.getRange()
if (!~startIndex && !~endIndex) return
const elementList = this.draw.getElementList()
+
const { valueList, url } = payload
const hyperlinkId = getUUID()
const newElementList = valueList?.map(v => ({
@@ -1180,12 +1247,14 @@ export class CommandAdapt {
}
public replace(payload: string) {
- console.log('替换:', payload);
-
+ // console.log('替换', payload)
+
const isReadonly = this.draw.isReadonly()
if (isReadonly) return
if (!payload || new RegExp(`${ZERO}`, 'g').test(payload)) return
const matchList = this.draw.getSearch().getSearchMatchList()
+ // console.log('ssssss:', matchList)
+
if (!matchList.length) return
// 匹配index变化的差值
let pageDiffCount = 0
@@ -1231,6 +1300,8 @@ export class CommandAdapt {
} else {
const curIndex = match.index + pageDiffCount
const element = elementList[curIndex]
+ console.log(element);
+
if (
element.type === ElementType.CONTROL &&
element.controlComponent !== ControlComponent.VALUE
diff --git a/packages/word/src/main.ts b/packages/word/src/main.ts
index ff8dbe1..ea55ae3 100644
--- a/packages/word/src/main.ts
+++ b/packages/word/src/main.ts
@@ -238,12 +238,12 @@ window.onload = function () {
}
//ai
- const aiEditDom = document.querySelector('.menu-item__ai-edit')!
- aiEditDom.title = `ai帮助`
- aiEditDom.onclick = function () {
- console.log('ai-edit')
- instance.command.executeAiEdit('')
- }
+ // const aiEditDom = document.querySelector('.menu-item__ai-edit')!
+ // aiEditDom.title = `ai帮助`
+ // aiEditDom.onclick = function () {
+ // console.log('ai-edit')
+ // instance.command.executeAiEdit('')
+ // }
const colorControlDom = document.querySelector('#color')!
colorControlDom.oninput = function () {
@@ -1131,6 +1131,76 @@ window.onload = function () {
})
}
+ //添加AI功能
+ const aiEditDom = document.querySelector('.menu-item__ai-edit')!
+ const aiMenuBox = document.querySelector('.menu-item__ai-edit-box')!
+ const aiMenuBoxClose = document.querySelector('.menu-item__ai-edit-box span')!
+ const aiOutlineDom = document.querySelector('.ai-edit-outline-box')!
+ const aiContentDom = document.querySelector('.ai-edit-content-box')!
+ aiEditDom.title = `ai写作`
+ aiEditDom.onclick = function () {
+ console.log('ai-edit')
+ instance.command.executeAiEdit('')
+ aiMenuBox.classList.contains('hide') ? aiMenuBox.classList.remove('hide') : aiMenuBox.classList.add('hide')
+ }
+
+ function initAiDialog() {
+ aiMenuBox.classList.add('hide')
+ aiMenuBox.classList.remove('add-height')
+ aiOutlineDom?.classList.remove('hide')
+ aiContentDom?.classList.add('hide')
+ }
+ aiMenuBoxClose.onclick = function () {
+ initAiDialog()
+ }
+ // 点击生成大纲,弹窗切换
+ document.querySelector('#aiArticle')!.onclick =
+ function () {
+ aiOutlineDom?.classList.add('hide')
+ aiContentDom?.classList.remove('hide')
+ aiMenuBox.classList.add('add-height')
+ }
+ const watchOutline = document.querySelector('#watchOutline')!
+ const watchArticle = document.querySelector('#watchArticle')!
+ const outlineViewDom = document.querySelector('#outlineView')!
+ const articleViewDom = document.querySelector('#articleView')!
+ const aiInertBtn = document.querySelector('#articleInsert')!
+ watchOutline.onclick =
+ function() {
+ watchOutline.classList.add('active-ai')
+ watchArticle.classList.remove('active-ai')
+ aiInertBtn?.classList.add('hide')
+ outlineViewDom.classList.remove('hide')
+ articleViewDom.classList.add('hide')
+ }
+ watchArticle.onclick =
+ function() {
+ watchArticle.classList.add('active-ai')
+ watchOutline.classList.remove('active-ai')
+ aiInertBtn?.classList.remove('hide')
+ outlineViewDom.classList.add('hide')
+ articleViewDom.classList.remove('hide')
+ }
+ //插入文章
+ aiInertBtn.onclick = function () {
+ const text = document.querySelector('#articleText')?.textContent || ''
+ // instance.command.executeSelectAll()
+ // instance.command.executeSearch()
+ // text ? instance.command.executeReplace(text) : ''
+ // const temp = {
+ // type: ElementType.TEXT,
+ // value: '',
+ // url: '',
+ // valueList: splitText(text).map(n => ({
+ // value: n,
+ // size: 16
+ // }))
+ // }
+ // console.log('数字:', temp);
+
+ instance.command.executeAiArticle(text)
+ initAiDialog()
+ }
// 5. | 搜索&替换 | 打印 |
const searchCollapseDom = document.querySelector(
'.menu-item__search__collapse'
diff --git a/packages/word/src/plugins/floatingToolbar/icons/Svgs.ts b/packages/word/src/plugins/floatingToolbar/icons/Svgs.ts
index 891ab80..95ee8fa 100644
--- a/packages/word/src/plugins/floatingToolbar/icons/Svgs.ts
+++ b/packages/word/src/plugins/floatingToolbar/icons/Svgs.ts
@@ -12,5 +12,7 @@ export const Svgs = {
simplification: ``,
richContent: ``,
translation: ``,
- summary: ``
+ summary: ``,
+ outline: ``,
+ compose: ``
}
\ No newline at end of file
diff --git a/packages/word/src/plugins/floatingToolbar/index.ts b/packages/word/src/plugins/floatingToolbar/index.ts
index 434b8a5..1c4cc00 100644
--- a/packages/word/src/plugins/floatingToolbar/index.ts
+++ b/packages/word/src/plugins/floatingToolbar/index.ts
@@ -63,23 +63,16 @@ function createPickerToolbar(
export const defaultAiPanelMenus = [
{
icon: Svgs.optimize,
- // title: '改进写作',
title: '优化',
key: 'creation_optimization'
},
{
icon: Svgs.checkGrammar,
- // title: '检查拼写和语法'
title: '纠错',
key: 'creation_proofreading'
},
- // {
- // icon: Svgs.simplification,
- // title: '简化内容'
- // },
{
icon: Svgs.richContent,
- // title: '丰富内容'
title: '续写',
key: 'creation_continuation'
},
@@ -166,18 +159,8 @@ function bindAiPanelEvent(container: HTMLDivElement, editor: Editor) {
container.querySelector('#footer-one')?.classList.remove('ai-hide')
container.querySelector('#footer-two')?.classList.add('ai-hide')
container.querySelector('.aie-ai-panel-body-content')?.classList.remove('ai-hide')
- // const goBtn = container.querySelector('#go')
- // goBtn ? goBtn.innerHTML = Svgs.aiPanelStop : ''
- //console.log('选项点击');
const chooseType = item.getAttribute('data-type')
- // const aiContent = editor.command.excuteAiResult()
let aiContent = editor.command.executeAiEdit(chooseType)
- // editor.eventBus.on('aiProcessedData', (msg: string) => {
- // console.log('收到');
-
- // aiContent = msg
- // })
-
const textarea = container.querySelector('textarea')!
if (aiContent) {
textarea.textContent = aiContent
@@ -223,20 +206,6 @@ function bindAiPanelEvent(container: HTMLDivElement, editor: Editor) {
}
}
})
-
- container.querySelectorAll('.aie-ai-panel-actions p').forEach(element => {
- // const prompt = element.getAttribute('data-prompt')!
- // element.addEventListener('click', () => {
- // startChat(holder, container, prompt)
- // })
- })
-
- container.addEventListener('click', e => {
- // if (e.target === container) {
- // holder.aiPanelInstance?.hide()
- // holder.tippyInstance?.show()
- // }
- })
}
//ai弹窗初始化
function initAiDialog(container: HTMLDivElement, editor: Editor) {
diff --git a/packages/word/src/style.css b/packages/word/src/style.css
index cba0e4c..091e1be 100644
--- a/packages/word/src/style.css
+++ b/packages/word/src/style.css
@@ -1073,3 +1073,129 @@ ul {
.menu-item__ai-edit i{
background-image: url('./assets/images/ai-edit.svg');
}
+.outline-svg i{
+ margin-right: 5px;
+ background-image: url('./assets/images/outline.svg');
+}
+.article-svg i{
+ margin-right: 5px;
+ background-image: url('./assets/images/article.svg');
+}
+.hide {
+ display: none !important;
+}
+.active-ai {
+ font-weight: bold;
+}
+.add-height {
+ height: 300px !important;
+}
+.menu-item .menu-item__ai-edit-box {
+ /* display: block; */
+ position: absolute;
+ top: 25px;
+ width: 500px;
+ min-height: 120px;
+ /* height: 80px; */
+ font-size: 14px;
+ padding: 10px 15px 10px 0;
+ background-color: #ebf9fb !important;
+ box-shadow: 0px 5px 5px #e3dfdf;
+}
+
+.menu-item .menu-item__ai-edit-box span {
+ position: absolute;
+ top: 0px;
+ right: 0px;
+ width: 25px;
+ height: 25px;
+ /* height: 100%; */
+ color: #dcdfe6;
+ font-size: 25px;
+ text-align: center;
+ line-height: 25px;
+ border: 0;
+}
+.menu-item .menu-item__ai-edit-box input ,
+.menu-item .menu-item__ai-edit-box select{
+ width: 180px;
+ height: 27px;
+ appearance: none;
+ background-color: #fff;
+ background-image: none;
+ border-radius: 4px;
+ border: 1px solid #ebebeb;
+ box-sizing: border-box;
+ color: #606266;
+ display: inline-block;
+ line-height: 27px;
+ outline: none;
+ padding: 0 10px;
+}
+.menu-item .menu-item__ai-edit-box button {
+ display: inline-block;
+ border: 1px solid #e2e6ed;
+ border-radius: 2px;
+ background: #fff;
+ line-height: 22px;
+ padding: 0 6px;
+ white-space: nowrap;
+ margin-left: 4px;
+ cursor: pointer;
+ font-size: 12px;
+}
+
+.menu-item .ai-edit-outline-box,
+.menu-item .ai-edit-content-box{
+ width: 100%;
+ height: 100%;
+ text-align: center;
+}
+
+.menu-item .ai-menu {
+ display: inline-block;
+ position: relative;
+ width: 20%;
+ min-width: 85px;
+ height: 100%;
+ padding: 10px 0;
+ box-sizing: border-box;
+ vertical-align: top;
+}
+.menu-item .ai-menu button {
+ position: absolute;
+ bottom: 10px;
+ right: 10px;
+}
+.menu-item .ai-menu button:hover {
+ background: rgba(25, 55, 88, .04);
+}
+.menu-item .ai-menu p {
+ display: inline-block;
+ height: 25px;
+ line-height: 25px;
+ vertical-align: middle;
+}
+.menu-item .ai-content-box {
+ display: inline-block;
+ width: 70%;
+ height: 100%;
+ /* padding: 10px 15px; */
+ border-radius: 5px;
+ background-color: #ffffff;
+ box-sizing: border-box;
+}
+.menu-item .ai-content-box textarea {
+ width: 100%;
+ height: 100%;
+ padding: 10px 15px;
+ /* height: 250px; */
+ border-color: #f4f4f5;
+ border-radius: 5px;
+ outline: none;
+ resize: none;
+ box-sizing: border-box;
+}
+.ai-content-box div {
+ margin: 5px 0;
+}
\ No newline at end of file