feat(module-management): 字段定义面板增加 表单/列表/查询 参与开关
跨 tab 的「字段参与了哪些界面」在字段定义一行内表达并可就地切换, tab 结构不变。「参与是选择不是缺失」——不引入任何完整性提示。 - 语义沿用 fieldAreaDefaults 既有约定:行存在=已配置,行内开关=是否参与 (表单/列表 b_visible、查询 b_canuse);关=置 0 不删行,保留画布布局与既有查询配置 - fieldParticipation.js(纯逻辑):判定与切换;行不存在时按默认工厂生成且强制参与 (显式意愿覆盖大文本默认 参与=0),表单新行 b_colspan=24 追加到末尾序号 - fieldAreaDefaults 增加列表/查询默认行工厂,useModuleConfig.buildMissingDefaultConfigs 改用工厂——「同步字段自动补全」与「手动打开开关」生成的行结构同源 - ParticipationCell(h 渲染 ui Switch)接 FmsTable customCell;表单列仅 data 模块展示 - 新 spec field-participation 9 用例:判定/两路切换/大文本强制参与/不变性
This commit is contained in:
1 parent
08646c547f
commit
f019a1c1ac
8 files changed
+363
-26
No files matched your search
+73
-3
@@ -2,21 +2,45 @@
|
||||
/**
|
||||
* 字段定义面板(s_field):可编辑表格维护模块字段。
|
||||
* i18n 键按 field.{moduleCode}.{fieldName} 自动同步。
|
||||
* 表单/列表/查询三列为「参与开关」:在一行内表达该字段参与了哪些界面,
|
||||
* 开关即改即生效(生成/隐藏默认配置行);布局细节仍在对应设计器调整。
|
||||
* 语义见 fieldParticipation.js(沿用 fieldAreaDefaults 的行内开关约定)。
|
||||
*/
|
||||
import { ref, shallowRef, watch } from 'vue'
|
||||
import FmsTable from '@/components/fms-table/FmsTable.vue'
|
||||
import { buildModuleItemI18nKey, syncModuleItemI18nKeys } from '@/utils/i18n'
|
||||
import I18nQuickSetModal from './I18nQuickSetModal.vue'
|
||||
import { createI18nKeyCell } from './I18nKeyCell'
|
||||
import { createParticipationCell } from './ParticipationCell'
|
||||
import {
|
||||
isFormOn,
|
||||
isListOn,
|
||||
isQueryOn,
|
||||
toggleForm,
|
||||
toggleList,
|
||||
toggleQuery,
|
||||
} from '../fieldParticipation'
|
||||
|
||||
const props = defineProps({
|
||||
moduleId: { type: String, required: true },
|
||||
moduleCode: { type: String, default: '' },
|
||||
fields: { type: Array, default: () => [] },
|
||||
/** 参与开关所需的三个配置草稿(由 index.vue 传入,切换后事件回写) */
|
||||
editConfig: { type: Array, default: () => [] },
|
||||
listConfig: { type: Array, default: () => [] },
|
||||
queryConfig: { type: Array, default: () => [] },
|
||||
/** 模块类型:表单参与列仅 data 模块展示(查询模块无表单设计) */
|
||||
moduleType: { type: String, default: null },
|
||||
loading: { type: Boolean, default: false },
|
||||
})
|
||||
|
||||
const emit = defineEmits(['update', 'i18nSaved'])
|
||||
const emit = defineEmits([
|
||||
'update',
|
||||
'i18nSaved',
|
||||
'updateEditConfig',
|
||||
'updateListConfig',
|
||||
'updateQueryConfig',
|
||||
])
|
||||
|
||||
const FIELD_TYPES = [
|
||||
{ label: '输入框', value: 'input' },
|
||||
@@ -74,7 +98,41 @@ function openI18n(row) {
|
||||
|
||||
const I18nKeyCell = createI18nKeyCell({ onOpen: openI18n })
|
||||
|
||||
const columns = shallowRef([
|
||||
/* ---------- 参与开关(表单/列表/查询) ---------- */
|
||||
/* 字段行 → 配置行:字段定义行的 b_id 与配置行的 b_field_id 对应;
|
||||
字段本身未启用时开关禁用(停用字段运行时不显示,参与无意义) */
|
||||
|
||||
function onToggleForm(field) {
|
||||
if (props.loading) return
|
||||
emit('updateEditConfig', toggleForm(props.editConfig, field, props.moduleId))
|
||||
}
|
||||
|
||||
function onToggleList(field) {
|
||||
if (props.loading) return
|
||||
emit('updateListConfig', toggleList(props.listConfig, field, props.moduleId))
|
||||
}
|
||||
|
||||
function onToggleQuery(field) {
|
||||
if (props.loading) return
|
||||
emit('updateQueryConfig', toggleQuery(props.queryConfig, field, props.moduleId))
|
||||
}
|
||||
|
||||
const FormCell = createParticipationCell({ isOn: (f) => isFormOn(props.editConfig, f), onToggle: onToggleForm, title: '参与表单' })
|
||||
const ListCell = createParticipationCell({ isOn: (f) => isListOn(props.listConfig, f), onToggle: onToggleList, title: '参与列表显示' })
|
||||
const QueryCell = createParticipationCell({ isOn: (f) => isQueryOn(props.queryConfig, f), onToggle: onToggleQuery, title: '作为查询条件' })
|
||||
|
||||
const columns = shallowRef(buildColumns())
|
||||
|
||||
// 列宽拖拽结果随 v-model 写回 columns,仅在模块类型变化时重建
|
||||
watch(
|
||||
() => props.moduleType,
|
||||
() => {
|
||||
columns.value = buildColumns()
|
||||
},
|
||||
)
|
||||
|
||||
function buildColumns() {
|
||||
const baseColumns = [
|
||||
{ dataIndex: 'b_field', title: '字段名', width: 150 },
|
||||
{ dataIndex: 'b_name', title: '字段名称', width: 140, editor: { type: 'input' } },
|
||||
{
|
||||
@@ -97,6 +155,16 @@ const columns = shallowRef([
|
||||
},
|
||||
{ dataIndex: 'b_default_value', title: '默认值', width: 120, editor: { type: 'input' } },
|
||||
{ dataIndex: 'b_i18n', title: '多语言键', width: 220, customCell: I18nKeyCell },
|
||||
]
|
||||
// 表单参与列仅数据模块展示(查询模块无表单设计)
|
||||
const participationColumns = [
|
||||
...(props.moduleType === 'data'
|
||||
? [{ dataIndex: '__form', title: '表单', width: 64, align: 'center', customCell: FormCell }]
|
||||
: []),
|
||||
{ dataIndex: '__list', title: '列表', width: 64, align: 'center', customCell: ListCell },
|
||||
{ dataIndex: '__query', title: '查询', width: 64, align: 'center', customCell: QueryCell },
|
||||
]
|
||||
const tailColumns = [
|
||||
{
|
||||
dataIndex: 'b_canuse',
|
||||
title: '启用',
|
||||
@@ -104,7 +172,9 @@ const columns = shallowRef([
|
||||
align: 'center',
|
||||
editor: { type: 'checkbox' },
|
||||
},
|
||||
])
|
||||
]
|
||||
return [...baseColumns, ...participationColumns, ...tailColumns]
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* 字段参与开关单元格(h 渲染函数):ui Switch 居中渲染,点击切换参与状态。
|
||||
* 供字段定义面板 FmsTable 的 表单/列表/查询 三列 customCell 使用。
|
||||
* 表格 cell 由 h() 动态渲染、不受 scoped 样式约束,样式放独立 scss 随本模块全局引入。
|
||||
*/
|
||||
import { h } from 'vue'
|
||||
import { Switch } from '@/components/ui'
|
||||
import './participation-cell.scss'
|
||||
|
||||
/**
|
||||
* @param {object} opts
|
||||
* @param {(row: object) => boolean} opts.isOn 该行当前是否参与
|
||||
* @param {(row: object) => void} opts.onToggle 点击开关
|
||||
* @param {string} opts.title 开关提示文案(如「参与列表显示」)
|
||||
*/
|
||||
export function createParticipationCell({ isOn, onToggle, title }) {
|
||||
return ({ row }) =>
|
||||
h('div', { class: 'mm-part-cell' }, [
|
||||
h(Switch, {
|
||||
modelValue: isOn(row),
|
||||
title,
|
||||
'aria-label': title,
|
||||
onClick: (event) => {
|
||||
event.stopPropagation()
|
||||
onToggle(row)
|
||||
},
|
||||
}),
|
||||
])
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
/* 字段参与开关单元格(ParticipationCell):随 JS 模块全局引入 */
|
||||
.mm-part-cell {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
}
|
||||
@@ -10,7 +10,10 @@ import { loadDataApi, describeApi } from '@/services/api'
|
||||
import { cloneData } from '@/utils/dataChanges'
|
||||
import { createTempId } from '@/utils/tempId'
|
||||
import { buildModuleItemI18nKey } from '@/utils/i18n'
|
||||
import { listRowDefaults, queryRowDefaults } from '../fieldAreaDefaults'
|
||||
import {
|
||||
createListConfigRow,
|
||||
createQueryConfigRow,
|
||||
} from '../fieldAreaDefaults'
|
||||
|
||||
export function useModuleConfig(deps) {
|
||||
const {
|
||||
@@ -214,7 +217,7 @@ export function useModuleConfig(deps) {
|
||||
return ids
|
||||
}
|
||||
|
||||
// 为尚未配置的字段生成列表/查询默认行(参考旧系统 buildMissingDefaultConfigs)。
|
||||
// 为尚未配置的字段生成列表/查询默认行(行结构统一走 fieldAreaDefaults 的工厂)。
|
||||
// 默认属性见 fieldAreaDefaults:默认不参与的字段(大文本等)同样生成行、开关置 0,
|
||||
// 保留配置空间;表单设计(editConfig)不自动生成:字段由用户在表单设计器中逐个添加,
|
||||
// 自动铺满会与设计器的画布/分组/栅格编辑冲突。
|
||||
@@ -230,27 +233,10 @@ export function useModuleConfig(deps) {
|
||||
const fieldId = String(field.b_id)
|
||||
const order = orderIndex * 10
|
||||
if (!listFieldIds.has(fieldId)) {
|
||||
generated.listConfig.push({
|
||||
b_id: createTempId(),
|
||||
b_module_id: moduleId,
|
||||
b_field_id: fieldId,
|
||||
b_group_id: null,
|
||||
b_i18n: field.b_i18n || null,
|
||||
b_xh: order,
|
||||
...listRowDefaults(field),
|
||||
})
|
||||
generated.listConfig.push({ ...createListConfigRow(moduleId, field, []), b_xh: order })
|
||||
}
|
||||
if (!queryFieldIds.has(fieldId)) {
|
||||
generated.queryConfig.push({
|
||||
b_id: createTempId(),
|
||||
b_module_id: moduleId,
|
||||
b_field_module_id: moduleId,
|
||||
b_field_id: fieldId,
|
||||
b_relation_id: null,
|
||||
b_default_value: null,
|
||||
b_xh: order,
|
||||
...queryRowDefaults(field),
|
||||
})
|
||||
generated.queryConfig.push({ ...createQueryConfigRow(moduleId, field, []), b_xh: order })
|
||||
}
|
||||
}
|
||||
return generated
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
/**
|
||||
* 字段区域默认策略(唯一真源):
|
||||
* 「字段定义 → 列表列 / 查询条件默认配置行」的规则集中于此,供
|
||||
* useModuleConfig.buildMissingDefaultConfigs(同步字段、补充缺失)与查询面板
|
||||
* (选定字段后的组件/操作符重置)共用。
|
||||
* useModuleConfig.buildMissingDefaultConfigs(同步字段、补充缺失)、查询面板
|
||||
* (选定字段后的组件/操作符重置)与字段定义面板的参与开关共用。
|
||||
*
|
||||
* 参与语义约定:配置行存在 = 已配置;是否参与运行时由行内开关表达
|
||||
* (列表 b_visible、查询 b_canuse)。默认不参与的字段(大文本)同样生成行、
|
||||
* 开关置 0——保留配置空间,勾选即恢复;删除行仅用于清掉不该存在的行(误加的查询条件)。
|
||||
*/
|
||||
|
||||
import { createTempId } from '@/utils/tempId'
|
||||
|
||||
/** 大文本字段:默认不进列表、默认不作为查询条件 */
|
||||
function isLargeText(field) {
|
||||
return field.b_type === 'textarea' || field.b_dbtype === 'text'
|
||||
@@ -57,3 +59,47 @@ export function queryRowDefaults(field) {
|
||||
b_canuse: isLargeText(field) ? 0 : 1,
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------- 默认配置行工厂 ----------
|
||||
* 与 useModuleConfig.buildMissingDefaultConfigs、字段定义面板参与开关共用,
|
||||
* 保证「同步字段自动补全」与「手动打开参与开关」生成的行结构一致。
|
||||
* forceOn:显式意愿(手动开开关)时无视大文本默认不参与的策略,置 1。
|
||||
*/
|
||||
|
||||
function nextXh(rows) {
|
||||
let max = 0
|
||||
for (const row of rows || []) {
|
||||
const xh = Number(row.b_xh) || 0
|
||||
if (xh > max) max = xh
|
||||
}
|
||||
return max + 10
|
||||
}
|
||||
|
||||
/** 字段 → 列表列配置行(s_field_view),追加到末尾时使用 */
|
||||
export function createListConfigRow(moduleId, field, rows, { forceOn = false } = {}) {
|
||||
return {
|
||||
b_id: createTempId(),
|
||||
b_module_id: String(moduleId),
|
||||
b_field_id: String(field.b_id),
|
||||
b_group_id: null,
|
||||
b_i18n: field.b_i18n || null,
|
||||
b_xh: nextXh(rows),
|
||||
...listRowDefaults(field),
|
||||
...(forceOn ? { b_visible: 1 } : {}),
|
||||
}
|
||||
}
|
||||
|
||||
/** 字段 → 查询条件配置行(s_field_query) */
|
||||
export function createQueryConfigRow(moduleId, field, rows, { forceOn = false } = {}) {
|
||||
return {
|
||||
b_id: createTempId(),
|
||||
b_module_id: String(moduleId),
|
||||
b_field_module_id: String(moduleId),
|
||||
b_field_id: String(field.b_id),
|
||||
b_relation_id: null,
|
||||
b_default_value: null,
|
||||
b_xh: nextXh(rows),
|
||||
...queryRowDefaults(field),
|
||||
...(forceOn ? { b_canuse: 1 } : {}),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/**
|
||||
* 字段参与开关(纯逻辑,无 Vue 依赖):
|
||||
* 「字段是否参与 表单/列表/查询」的判定与切换,供字段定义面板的三个开关列使用。
|
||||
*
|
||||
* 语义沿用 fieldAreaDefaults 的项目约定(行存在 = 已配置,行内开关 = 是否参与):
|
||||
* - 表单参与:editConfig 行存在且 b_visible=1;关 = 置 b_visible=0,不删行
|
||||
* (保留画布布局/栅格,与列表「删除列=隐藏」同一哲学)
|
||||
* - 列表参与:listConfig 行存在且 b_visible=1(行由加载自动补全,通常恒存在)
|
||||
* - 查询参与:queryConfig 行存在且 b_canuse=1(行不自动生成,开 = 需要时按默认生成)
|
||||
*
|
||||
* 所有 toggle 返回新数组:目标行浅拷贝后修改,其余行保持原引用;
|
||||
* 行不存在且要「关」时无操作,原样返回(调用方可直接 emit)。
|
||||
*/
|
||||
import { createListConfigRow, createQueryConfigRow } from './fieldAreaDefaults'
|
||||
import { createEditRowFactory } from './editPanelShared'
|
||||
|
||||
const findRow = (rows, fieldId) =>
|
||||
(rows || []).find((row) => String(row.b_field_id) === String(fieldId))
|
||||
|
||||
/** 表单行工厂:b_colspan 24 独占一行(点击新增语义,见 FormEditPanel.insertField) */
|
||||
function createFormRow(field, moduleId, rows) {
|
||||
const row = createEditRowFactory({ moduleId: String(moduleId) })(field, null)
|
||||
// 末尾追加:b_xh 取现有最大值 + 10(工厂默认 0 会排到表单最前)
|
||||
let max = 0
|
||||
for (const item of rows || []) {
|
||||
const xh = Number(item.b_xh) || 0
|
||||
if (xh > max) max = xh
|
||||
}
|
||||
row.b_xh = max + 10
|
||||
return row
|
||||
}
|
||||
|
||||
function withRowToggled(rows, row, key) {
|
||||
return rows.map((item) => (item === row ? { ...item, [key]: Number(item[key]) === 1 ? 0 : 1 } : item))
|
||||
}
|
||||
|
||||
/* ---------- 判定 ---------- */
|
||||
|
||||
export function isFormOn(editConfig, field) {
|
||||
const row = findRow(editConfig, field.b_id)
|
||||
return !!row && Number(row.b_visible) === 1
|
||||
}
|
||||
|
||||
export function isListOn(listConfig, field) {
|
||||
const row = findRow(listConfig, field.b_id)
|
||||
return !!row && Number(row.b_visible) === 1
|
||||
}
|
||||
|
||||
export function isQueryOn(queryConfig, field) {
|
||||
const row = findRow(queryConfig, field.b_id)
|
||||
return !!row && Number(row.b_canuse) === 1
|
||||
}
|
||||
|
||||
/* ---------- 切换 ---------- */
|
||||
|
||||
/** 行不存在时追加到末尾;forceOn 的行由工厂置参与标志为 1(显式意愿) */
|
||||
function appendRow(rows, row) {
|
||||
return [...(rows || []), row]
|
||||
}
|
||||
|
||||
export function toggleForm(editConfig, field, moduleId) {
|
||||
const rows = editConfig || []
|
||||
const row = findRow(rows, field.b_id)
|
||||
if (row) return withRowToggled(rows, row, 'b_visible')
|
||||
return appendRow(rows, createFormRow(field, moduleId, rows))
|
||||
}
|
||||
|
||||
export function toggleList(listConfig, field, moduleId) {
|
||||
const rows = listConfig || []
|
||||
const row = findRow(rows, field.b_id)
|
||||
if (row) return withRowToggled(rows, row, 'b_visible')
|
||||
return appendRow(rows, createListConfigRow(moduleId, field, rows, { forceOn: true }))
|
||||
}
|
||||
|
||||
export function toggleQuery(queryConfig, field, moduleId) {
|
||||
const rows = queryConfig || []
|
||||
const row = findRow(rows, field.b_id)
|
||||
if (row) return withRowToggled(rows, row, 'b_canuse')
|
||||
return appendRow(rows, createQueryConfigRow(moduleId, field, rows, { forceOn: true }))
|
||||
}
|
||||
@@ -503,8 +503,15 @@ loadModuleTree()
|
||||
:module-id="String(selectedModule.b_id)"
|
||||
:module-code="drafts?.module?.b_code || ''"
|
||||
:fields="drafts?.fields"
|
||||
:edit-config="drafts?.editConfig"
|
||||
:list-config="drafts?.listConfig"
|
||||
:query-config="drafts?.queryConfig"
|
||||
:module-type="moduleType"
|
||||
:loading="busy"
|
||||
@update="onFieldsUpdate"
|
||||
@update-edit-config="(v) => onModuleUpdate('editConfig', v)"
|
||||
@update-list-config="(v) => onModuleUpdate('listConfig', v)"
|
||||
@update-query-config="(v) => onModuleUpdate('queryConfig', v)"
|
||||
@i18n-saved="onModuleI18nSaved"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
/**
|
||||
* 字段参与开关(fieldParticipation)测试:
|
||||
* - 判定:行存在 + 行内开关(表单/列表 b_visible、查询 b_canuse),b_field_id 与 b_id 类型不一致按字符串比较
|
||||
* - 切换:行为空/存在两路;关 = 置行内开关 0(不删行,保留布局/配置);开 = 行不存在时按默认生成且强制参与
|
||||
* - 不变性:toggle 返回新数组、非目标行保持原引用
|
||||
*/
|
||||
import { describe, it, expect } from 'vitest'
|
||||
import {
|
||||
isFormOn,
|
||||
isListOn,
|
||||
isQueryOn,
|
||||
toggleForm,
|
||||
toggleList,
|
||||
toggleQuery,
|
||||
} from '@/views/system/module-management/fieldParticipation'
|
||||
|
||||
const MODULE_ID = 'm1'
|
||||
|
||||
function makeField(over = {}) {
|
||||
return { b_id: '10', b_field: 'amount', b_name: '金额', b_type: 'money', b_canuse: 1, ...over }
|
||||
}
|
||||
|
||||
describe('参与判定', () => {
|
||||
const field = makeField()
|
||||
|
||||
it('行存在且开关为 1 即参与;行不存在不参与', () => {
|
||||
expect(isFormOn([{ b_field_id: '10', b_visible: 1 }], field)).toBe(true)
|
||||
expect(isFormOn([{ b_field_id: '10', b_visible: 0 }], field)).toBe(false)
|
||||
expect(isFormOn([], field)).toBe(false)
|
||||
expect(isListOn([{ b_field_id: 10, b_visible: 1 }], field)).toBe(true) // 类型不一致按字符串比较
|
||||
expect(isQueryOn([{ b_field_id: '10', b_canuse: 1 }], field)).toBe(true)
|
||||
expect(isQueryOn([{ b_field_id: '10', b_canuse: 0 }], field)).toBe(false)
|
||||
})
|
||||
|
||||
it('空配置安全', () => {
|
||||
expect(isFormOn(undefined, field)).toBe(false)
|
||||
expect(isListOn(null, field)).toBe(false)
|
||||
expect(isQueryOn([], field)).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('表单参与切换', () => {
|
||||
it('行存在:切换 b_visible,不删行(保留布局)', () => {
|
||||
const rows = [{ b_id: 'e1', b_field_id: '10', b_visible: 1, b_colspan: 12, b_group_id: 'g1' }]
|
||||
const off = toggleForm(rows, makeField(), MODULE_ID)
|
||||
expect(off).toHaveLength(1)
|
||||
expect(off[0].b_visible).toBe(0)
|
||||
expect(off[0].b_colspan).toBe(12) // 布局属性保留
|
||||
expect(off[0].b_group_id).toBe('g1')
|
||||
const on = toggleForm(off, makeField(), MODULE_ID)
|
||||
expect(on[0].b_visible).toBe(1)
|
||||
})
|
||||
|
||||
it('行不存在:生成默认行追加到末尾(b_visible=1、b_colspan=24、b_xh 为末尾序号)', () => {
|
||||
const rows = [{ b_id: 'e1', b_field_id: '9', b_visible: 1, b_xh: 30 }]
|
||||
const next = toggleForm(rows, makeField(), MODULE_ID)
|
||||
expect(next).toHaveLength(2)
|
||||
const created = next[1]
|
||||
expect(created.b_field_id).toBe('10')
|
||||
expect(created.b_visible).toBe(1)
|
||||
expect(created.b_colspan).toBe(24)
|
||||
expect(created.b_module_id).toBe('m1')
|
||||
expect(created.b_xh).toBe(40) // 末尾追加,不排到表单最前
|
||||
expect(next[0]).toBe(rows[0]) // 非目标行保持原引用
|
||||
})
|
||||
})
|
||||
|
||||
describe('列表参与切换', () => {
|
||||
it('行存在:切换 b_visible(与「删除列=隐藏」语义一致)', () => {
|
||||
const rows = [{ b_id: 'v1', b_field_id: '10', b_visible: 1, b_width: 110 }]
|
||||
const off = toggleList(rows, makeField(), MODULE_ID)
|
||||
expect(off[0].b_visible).toBe(0)
|
||||
expect(off[0].b_width).toBe(110)
|
||||
expect(toggleList(off, makeField(), MODULE_ID)[0].b_visible).toBe(1)
|
||||
})
|
||||
|
||||
it('行不存在:按默认生成且强制显示(含大文本)', () => {
|
||||
const textarea = makeField({ b_type: 'textarea' })
|
||||
const next = toggleList([], textarea, MODULE_ID)
|
||||
expect(next).toHaveLength(1)
|
||||
expect(next[0].b_visible).toBe(1) // 显式意愿覆盖大文本默认不参与
|
||||
expect(next[0].b_xh).toBe(10)
|
||||
})
|
||||
})
|
||||
|
||||
describe('查询参与切换', () => {
|
||||
it('行存在:切换 b_canuse', () => {
|
||||
const rows = [{ b_id: 'q1', b_field_id: '10', b_canuse: 0, b_operator: 'eq' }]
|
||||
const on = toggleQuery(rows, makeField(), MODULE_ID)
|
||||
expect(on[0].b_canuse).toBe(1)
|
||||
expect(on[0].b_operator).toBe('eq') // 既有查询配置保留
|
||||
expect(toggleQuery(on, makeField(), MODULE_ID)[0].b_canuse).toBe(0)
|
||||
})
|
||||
|
||||
it('行不存在:按默认生成(money → number/eq)且强制参与', () => {
|
||||
const next = toggleQuery([], makeField(), MODULE_ID)
|
||||
expect(next).toHaveLength(1)
|
||||
expect(next[0].b_canuse).toBe(1)
|
||||
expect(next[0].b_component).toBe('number')
|
||||
expect(next[0].b_operator).toBe('eq')
|
||||
expect(next[0].b_field_module_id).toBe('m1')
|
||||
})
|
||||
})
|
||||
|
||||
describe('切换的不变性', () => {
|
||||
it('返回新数组,不修改原数组', () => {
|
||||
const rows = [{ b_id: 'e1', b_field_id: '10', b_visible: 1 }]
|
||||
const next = toggleForm(rows, makeField(), MODULE_ID)
|
||||
expect(next).not.toBe(rows)
|
||||
expect(rows[0].b_visible).toBe(1) // 原行未被修改
|
||||
})
|
||||
})
|
||||
Reference in new issue
Block a user