diff --git a/packages/local-version-control/ibiz.config.ts b/packages/local-version-control/ibiz.config.ts index b04c5733863a9f5ea28e96506211008b1308a5b9..f406994f30dbec774899ddde3281200d23be38be 100644 --- a/packages/local-version-control/ibiz.config.ts +++ b/packages/local-version-control/ibiz.config.ts @@ -59,5 +59,6 @@ export default defineConfig({ '@wangeditor/editor-for-vue', '@imengyu/vue3-context-menu', '@ibiz-template-plugin/ai-chat', + 'monaco-editor', ], }); diff --git a/packages/local-version-control/package.json b/packages/local-version-control/package.json index fc7591c411e8f78699b2c5ee9911dc037411d03a..7dd4e65f44e12050cea2b1ea06ef29380a1bf5ff 100644 --- a/packages/local-version-control/package.json +++ b/packages/local-version-control/package.json @@ -40,11 +40,13 @@ "@ibiz-template/vue3-util": "0.7.38-alpha.63", "@ibiz/model-core": "^0.1.58", "@imengyu/vue3-context-menu": "^1.3.3", + "@monaco-editor/loader": "^1.4.0", "async-validator": "^4.2.5", "axios": "^1.6.2", "dayjs": "^1.11.10", "element-plus": "^2.4.2", "lodash-es": "^4.17.21", + "monaco-editor": "^0.51.0", "pluralize": "^8.0.0", "qs": "^6.11.2", "qx-util": "^0.4.8", diff --git a/packages/local-version-control/src/components/index.ts b/packages/local-version-control/src/components/index.ts index 1c91b526d1cf631d68a0a17039da29d3167e3230..d9b40bc000d38428fec6d2f548721c686669f650 100644 --- a/packages/local-version-control/src/components/index.ts +++ b/packages/local-version-control/src/components/index.ts @@ -2,11 +2,13 @@ import { App } from 'vue'; import IBizLocalVersionContainer from './local-version-container/local-version-container'; import IBizLocalVersionList from './local-version-list/local-version-list'; import IBizLocalVersionItem from './local-version-item/local-version-item'; +import IBizLocalVersionDiff from './local-version-diff/local-version-diff'; export default { install(app: App) { app.component('IBizLocalVersionContainer', IBizLocalVersionContainer); app.component('IBizLocalVersionList', IBizLocalVersionList); app.component('IBizLocalVersionItem', IBizLocalVersionItem); + app.component('IBizLocalVersionDiff', IBizLocalVersionDiff); }, }; diff --git a/packages/local-version-control/src/components/local-version-diff/local-version-diff.scss b/packages/local-version-control/src/components/local-version-diff/local-version-diff.scss new file mode 100644 index 0000000000000000000000000000000000000000..8cc45a4ce9e183348efbe0bdcd5f74cbf2a6d50b --- /dev/null +++ b/packages/local-version-control/src/components/local-version-diff/local-version-diff.scss @@ -0,0 +1,55 @@ +/* stylelint-disable selector-class-pattern */ +@include b(local-version-diff) { + display: flex; + flex-direction: column; + width: 100%; + height: 100%; + padding: getCssVar('spacing', 'tight') getCssVar('spacing', 'base'); +} + +@include b(local-version-diff-header) { + display: flex; + flex: 0 0 auto; + align-items: center; + height: 40px; + padding: getCssVar('spacing', 'base-tight') 0; + margin: 0 getCssVar('spacing', 'base-tight'); + overflow: hidden; + font-size: getCssVar('font-size', 'header-5'); + font-weight: getCssVar('font-weight', 'bold'); + color: getCssVar(color, text, 0); + text-overflow: ellipsis; + white-space: nowrap; + border-bottom: 1px solid getCssVar('color', 'border'); +} + +@include b(local-version-diff-content) { + display: flex; + flex: 1 1 0; + flex-direction: column; + padding: getCssVar('spacing', 'tight') getCssVar('spacing', 'base-tight'); +} + +@include b(local-version-diff-toolbar) { + flex: 0 0 auto; + padding-top: getCssVar('spacing', 'tight'); + padding-bottom: getCssVar('spacing', 'base'); + + .el-select:first-child { + margin-right: getCssVar('spacing', 'tight'); + } +} + +@include b(local-version-diff-editor) { + flex: 1 1 0; + border: 1px solid getCssVar('color', 'border'); +} + +:root.studio_dark { + @include b(local-version-diff-header) { + height: 36px; + font-size: getCssVar('font-size', 'header-6'); + font-weight: getCssVar('font-weight', 'regular'); + color: getCssVar(color, white); + } +} \ No newline at end of file diff --git a/packages/local-version-control/src/components/local-version-diff/local-version-diff.tsx b/packages/local-version-control/src/components/local-version-diff/local-version-diff.tsx new file mode 100644 index 0000000000000000000000000000000000000000..e4666757386d4345ab7e46f893b5f7ee49bfbcd9 --- /dev/null +++ b/packages/local-version-control/src/components/local-version-diff/local-version-diff.tsx @@ -0,0 +1,183 @@ +import { + PropType, + defineComponent, + onMounted, + onUnmounted, + ref, + watch, +} from 'vue'; +import { useNamespace, useUIStore } from '@ibiz-template/vue3-util'; +import * as monaco from 'monaco-editor'; +import loader from '@monaco-editor/loader'; +import { IDBEntity } from '../../interface'; +import './local-version-diff.scss'; + +export default defineComponent({ + props: { + current: { + type: Object as PropType, + required: true, + }, + items: { + type: Object as PropType, + required: true, + }, + }, + setup(props) { + const ns = useNamespace('local-version-diff'); + + // 是否正在加载 + const isLoading = ref(false); + + // 选中项 + const selectedItem = ref( + props.items.find(item => item.id !== props.current.id) || props.current, + ); + + // diff编辑器元素 + const diffEditorRef = ref(); + + // monaco编辑器 + let monacoEditor: typeof monaco.editor | undefined; + + // diff编辑器 + let diffEditor: monaco.editor.IStandaloneDiffEditor | undefined; + + // 原始模型 + let originalModel: monaco.editor.ITextModel | undefined; + + // 比对模型 + let modifiedModel: monaco.editor.ITextModel | undefined; + + // 元素尺寸变化监听器 + let resizeObserver: ResizeObserver | undefined; + + // UI主题 + const { UIStore } = useUIStore(); + + // 获取monaco主题 + const getMonacoTheme = (name: string): string => { + return name === 'dark' ? `vs-${UIStore.theme}` : 'vs'; + }; + + watch( + () => UIStore.theme, + newVal => { + monacoEditor?.setTheme(getMonacoTheme(newVal)); + diffEditor?.layout(); + }, + ); + + // 初始化编辑器 + const initEditor = async () => { + if (!diffEditorRef.value) { + return; + } + try { + isLoading.value = true; + loader.config({ + paths: { + vs: `${ibiz.env.pluginBaseUrl}/monaco-editor@0.45.0/min/vs`, + }, + }); + const loaderMonaco = await loader.init(); + monacoEditor = loaderMonaco.editor; + diffEditor = monacoEditor.createDiffEditor(diffEditorRef.value, { + theme: getMonacoTheme(UIStore.theme), + readOnly: true, + readOnlyMessage: { + value: ibiz.i18n.t('editor.code.readOnlyPrompt'), + }, + }); + originalModel = monacoEditor.createModel( + props.current.data ? JSON.stringify(props.current.data, null, 2) : '', + 'json', + ); + modifiedModel = monacoEditor.createModel( + selectedItem.value.data + ? JSON.stringify(selectedItem.value.data, null, 2) + : '', + 'json', + ); + diffEditor.setModel({ + original: originalModel, + modified: modifiedModel, + }); + } finally { + isLoading.value = false; + } + }; + + // 处理选中项变化 + const handleSelectChange = (value: string) => { + selectedItem.value = + props.items.find(item => item.id === value) || props.current; + if (!diffEditor || !monacoEditor || !originalModel || !modifiedModel) { + return; + } + modifiedModel.setValue( + selectedItem.value.data + ? JSON.stringify(selectedItem.value.data, null, 2) + : '', + ); + diffEditor.setModel({ + original: originalModel, + modified: modifiedModel, + }); + }; + + onMounted(() => { + initEditor(); + if (diffEditorRef.value) { + resizeObserver = new ResizeObserver(() => { + diffEditor?.layout(); + }); + resizeObserver.observe(diffEditorRef.value); + } + }); + + onUnmounted(() => { + resizeObserver?.disconnect(); + }); + + return { + ns, + isLoading, + selectedItem, + diffEditorRef, + handleSelectChange, + }; + }, + render() { + return ( +
+
版本比对
+
+
+ + + + + {this.items.map(item => { + return ( + + ); + })} + +
+
+
+
+ ); + }, +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d57e34346b4e2a453f862fad1c4c06629fca2b1c..ece3e6d69aeab9bc0771f91ea2473836960da9e4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1090,6 +1090,9 @@ importers: '@imengyu/vue3-context-menu': specifier: ^1.3.3 version: 1.3.3 + '@monaco-editor/loader': + specifier: ^1.4.0 + version: 1.4.0(monaco-editor@0.51.0) async-validator: specifier: ^4.2.5 version: 4.2.5 @@ -1105,6 +1108,9 @@ importers: lodash-es: specifier: ^4.17.21 version: 4.17.21 + monaco-editor: + specifier: ^0.51.0 + version: 0.51.0 pluralize: specifier: ^8.0.0 version: 8.0.0