From 5711bf4b50ca0bf4f688d21bd6847c86cb382b11 Mon Sep 17 00:00:00 2001 From: "jlj05024111@163.com" Date: Wed, 19 Nov 2025 20:52:14 +0800 Subject: [PATCH 1/3] =?UTF-8?q?feat:=20=E6=9B=B4=E6=96=B0html=E5=85=A8?= =?UTF-8?q?=E5=B1=8F=E6=A0=B7=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 4 ++ src/editor/html/wang-editor/wang-editor.scss | 53 +++++++++++++++++++- src/editor/html/wang-editor/wang-editor.tsx | 12 ++++- 3 files changed, 65 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 68efd5a59..4557863b6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ ## [Unreleased] +### Changed + +- 更新html全屏样式 + ### Added - 新增markdown支持手动编辑模式 diff --git a/src/editor/html/wang-editor/wang-editor.scss b/src/editor/html/wang-editor/wang-editor.scss index 2b4e41eae..10e6aa671 100644 --- a/src/editor/html/wang-editor/wang-editor.scss +++ b/src/editor/html/wang-editor/wang-editor.scss @@ -84,6 +84,18 @@ $html: ( width: 100%; } } + + @include when('enable-edit'){ + // 整体处于允许编辑的情况下,默认的工具栏样式变为聚焦时的样式 + .w-e-bar-item>button{ + color: var(--w-e-toolbar-color); + cursor: pointer; + + svg{ + fill: var(--w-e-toolbar-color); + } + } + } } @include b('html-editor-readonly') { @@ -96,6 +108,21 @@ $html: ( } } +@include b('html-toolbar'){ + .w-e-toolbar{ + background-color: getCssVar(color, bg, 0); + border: 1px solid getCssVar(color, border); + border-bottom: none; + box-shadow: none; + + .w-e-bar-item>button{ + &:hover{ + background-color: getCssVar(color, bg, 0); + } + } + } +} + @include b('html-footer') { display: flex; align-items: center; @@ -187,28 +214,50 @@ $html: ( @include b('html-dialog-full-screen') { height: 80%; + .el-dialog__header{ + display: none; + } + + .el-dialog__body{ + height: 100%; + padding-top: 0; + } + + @include when('editing'){ + .el-dialog__body{ + padding-bottom: 0; + } + } + @include b('html') { - padding: 0 getCssVar('spacing', 'extra-loose'); + padding: 0; --w-e-toolbar-bg-color: #{getCssVar(color, bg, 0)}; } @include b('html-custom-toolbar') { height: 56px; + padding-right: 0; } @include b('html-content') { - height: calc(100% - 124px); + height: calc(100% - 56px); @include b('html-editor') { height: 100% !important; } + + @include when('editing'){ + height: calc(100% - 128px); + } } + } @include b('html-footer-dialog') { height: 68px; margin-top: 0; + margin-right: 0; } // 表情元素 diff --git a/src/editor/html/wang-editor/wang-editor.tsx b/src/editor/html/wang-editor/wang-editor.tsx index 970f79bd4..3c2ae8cca 100644 --- a/src/editor/html/wang-editor/wang-editor.tsx +++ b/src/editor/html/wang-editor/wang-editor.tsx @@ -966,7 +966,11 @@ const IBizHtml = defineComponent({ // 绘制编辑器内容 const renderEditorContent = () => { return ( -
+
{this.renderHeaserToolbar()} @@ -1053,7 +1058,10 @@ const IBizHtml = defineComponent({ v-model={this.isFullScreen} width='80%' top='10vh' - class={this.ns.b('dialog-full-screen')} + class={[ + this.ns.b('dialog-full-screen'), + this.ns.is('editing', !this.readonlyState), + ]} onClose={() => this.changeFullScreenState()} >
Date: Wed, 19 Nov 2025 20:53:24 +0800 Subject: [PATCH 2/3] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9Emarkdown=E6=94=AF?= =?UTF-8?q?=E6=8C=81AI=E8=A1=8C=E5=86=85=E8=81=8A=E5=A4=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 1 + .../ibiz-markdown-editor/custom-menu.ts | 74 ++++++++++ .../ibiz-markdown-editor.tsx | 57 +++++--- .../markdown/markdown-editor.controller.ts | 129 +++++++++++++++++- 4 files changed, 241 insertions(+), 20 deletions(-) create mode 100644 src/editor/markdown/ibiz-markdown-editor/custom-menu.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 4557863b6..924ca6ca4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ ### Added +- 新增markdown支持AI行内聊天 - 新增markdown支持手动编辑模式 - 新增重复器表格样式2组件 - 新增代码编辑器支持AI行内聊天 diff --git a/src/editor/markdown/ibiz-markdown-editor/custom-menu.ts b/src/editor/markdown/ibiz-markdown-editor/custom-menu.ts new file mode 100644 index 000000000..b6ad79330 --- /dev/null +++ b/src/editor/markdown/ibiz-markdown-editor/custom-menu.ts @@ -0,0 +1,74 @@ +import Cherry from 'cherry-markdown'; +import { nextTick } from 'vue'; +import { MenuItem } from '@imengyu/vue3-context-menu'; +import { MarkDownEditorController } from '../markdown-editor.controller'; + +/** + * 初始化自定义菜单 + * + * @export + * @param {(IData | null)} editor + * @param {MarkDownEditorController} c + * @return {*} {IData[]} + */ +export function initCustomMenu(c: MarkDownEditorController): IData[] { + const AIMenu = Cherry.createMenuHook('AI', { + icon: { + type: 'svg', + content: ` + + + + + `, + }, + onClick: (_selection: string, _menukey: string, event: MouseEvent) => { + const startPos = c.mdeditor?.editor.editor.getCursor('start'); + const endPos = c.mdeditor?.editor.editor.getCursor('end'); + c.setCursorPos(startPos, endPos); + event.stopPropagation(); + event.preventDefault(); + nextTick(() => { + if (c.mdeditor?.bubble) { + c.mdeditor.bubble.visible = true; + const selectionPosition = + c.mdeditor.bubble.bubbleDom.getBoundingClientRect(); + if ( + !selectionPosition || + !selectionPosition.left || + !selectionPosition.top + ) + return; + const items: MenuItem[] = ibiz.inLineAIUtil.calcContextMenus( + c.deACMode, + (tag: string) => { + c.doInLineAIUIAction(tag, c.model.appId); + }, + ); + if (items.length === 0) return; + ibiz.inLineAIUtil.showContextMenus( + selectionPosition.left, + selectionPosition.top + 60, + items, + ); + } + }); + }, + }); + return [AIMenu]; +} diff --git a/src/editor/markdown/ibiz-markdown-editor/ibiz-markdown-editor.tsx b/src/editor/markdown/ibiz-markdown-editor/ibiz-markdown-editor.tsx index 7ad9133b7..0604dac9f 100644 --- a/src/editor/markdown/ibiz-markdown-editor/ibiz-markdown-editor.tsx +++ b/src/editor/markdown/ibiz-markdown-editor/ibiz-markdown-editor.tsx @@ -19,6 +19,7 @@ import { createUUID } from 'qx-util'; import Cherry from 'cherry-markdown'; import { MarkDownEditorController } from '../markdown-editor.controller'; import './ibiz-markdown-editor.scss'; +import { initCustomMenu } from './custom-menu'; /** * Markdown编辑框 @@ -52,6 +53,8 @@ const IBizMarkDown: any = defineComponent({ const id = createUUID(); + const [AIMenu] = initCustomMenu(c); + // 请求头 const uploadHeaders = ibiz.util.file.getUploadHeaders(); const headers: Ref = ref({ ...uploadHeaders }); @@ -317,6 +320,7 @@ const IBizMarkDown: any = defineComponent({ // 关闭全屏 if (isFullscreen()) { closeFullscreen(); + isFullScreen.value = false; } } }; @@ -326,6 +330,20 @@ const IBizMarkDown: any = defineComponent({ defaultModel.value = 'previewOnly'; } nextTick(() => { + const bubble = [ + 'bold', + 'italic', + 'underline', + 'strikethrough', + 'sub', + 'sup', + '|', + 'size', + 'color', + ]; + if (c.editorParams.ac && c.deACMode) { + bubble.unshift('AI'); + } editor = new Cherry({ id, value: currentVal.value, @@ -386,17 +404,7 @@ const IBizMarkDown: any = defineComponent({ 'settings', 'togglePreview', ], - bubble: [ - 'bold', - 'italic', - 'underline', - 'strikethrough', - 'sub', - 'sup', - '|', - 'size', - 'color', - ], + bubble, float: [ 'h1', 'h2', @@ -407,7 +415,9 @@ const IBizMarkDown: any = defineComponent({ 'quickTable', 'code', ], - customMenu: [], + customMenu: { + AI: AIMenu, + }, // 定义侧边栏,默认为空 sidebar: ['theme', 'copy'], // 定义顶部右侧工具栏,默认为空 @@ -456,6 +466,7 @@ const IBizMarkDown: any = defineComponent({ '.cherry-toolbar>.toolbar-right', ); parentElement?.appendChild(span); + c.setMDEditor(editor); }); }; @@ -542,15 +553,23 @@ const IBizMarkDown: any = defineComponent({ onClick={onEnableEdit} title={ibiz.i18n.t('editor.markdown.edit')} > - +
)} -
- +
+ {isFullScreen.value ? ( + + ) : ( + + )}
); diff --git a/src/editor/markdown/markdown-editor.controller.ts b/src/editor/markdown/markdown-editor.controller.ts index 2f99b7bb5..fa7509996 100644 --- a/src/editor/markdown/markdown-editor.controller.ts +++ b/src/editor/markdown/markdown-editor.controller.ts @@ -2,6 +2,9 @@ import { RuntimeModelError } from '@ibiz-template/core'; import { EditorController, IAppDEService, + IInLineAIEditor, + IInLineAiChatOptions, + UIActionUtil, getDeACMode, } from '@ibiz-template/runtime'; import { IAppDEACMode, IDEACModeDataItem, IMarkdown } from '@ibiz/model-core'; @@ -13,7 +16,10 @@ import { IAppDEACMode, IDEACModeDataItem, IMarkdown } from '@ibiz/model-core'; * @class MarkDownEditorController * @extends {EditorController} */ -export class MarkDownEditorController extends EditorController { +export class MarkDownEditorController + extends EditorController + implements IInLineAIEditor +{ /** * 上传参数 */ @@ -87,6 +93,22 @@ export class MarkDownEditorController extends EditorController { */ chatCompletion: boolean = false; + /** + * 编辑器实例 + * + * @type {IData} + * @memberof MarkDownEditorController + */ + mdeditor: IData | null = null; + + /** + * 选区位置缓存 + * + * @type {(IData | null)} + * @memberof MarkDownEditorController + */ + selectionAreaPosition: IData | null = null; + protected async onInit(): Promise { await super.onInit(); @@ -161,4 +183,109 @@ export class MarkDownEditorController extends EditorController { } } } + + /** + * 设置编辑器实例 + * + * @param {IData} mdeditor + * @memberof MarkDownEditorController + */ + public setMDEditor(mdeditor: IData): void { + this.mdeditor = mdeditor; + } + + /** + * 设置保存当前选区位置 + * + * @param {IData} start + * @param {IData} end + * @memberof MarkDownEditorController + */ + setCursorPos(start: IData, end: IData): void { + this.selectionAreaPosition = { start, end }; + } + + /** + * 获取选中文本 + * + * @return {*} {string} + * @memberof MarkDownEditorController + */ + public getSelectionText(): string { + return this.mdeditor?.editor.editor.getSelection(); + } + + /** + * 插入文本 + * + * @param {string} text + * @memberof MarkDownEditorController + */ + insertText(text: string): void { + this.mdeditor?.insert(text); + } + + /** + * 替换选中文本 + * + * @param {string} text + * @memberof MarkDownEditorController + */ + replaceSelectionText(text: string): void { + this.mdeditor?.editor.editor.replaceSelection(text); + } + + /** + * 恢复选区 + * + * @memberof MarkDownEditorController + */ + restoreSelection(): void { + this.mdeditor?.editor.editor.setSelection( + this.selectionAreaPosition?.start, + this.selectionAreaPosition?.end, + ); + } + + /** + * 获取内联AI参数 + * + * @return {*} {IData} + * @memberof MarkDownEditorController + */ + getInLineAiChatOptions(): IInLineAiChatOptions { + const editorRect = this.mdeditor?.wrapperDom.getBoundingClientRect(); + return { + left: editorRect?.left, + top: editorRect?.top, + width: editorRect?.width, + }; + } + + /** + * 执行内联AIUI操作 + * + * @param {string} _uiAction + * @param {string} _appId + * @return {*} {Promise} + * @memberof MarkDownEditorController + */ + async doInLineAIUIAction(uiActionId: string, appId: string): Promise { + const eventArgs = this.ctrl.getEventArgs(); + eventArgs.params.editor = this; + // 编辑器参数srfaiappendcurdata,是否传入对象参数,用于历史查询传参 + if ( + this.editorParams.srfaiappendcurdata && + this.editorParams.srfaiappendcurdata === 'true' + ) { + eventArgs.context.srfaiappendcurdata = true; + } + await UIActionUtil.exec( + uiActionId!, + { + ...eventArgs, + }, + appId, + ); + } } -- Gitee From 2ce39ff534dec79c992f3c94d4153a3e0a6dd0e1 Mon Sep 17 00:00:00 2001 From: "jlj05024111@163.com" Date: Wed, 19 Nov 2025 20:54:32 +0800 Subject: [PATCH 3/3] =?UTF-8?q?feat:=20=E6=9B=B4=E6=96=B0AI=E8=A1=8C?= =?UTF-8?q?=E5=86=85=E8=81=8A=E5=A4=A9=E4=B8=8A=E4=B8=8B=E6=96=87=E8=8F=9C?= =?UTF-8?q?=E5=8D=95=E6=A0=B7=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 1 + .../inline-ai-textarea.scss | 24 ++++++++++++++++++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 924ca6ca4..fbdde680b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ ### Changed +- 更新AI行内聊天上下文菜单样式 - 更新html全屏样式 ### Added diff --git a/src/util/inline-ai-util/inline-ai-textarea/inline-ai-textarea.scss b/src/util/inline-ai-util/inline-ai-textarea/inline-ai-textarea.scss index e13df9738..64fc5a39c 100644 --- a/src/util/inline-ai-util/inline-ai-textarea/inline-ai-textarea.scss +++ b/src/util/inline-ai-util/inline-ai-textarea/inline-ai-textarea.scss @@ -1,5 +1,27 @@ +$inline-ai-context-menu: ( + color-bg: getCssVar(color,bg,2), + color-text: getCssVar(color,text,0), + color-bg-active: getCssVar(color,fill,0), +); @include b(inline-ai-container-context-menu) { - color: red; + @include set-component-css-var('inline-ai-context-menu',$inline-ai-context-menu); + + --mx-menu-text: #{getCssVar(inline-ai-context-menu,color-text)}; + --mx-menu-backgroud: #{getCssVar(inline-ai-context-menu,color-bg)}; + --mx-menu-hover-backgroud: #{getCssVar(inline-ai-context-menu,color-bg-active)}; + --mx-menu-hover-text: #{getCssVar(inline-ai-context-menu,color-text)}; + --mx-menu-open-text: #{getCssVar(inline-ai-context-menu,color-text)}; + --mx-menu-open-backgroud:#{getCssVar(inline-ai-context-menu,color-bg-active)}; + --mx-menu-open-hover-text:#{getCssVar(inline-ai-context-menu,color-text)}; + --mx-menu-open-hover-backgroud:#{getCssVar(inline-ai-context-menu,color-bg-active)}; + + .scroll-content{ + pointer-events: unset; + } + + .mx-context-menu{ + cursor: pointer; + } } @include b(inline-ai-textarea-container) { -- Gitee