20260727225141
This commit is contained in:
1 parent
9dbaef7787
commit
63588bd217
97 files changed
+1309
-145
No files matched your search
@@ -13,7 +13,12 @@ import {
|
||||
hasChanges,
|
||||
} from "@/utils/dataChanges";
|
||||
import { createTempId } from "@/utils/tempId";
|
||||
import { buildModuleItemI18nKey, syncModuleItemI18nKeys } from "@/utils/i18n";
|
||||
import {
|
||||
buildModuleI18nKey,
|
||||
buildModuleItemI18nKey,
|
||||
syncModuleItemI18nKeys,
|
||||
validateModuleCode,
|
||||
} from "@/utils/i18n";
|
||||
import { Plus } from "@lucide/vue";
|
||||
import ModuleBasicPanel from "./components/ModuleBasicPanel.vue";
|
||||
import ModuleFieldsPanel from "./components/ModuleFieldsPanel.vue";
|
||||
@@ -95,17 +100,61 @@ const isCurrentModule = computed(
|
||||
() =>
|
||||
loadedModuleId.value != null && String(loadedModuleId.value) === String(selectedModuleId.value),
|
||||
);
|
||||
const i18nKeys = computed(() => {
|
||||
const keys = new Set();
|
||||
const add = (key) => {
|
||||
if (key) keys.add(String(key));
|
||||
// 构建受管多语言项。managedSource 提供模块/字段/权限的受管键来源,
|
||||
// plainSource 提供分组/列表标题等非受管键来源(手动填写,需即时反馈)。
|
||||
function buildI18nItems(managedSource, plainSource) {
|
||||
const items = new Map();
|
||||
const add = (item) => {
|
||||
if (!item.key) return;
|
||||
const key = String(item.key);
|
||||
const existing = items.get(key);
|
||||
items.set(key, existing?.managed ? existing : { ...item, key });
|
||||
};
|
||||
add(drafts.value.module?.b_i18n);
|
||||
for (const section of ["fields", "groups", "listConfig", "powers"]) {
|
||||
for (const row of drafts.value[section] || []) add(row.b_i18n);
|
||||
|
||||
const module = managedSource.module;
|
||||
if (module?.b_code) {
|
||||
const moduleKey = buildModuleI18nKey(module.b_module_type, module.b_code);
|
||||
add({
|
||||
id: `module:${module.b_id}`,
|
||||
key: moduleKey,
|
||||
sourceKey: module.b_i18n,
|
||||
defaultValue: module.b_name || module.b_code,
|
||||
managed: true,
|
||||
});
|
||||
}
|
||||
return [...keys];
|
||||
});
|
||||
for (const field of managedSource.fields || []) {
|
||||
add({
|
||||
id: `field:${field.b_id}`,
|
||||
key: buildModuleItemI18nKey("field", module?.b_code, field.b_field),
|
||||
sourceKey: field.b_i18n,
|
||||
defaultValue: field.b_name || field.b_field,
|
||||
managed: true,
|
||||
});
|
||||
}
|
||||
for (const power of managedSource.powers || []) {
|
||||
add({
|
||||
id: `power:${power.b_id}`,
|
||||
key: buildModuleItemI18nKey("power", module?.b_code, power.b_code),
|
||||
sourceKey: power.b_i18n,
|
||||
defaultValue: power.b_name || power.b_code,
|
||||
managed: true,
|
||||
});
|
||||
}
|
||||
|
||||
// 分组和列表标题仍显示在本模块的多语言面板中,但不是系统生成的受管键。
|
||||
for (const section of ["groups", "listConfig"]) {
|
||||
for (const row of plainSource[section] || []) {
|
||||
add({ key: row.b_i18n, managed: false });
|
||||
}
|
||||
}
|
||||
return [...items.values()];
|
||||
}
|
||||
|
||||
// 实时展示:受管键基于已保存快照(originals),编辑过程中不随草稿实时生成;
|
||||
// 非受管键(分组/列表标题)基于草稿,保留手动编辑的即时反馈。
|
||||
const i18nItems = computed(() => buildI18nItems(originals.value, drafts.value));
|
||||
// 保存时:受管键基于最终草稿态(drafts),此时才按模块编码生成并落库。
|
||||
const finalI18nItems = computed(() => buildI18nItems(drafts.value, drafts.value));
|
||||
const referencedGroupIds = computed(() => {
|
||||
const ids = new Set();
|
||||
for (const section of ["listConfig", "editConfig"]) {
|
||||
@@ -435,7 +484,24 @@ async function onDeleteNodeById(moduleId) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await saveObjectApi([{ table: "s_module", key_field: "b_id", deletes: [{ b_id: moduleId }] }]);
|
||||
const id = String(moduleId);
|
||||
const deleteByModuleId = (table) => ({
|
||||
table,
|
||||
key_field: "b_module_id",
|
||||
deletes: [{ b_module_id: id }],
|
||||
});
|
||||
|
||||
await saveObjectApi([
|
||||
deleteByModuleId("b_user_module"),
|
||||
deleteByModuleId("b_user_power"),
|
||||
deleteByModuleId("s_module_field_list"),
|
||||
deleteByModuleId("s_module_field_edit"),
|
||||
deleteByModuleId("s_module_field_query"),
|
||||
deleteByModuleId("s_module_power"),
|
||||
deleteByModuleId("s_module_field"),
|
||||
deleteByModuleId("s_module_field_group"),
|
||||
{ table: "s_module", key_field: "b_id", deletes: [{ b_id: id }] },
|
||||
]);
|
||||
message.success("模块已删除");
|
||||
if (selectedModuleId.value === moduleId) {
|
||||
selectedModuleId.value = null;
|
||||
@@ -460,10 +526,16 @@ async function saveAll() {
|
||||
// s_module 主表
|
||||
const moduleData = drafts.value.module;
|
||||
const moduleOriginal = originals.value.module;
|
||||
if (!String(moduleData?.b_code || "").trim()) {
|
||||
const moduleCode = String(moduleData?.b_code || "").trim();
|
||||
if (!moduleCode) {
|
||||
message.warning(`请填写${moduleData?.b_module_type === "data" ? "模块编码" : "菜单编码"}`);
|
||||
return;
|
||||
}
|
||||
const codeError = validateModuleCode(moduleCode);
|
||||
if (codeError) {
|
||||
message.error(`编码格式不正确:${codeError}`);
|
||||
return;
|
||||
}
|
||||
if (!String(moduleData?.b_name || "").trim()) {
|
||||
message.warning("请填写模块名称");
|
||||
return;
|
||||
@@ -478,6 +550,7 @@ async function saveAll() {
|
||||
}
|
||||
syncModuleItemI18nKeys(drafts.value.fields, "field", moduleData.b_code, "b_field");
|
||||
syncModuleItemI18nKeys(drafts.value.powers, "power", moduleData.b_code, "b_code");
|
||||
moduleData.b_i18n = buildModuleI18nKey(moduleData.b_module_type, moduleData.b_code);
|
||||
const isNew = !moduleOriginal?.b_code;
|
||||
if (moduleData && JSON.stringify(moduleData) !== JSON.stringify(moduleOriginal)) {
|
||||
saveReqs.push({
|
||||
@@ -502,6 +575,13 @@ async function saveAll() {
|
||||
const req = tableChange(table, changes);
|
||||
if (hasChanges(req)) {
|
||||
await allocateTemporaryIds([req.inserts || [], req.updates || [], req.deletes || []]);
|
||||
if (table === "s_module_power" && changes.deletes.length) {
|
||||
saveReqs.push({
|
||||
table: "b_user_power",
|
||||
key_field: "b_power_id",
|
||||
deletes: changes.deletes.map(({ b_id }) => ({ b_power_id: String(b_id) })),
|
||||
});
|
||||
}
|
||||
saveReqs.push(req);
|
||||
}
|
||||
}
|
||||
@@ -510,6 +590,10 @@ async function saveAll() {
|
||||
if (currentOperationId !== operationId || String(selectedModule.value?.b_id) !== moduleId)
|
||||
return;
|
||||
const i18nPanel = i18nPanelRef.value;
|
||||
if (i18nPanel && typeof i18nPanel.reconcileManagedRows === "function") {
|
||||
// 保存时才按最终草稿态生成受管键(模块编码/字段/权限),避免编辑过程中实时生成。
|
||||
i18nPanel.reconcileManagedRows(finalI18nItems.value);
|
||||
}
|
||||
if (typeof i18nPanel?.buildSaveRequest === "function") {
|
||||
const i18nReq = await i18nPanel.buildSaveRequest();
|
||||
if (i18nReq) saveReqs.push(i18nReq);
|
||||
@@ -859,19 +943,6 @@ void loadTree().catch((e) => message.error("模块树加载失败:" + (e.messa
|
||||
/>
|
||||
</a-space>
|
||||
</div>
|
||||
<span class="mm-header-title">{{
|
||||
selectedModule.b_name || selectedModule.b_code
|
||||
}}</span>
|
||||
<span class="mm-header-code">{{ selectedModule.b_code || "(未设置编码)" }}</span>
|
||||
<span class="mm-header-type">
|
||||
<a-tag>{{
|
||||
selectedModule.b_module_type === "directory"
|
||||
? "目录"
|
||||
: selectedModule.b_module_type === "page"
|
||||
? "页面"
|
||||
: "数据"
|
||||
}}</a-tag>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- Tab 面板 -->
|
||||
@@ -943,7 +1014,7 @@ void loadTree().catch((e) => message.error("模块树加载失败:" + (e.messa
|
||||
v-else-if="tab.key === 'i18n'"
|
||||
:ref="setI18nPanelRef"
|
||||
:module-id="String(selectedModule.b_id)"
|
||||
:i18n-keys="i18nKeys"
|
||||
:i18n-items="i18nItems"
|
||||
:loading="busy"
|
||||
/>
|
||||
</a-tab-pane>
|
||||
@@ -1051,22 +1122,6 @@ void loadTree().catch((e) => message.error("模块树加载失败:" + (e.messa
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.mm-header-title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: var(--fms-text);
|
||||
}
|
||||
|
||||
.mm-header-code {
|
||||
font-size: 13px;
|
||||
color: var(--fms-text-secondary);
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
.mm-header-type {
|
||||
flex: none;
|
||||
}
|
||||
|
||||
.mm-body {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
|
||||
Reference in new issue
Block a user