chore(fms-vue): WIP 基线快照——收编工作区未提交的前端改动

不含 fms-api Java 侧改动与后续导航状态化阶段提交。主要内容:
- ui 组件库:date/dropdown/form/input/popover/select/tooltip 调整,
  新增 Segmented 组件;fms-table 可编辑单元格渲染器与 FileCard 更新
- 模块管理:列表配置加载自动补全、查询缺配徽标与一键补充、
  结构编辑内核 useStructureEditing/useBandLayout、子表表格编辑方式、
  分组标题多语言、I18nKeyCell 等(含配套 spec)
- 布局/主题/仪表盘/演示页小幅更新
This commit is contained in:
oneao committed 2026-08-30 20:06:19 +08:00
1 parent a1079a7150
commit 05d0c7f304
58 files changed
+3698 -1343

No files matched your search

@@ -19,7 +19,6 @@ import {
List,
Pencil,
Hash,
RefreshCw,
Shield,
Globe,
Info,
@@ -94,7 +93,6 @@ const isQueryModule = computed(() => moduleType.value === 'query')
/* ================= 编辑方式 / 导航 / i18n 展示(面板编排) ================= */
const editMode = computed(() => drafts.value?.module?.b_edit_mode || 'form')
const editNavLabel = computed(() => (editMode.value === 'table' ? '表格设计' : '表单设计'))
const finalI18nItems = computed(() => {
const module = drafts.value?.module
@@ -117,6 +115,11 @@ const finalI18nItems = computed(() => {
const key = buildModuleItemI18nKey('power', module.b_code, power.b_code)
if (key) items.push({ key, managed: true, defaultValue: power.b_name || '', id: `power:${key}` })
}
// 分组标题多语言:b_i18n 为用户手填 key(空则运行时直接用标题原文,不纳入受管)
for (const group of drafts.value?.groups || []) {
const key = String(group.b_i18n || '').trim()
if (key) items.push({ key, managed: true, defaultValue: group.b_title || '', id: `group:${group.b_id}` })
}
return items
})
@@ -137,30 +140,18 @@ const configGroups = computed(() => {
items: [{ key: 'fields', label: '字段定义', icon: Table2 }],
})
// 界面配置:表单设计(数据模块)→ 列表配置 → 查询配置
// 界面配置:表单设计(数据模块,含主表表单/子表表格两种编辑方式)→ 列表配置 → 查询配置
const uiItems = []
if (isDataModule.value) {
const editLen = drafts.value?.editConfig?.length ?? 0
uiItems.push({
key: 'edit',
label: editNavLabel.value,
icon: Pencil,
badge: editLen ? '已配置' : '',
})
uiItems.push({ key: 'edit', label: '表单设计', icon: Pencil })
}
const listLen = drafts.value?.listConfig?.length ?? 0
uiItems.push({
key: 'list',
label: '列表配置',
icon: List,
badge: listLen ? '已配置' : '',
})
const queryLen = drafts.value?.queryConfig?.length ?? 0
// 列表配置行在加载时自动补全全部启用字段,无「缺失」概念,不带徽标
uiItems.push({ key: 'list', label: '列表配置', icon: List })
uiItems.push({
key: 'query',
label: '查询配置',
icon: Search,
badge: queryLen ? '已配置' : '',
badge: missingQueryCount.value ? `缺 ${missingQueryCount.value}` : '',
})
groups.push({ key: 'display', label: '界面配置', items: uiItems })
@@ -195,6 +186,9 @@ const configNavItems = computed(() =>
configGroups.value.flatMap((group) => group.items.map((item) => ({ ...item }))),
)
/* 编辑设计器:form/table 两面板 props/emits 契约一致,用动态组件消除模板重复 */
const activeEditPanel = computed(() => (editMode.value === 'table' ? ModuleTableEditPanel : ModuleFormEditPanel))
/* ================= composables ================= */
const { saveModule } = useModuleSave({
selectedModule,
@@ -298,11 +292,12 @@ const {
})
const {
reloadModule,
onModuleSelect,
onFieldsUpdate,
onAutoCodeUpdate,
syncFields,
missingQueryCount,
fillMissingConfigs,
} = useModuleConfig({
moduleSelectedId,
moduleTreeData,
@@ -337,6 +332,19 @@ function onModuleUpdate(section, newData) {
if (drafts.value) drafts.value[section] = newData
}
/* 分组管理弹层提交:写回分组草稿,并清理被删分组在列表/编辑配置中的引用 */
function onGroupsUpdate(groups, removedGroupIds) {
if (!drafts.value) return
drafts.value.groups = groups
const removed = new Set((removedGroupIds || []).map(String))
if (!removed.size) return
for (const section of ['listConfig', 'editConfig']) {
drafts.value[section] = (drafts.value[section] || []).map((row) =>
removed.has(String(row.b_group_id)) ? { ...row, b_group_id: null } : row,
)
}
}
function onModuleI18nSaved() {
i18nPanelRef.value?.refreshKey?.()
}
@@ -408,6 +416,27 @@ loadModuleTree()
<SplitterPanel>
<main class="mm-main">
<template v-if="selectedModule">
<!-- 顶部通栏操作:保存 / 同步字段(全 tab 生效,不随内容区切换) -->
<div class="mm-main-toolbar">
<Button
type="primary"
:loading="configSaving"
:disabled="configLoading || !drafts"
@click="saveModule"
>
<Save :size="14" /> 保存
</Button>
<Button
v-if="isDataModule || isQueryModule"
type="outline"
:disabled="busy"
title="按数据库视图结构对齐字段定义"
@click="syncFields"
>
同步字段
</Button>
</div>
<Tabs
v-if="drafts"
v-model="activeSection"
@@ -421,21 +450,6 @@ loadModuleTree()
<span class="mm-config-nav__label">{{ item.label }}</span>
<span v-if="item.badge" class="mm-config-nav__badge">{{ item.badge }}</span>
</template>
<template #rightExtra>
<div class="mm-header__actions">
<Button type="outline" :disabled="busy || !selectedModule" @click="reloadModule">
<RefreshCw :size="14" /> 重载
</Button>
<Button
type="primary"
:loading="configSaving"
:disabled="configLoading"
@click="saveModule"
>
<Save :size="14" /> 保存
</Button>
</div>
</template>
</Tabs>
<div class="mm-body__inner">
@@ -456,9 +470,6 @@ loadModuleTree()
v-show="activeSection === 'fields'"
class="mm-config-pane"
>
<div class="mm-section-toolbar">
<Button type="outline" :disabled="busy" @click="syncFields">同步字段</Button>
</div>
<ModuleFieldsPanel
:module-id="String(selectedModule.b_id)"
:module-code="drafts?.module?.b_code || ''"
@@ -466,7 +477,6 @@ loadModuleTree()
:loading="busy"
@update="onFieldsUpdate"
@i18n-saved="onModuleI18nSaved"
@sync-fields="syncFields"
/>
</div>
@@ -477,25 +487,23 @@ loadModuleTree()
>
<ModuleListConfigPanel
:module-id="String(selectedModule.b_id)"
:module-code="drafts?.module?.b_code || ''"
:list-config="drafts?.listConfig"
:edit-config="drafts?.editConfig"
:query-config="drafts?.queryConfig"
:fields="drafts?.fields"
:groups="drafts?.groups"
:loading="busy"
@update="(v) => onModuleUpdate('listConfig', v)"
@sync-edit="(v) => onModuleUpdate('editConfig', v)"
@sync-query="(v) => onModuleUpdate('queryConfig', v)"
@update-groups="onGroupsUpdate"
@i18n-saved="onModuleI18nSaved"
/>
</div>
<div v-if="isDataModule" v-show="activeSection === 'edit'" class="mm-config-pane">
<ModuleTableEditPanel
v-if="editMode === 'table'"
<component
:is="activeEditPanel"
:module-id="String(selectedModule.b_id)"
:edit-config="drafts?.editConfig"
:list-config="drafts?.listConfig"
:query-config="drafts?.queryConfig"
:fields="drafts?.fields"
:groups="drafts?.groups"
:edit-mode="editMode"
@@ -505,28 +513,8 @@ loadModuleTree()
@update:edit-mode="
(v) => onModuleUpdate('module', { ...(drafts?.module || {}), b_edit_mode: v })
"
@update-groups="(v) => onModuleUpdate('groups', v)"
@sync-list="(v) => onModuleUpdate('listConfig', v)"
@sync-query="(v) => onModuleUpdate('queryConfig', v)"
/>
<ModuleFormEditPanel
v-else
:module-id="String(selectedModule.b_id)"
:edit-config="drafts?.editConfig"
:list-config="drafts?.listConfig"
:query-config="drafts?.queryConfig"
:fields="drafts?.fields"
:groups="drafts?.groups"
:edit-mode="editMode"
:active="activeSection === 'edit'"
:loading="busy"
@update="(v) => onModuleUpdate('editConfig', v)"
@update:edit-mode="
(v) => onModuleUpdate('module', { ...(drafts?.module || {}), b_edit_mode: v })
"
@update-groups="(v) => onModuleUpdate('groups', v)"
@sync-list="(v) => onModuleUpdate('listConfig', v)"
@sync-query="(v) => onModuleUpdate('queryConfig', v)"
@update-groups="onGroupsUpdate"
@update-list-config="(v) => onModuleUpdate('listConfig', v)"
/>
</div>
@@ -540,7 +528,9 @@ loadModuleTree()
:query-config="drafts?.queryConfig"
:fields="drafts?.fields"
:loading="busy"
:missing-count="missingQueryCount"
@update="(v) => onModuleUpdate('queryConfig', v)"
@fill-missing="() => fillMissingConfigs(['queryConfig'])"
/>
</div>
@@ -803,12 +793,13 @@ loadModuleTree()
font-size: 13px;
}
/* 操作按钮组(Tabs 的 rightExtra 插槽内) */
.mm-header__actions {
/* 顶部通栏操作条:保存 / 同步字段(位于 tabs 之上,全 tab 生效) */
.mm-main-toolbar {
display: flex;
align-items: center;
gap: 12px;
gap: 8px;
flex: none;
padding: 8px 10px;
}
/* ---- 右侧:配置工作区 ---- */
@@ -897,11 +888,4 @@ loadModuleTree()
transform: rotate(360deg);
}
}
.mm-section-toolbar {
display: flex;
align-items: center;
gap: 8px;
padding-bottom: 8px;
}
</style>