From 3bbcafc5be66f7bae67aba3260f159f3e3b3fca2 Mon Sep 17 00:00:00 2001 From: oneao Date: Mon, 31 Aug 2026 22:32:03 +0800 Subject: [PATCH] 20260831223203 --- .../fms-table/utils/createCellRenderer.js | 6 +- .../module-management/ModuleAutoCodePanel.vue | 8 +- .../module-management/ModuleBasicPanel.vue | 10 +- .../module-management/ModuleFieldsPanel.vue | 52 +- .../module-management/ModuleI18nPanel.vue | 347 +- .../ModuleListConfigPanel.vue | 4 +- .../module-management/ModulePowersPanel.vue | 20 +- .../ModuleQueryConfigPanel.vue | 185 +- .../design-editor/FormDesignEditor.vue | 25 +- .../design-editor/TableDesignEditor.vue | 40 +- .../design-editor/table/StructureTree.vue | 2 +- .../design-editor/table/StructureTreeNode.vue | 2 +- .../design-editor/table/TableInspector.vue | 2 +- .../design-editor/table/TablePreview.vue | 2 + .../components/fieldDefaults.js | 29 +- .../views/system/module-management/index.vue | 329 +- .../unit/delete-confirm-regression.spec.js | 187 + .../link-nuxt/.agents/skills/nuxt-ui/SKILL.md | 176 + .../skills/nuxt-ui/references/components.md | 245 + .../guidelines/component-selection.md | 124 + .../references/guidelines/conventions.md | 376 + .../references/guidelines/design-system.md | 378 + .../nuxt-ui/references/guidelines/forms.md | 233 + .../skills/nuxt-ui/references/layouts/chat.md | 263 + .../nuxt-ui/references/layouts/dashboard.md | 233 + .../skills/nuxt-ui/references/layouts/docs.md | 152 + .../nuxt-ui/references/layouts/editor.md | 153 + .../nuxt-ui/references/layouts/landing.md | 185 + .../skills/nuxt-ui/references/recipes/auth.md | 162 + .../nuxt-ui/references/recipes/data-tables.md | 225 + .../nuxt-ui/references/recipes/navigation.md | 90 + .../nuxt-ui/references/recipes/overlays.md | 173 + .../link-nuxt/.claude/skills/nuxt-ui/SKILL.md | 176 + .../skills/nuxt-ui/references/components.md | 245 + .../guidelines/component-selection.md | 124 + .../references/guidelines/conventions.md | 376 + .../references/guidelines/design-system.md | 378 + .../nuxt-ui/references/guidelines/forms.md | 233 + .../skills/nuxt-ui/references/layouts/chat.md | 263 + .../nuxt-ui/references/layouts/dashboard.md | 233 + .../skills/nuxt-ui/references/layouts/docs.md | 152 + .../nuxt-ui/references/layouts/editor.md | 153 + .../nuxt-ui/references/layouts/landing.md | 185 + .../skills/nuxt-ui/references/recipes/auth.md | 162 + .../nuxt-ui/references/recipes/data-tables.md | 225 + .../nuxt-ui/references/recipes/navigation.md | 90 + .../nuxt-ui/references/recipes/overlays.md | 173 + code/link-site/link-nuxt/.editorconfig | 13 + .../link-nuxt/.github/workflows/ci.yml | 34 + code/link-site/link-nuxt/.gitignore | 24 + .../page-2026-08-31T12-50-58-825Z.yml | 158 + .../page-2026-08-31T12-57-42-004Z.yml | 148 + .../page-2026-08-31T13-24-59-639Z.yml | 124 + code/link-site/link-nuxt/CLAUDE.md | 28 + code/link-site/link-nuxt/LICENSE | 21 + code/link-site/link-nuxt/README.md | 64 + code/link-site/link-nuxt/app/app.config.ts | 8 + code/link-site/link-nuxt/app/app.vue | 23 + .../link-nuxt/app/assets/css/main.css | 6 + .../link-nuxt/app/components/ArticleCard.vue | 60 + .../link-nuxt/app/components/CompanyCard.vue | 72 + .../app/components/CompanyIdentityHeader.vue | 93 + .../link-nuxt/app/components/CompanyLogo.vue | 39 + .../app/components/CompanyPageBanner.vue | 46 + .../app/components/CompanyPageTabs.vue | 62 + code/link-site/link-nuxt/app/data/mock.ts | 414 + .../link-nuxt/app/layouts/company.vue | 19 + .../link-nuxt/app/layouts/default.vue | 131 + .../link-nuxt/app/pages/company/[slug].vue | 43 + .../app/pages/company/[slug]/about.vue | 76 + .../app/pages/company/[slug]/articles.vue | 41 + .../app/pages/company/[slug]/contact.vue | 85 + .../app/pages/company/[slug]/index.vue | 157 + .../app/pages/company/[slug]/services.vue | 65 + .../link-nuxt/app/pages/directory.vue | 142 + code/link-site/link-nuxt/app/pages/index.vue | 149 + .../link-nuxt/app/pages/news/[id].vue | 134 + .../link-nuxt/app/pages/news/index.vue | 66 + code/link-site/link-nuxt/company-final.png | Bin 0 -> 189138 bytes code/link-site/link-nuxt/company-new.png | Bin 0 -> 91017 bytes code/link-site/link-nuxt/current-company.png | Bin 0 -> 165042 bytes code/link-site/link-nuxt/eslint.config.mjs | 6 + code/link-site/link-nuxt/nuxt.config.ts | 28 + code/link-site/link-nuxt/package.json | 27 + code/link-site/link-nuxt/pnpm-lock.yaml | 11072 ++++++++++++++++ code/link-site/link-nuxt/pnpm-workspace.yaml | 6 + code/link-site/link-nuxt/public/favicon.ico | Bin 0 -> 4286 bytes code/link-site/link-nuxt/renovate.json | 4 + code/link-site/link-nuxt/skills-lock.json | 11 + code/link-site/link-nuxt/tsconfig.json | 10 + code/link-site/需求分析.md | 210 + 91 files changed, 20921 insertions(+), 584 deletions(-) create mode 100644 code/fms/fms-vue/tests/unit/delete-confirm-regression.spec.js create mode 100644 code/link-site/link-nuxt/.agents/skills/nuxt-ui/SKILL.md create mode 100644 code/link-site/link-nuxt/.agents/skills/nuxt-ui/references/components.md create mode 100644 code/link-site/link-nuxt/.agents/skills/nuxt-ui/references/guidelines/component-selection.md create mode 100644 code/link-site/link-nuxt/.agents/skills/nuxt-ui/references/guidelines/conventions.md create mode 100644 code/link-site/link-nuxt/.agents/skills/nuxt-ui/references/guidelines/design-system.md create mode 100644 code/link-site/link-nuxt/.agents/skills/nuxt-ui/references/guidelines/forms.md create mode 100644 code/link-site/link-nuxt/.agents/skills/nuxt-ui/references/layouts/chat.md create mode 100644 code/link-site/link-nuxt/.agents/skills/nuxt-ui/references/layouts/dashboard.md create mode 100644 code/link-site/link-nuxt/.agents/skills/nuxt-ui/references/layouts/docs.md create mode 100644 code/link-site/link-nuxt/.agents/skills/nuxt-ui/references/layouts/editor.md create mode 100644 code/link-site/link-nuxt/.agents/skills/nuxt-ui/references/layouts/landing.md create mode 100644 code/link-site/link-nuxt/.agents/skills/nuxt-ui/references/recipes/auth.md create mode 100644 code/link-site/link-nuxt/.agents/skills/nuxt-ui/references/recipes/data-tables.md create mode 100644 code/link-site/link-nuxt/.agents/skills/nuxt-ui/references/recipes/navigation.md create mode 100644 code/link-site/link-nuxt/.agents/skills/nuxt-ui/references/recipes/overlays.md create mode 100644 code/link-site/link-nuxt/.claude/skills/nuxt-ui/SKILL.md create mode 100644 code/link-site/link-nuxt/.claude/skills/nuxt-ui/references/components.md create mode 100644 code/link-site/link-nuxt/.claude/skills/nuxt-ui/references/guidelines/component-selection.md create mode 100644 code/link-site/link-nuxt/.claude/skills/nuxt-ui/references/guidelines/conventions.md create mode 100644 code/link-site/link-nuxt/.claude/skills/nuxt-ui/references/guidelines/design-system.md create mode 100644 code/link-site/link-nuxt/.claude/skills/nuxt-ui/references/guidelines/forms.md create mode 100644 code/link-site/link-nuxt/.claude/skills/nuxt-ui/references/layouts/chat.md create mode 100644 code/link-site/link-nuxt/.claude/skills/nuxt-ui/references/layouts/dashboard.md create mode 100644 code/link-site/link-nuxt/.claude/skills/nuxt-ui/references/layouts/docs.md create mode 100644 code/link-site/link-nuxt/.claude/skills/nuxt-ui/references/layouts/editor.md create mode 100644 code/link-site/link-nuxt/.claude/skills/nuxt-ui/references/layouts/landing.md create mode 100644 code/link-site/link-nuxt/.claude/skills/nuxt-ui/references/recipes/auth.md create mode 100644 code/link-site/link-nuxt/.claude/skills/nuxt-ui/references/recipes/data-tables.md create mode 100644 code/link-site/link-nuxt/.claude/skills/nuxt-ui/references/recipes/navigation.md create mode 100644 code/link-site/link-nuxt/.claude/skills/nuxt-ui/references/recipes/overlays.md create mode 100644 code/link-site/link-nuxt/.editorconfig create mode 100644 code/link-site/link-nuxt/.github/workflows/ci.yml create mode 100644 code/link-site/link-nuxt/.gitignore create mode 100644 code/link-site/link-nuxt/.playwright-cli/page-2026-08-31T12-50-58-825Z.yml create mode 100644 code/link-site/link-nuxt/.playwright-cli/page-2026-08-31T12-57-42-004Z.yml create mode 100644 code/link-site/link-nuxt/.playwright-cli/page-2026-08-31T13-24-59-639Z.yml create mode 100644 code/link-site/link-nuxt/CLAUDE.md create mode 100644 code/link-site/link-nuxt/LICENSE create mode 100644 code/link-site/link-nuxt/README.md create mode 100644 code/link-site/link-nuxt/app/app.config.ts create mode 100644 code/link-site/link-nuxt/app/app.vue create mode 100644 code/link-site/link-nuxt/app/assets/css/main.css create mode 100644 code/link-site/link-nuxt/app/components/ArticleCard.vue create mode 100644 code/link-site/link-nuxt/app/components/CompanyCard.vue create mode 100644 code/link-site/link-nuxt/app/components/CompanyIdentityHeader.vue create mode 100644 code/link-site/link-nuxt/app/components/CompanyLogo.vue create mode 100644 code/link-site/link-nuxt/app/components/CompanyPageBanner.vue create mode 100644 code/link-site/link-nuxt/app/components/CompanyPageTabs.vue create mode 100644 code/link-site/link-nuxt/app/data/mock.ts create mode 100644 code/link-site/link-nuxt/app/layouts/company.vue create mode 100644 code/link-site/link-nuxt/app/layouts/default.vue create mode 100644 code/link-site/link-nuxt/app/pages/company/[slug].vue create mode 100644 code/link-site/link-nuxt/app/pages/company/[slug]/about.vue create mode 100644 code/link-site/link-nuxt/app/pages/company/[slug]/articles.vue create mode 100644 code/link-site/link-nuxt/app/pages/company/[slug]/contact.vue create mode 100644 code/link-site/link-nuxt/app/pages/company/[slug]/index.vue create mode 100644 code/link-site/link-nuxt/app/pages/company/[slug]/services.vue create mode 100644 code/link-site/link-nuxt/app/pages/directory.vue create mode 100644 code/link-site/link-nuxt/app/pages/index.vue create mode 100644 code/link-site/link-nuxt/app/pages/news/[id].vue create mode 100644 code/link-site/link-nuxt/app/pages/news/index.vue create mode 100644 code/link-site/link-nuxt/company-final.png create mode 100644 code/link-site/link-nuxt/company-new.png create mode 100644 code/link-site/link-nuxt/current-company.png create mode 100644 code/link-site/link-nuxt/eslint.config.mjs create mode 100644 code/link-site/link-nuxt/nuxt.config.ts create mode 100644 code/link-site/link-nuxt/package.json create mode 100644 code/link-site/link-nuxt/pnpm-lock.yaml create mode 100644 code/link-site/link-nuxt/pnpm-workspace.yaml create mode 100644 code/link-site/link-nuxt/public/favicon.ico create mode 100644 code/link-site/link-nuxt/renovate.json create mode 100644 code/link-site/link-nuxt/skills-lock.json create mode 100644 code/link-site/link-nuxt/tsconfig.json create mode 100644 code/link-site/需求分析.md diff --git a/code/fms/fms-vue/src/components/fms-table/utils/createCellRenderer.js b/code/fms/fms-vue/src/components/fms-table/utils/createCellRenderer.js index 75608f7e..89ea4da4 100644 --- a/code/fms/fms-vue/src/components/fms-table/utils/createCellRenderer.js +++ b/code/fms/fms-vue/src/components/fms-table/utils/createCellRenderer.js @@ -45,7 +45,7 @@ function actionButton(action, row, triggerAction, className = 'fms-action-btn') // 确认弹窗:状态化渲染(替代 antdv 的 Modal.confirm 命令式调用), // 由内部 Modal 承载;okType=danger(默认)时用 danger 按钮定制 footer。 function createConfirmDialog(state, close) { - const { action, row } = state + const { action, row } = state.value const config = typeof action.confirm === 'string' ? { title: action.confirm } : action.confirm || {} const title = config.title || '确认操作' const description = config.description ?? config.content ?? '确定要执行此操作吗?' @@ -132,6 +132,9 @@ function createActionsCell(actions) { .filter((action) => isActionVisible(action, row)) .map((action) => actionButton(action, row, triggerAction)) const visibleMoreItems = (moreAction?.items || []).filter((item) => isActionVisible(item, row)) + // 确认弹窗必须先于「无更多项」的提前 return 渲染——否则仅内联操作(如删除)点击后 + // confirmState 已设置但弹窗永远不会出现(表现为「删除按钮没有反应」)。 + if (confirmState.value) children.push(createConfirmDialog(confirmState, closeConfirm)) if (!visibleMoreItems.length) return h('span', { class: 'fms-actions-cell' }, children) const menuItems = visibleMoreItems.map((item, index) => ({ @@ -200,7 +203,6 @@ function createActionsCell(actions) { ) } - if (confirmState.value) children.push(createConfirmDialog(confirmState, closeConfirm)) return h('span', { class: 'fms-actions-cell' }, children) } } diff --git a/code/fms/fms-vue/src/views/system/module-management/ModuleAutoCodePanel.vue b/code/fms/fms-vue/src/views/system/module-management/ModuleAutoCodePanel.vue index 6e1f305a..aad58f1e 100644 --- a/code/fms/fms-vue/src/views/system/module-management/ModuleAutoCodePanel.vue +++ b/code/fms/fms-vue/src/views/system/module-management/ModuleAutoCodePanel.vue @@ -149,20 +149,16 @@ watch( { immediate: true }, ) -function notifyUpdate() { - if (localRow.value) emit('update', [{ ...localRow.value }]) -} - function toggleEnabled(checked) { if (!localRow.value) return localRow.value.b_canuse = checked ? 1 : 0 - notifyUpdate() + if (localRow.value) emit('update', [{ ...localRow.value }]) } function setRowValue(field, value) { if (!localRow.value) return localRow.value[field] = value - notifyUpdate() + if (localRow.value) emit('update', [{ ...localRow.value }]) } function pad(value) { diff --git a/code/fms/fms-vue/src/views/system/module-management/ModuleBasicPanel.vue b/code/fms/fms-vue/src/views/system/module-management/ModuleBasicPanel.vue index 50863aef..bbfa15df 100644 --- a/code/fms/fms-vue/src/views/system/module-management/ModuleBasicPanel.vue +++ b/code/fms/fms-vue/src/views/system/module-management/ModuleBasicPanel.vue @@ -77,14 +77,10 @@ function validate() { defineExpose({ validate }) -function emitUpdate() { - if (formData.value) emit('update', formData.value) -} - function setField(field, value) { if (!formData.value) return formData.value[field] = value === '' ? null : value - emitUpdate() + emit('update', formData.value) } // 编码变化时始终以完整编码重新派生多语言键 @@ -92,7 +88,7 @@ function onCodeInput(v) { setField('b_code', v) if (formData.value) { formData.value.b_i18n = buildModuleI18nKey(formData.value.b_module_type, v) - emitUpdate() + emit('update', formData.value) } } @@ -112,7 +108,7 @@ function onModuleTypeChange(v) { formData.value.b_delete_policy = null } formData.value.b_i18n = buildModuleI18nKey(v, formData.value.b_code) - emitUpdate() + emit('update', formData.value) } diff --git a/code/fms/fms-vue/src/views/system/module-management/ModuleFieldsPanel.vue b/code/fms/fms-vue/src/views/system/module-management/ModuleFieldsPanel.vue index 8535c105..a080e3ac 100644 --- a/code/fms/fms-vue/src/views/system/module-management/ModuleFieldsPanel.vue +++ b/code/fms/fms-vue/src/views/system/module-management/ModuleFieldsPanel.vue @@ -3,8 +3,8 @@ * 字段定义面板(s_field):可编辑表格维护模块字段。 * i18n 键按 field.{moduleCode}.{fieldName} 自动同步。 * 表单/列表/查询三列为「参与勾选」:在一行内表达该字段参与了哪些界面, - * 勾选即改即生效(生成/隐藏默认配置行);布局细节仍在对应设计器调整。 - * 参与是派生态(配置行存在且行内开关为 1),物化为字段行的 __form/__list/__query + * 勾选即改即生效(建行/删行);布局细节仍在对应设计器调整。 + * 参与是派生态(配置行存在 = 参与),物化为字段行的 __form/__list/__query * 虚拟字段交给 FmsTable 内置 checkbox 渲染(与「启用」列同款),change 按列路由 * 回 toggle 写配置草稿。参与开关语义见本文件内「字段参与开关」一节。 */ @@ -16,11 +16,13 @@ import { createListConfigRow, createQueryConfigRow } from './components/fieldDef /* ================= 字段参与开关(原 fieldParticipation.js 内联) ================= * 「字段是否参与 表单/列表/查询」的判定与切换。语义沿用 fieldAreaDefaults 的 - * 项目约定(行存在 = 已配置,行内开关 = 是否参与): + * 项目约定(行存在 = 参与): * - 表单参与:editConfig 行存在且 b_visible=1;关 = 置 b_visible=0,不删行 - * (保留画布布局/栅格,与列表「删除列=隐藏」同一哲学) - * - 列表参与:listConfig 行存在且 b_visible=1(行由加载自动补全,通常恒存在) - * - 查询参与:queryConfig 行存在且 b_canuse=1(行不自动生成,开 = 需要时按默认生成) + * (保留画布布局/栅格) + * - 列表参与:listConfig 行存在即参与(行由用户手动管理,加载时不自动补全, + * 开 = 建行、关 = 删行,与查询面板的行存在语义一致) + * - 查询参与:queryConfig 行存在即参与(无 b_canuse 开关,开 = 建行、关 = 删行, + * 与查询面板「左字段库 + 右表格」的行存在语义一致) * * 所有 toggle 返回新数组:目标行浅拷贝后修改,其余行保持原引用; * 行不存在且要「关」时无操作,原样返回(调用方可直接 emit)。 @@ -51,16 +53,14 @@ function isFormOn(editConfig, field) { } function isListOn(listConfig, field) { - const row = findParticipationRow(listConfig, field.b_id) - return !!row && Number(row.b_visible) === 1 + return !!findParticipationRow(listConfig, field.b_id) } function isQueryOn(queryConfig, field) { - const row = findParticipationRow(queryConfig, field.b_id) - return !!row && Number(row.b_canuse) === 1 + return !!findParticipationRow(queryConfig, field.b_id) } -/** 行不存在时追加到末尾;forceOn 的行由工厂置参与标志为 1(显式意愿) */ +/** 行不存在时追加到末尾 */ function appendRow(rows, row) { return [...(rows || []), row] } @@ -75,15 +75,17 @@ function toggleForm(editConfig, field, moduleId) { function toggleList(listConfig, field, moduleId) { const rows = listConfig || [] const row = findParticipationRow(rows, field.b_id) - if (row) return withRowToggled(rows, row, 'b_visible') - return appendRow(rows, createListConfigRow(moduleId, field, rows, { forceOn: true })) + // 行存在 = 参与:取消勾选即删行;不存在 = 未参与:勾选即建默认行 + if (row) return rows.filter((item) => item !== row) + return appendRow(rows, createListConfigRow(moduleId, field, rows)) } function toggleQuery(queryConfig, field, moduleId) { const rows = queryConfig || [] const row = findParticipationRow(rows, field.b_id) - if (row) return withRowToggled(rows, row, 'b_canuse') - return appendRow(rows, createQueryConfigRow(moduleId, field, rows, { forceOn: true })) + // 行存在 = 参与:取消勾选即删行;不存在 = 未参与:勾选即建默认行 + if (row) return rows.filter((item) => item !== row) + return appendRow(rows, createQueryConfigRow(moduleId, field, rows)) } const props = defineProps({ @@ -161,17 +163,6 @@ watch( { immediate: true }, ) -function emitUpdate() { - // 剥离参与虚拟字段:__ 前缀仅供表格渲染,不进字段草稿与保存请求 - emit( - 'update', - localFields.value.map((row) => { - const { __form, __list, __query, ...field } = row - return field - }), - ) -} - function onCellChange(row, col) { // 参与勾选:内置 checkbox 已把值写在字段行虚拟字段上(展示用途), // 真实状态经 toggle 写回对应配置草稿,不走字段 i18n 同步 @@ -188,7 +179,14 @@ function onCellChange(row, col) { return } syncModuleItemI18nKeys(localFields.value, 'field', props.moduleCode, 'b_field') - emitUpdate() + // 剥离参与虚拟字段:__ 前缀仅供表格渲染,不进字段草稿与保存请求 + emit( + 'update', + localFields.value.map((row) => { + const { __form, __list, __query, ...field } = row + return field + }), + ) } const columns = shallowRef(buildColumns()) diff --git a/code/fms/fms-vue/src/views/system/module-management/ModuleI18nPanel.vue b/code/fms/fms-vue/src/views/system/module-management/ModuleI18nPanel.vue index dee61772..7da9f121 100644 --- a/code/fms/fms-vue/src/views/system/module-management/ModuleI18nPanel.vue +++ b/code/fms/fms-vue/src/views/system/module-management/ModuleI18nPanel.vue @@ -1,233 +1,101 @@