20260729173317
This commit is contained in:
1 parent
f6b79ea09a
commit
1c839b707a
26 files changed
+1902
-29
No files matched your search
@@ -27,8 +27,10 @@ import ModuleFieldsPanel from "./components/ModuleFieldsPanel.vue";
|
||||
import ModuleListConfigPanel from "./components/ModuleListConfigPanel.vue";
|
||||
import ModuleEditConfigPanel from "./components/ModuleEditConfigPanel.vue";
|
||||
import ModuleQueryConfigPanel from "./components/ModuleQueryConfigPanel.vue";
|
||||
import ModuleAutoCodePanel from "./components/ModuleAutoCodePanel.vue";
|
||||
import ModulePowersPanel from "./components/ModulePowersPanel.vue";
|
||||
import ModuleI18nPanel from "./components/ModuleI18nPanel.vue";
|
||||
import { createAutoCodeDraft } from "./autoCode";
|
||||
|
||||
// ---- 状态 ----
|
||||
const appStore = useAppStore();
|
||||
@@ -63,6 +65,7 @@ const originals = ref({
|
||||
listConfig: [],
|
||||
editConfig: [],
|
||||
queryConfig: [],
|
||||
autoCode: [],
|
||||
powers: [],
|
||||
});
|
||||
|
||||
@@ -74,6 +77,7 @@ const drafts = ref({
|
||||
listConfig: [],
|
||||
editConfig: [],
|
||||
queryConfig: [],
|
||||
autoCode: [],
|
||||
powers: [],
|
||||
});
|
||||
|
||||
@@ -90,6 +94,7 @@ function setI18nPanelRef(instance) {
|
||||
|
||||
// 当前选中模块对象(从 drafts.module 获取)
|
||||
const selectedModule = computed(() => drafts.value.module);
|
||||
const autoCodeEnabled = computed(() => Number(drafts.value.autoCode?.[0]?.b_canuse) === 1);
|
||||
const busy = computed(() => configLoading.value || configSaving.value || configSyncing.value);
|
||||
const syncDisabled = computed(
|
||||
() => busy.value || !String(selectedModule.value?.b_viewtable || "").trim(),
|
||||
@@ -185,6 +190,7 @@ const visibleTabs = computed(() => {
|
||||
{ key: "list", tab: "列表配置" },
|
||||
{ key: "edit", tab: "编辑配置" },
|
||||
{ key: "query", tab: "查询配置" },
|
||||
{ key: "auto-code", tab: "自动编码" },
|
||||
);
|
||||
}
|
||||
if (type === "page") {
|
||||
@@ -252,6 +258,7 @@ async function loadModuleConfig(moduleId) {
|
||||
let listResponse;
|
||||
let editResponse;
|
||||
let queryResponse;
|
||||
let autoCodeResponse;
|
||||
let powersResponse;
|
||||
|
||||
if (moduleType === "data") {
|
||||
@@ -262,6 +269,7 @@ async function loadModuleConfig(moduleId) {
|
||||
loadDataApi("s_module_field_list", `b_module_id = ${id}`, "b_xh ASC, b_id ASC"),
|
||||
loadDataApi("s_module_field_edit", `b_module_id = ${id}`, "b_xh ASC, b_id ASC"),
|
||||
loadDataApi("s_module_field_query", `b_module_id = ${id}`, "b_xh ASC, b_id ASC"),
|
||||
loadDataApi("s_module_auto_code", `b_module_id = ${id}`, "b_id ASC"),
|
||||
]);
|
||||
moduleResponse = responses[0];
|
||||
fieldsResponse = responses[1];
|
||||
@@ -269,6 +277,7 @@ async function loadModuleConfig(moduleId) {
|
||||
listResponse = responses[3];
|
||||
editResponse = responses[4];
|
||||
queryResponse = responses[5];
|
||||
autoCodeResponse = responses[6];
|
||||
} else if (moduleType === "page") {
|
||||
const responses = await Promise.all([
|
||||
loadDataApi("s_module", `b_id = ${id}`),
|
||||
@@ -289,6 +298,7 @@ async function loadModuleConfig(moduleId) {
|
||||
listConfig: listResponse ? listResponse.data || [] : [],
|
||||
editConfig: editResponse ? editResponse.data || [] : [],
|
||||
queryConfig: queryResponse ? queryResponse.data || [] : [],
|
||||
autoCode: autoCodeResponse ? autoCodeResponse.data || [] : [],
|
||||
powers: powersResponse ? powersResponse.data || [] : [],
|
||||
};
|
||||
originals.value = original;
|
||||
@@ -309,11 +319,20 @@ async function loadModuleConfig(moduleId) {
|
||||
}
|
||||
|
||||
// ---- 树节点选择 ----
|
||||
function onTreeSelect(keys) {
|
||||
function onTreeSelect(keys, info) {
|
||||
if (busy.value) return;
|
||||
if (keys.length > 0) {
|
||||
selectedModuleId.value = String(keys[0]);
|
||||
}
|
||||
const nodeKey = info?.node?.key ?? keys[0];
|
||||
if (nodeKey == null) return;
|
||||
|
||||
const key = String(nodeKey);
|
||||
selectedModuleId.value = key;
|
||||
|
||||
const node = findNode(key);
|
||||
if (!node?.children?.length) return;
|
||||
const expandedKeys = expandedTreeKeys.value.map(String);
|
||||
expandedTreeKeys.value = expandedKeys.includes(key)
|
||||
? expandedKeys.filter((item) => item !== key)
|
||||
: [...expandedKeys, key];
|
||||
}
|
||||
|
||||
watch(selectedModuleId, (id) => {
|
||||
@@ -337,6 +356,128 @@ function onUpdate(section, newData) {
|
||||
drafts.value[section] = newData;
|
||||
}
|
||||
|
||||
function isFieldEnabled(field) {
|
||||
if (!field) return false;
|
||||
return Number(field.b_canuse) === 1;
|
||||
}
|
||||
|
||||
function applyDisabledFieldDefaults(previousFields, nextFields) {
|
||||
const previousEnabledStates = new Map();
|
||||
for (const field of previousFields || []) {
|
||||
if (field.b_id != null) {
|
||||
previousEnabledStates.set(String(field.b_id), isFieldEnabled(field));
|
||||
}
|
||||
}
|
||||
|
||||
const disabledFieldIds = new Set();
|
||||
for (const field of nextFields || []) {
|
||||
if (field.b_id == null) continue;
|
||||
const fieldId = String(field.b_id);
|
||||
if (previousEnabledStates.get(fieldId) && !isFieldEnabled(field)) {
|
||||
disabledFieldIds.add(fieldId);
|
||||
}
|
||||
}
|
||||
if (disabledFieldIds.size === 0) return;
|
||||
|
||||
for (const row of drafts.value.listConfig || []) {
|
||||
if (disabledFieldIds.has(String(row.b_field_id))) row.b_visible = 0;
|
||||
}
|
||||
for (const row of drafts.value.editConfig || []) {
|
||||
if (disabledFieldIds.has(String(row.b_field_id))) row.b_visible = 0;
|
||||
}
|
||||
for (const row of drafts.value.queryConfig || []) {
|
||||
if (disabledFieldIds.has(String(row.b_field_id))) row.b_canuse = 0;
|
||||
}
|
||||
}
|
||||
|
||||
function onFieldsUpdate(newFields) {
|
||||
applyDisabledFieldDefaults(drafts.value.fields, newFields);
|
||||
drafts.value.fields = newFields;
|
||||
}
|
||||
|
||||
function onAutoCodeUpdate(rows) {
|
||||
const previousRule = drafts.value.autoCode?.[0];
|
||||
const previousFieldId =
|
||||
previousRule && Number(previousRule.b_canuse) === 1 ? previousRule.b_field_id : null;
|
||||
drafts.value.autoCode = rows;
|
||||
const rule = rows && rows.length ? rows[0] : null;
|
||||
const nextFieldId = rule && Number(rule.b_canuse) === 1 ? rule.b_field_id : null;
|
||||
if (previousFieldId != null && String(previousFieldId) !== String(nextFieldId)) {
|
||||
const original = (originals.value.editConfig || []).find(
|
||||
(config) => String(config.b_field_id) === String(previousFieldId),
|
||||
);
|
||||
for (const config of drafts.value.editConfig || []) {
|
||||
if (String(config.b_field_id) === String(previousFieldId)) {
|
||||
config.b_readonly = Number(original?.b_readonly) === 1 ? 1 : 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (nextFieldId == null) return;
|
||||
for (const config of drafts.value.editConfig || []) {
|
||||
if (String(config.b_field_id) === String(nextFieldId)) {
|
||||
config.b_readonly = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function setAutoCodeEnabled(enabled) {
|
||||
const current = drafts.value.autoCode?.[0];
|
||||
const rule = current
|
||||
? { ...current, b_canuse: enabled ? 1 : 0 }
|
||||
: createAutoCodeDraft(selectedModule.value?.b_id, drafts.value.fields, enabled);
|
||||
onAutoCodeUpdate([rule]);
|
||||
}
|
||||
|
||||
function validateAutoCode() {
|
||||
const rows = drafts.value.autoCode || [];
|
||||
const rule = rows.length ? rows[0] : null;
|
||||
if (!rule || Number(rule.b_canuse) !== 1) return "";
|
||||
if (!String(selectedModule.value?.b_savetable || "").trim()) {
|
||||
return "启用自动编码前请先配置保存表";
|
||||
}
|
||||
const field = (drafts.value.fields || []).find(
|
||||
(item) => String(item.b_id) === String(rule.b_field_id),
|
||||
);
|
||||
if (!field || Number(field.b_canuse) !== 1) return "请选择已启用的业务编号字段";
|
||||
if (field.b_type !== "input" && field.b_type !== "textarea") {
|
||||
return "业务编号字段必须使用文本控件类型";
|
||||
}
|
||||
if (!Number.isInteger(Number(rule.b_start_value)) || Number(rule.b_start_value) < 0) {
|
||||
return "起始值必须是大于或等于 0 的整数";
|
||||
}
|
||||
if (!["none", "year", "month", "day"].includes(rule.b_reset_type)) {
|
||||
return "请选择正确的重置周期";
|
||||
}
|
||||
const width = Number(rule.b_sequence_width);
|
||||
if (!Number.isInteger(width) || width < 1 || width > 18) {
|
||||
return "流水号位数必须是 1 到 18 之间的整数";
|
||||
}
|
||||
if (String(rule.b_prefix || "").length > 100) return "固定前缀长度不能超过 100 个字符";
|
||||
if (String(rule.b_separator || "").length > 10) return "分隔符长度不能超过 10 个字符";
|
||||
const dateFormat = String(rule.b_date_format || "").trim();
|
||||
if (dateFormat.length > 30) return "日期格式长度不能超过 30 个字符";
|
||||
const dateLiterals = dateFormat
|
||||
.replaceAll("yyyy", "")
|
||||
.replaceAll("yy", "")
|
||||
.replaceAll("MM", "")
|
||||
.replaceAll("dd", "");
|
||||
if (/[A-Za-z]/.test(dateLiterals)) return "日期格式只支持 yyyy、yy、MM 和 dd";
|
||||
const hasYear = dateFormat.includes("yyyy") || dateFormat.includes("yy");
|
||||
const hasMonth = dateFormat.includes("MM");
|
||||
const hasDay = dateFormat.includes("dd");
|
||||
if (rule.b_reset_type === "year" && !hasYear) return "按年重置时,日期格式必须包含年份";
|
||||
if (rule.b_reset_type === "month" && (!hasYear || !hasMonth)) {
|
||||
return "按月重置时,日期格式必须包含年份和月份";
|
||||
}
|
||||
if (rule.b_reset_type === "day" && (!hasYear || !hasMonth || !hasDay)) {
|
||||
return "按日重置时,日期格式必须包含年月日";
|
||||
}
|
||||
for (const config of drafts.value.editConfig || []) {
|
||||
if (String(config.b_field_id) === String(rule.b_field_id)) config.b_readonly = 1;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
function onSetField(field, value) {
|
||||
if (drafts.value.module) {
|
||||
drafts.value.module[field] = value;
|
||||
@@ -388,6 +529,7 @@ async function onAddModule(parentId, moduleType = "directory") {
|
||||
listConfig: [],
|
||||
editConfig: [],
|
||||
queryConfig: [],
|
||||
autoCode: [],
|
||||
powers: [],
|
||||
};
|
||||
drafts.value = cloneData(originals.value);
|
||||
@@ -469,6 +611,7 @@ async function onDeleteNodeById(moduleId) {
|
||||
deleteByModuleId("s_module_field_list"),
|
||||
deleteByModuleId("s_module_field_edit"),
|
||||
deleteByModuleId("s_module_field_query"),
|
||||
deleteByModuleId("s_module_auto_code"),
|
||||
deleteByModuleId("s_module_power"),
|
||||
deleteByModuleId("s_module_field"),
|
||||
deleteByModuleId("s_module_field_group"),
|
||||
@@ -497,6 +640,12 @@ async function saveAll() {
|
||||
try {
|
||||
const saveReqs = [];
|
||||
|
||||
const autoCodeError = validateAutoCode();
|
||||
if (autoCodeError) {
|
||||
message.warning(autoCodeError);
|
||||
return;
|
||||
}
|
||||
|
||||
// s_module 主表
|
||||
const moduleData = drafts.value.module;
|
||||
const moduleOriginal = originals.value.module;
|
||||
@@ -543,18 +692,25 @@ async function saveAll() {
|
||||
saveReqs.push(moduleRequest);
|
||||
}
|
||||
|
||||
// 子表:fields, listConfig, editConfig, queryConfig, powers
|
||||
// 子表:fields, listConfig, editConfig, queryConfig, autoCode, powers
|
||||
const subTables = [
|
||||
["s_module_field", "fields"],
|
||||
["s_module_field_list", "listConfig"],
|
||||
["s_module_field_edit", "editConfig"],
|
||||
["s_module_field_query", "queryConfig"],
|
||||
["s_module_auto_code", "autoCode"],
|
||||
["s_module_power", "powers"],
|
||||
];
|
||||
for (const [table, section] of subTables) {
|
||||
const current = drafts.value[section] || [];
|
||||
const previous = originals.value[section] || [];
|
||||
const changes = diffRows(current, previous);
|
||||
if (table === "s_module_auto_code") {
|
||||
changes.updates = changes.updates.map((row) => {
|
||||
const { b_current_period: _period, b_current_value: _value, ...config } = row;
|
||||
return config;
|
||||
});
|
||||
}
|
||||
const req = tableChange(table, changes);
|
||||
if (hasChanges(req)) {
|
||||
await allocateTemporaryIds([req.inserts || [], req.updates || [], req.deletes || []]);
|
||||
@@ -654,6 +810,7 @@ function buildMissingDefaultConfigs(module, fields) {
|
||||
b_required: 0,
|
||||
b_readonly: 0,
|
||||
b_disabled: 0,
|
||||
b_visible: 1,
|
||||
b_group_id: null,
|
||||
b_xh: order,
|
||||
});
|
||||
@@ -787,6 +944,7 @@ async function syncFields() {
|
||||
}
|
||||
}
|
||||
|
||||
applyDisabledFieldDefaults(existingFields, mergedFields);
|
||||
const generated = buildMissingDefaultConfigs(module, mergedFields);
|
||||
const generatedSections = ["listConfig", "editConfig", "queryConfig"];
|
||||
let generatedCount = 0;
|
||||
@@ -898,6 +1056,15 @@ void loadTree().catch((e) => message.error("模块树加载失败:" + (e.messa
|
||||
:disabled="busy || drafts.module?.b_module_type === 'data'"
|
||||
@update:checked="(v) => onSetField('b_canmenu', v ? 1 : 0)"
|
||||
/>
|
||||
<template v-if="drafts.module?.b_module_type === 'data'">
|
||||
<a-divider type="vertical" />
|
||||
<span>自动编码</span>
|
||||
<a-checkbox
|
||||
:checked="autoCodeEnabled"
|
||||
:disabled="busy"
|
||||
@update:checked="setAutoCodeEnabled"
|
||||
/>
|
||||
</template>
|
||||
</a-space>
|
||||
</div>
|
||||
</div>
|
||||
@@ -926,7 +1093,7 @@ void loadTree().catch((e) => message.error("模块树加载失败:" + (e.messa
|
||||
:module-code="selectedModule?.b_code || ''"
|
||||
:fields="drafts.fields"
|
||||
:loading="busy"
|
||||
@update="(v) => onUpdate('fields', v)"
|
||||
@update="onFieldsUpdate"
|
||||
@i18n-saved="onI18nSaved"
|
||||
/>
|
||||
<ModuleListConfigPanel
|
||||
@@ -959,6 +1126,14 @@ void loadTree().catch((e) => message.error("模块树加载失败:" + (e.messa
|
||||
:loading="busy"
|
||||
@update="(v) => onUpdate('queryConfig', v)"
|
||||
/>
|
||||
<ModuleAutoCodePanel
|
||||
v-else-if="tab.key === 'auto-code'"
|
||||
:module-id="String(selectedModule.b_id)"
|
||||
:auto-code="drafts.autoCode"
|
||||
:fields="drafts.fields"
|
||||
:loading="busy"
|
||||
@update="onAutoCodeUpdate"
|
||||
/>
|
||||
<ModulePowersPanel
|
||||
v-else-if="tab.key === 'powers'"
|
||||
:module-id="String(selectedModule.b_id)"
|
||||
|
||||
Reference in new issue
Block a user