20260905172534
This commit is contained in:
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"
|
||||
|
||||
Reference in new issue
Block a user