20260911173133
This commit is contained in:
1 parent
3838ed74b1
commit
f3ad727f1c
60 files changed
+4971
-6621
No files matched your search
@@ -5,33 +5,48 @@ import { isEmptyValue } from './queryUtils'
|
||||
|
||||
const padDatePart = (number) => String(number).padStart(2, '0')
|
||||
|
||||
export function parseOptions(field) {
|
||||
if (!field?.b_options) return { optionConfig: {}, options: [] }
|
||||
try {
|
||||
const parsed = JSON.parse(field.b_options)
|
||||
let optionConfig = {}
|
||||
let source = []
|
||||
if (Array.isArray(parsed)) {
|
||||
source = parsed
|
||||
} else if (parsed && typeof parsed === 'object') {
|
||||
optionConfig = parsed
|
||||
if (Array.isArray(parsed.options)) {
|
||||
source = parsed.options
|
||||
} else if (Array.isArray(parsed.items)) {
|
||||
source = parsed.items
|
||||
}
|
||||
/** 归一化选项定义:数组 / { options: [] } / { items: [] } */
|
||||
function normalizeOptions(parsed) {
|
||||
let optionConfig = {}
|
||||
let source = []
|
||||
if (Array.isArray(parsed)) {
|
||||
source = parsed
|
||||
} else if (parsed && typeof parsed === 'object') {
|
||||
optionConfig = parsed
|
||||
if (Array.isArray(parsed.options)) {
|
||||
source = parsed.options
|
||||
} else if (Array.isArray(parsed.items)) {
|
||||
source = parsed.items
|
||||
}
|
||||
const options = source.map((option) => {
|
||||
if (option && typeof option === 'object') {
|
||||
const value = option.value ?? option.key ?? option.id
|
||||
return { ...option, value, label: String(option.label ?? option.name ?? value ?? '') }
|
||||
}
|
||||
return { value: option, label: String(option ?? '') }
|
||||
})
|
||||
return { optionConfig, options }
|
||||
} catch {
|
||||
return { optionConfig: {}, options: [] }
|
||||
}
|
||||
const options = source.map((option) => {
|
||||
if (option && typeof option === 'object') {
|
||||
const value = option.value ?? option.key ?? option.id
|
||||
return { ...option, value, label: String(option.label ?? option.name ?? value ?? '') }
|
||||
}
|
||||
return { value: option, label: String(option ?? '') }
|
||||
})
|
||||
return { optionConfig, options }
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析字段选项。
|
||||
* V2:选项定义在界面配置 JSON 节点上(node.options),优先读取;
|
||||
* 兼容旧字段行:field.b_options 为 JSON 字符串。
|
||||
*/
|
||||
export function parseOptions(source) {
|
||||
if (!source) return { optionConfig: {}, options: [] }
|
||||
if (source.options !== undefined && source.options !== null) {
|
||||
return normalizeOptions(source.options)
|
||||
}
|
||||
if (source.b_options) {
|
||||
try {
|
||||
return normalizeOptions(JSON.parse(source.b_options))
|
||||
} catch {
|
||||
return { optionConfig: {}, options: [] }
|
||||
}
|
||||
}
|
||||
return { optionConfig: {}, options: [] }
|
||||
}
|
||||
|
||||
export function formatDateValue(value, withTime = false) {
|
||||
|
||||
@@ -0,0 +1,205 @@
|
||||
/**
|
||||
* 界面配置 JSON → 运行时渲染配置 适配层(s_module_schema.b_schema_json 消费侧)。
|
||||
*
|
||||
* module-management 负责生产 JSON(view/edit/query),本文件负责把 JSON 还原为
|
||||
* fms-module-list / fms-module-edit 已使用的「行/分组」渲染结构,使运行时组件
|
||||
* 无需感知 JSON 节点差异。覆盖:
|
||||
* - view → 列表列配置行(b_field / b_width / b_visible / b_xh,含节点 options)
|
||||
* - edit → 编辑分组 + 编辑行(b_group_id / b_colspan / b_readonly / b_required 等)
|
||||
* - query → 查询条件(field / operator / component / defaultValue)
|
||||
* - 列宽/顺序回写(栏位设置保存)→ 更新 view/edit JSON 节点
|
||||
*/
|
||||
import { loadDataApi } from '@/services/api'
|
||||
import { parseSchema } from '@/utils/schemaJson'
|
||||
|
||||
/** 需要还原的界面配置类型 */
|
||||
const RENDER_SCHEMA_TYPES = ['view', 'edit', 'query']
|
||||
|
||||
function sqlText(value) {
|
||||
return `N'${String(value ?? '').replace(/'/g, "''")}'`
|
||||
}
|
||||
|
||||
/** 加载模块的三类界面配置对象;缺行时回退默认结构,并记录是否已有持久化行 */
|
||||
export async function loadModuleSchemas(moduleId) {
|
||||
const id = String(moduleId || '').trim()
|
||||
const result = {
|
||||
view: parseSchema('view'),
|
||||
edit: parseSchema('edit'),
|
||||
query: parseSchema('query'),
|
||||
existed: { view: false, edit: false, query: false },
|
||||
}
|
||||
if (!id) return result
|
||||
const res = await loadDataApi(
|
||||
's_module_schema',
|
||||
`b_module_id = ${sqlText(id)}`,
|
||||
'b_schema_type ASC',
|
||||
)
|
||||
for (const type of RENDER_SCHEMA_TYPES) {
|
||||
const row = (res.data || []).find((item) => String(item.b_schema_type) === type)
|
||||
result[type] = parseSchema(type, row ? row.b_schema_json : null)
|
||||
result.existed[type] = !!row
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
/** 按文档顺序收集节点树中的所有叶子字段节点(分组节点递归展开) */
|
||||
function collectFieldNodes(nodes) {
|
||||
const out = []
|
||||
const walk = (list) => {
|
||||
for (const node of list || []) {
|
||||
if (!node || typeof node !== 'object') continue
|
||||
if (node.type === 'group') {
|
||||
walk(node.children)
|
||||
continue
|
||||
}
|
||||
if (node.field != null) out.push(node)
|
||||
}
|
||||
}
|
||||
walk(nodes)
|
||||
return out
|
||||
}
|
||||
|
||||
/**
|
||||
* view JSON → 列表配置行(列表页/表格消费)。
|
||||
* 返回结构与旧 s_field_view 行兼容,便于复用既有表格渲染。
|
||||
*/
|
||||
export function buildListConfig(viewSchema) {
|
||||
return collectFieldNodes(viewSchema?.columns || []).map((node, index) => ({
|
||||
b_field: String(node.field),
|
||||
b_width: node.width == null ? null : Number(node.width),
|
||||
b_visible: node.visible === false ? 0 : 1,
|
||||
b_xh: (index + 1) * 10,
|
||||
options: node.options,
|
||||
}))
|
||||
}
|
||||
|
||||
/** 编辑分组 id(JSON 无主键,进入运行时生成临时编码) */
|
||||
let groupSequence = 0
|
||||
function nextGroupId() {
|
||||
groupSequence += 1
|
||||
return `g${Date.now().toString(36)}${groupSequence.toString(36)}`
|
||||
}
|
||||
|
||||
/**
|
||||
* edit JSON → { groups, rows }(编辑弹窗消费)。
|
||||
* groups 为分组节点(b_id/b_title/b_xh),rows 为字段行(含栅格/只读/必填/默认值)。
|
||||
*/
|
||||
export function buildEditRender(editSchema) {
|
||||
const groups = []
|
||||
const rows = []
|
||||
const walk = (list, parentGroupId) => {
|
||||
for (const node of list || []) {
|
||||
if (!node || typeof node !== 'object') continue
|
||||
if (node.type === 'group') {
|
||||
const gid = nextGroupId()
|
||||
groups.push({
|
||||
b_id: gid,
|
||||
b_parent_id: parentGroupId,
|
||||
b_title: node.title || '',
|
||||
b_i18n: node.i18n ?? null,
|
||||
b_xh: (groups.length + 1) * 10,
|
||||
b_canuse: 1,
|
||||
b_colspan: Number(node.colspan) || 48,
|
||||
options: node.options,
|
||||
node,
|
||||
})
|
||||
walk(node.children, gid)
|
||||
continue
|
||||
}
|
||||
if (node.field == null) continue
|
||||
rows.push({
|
||||
b_field: String(node.field),
|
||||
b_group_id: parentGroupId,
|
||||
b_visible: node.visible === false ? 0 : 1,
|
||||
b_required: node.required ? 1 : 0,
|
||||
b_readonly: node.readonly ? 1 : 0,
|
||||
b_disabled: node.disabled ? 1 : 0,
|
||||
b_colspan: Number(node.span) || 24,
|
||||
b_height: node.height ?? null,
|
||||
b_placeholder: node.placeholder ?? null,
|
||||
b_default_value: node.defaultValue ?? null,
|
||||
b_xh: 0,
|
||||
options: node.options,
|
||||
node,
|
||||
})
|
||||
}
|
||||
}
|
||||
walk(editSchema?.children || [], null)
|
||||
rows.forEach((row, index) => {
|
||||
row.b_xh = (index + 1) * 10
|
||||
})
|
||||
return { groups, rows }
|
||||
}
|
||||
|
||||
/** query JSON → 查询条件列表(含 quick 顺序,供页面排序) */
|
||||
export function buildQueryRender(querySchema) {
|
||||
const conditions = []
|
||||
for (const group of querySchema?.groups || []) {
|
||||
for (const condition of group?.conditions || []) {
|
||||
if (condition?.field == null) continue
|
||||
conditions.push({
|
||||
field: String(condition.field),
|
||||
operator: condition.operator || 'like',
|
||||
component: condition.component || '',
|
||||
defaultValue: condition.defaultValue ?? null,
|
||||
options: condition.options,
|
||||
node: condition,
|
||||
})
|
||||
}
|
||||
}
|
||||
const quick = Array.isArray(querySchema?.quick) ? [...querySchema.quick] : []
|
||||
return { quick, conditions }
|
||||
}
|
||||
|
||||
/** 按 quick 顺序优先排列条件(quick 未列出的保持原顺序追加在后) */
|
||||
export function orderQueryConditions(conditions, quick) {
|
||||
if (!quick?.length) return conditions
|
||||
const rank = new Map(quick.map((field, index) => [String(field), index]))
|
||||
return [...conditions].toSorted((a, b) => {
|
||||
const ra = rank.has(a.field) ? rank.get(a.field) : Number.MAX_SAFE_INTEGER
|
||||
const rb = rank.has(b.field) ? rank.get(b.field) : Number.MAX_SAFE_INTEGER
|
||||
return ra - rb
|
||||
})
|
||||
}
|
||||
|
||||
/** 节点(含分组子树)在 settings 顺序中的最小序号,用于同层稳定排序 */
|
||||
function minRank(node, rank) {
|
||||
if (node?.type === 'group') {
|
||||
const ranks = (node.children || []).map((child) => minRank(child, rank)).filter((r) => r != null)
|
||||
return ranks.length ? Math.min(...ranks) : null
|
||||
}
|
||||
const key = String(node?.field)
|
||||
return rank.has(key) ? rank.get(key) : null
|
||||
}
|
||||
|
||||
/**
|
||||
* 栏位设置(列宽/顺序)回写到 view/edit JSON 对象,返回新的配置对象。
|
||||
* 仅调整同层节点顺序并更新 width,保留分组结构与未知扩展属性。
|
||||
*/
|
||||
export function applyColumnSettings(schemaType, schema, settings) {
|
||||
const rootKey = schemaType === 'view' ? 'columns' : 'children'
|
||||
const rank = new Map(settings.map((item, index) => [String(item.b_field), index]))
|
||||
const width = new Map(
|
||||
settings.map((item) => [String(item.b_field), item.b_width]).filter(([, w]) => w != null),
|
||||
)
|
||||
const patch = (nodes) => {
|
||||
const mapped = (nodes || []).map((node) => {
|
||||
if (!node || typeof node !== 'object') return node
|
||||
if (node.type === 'group') return { ...node, children: patch(node.children) }
|
||||
const next = { ...node }
|
||||
const field = String(next.field)
|
||||
if (width.has(field)) next.width = Number(width.get(field))
|
||||
return next
|
||||
})
|
||||
return mapped.toSorted((a, b) => {
|
||||
const ra = minRank(a, rank)
|
||||
const rb = minRank(b, rank)
|
||||
if (ra == null && rb == null) return 0
|
||||
if (ra == null) return 1
|
||||
if (rb == null) return -1
|
||||
return ra - rb
|
||||
})
|
||||
}
|
||||
const base = schema || parseSchema(schemaType)
|
||||
return { ...base, [rootKey]: patch(base[rootKey] || []) }
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
* FmsModuleEditModal —— 元数据驱动的通用新增/编辑弹窗。
|
||||
*
|
||||
* 与 FmsModuleListPage 同族:传 data-code,组件按模块元数据自动渲染编辑表单,
|
||||
* 字段/分组/校验/控件类型全部来自数据库(s_field_edit + s_field_group + s_field)。
|
||||
* 字段/分组/校验/控件类型全部来自数据库(s_module_schema.edit JSON + s_field)。
|
||||
*
|
||||
* 渲染结构对齐表单设计器的 FormPreview(组内 24 栅格):
|
||||
* Form(columns=24) → FormGroup(span=整行, 组内 24 栅格) → FormItem(span=b_colspan)
|
||||
@@ -37,6 +37,7 @@ import { loadDataApi, loadDataBySqlApi, nextIdApi, saveObjectApi } from '@/servi
|
||||
import { diffRow } from '@/utils/dataChanges'
|
||||
import { identifierRe, isEmptyValue } from '@/components/fms-module-common/queryUtils'
|
||||
import { parseOptions } from '@/components/fms-module-common/fieldUtils'
|
||||
import { loadModuleSchemas, buildEditRender } from '@/components/fms-module-common/schemaRender'
|
||||
|
||||
const props = defineProps({
|
||||
/** 受控打开 */
|
||||
@@ -65,8 +66,8 @@ const saving = ref(false)
|
||||
const configError = ref('')
|
||||
const moduleMeta = ref(null) // s_module 行
|
||||
const fields = ref([]) // s_field
|
||||
const groups = ref([]) // s_field_group
|
||||
const editRows = ref([]) // s_field_edit 可见行(含关联字段引用)
|
||||
const groups = ref([]) // 编辑分组节点(由 edit JSON 还原)
|
||||
const editRows = ref([]) // 编辑行(由 edit JSON 还原,含关联字段引用)
|
||||
const formData = ref({})
|
||||
const keyField = ref('b_id')
|
||||
/** 编辑基线(origin):打开弹窗时对 record 深拷贝快照,保存只提交与它的差异;新建模式为 null */
|
||||
@@ -141,24 +142,18 @@ async function loadConfig() {
|
||||
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 = N'${moduleId.replaceAll("'", "''")}'`, 'b_xh ASC, b_field ASC'),
|
||||
// 字段(s_field)+ 编辑界面配置(s_module_schema.edit JSON)
|
||||
const [fieldRes, schemas] = await Promise.all([
|
||||
loadDataApi(
|
||||
's_field_edit',
|
||||
's_field',
|
||||
`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',
|
||||
),
|
||||
loadModuleSchemas(moduleId),
|
||||
])
|
||||
|
||||
moduleMeta.value = module
|
||||
keyField.value = module.b_keyfield || 'b_id'
|
||||
groups.value = groupRes.data || []
|
||||
keyField.value = module.b_key_field || 'b_id'
|
||||
|
||||
// 关联字段信息(字段身份 = 字段列名 b_field)
|
||||
const fieldByField = new Map()
|
||||
@@ -170,9 +165,11 @@ async function loadConfig() {
|
||||
}
|
||||
fields.value = validFields
|
||||
|
||||
// 只保留可见行并注入字段对象
|
||||
// edit JSON → 分组 + 编辑行;只保留可见行并注入字段对象
|
||||
const render = buildEditRender(schemas.edit)
|
||||
groups.value = render.groups
|
||||
const rows = []
|
||||
for (const row of editRes.data || []) {
|
||||
for (const row of render.rows) {
|
||||
if (Number(row.b_visible) !== 1) continue
|
||||
const field = fieldByField.get(String(row.b_field))
|
||||
if (!field) continue
|
||||
@@ -204,10 +201,10 @@ function buildFormData() {
|
||||
data[fieldName] = existing
|
||||
} else if (row.field.b_type === 'checkbox') {
|
||||
data[fieldName] = 0
|
||||
} else if (isEmptyValue(row.field.b_default_value)) {
|
||||
} else if (isEmptyValue(row.b_default_value)) {
|
||||
data[fieldName] = row.field.b_type === 'number' || row.field.b_type === 'money' ? null : ''
|
||||
} else {
|
||||
data[fieldName] = row.field.b_default_value
|
||||
data[fieldName] = row.b_default_value
|
||||
}
|
||||
}
|
||||
formData.value = data
|
||||
@@ -294,9 +291,9 @@ const resolvedWidth = computed(() => {
|
||||
/** 保存过程上下文:beforeSave 阶段准备的数据,buildSaveData / afterSave 阶段消费 */
|
||||
let saveCtx = { isNew: false, row: null, extraUpdates: [] }
|
||||
|
||||
/** 模块保存表(s_module.b_savetable 优先,其次 b_viewtable) */
|
||||
/** 模块保存表(s_module.b_save_table 优先,其次 b_view_table) */
|
||||
function saveTableName() {
|
||||
return String(moduleMeta.value?.b_savetable || moduleMeta.value?.b_viewtable || '')
|
||||
return String(moduleMeta.value?.b_save_table || moduleMeta.value?.b_view_table || '')
|
||||
}
|
||||
|
||||
/** 构造完整合并行(含主键;checkbox→0/1、''→null 归一化),供保存前准备与 diff 使用 */
|
||||
@@ -321,7 +318,7 @@ function collectRowData() {
|
||||
|
||||
/** 保存前校验、数据准备与业务钩子;返回 false 终止保存 */
|
||||
async function beforeSave() {
|
||||
// 必填校验:s_field_edit.b_required=1 且值为空 → 提示并定位
|
||||
// 必填校验:编辑节点 required 且值为空 → 提示并定位
|
||||
for (const editRow of editableRows.value) {
|
||||
if (Number(editRow.b_required) !== 1) continue
|
||||
if (editRow.field.b_type === 'checkbox') continue
|
||||
@@ -346,7 +343,7 @@ async function beforeSave() {
|
||||
!Number(row[props.orderField])
|
||||
) {
|
||||
try {
|
||||
const viewTable = String(moduleMeta.value?.b_viewtable || '')
|
||||
const viewTable = String(moduleMeta.value?.b_view_table || '')
|
||||
if (viewTable) {
|
||||
const res = await loadDataBySqlApi(
|
||||
`SELECT ISNULL(MAX([${props.orderField}]), 0) AS mx FROM [${viewTable}]`,
|
||||
|
||||
@@ -12,6 +12,15 @@ import {
|
||||
escapeSqlText,
|
||||
} from '@/components/fms-module-common/queryUtils'
|
||||
import { parseOptions } from '@/components/fms-module-common/fieldUtils'
|
||||
import {
|
||||
loadModuleSchemas,
|
||||
buildListConfig,
|
||||
buildEditRender,
|
||||
buildQueryRender,
|
||||
orderQueryConditions,
|
||||
applyColumnSettings,
|
||||
} from '@/components/fms-module-common/schemaRender'
|
||||
import { stableStringify } from '@/utils/schemaJson'
|
||||
import FmsModuleTable from './FmsModuleTable.vue'
|
||||
import FmsQueryToolbar from './FmsQueryToolbar.vue'
|
||||
|
||||
@@ -56,6 +65,10 @@ const activeFieldById = shallowRef(new Map())
|
||||
const listConfig = shallowRef([])
|
||||
const editConfigById = shallowRef(new Map())
|
||||
const queryItems = shallowRef([])
|
||||
// 界面配置 JSON(s_module_schema):栏位设置回写时使用
|
||||
const viewSchema = shallowRef(null)
|
||||
const editSchema = shallowRef(null)
|
||||
const schemaExisted = shallowRef({ view: false, edit: false, query: false })
|
||||
const dataSource = shallowRef([])
|
||||
const searchConditions = shallowRef([])
|
||||
const keyField = ref('')
|
||||
@@ -106,7 +119,7 @@ const cellSlotNames = computed(() => Object.keys(slots).filter((name) => name.st
|
||||
|
||||
// ── 模块配置加载 ──
|
||||
function resolveKeyField(module, fields) {
|
||||
if (identifierRe.test(module.b_keyfield || '')) return module.b_keyfield
|
||||
if (identifierRe.test(module.b_key_field || '')) return module.b_key_field
|
||||
for (const field of fields) {
|
||||
if (field.b_field === 'b_id') return field.b_field
|
||||
}
|
||||
@@ -153,59 +166,65 @@ async function loadModuleConfig() {
|
||||
'b_id ASC',
|
||||
)
|
||||
runtimeData = moduleRes.data?.[0]
|
||||
if (!runtimeData || !runtimeData.b_viewtable)
|
||||
if (!runtimeData || !runtimeData.b_view_table)
|
||||
throw new Error('当前路由没有配置可用的数据模块')
|
||||
}
|
||||
|
||||
const dataId = String(runtimeData.b_id || '').trim()
|
||||
// 列显示配置:普通模式取列表配置,可编辑模式取编辑配置,二者只取其一。
|
||||
const listTable = props.editable ? 's_field_edit' : 's_field_view'
|
||||
const responses = await Promise.all([
|
||||
// 元数据:字段(s_field)+ 三类界面配置(s_module_schema JSON)
|
||||
const [fieldRes, schemas] = await Promise.all([
|
||||
loadDataApi('s_field', `b_module_id = N'${escapeSqlText(dataId)}'`, 'b_xh ASC, b_field ASC'),
|
||||
loadDataApi(listTable, `b_module_id = N'${escapeSqlText(dataId)}'`, 'b_xh ASC, b_field ASC'),
|
||||
loadDataApi(
|
||||
's_field_query',
|
||||
`b_module_id = N'${escapeSqlText(dataId)}' AND b_canuse = 1`,
|
||||
'b_xh ASC, b_field ASC',
|
||||
),
|
||||
loadModuleSchemas(dataId),
|
||||
])
|
||||
if (getDataCode() !== code) return false
|
||||
|
||||
// 字符串业务键:字段与布局行均以字段列名 b_field 关联
|
||||
// (s_field_query 主键含 b_field,只引用本模块字段,无跨模块 b_field_module_id)
|
||||
const fields = []
|
||||
const fieldById = new Map()
|
||||
for (const field of responses[0].data || []) {
|
||||
for (const field of fieldRes.data || []) {
|
||||
if (Number(field.b_canuse) !== 1 || !identifierRe.test(field.b_field || '')) continue
|
||||
fields.push(field)
|
||||
fieldById.set(String(field.b_field), field)
|
||||
}
|
||||
if (getDataCode() !== code) return false
|
||||
|
||||
// 可编辑模式下:记录编辑配置的 readonly/disabled,用于生成只读编辑器。
|
||||
// 列显示配置:普通模式取 view JSON,可编辑模式取 edit JSON
|
||||
let listRows = []
|
||||
const editConfigByIdMap = new Map()
|
||||
for (const item of props.editable ? responses[1].data || [] : []) {
|
||||
if (Number(item.b_visible) !== 1) continue
|
||||
if (!fieldById.has(String(item.b_field))) continue
|
||||
editConfigByIdMap.set(String(item.b_field), item)
|
||||
if (props.editable) {
|
||||
const render = buildEditRender(schemas.edit)
|
||||
listRows = render.rows
|
||||
for (const row of render.rows) {
|
||||
if (Number(row.b_visible) !== 1) continue
|
||||
if (!fieldById.has(String(row.b_field))) continue
|
||||
editConfigByIdMap.set(String(row.b_field), row)
|
||||
}
|
||||
} else {
|
||||
listRows = buildListConfig(schemas.view)
|
||||
}
|
||||
editConfigById.value = editConfigByIdMap
|
||||
|
||||
// 列表配置:普通模式为 s_field_view,可编辑模式为 s_field_edit。
|
||||
const lists = []
|
||||
for (const item of responses[1].data || []) {
|
||||
if (item.b_visible !== 1) continue
|
||||
for (const item of listRows) {
|
||||
if (Number(item.b_visible) !== 1) continue
|
||||
if (!fieldById.has(String(item.b_field))) continue
|
||||
lists.push(item)
|
||||
}
|
||||
|
||||
// 查询条件:query JSON(quick 顺序优先)
|
||||
const queryRender = buildQueryRender(schemas.query)
|
||||
const orderedConditions = orderQueryConditions(queryRender.conditions, queryRender.quick)
|
||||
const queries = []
|
||||
for (const config of responses[2].data || []) {
|
||||
const field = fieldById.get(String(config.b_field))
|
||||
for (const condition of orderedConditions) {
|
||||
const field = fieldById.get(condition.field)
|
||||
if (!field) continue
|
||||
const optionInfo = parseOptions(field)
|
||||
const optionInfo = parseOptions({ options: condition.options })
|
||||
queries.push({
|
||||
config,
|
||||
config: {
|
||||
b_field: condition.field,
|
||||
b_operator: condition.operator,
|
||||
b_component: condition.component,
|
||||
b_default_value: condition.defaultValue,
|
||||
},
|
||||
field,
|
||||
optionConfig: optionInfo.optionConfig,
|
||||
options: optionInfo.options,
|
||||
@@ -224,6 +243,9 @@ async function loadModuleConfig() {
|
||||
listConfig.value = lists
|
||||
queryItems.value = queries
|
||||
searchConditions.value = conditions
|
||||
viewSchema.value = schemas.view
|
||||
editSchema.value = schemas.edit
|
||||
schemaExisted.value = schemas.existed
|
||||
keyField.value = resolveKeyField(runtimeData, fields)
|
||||
dirtyRows.value = new Map()
|
||||
newRowKeys.value = new Set()
|
||||
@@ -243,17 +265,17 @@ async function loadModuleConfig() {
|
||||
// ── 数据查询 ──
|
||||
function resolveOrderBy() {
|
||||
if (!dataModule.value) throw new Error('数据模块尚未加载')
|
||||
const configured = String(dataModule.value.b_orderfield || '').trim()
|
||||
const configured = String(dataModule.value.b_order_sql || '').trim()
|
||||
if (configured) return configured
|
||||
if (keyField.value) return `${keyField.value} DESC`
|
||||
return 'b_id DESC'
|
||||
}
|
||||
|
||||
async function fetchData() {
|
||||
if (!dataModule.value || !dataModule.value.b_viewtable) return
|
||||
if (!dataModule.value || !dataModule.value.b_view_table) return
|
||||
|
||||
const currentModule = dataModule.value
|
||||
const viewName = currentModule.b_viewtable
|
||||
const viewName = currentModule.b_view_table
|
||||
const currentCode = getDataCode()
|
||||
const requestVersion = ++dataRequestVersion
|
||||
const conditions = []
|
||||
@@ -307,6 +329,9 @@ async function initialize() {
|
||||
listConfig.value = []
|
||||
editConfigById.value = new Map()
|
||||
queryItems.value = []
|
||||
viewSchema.value = null
|
||||
editSchema.value = null
|
||||
schemaExisted.value = { view: false, edit: false, query: false }
|
||||
searchConditions.value = []
|
||||
keyField.value = ''
|
||||
dirtyRows.value = new Map()
|
||||
@@ -367,34 +392,33 @@ async function saveColumnSettings() {
|
||||
Message.info('当前没有可保存的栏位设置')
|
||||
return
|
||||
}
|
||||
const moduleId = String(dataModule.value?.b_id || '').trim()
|
||||
if (!moduleId) return
|
||||
|
||||
const updates = []
|
||||
for (const row of settings) {
|
||||
// 字符串业务键:布局配置行主键为 (b_module_id, b_field),无独立 b_id
|
||||
updates.push({
|
||||
b_module_id: row.b_module_id,
|
||||
b_field: row.b_field,
|
||||
b_xh: row.b_xh,
|
||||
b_width: row.b_width,
|
||||
})
|
||||
}
|
||||
// V2:栏位设置回写到界面配置 JSON(可编辑模式 → edit,普通模式 → view)
|
||||
const schemaType = props.editable ? 'edit' : 'view'
|
||||
const baseSchema = schemaType === 'edit' ? editSchema.value : viewSchema.value
|
||||
const nextSchema = applyColumnSettings(schemaType, baseSchema, settings)
|
||||
|
||||
columnSaving.value = true
|
||||
try {
|
||||
// 可编辑表格的列来自编辑配置,栏位设置保存到 s_field_edit;普通模式保存到列表配置。
|
||||
const table = props.editable ? 's_field_edit' : 's_field_view'
|
||||
await saveObjectApi([
|
||||
{
|
||||
table,
|
||||
key_field: 'b_module_id,b_field',
|
||||
updates,
|
||||
},
|
||||
])
|
||||
|
||||
const currentByField = new Map()
|
||||
for (const row of listConfig.value) {
|
||||
currentByField.set(String(row.b_field), row)
|
||||
const row = {
|
||||
b_module_id: moduleId,
|
||||
b_schema_type: schemaType,
|
||||
b_schema_json: stableStringify(nextSchema),
|
||||
b_canuse: 1,
|
||||
}
|
||||
const request = { table: 's_module_schema', key_field: 'b_module_id,b_schema_type' }
|
||||
if (schemaExisted.value?.[schemaType]) request.updates = [row]
|
||||
else request.inserts = [row]
|
||||
await saveObjectApi([request])
|
||||
|
||||
if (schemaType === 'edit') editSchema.value = nextSchema
|
||||
else viewSchema.value = nextSchema
|
||||
|
||||
// 本地列表列宽/顺序同步,避免等待整页重载
|
||||
const currentByField = new Map()
|
||||
for (const item of listConfig.value) currentByField.set(String(item.b_field), item)
|
||||
const savedListConfig = []
|
||||
for (const saved of settings) {
|
||||
const current = currentByField.get(String(saved.b_field))
|
||||
@@ -440,7 +464,7 @@ function handleCellChange({ row, field }) {
|
||||
|
||||
function resolveSaveTable() {
|
||||
if (!dataModule.value) throw new Error('数据模块尚未加载')
|
||||
return String(dataModule.value.b_savetable || dataModule.value.b_viewtable || '')
|
||||
return String(dataModule.value.b_save_table || dataModule.value.b_view_table || '')
|
||||
}
|
||||
|
||||
function dirtyUpdateRows() {
|
||||
|
||||
@@ -92,14 +92,15 @@ function buildEditor(field, config) {
|
||||
}
|
||||
if (field.b_type === 'checkbox') return { type: 'checkbox' }
|
||||
if (field.b_type === 'select') {
|
||||
const { options } = parseOptions(field)
|
||||
// V2:选项来自界面配置节点(config.options);兼容旧字段行 b_options
|
||||
const { options } = parseOptions({ options: config?.options, b_options: field.b_options })
|
||||
return { type: 'select', options }
|
||||
}
|
||||
return { type: 'input' }
|
||||
}
|
||||
|
||||
function createRuntimeColumn(config, field) {
|
||||
const optionInfo = parseOptions(field)
|
||||
const optionInfo = parseOptions({ options: config?.options, b_options: field.b_options })
|
||||
const extension = resolveExtension(field.b_field)
|
||||
const { formatter, clickable, cellClassName, onClick: _onClick, onChange, disabled: cellDisabled, ...columnProps } = extension
|
||||
const slot = slots[`cell-${field.b_field}`]
|
||||
|
||||
Reference in new issue
Block a user