20260905172534

This commit is contained in:
oneao committed 2026-09-05 17:25:35 +08:00
1 parent 1b01a31252
commit 7b00eeb88c
711 files changed
+2849 -959

No files matched your search

@@ -41,7 +41,7 @@ import { parseOptions } from '@/components/fms-module-common/fieldUtils'
const props = defineProps({
/** 受控打开 */
open: { type: Boolean, default: false },
/** 模块编码(s_module.b_code),必填 */
/** 模块编码(s_module.b_id,即字符串业务键主键),必填 */
dataCode: { type: String, default: '' },
/** 编辑对象(含主键等现有值);null/undefined 表示新增 */
record: { type: Object, default: null },
@@ -72,10 +72,39 @@ const keyField = ref('b_id')
/** 编辑基线(origin):打开弹窗时对 record 深拷贝快照,保存只提交与它的差异;新建模式为 null */
const originRef = ref(null)
const isNewMode = computed(() => !props.record)
/* 业务键主键支持:新增且主键字段未被配置进表单时,自动追加主键输入行
* (字符串业务键模块如 s_i18n_type 需用户录入编码;已配置则原样展示) */
const editableRows = computed(() => {
const rows = [...editRows.value]
if (
isNewMode.value &&
keyField.value &&
!rows.some((row) => row.field.b_field === keyField.value)
) {
const keyRowField = fields.value.find((field) => field.b_field === keyField.value)
if (keyRowField) {
rows.unshift({
b_module_id: moduleMeta.value?.b_id ?? null,
b_field: keyField.value,
b_visible: 1,
b_required: 1,
b_readonly: 0,
b_disabled: 0,
b_colspan: 24,
b_placeholder: '主键/编码,新增必填',
field: keyRowField,
})
}
}
return rows
})
/* ================= 分组结构推导(与 FormPreview 一致) ================= */
const sections = computed(() => {
const byGroup = new Map()
const sortedRows = [...editRows.value].sort((a, b) => (a.b_xh || 0) - (b.b_xh || 0))
const sortedRows = [...editableRows.value].sort((a, b) => (a.b_xh || 0) - (b.b_xh || 0))
for (const row of sortedRows) {
const gid = row.b_group_id != null ? String(row.b_group_id) : ''
if (!byGroup.has(gid)) byGroup.set(gid, [])
@@ -105,30 +134,39 @@ async function loadConfig() {
try {
const moduleRes = await loadDataApi(
's_module',
`b_code = N'${code.replaceAll("'", "''")}' AND b_module_type = 'data' AND b_canuse = 1`,
`b_id = N'${code.replaceAll("'", "''")}' AND b_module_type = 'data' AND b_canuse = 1`,
'b_id ASC',
)
const module = moduleRes.data?.[0]
if (!module) throw new Error(`未找到编码为 ${code} 的启用数据模块`)
const moduleId = String(module.b_id)
// 字符串业务键:模块与字段/布局行均以编码/列名字符串关联
const [fieldRes, editRes, groupRes] = await Promise.all([
loadDataApi('s_field', `b_module_id = ${moduleId}`, 'b_id ASC'),
loadDataApi('s_field_edit', `b_module_id = ${moduleId}`, 'b_xh ASC, b_id ASC'),
loadDataApi('s_field_group', `b_module_id = ${moduleId}`, 'b_xh ASC, b_id ASC'),
loadDataApi('s_field', `b_module_id = N'${moduleId.replaceAll("'", "''")}'`, 'b_xh ASC, b_field ASC'),
loadDataApi(
's_field_edit',
`b_module_id = N'${moduleId.replaceAll("'", "''")}'`,
'b_xh ASC, b_field ASC',
),
loadDataApi(
's_field_group',
`b_module_id = N'${moduleId.replaceAll("'", "''")}'`,
'b_xh ASC, b_id ASC',
),
])
moduleMeta.value = module
keyField.value = module.b_keyfield || 'b_id'
groups.value = groupRes.data || []
// 关联字段信息
const fieldById = new Map()
// 关联字段信息(字段身份 = 字段列名 b_field)
const fieldByField = new Map()
const validFields = []
for (const field of fieldRes.data || []) {
if (Number(field.b_canuse) !== 1) continue
validFields.push(field)
fieldById.set(String(field.b_id), field)
fieldByField.set(String(field.b_field), field)
}
fields.value = validFields
@@ -136,7 +174,7 @@ async function loadConfig() {
const rows = []
for (const row of editRes.data || []) {
if (Number(row.b_visible) !== 1) continue
const field = fieldById.get(String(row.b_field_id))
const field = fieldByField.get(String(row.b_field))
if (!field) continue
rows.push({ ...row, field })
}
@@ -159,9 +197,8 @@ function buildFormData() {
originRef.value = isNew ? null : JSON.parse(JSON.stringify(props.record || {}))
const source = props.record || {}
const data = {}
for (const row of editRows.value) {
for (const row of editableRows.value) {
const fieldName = row.field.b_field
if (fieldName === keyField.value) continue // 主键不参与表单
const existing = source[fieldName]
if (existing !== undefined && existing !== null) {
data[fieldName] = existing
@@ -185,7 +222,8 @@ watch(
/* ================= 字段级禁用(编辑配置 readonly/disabled + 主键 + 页面动态规则) ================= */
function isFieldDisabled(row) {
if (row.field.b_field === keyField.value) return true
// 字符串业务键:新增时主键可录入(语言编码等),已保存记录主键锁定
if (row.field.b_field === keyField.value) return !isNewMode.value
if (Number(row.b_readonly) === 1 || Number(row.b_disabled) === 1) return true
if (props.fieldDisabled) {
return Boolean(
@@ -266,7 +304,8 @@ function collectRowData() {
const isNew = !props.record
const row = {}
if (isNew)
row[keyField.value] = null // 主键待 nextIdApi 分配
// 字符串业务键主键由用户在表单录入;未配置主键行时留空(由下方雪花兜底)
row[keyField.value] = formData.value[keyField.value] ?? ''
else row[keyField.value] = props.record[keyField.value]
for (const editRow of editRows.value) {
@@ -283,7 +322,7 @@ function collectRowData() {
/** 保存前校验、数据准备与业务钩子;返回 false 终止保存 */
async function beforeSave() {
// 必填校验:s_field_edit.b_required=1 且值为空 → 提示并定位
for (const editRow of editRows.value) {
for (const editRow of editableRows.value) {
if (Number(editRow.b_required) !== 1) continue
if (editRow.field.b_type === 'checkbox') continue
const value = formData.value[editRow.field.b_field]
@@ -319,8 +358,13 @@ async function beforeSave() {
}
}
// 新增时分配主键
if (isNew && !row[keyField.value]) {
// 新增:业务键主键必填(模块定义了主键字段);未定义主键字段时回退雪花自增
if (isNew && !String(row[keyField.value] || '').trim()) {
const hasKeyRow = fields.value.some((field) => field.b_field === keyField.value)
if (hasKeyRow) {
Message.warning(`请填写主键/编码「${keyField.value}」`)
return false
}
row[keyField.value] = String((await nextIdApi()).data)
}
@@ -428,8 +472,8 @@ const selectOptionsOf = (field) => parseOptions(field).options
:columns="24"
>
<FormItem
v-for="row in section.rows.filter((r) => r.field.b_field !== keyField)"
:key="row.b_id"
v-for="row in section.rows"
:key="row.b_field || row.field.b_field"
:name="row.field.b_field"
:label="fieldLabel(row)"
:required="Number(row.b_required) === 1"