From 91d720f6a57054b78410c6000e480dfc62a18a53 Mon Sep 17 00:00:00 2001 From: chenminjie <943130926@qq.com> Date: Thu, 28 Nov 2024 18:30:08 +0800 Subject: [PATCH 1/3] chore: update dependencies and add vue-dompurify-html plugin - Integrated vue-dompurify-html plugin in bootstrap.ts for HTML sanitization. --- apps/web-antd/package.json | 2 ++ apps/web-antd/src/bootstrap.ts | 4 +++ pnpm-lock.yaml | 47 +++++++++++++++++++++++++++------- pnpm-workspace.yaml | 2 ++ 4 files changed, 46 insertions(+), 9 deletions(-) diff --git a/apps/web-antd/package.json b/apps/web-antd/package.json index 42afa3c69..463e9f154 100644 --- a/apps/web-antd/package.json +++ b/apps/web-antd/package.json @@ -43,8 +43,10 @@ "@vueuse/core": "catalog:", "ant-design-vue": "catalog:", "dayjs": "catalog:", + "highlight.js": "catalog:", "pinia": "catalog:", "vue": "catalog:", + "vue-dompurify-html": "catalog:", "vue-router": "catalog:" } } diff --git a/apps/web-antd/src/bootstrap.ts b/apps/web-antd/src/bootstrap.ts index 963d1c7f7..a465d47b5 100644 --- a/apps/web-antd/src/bootstrap.ts +++ b/apps/web-antd/src/bootstrap.ts @@ -1,4 +1,5 @@ import { createApp, watchEffect } from 'vue'; +import VueDomPurifyHTML from 'vue-dompurify-html'; import { registerAccessDirective } from '@vben/access'; import { preferences } from '@vben/preferences'; @@ -32,6 +33,9 @@ async function bootstrap(namespace: string) { // 配置路由及路由守卫 app.use(router); + // 安装 vue-dompurify-html 插件 + app.use(VueDomPurifyHTML); + // 动态更新标题 watchEffect(() => { if (preferences.app.dynamicTitle) { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0ecc40168..cbc70f5c5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -279,6 +279,9 @@ catalogs: happy-dom: specifier: ^15.11.6 version: 15.11.6 + highlight.js: + specifier: ^11.10.0 + version: 11.10.0 html-minifier-terser: specifier: ^7.2.0 version: 7.2.0 @@ -465,6 +468,9 @@ catalogs: vitest: specifier: ^2.1.6 version: 2.1.6 + vue-dompurify-html: + specifier: ^5.2.0 + version: 5.2.0 vue-eslint-parser: specifier: ^9.4.3 version: 9.4.3 @@ -676,12 +682,18 @@ importers: dayjs: specifier: 'catalog:' version: 1.11.13 + highlight.js: + specifier: 'catalog:' + version: 11.10.0 pinia: specifier: 2.2.2 version: 2.2.2(typescript@5.7.2)(vue@3.5.13(typescript@5.7.2)) vue: specifier: ^3.5.13 version: 3.5.13(typescript@5.7.2) + vue-dompurify-html: + specifier: 'catalog:' + version: 5.2.0(vue@3.5.13(typescript@5.7.2)) vue-router: specifier: 'catalog:' version: 4.5.0(vue@3.5.13(typescript@5.7.2)) @@ -3645,16 +3657,16 @@ packages: resolution: {integrity: sha512-AFbhEo10DP095/45EauinQJ5hJ3rJUmuuqltGguvc3WsvezZN+g8qNHLGWKu60FHQVizMrQY7VJ+zVlBXlQQkQ==} engines: {node: '>= 16'} - '@intlify/message-compiler@11.0.0-beta.1': - resolution: {integrity: sha512-yMXfN4hg/EeSdtWfmoMrwB9X4TXwkBoZlTIpNydQaW9y0tSJHGnUPRoahtkbsyACCm9leSJINLY4jQ0rK6BK0Q==} + '@intlify/message-compiler@11.0.0-beta.2': + resolution: {integrity: sha512-/cJHP1n45Zlf9tbm/hudLrUwXzJZngR9OMTQk32H1S4lBjM2996wzKTHuLbaJJlJZNTTjnfWZUHPb+F6sE6p1Q==} engines: {node: '>= 16'} '@intlify/shared@10.0.4': resolution: {integrity: sha512-ukFn0I01HsSgr3VYhYcvkTCLS7rGa0gw4A4AMpcy/A9xx/zRJy7PS2BElMXLwUazVFMAr5zuiTk3MQeoeGXaJg==} engines: {node: '>= 16'} - '@intlify/shared@11.0.0-beta.1': - resolution: {integrity: sha512-Md/4T/QOx7wZ7zqVzSsMx2M/9Mx/1nsgsjXS5SFIowFKydqUhMz7K+y7pMFh781aNYz+rGXYwad8E9/+InK9SA==} + '@intlify/shared@11.0.0-beta.2': + resolution: {integrity: sha512-N6ngJfFaVA0l2iLtx/SymgHOBW4wiS5Pyue7YmY/G+mrGjesi+S+U+u/Xlv6pZa/YIBfeM4QB07lI7rz1YqKLg==} engines: {node: '>= 16'} '@intlify/unplugin-vue-i18n@6.0.0': @@ -5774,6 +5786,9 @@ packages: resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} engines: {node: '>= 4'} + dompurify@3.2.1: + resolution: {integrity: sha512-NBHEsc0/kzRYQd+AY6HR6B/IgsqzBABrqJbpCDQII/OK6h7B7LXzweZTDsqSW2LkTRpoxf18YUP+YjGySk6B3w==} + domutils@2.8.0: resolution: {integrity: sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==} @@ -9992,6 +10007,11 @@ packages: '@vue/composition-api': optional: true + vue-dompurify-html@5.2.0: + resolution: {integrity: sha512-GX+BStkKEJ8wu/+hU1EK2nu/gzXWhb4XzBu6aowpsuU/3nkvXvZ2jx4nZ9M3jtS/Vu7J7MtFXjc7x3cWQ+zbVQ==} + peerDependencies: + vue: ^3.5.13 + vue-eslint-parser@9.4.3: resolution: {integrity: sha512-2rYRLWlIpaiN8xbPiDyXZXRgLGOtWxERV7ND5fFAv5qo1D2N9Fu9MNajBNc6o13lZ+24DAWCkQCvj4klgmcITg==} engines: {node: ^14.17.0 || >=16.0.0} @@ -12262,8 +12282,8 @@ snapshots: '@intlify/bundle-utils@10.0.0(vue-i18n@10.0.4(vue@3.5.13(typescript@5.7.2)))': dependencies: - '@intlify/message-compiler': 11.0.0-beta.1 - '@intlify/shared': 11.0.0-beta.1 + '@intlify/message-compiler': 11.0.0-beta.2 + '@intlify/shared': 11.0.0-beta.2 acorn: 8.14.0 escodegen: 2.1.0 estree-walker: 2.0.2 @@ -12284,14 +12304,14 @@ snapshots: '@intlify/shared': 10.0.4 source-map-js: 1.2.1 - '@intlify/message-compiler@11.0.0-beta.1': + '@intlify/message-compiler@11.0.0-beta.2': dependencies: - '@intlify/shared': 11.0.0-beta.1 + '@intlify/shared': 11.0.0-beta.2 source-map-js: 1.2.1 '@intlify/shared@10.0.4': {} - '@intlify/shared@11.0.0-beta.1': {} + '@intlify/shared@11.0.0-beta.2': {} '@intlify/unplugin-vue-i18n@6.0.0(@vue/compiler-dom@3.5.13)(eslint@9.15.0(jiti@2.4.0))(rollup@4.27.4)(typescript@5.7.2)(vue-i18n@10.0.4(vue@3.5.13(typescript@5.7.2)))(vue@3.5.13(typescript@5.7.2))': dependencies: @@ -14825,6 +14845,10 @@ snapshots: dependencies: domelementtype: 2.3.0 + dompurify@3.2.1: + optionalDependencies: + '@types/trusted-types': 2.0.7 + domutils@2.8.0: dependencies: dom-serializer: 1.4.1 @@ -19485,6 +19509,11 @@ snapshots: dependencies: vue: 3.5.13(typescript@5.7.2) + vue-dompurify-html@5.2.0(vue@3.5.13(typescript@5.7.2)): + dependencies: + dompurify: 3.2.1 + vue: 3.5.13(typescript@5.7.2) + vue-eslint-parser@9.4.3(eslint@9.15.0(jiti@2.4.0)): dependencies: debug: 4.3.7(supports-color@9.4.0) diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 87eef1474..cd2e04fc8 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -108,6 +108,7 @@ catalog: globals: ^15.12.0 h3: ^1.13.0 happy-dom: ^15.11.6 + highlight.js: ^11.10.0 html-minifier-terser: ^7.2.0 husky: ^9.1.7 is-ci: ^3.0.1 @@ -172,6 +173,7 @@ catalog: vitepress-plugin-group-icons: ^1.3.0 vitest: ^2.1.6 vue: ^3.5.13 + vue-dompurify-html: ^5.2.0 vue-eslint-parser: ^9.4.3 vue-i18n: ^10.0.4 vue-router: ^4.5.0 From 462b434973b54fde7f9e460973d217d9b4454641 Mon Sep 17 00:00:00 2001 From: chenminjie <943130926@qq.com> Date: Fri, 29 Nov 2024 01:04:09 +0800 Subject: [PATCH 2/3] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E9=A1=B6=E7=BA=A7?= =?UTF-8?q?=E5=A4=96=E9=93=BE=E8=8F=9C=E5=8D=95=E5=A4=84=E7=90=86=E9=80=BB?= =?UTF-8?q?=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/web-antd/src/router/helper.ts | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/apps/web-antd/src/router/helper.ts b/apps/web-antd/src/router/helper.ts index b47b3f2e4..ad5571715 100644 --- a/apps/web-antd/src/router/helper.ts +++ b/apps/web-antd/src/router/helper.ts @@ -14,27 +14,16 @@ function buildMenus( // 处理顶级链接菜单 if (isHttpUrl(menu.path) && menu.parentId === 0) { const urlMenu: RouteRecordStringComponent = { - component: 'BasicLayout', + component: 'IFrameView', meta: { + hideInMenu: !menu.visible, icon: menu.icon, + link: menu.path, + orderNo: menu.sort, title: menu.name, }, name: menu.name, - path: `/${menu.path}`, - children: [ - { - component: 'IFrameView', - meta: { - hideInMenu: !menu.visible, - icon: menu.icon, - link: menu.path, - orderNo: menu.sort, - title: menu.name, - }, - name: menu.name, - path: `/${menu.path}/index`, - }, - ], + path: `/${menu.path}/index`, }; menus.push(urlMenu); return; From 8197f4dfc31a0267d3d3922ca2239827a1998a4e Mon Sep 17 00:00:00 2001 From: chenminjie <943130926@qq.com> Date: Fri, 29 Nov 2024 02:35:18 +0800 Subject: [PATCH 3/3] feat: enhance code generation page with preview functionality --- apps/web-antd/src/api/infra/codegen/index.ts | 2 +- .../src/views/infra/codegen/codegen.data.ts | 2 + .../codegen/components/preview-code-modal.vue | 206 ++++++++++++++++++ .../src/views/infra/codegen/index.vue | 40 +++- 4 files changed, 240 insertions(+), 10 deletions(-) create mode 100644 apps/web-antd/src/views/infra/codegen/components/preview-code-modal.vue diff --git a/apps/web-antd/src/api/infra/codegen/index.ts b/apps/web-antd/src/api/infra/codegen/index.ts index 8b3d22c45..19159bec8 100644 --- a/apps/web-antd/src/api/infra/codegen/index.ts +++ b/apps/web-antd/src/api/infra/codegen/index.ts @@ -280,7 +280,7 @@ export function syncCodegenFromDB(id: number) { } // 预览生成代码 -export function previewCodegen(id: number) { +export function getPreviewCodegen(id: number) { return requestClient.get(`/infra/codegen/preview?tableId=${id}`); } diff --git a/apps/web-antd/src/views/infra/codegen/codegen.data.ts b/apps/web-antd/src/views/infra/codegen/codegen.data.ts index 73d353d91..6eab77317 100644 --- a/apps/web-antd/src/views/infra/codegen/codegen.data.ts +++ b/apps/web-antd/src/views/infra/codegen/codegen.data.ts @@ -13,10 +13,12 @@ export namespace CodegenDefaultData { export const tableColumns: VxeGridProps['columns'] = [ { + fixed: 'left', type: 'checkbox', width: 50, }, { + fixed: 'left', type: 'seq', width: 50, }, diff --git a/apps/web-antd/src/views/infra/codegen/components/preview-code-modal.vue b/apps/web-antd/src/views/infra/codegen/components/preview-code-modal.vue new file mode 100644 index 000000000..26ca3e5e7 --- /dev/null +++ b/apps/web-antd/src/views/infra/codegen/components/preview-code-modal.vue @@ -0,0 +1,206 @@ + + + diff --git a/apps/web-antd/src/views/infra/codegen/index.vue b/apps/web-antd/src/views/infra/codegen/index.vue index 5f472834b..67bf7cecd 100644 --- a/apps/web-antd/src/views/infra/codegen/index.vue +++ b/apps/web-antd/src/views/infra/codegen/index.vue @@ -16,13 +16,6 @@ import { CodegenDefaultData } from './codegen.data'; // checked const checkedStatus = ref(false); -/** - * 查看详情 - */ -const handleView = (_row: CodegenApi.CodegenTableRespVO) => { - // console.log('查看详情', row); -}; - /** * 编辑 */ @@ -96,7 +89,13 @@ const gridOptions = reactive({ height: 'auto', checkboxConfig: { reserve: true, + highlight: true, + // labelField: 'id', }, + rowConfig: { + keyField: 'id', + }, + keepSource: true, proxyConfig: { ajax: { query: async ({ page }, params) => { @@ -138,6 +137,28 @@ const [ImportTableModal, importTableModalApi] = useVbenModal({ gridApi.reload(formOptions.values); }, }); + +// 使用预览代码弹窗组件 +const [PreviewCodeModal, previewCodeModalApi] = useVbenModal({ + connectedComponent: defineAsyncComponent( + () => import('./components/preview-code-modal.vue'), + ), +}); + +/** + * 打开导入表弹窗 + */ +const handleOpenImportTableModal = () => { + importTableModalApi.open(); +}; + +/** + * 打开预览代码弹窗 + */ +const handleOpenPreviewCodeModal = (row: CodegenApi.CodegenTableRespVO) => { + previewCodeModalApi.setData(row); + previewCodeModalApi.open(); +}; +