u
This commit is contained in:
1 parent
e7c84a82a2
commit
025d3232c4
65 files changed
+9838
-9111
No files matched your search
@@ -4,7 +4,7 @@
|
||||
* 这两块是保存编排里最容易出错、也最难靠肉眼验证的部分:
|
||||
* - 权限点行完全由菜单行派生(menu.{编码}),名称 / 顺序 / 启用态跟随菜单,
|
||||
* 目录不产生权限点;
|
||||
* - 删除菜单要连带清掉多语言资源、模块绑定与入口权限点,
|
||||
* - 删除菜单要连带清掉多语言资源与入口权限点,
|
||||
* 且权限点删除必须带 dependent_deletes(授权行随权限点删除)。
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,199 +0,0 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { mount } from '@vue/test-utils'
|
||||
import { nextTick } from 'vue'
|
||||
import ModuleBindPanel from '@/views/module/menu-management/ModuleBindPanel.vue'
|
||||
import {
|
||||
buildMenuModuleRows,
|
||||
filterBindableModules,
|
||||
isBindableModule,
|
||||
moduleBindSignature,
|
||||
normalizeMenuModulesByType,
|
||||
} from '@/views/module/menu-management/utils'
|
||||
|
||||
/**
|
||||
* 菜单「绑定模块」(s_menu_module)的纯逻辑与面板行为。
|
||||
*
|
||||
* 关键口径:只有页面(page)菜单绑定模块;落库只登记 data / virtual ——
|
||||
* module 类型只是模块树上的分类节点,不参与绑定。
|
||||
*/
|
||||
|
||||
const MODULE_TREE = [
|
||||
{
|
||||
b_id: 'sales',
|
||||
b_name: '销售',
|
||||
children: [
|
||||
{ b_id: 'v_order', b_name: '订单' },
|
||||
{ b_id: 'v_customer', b_name: '客户' },
|
||||
],
|
||||
},
|
||||
{ b_id: 'v_other', b_name: '其他' },
|
||||
]
|
||||
|
||||
/** 编码 → 类型:sales 是分类,其余是可绑定的数据模块 */
|
||||
const TYPES: Record<string, string> = {
|
||||
sales: 'module',
|
||||
v_order: 'data',
|
||||
v_customer: 'virtual',
|
||||
v_other: 'data',
|
||||
}
|
||||
|
||||
/** 挂面板;menuType 决定渲染树还是给一句说明,model 是已绑模块编码 */
|
||||
function mountPanel(props: Record<string, unknown> = {}, model: string[] = []) {
|
||||
return mount(ModuleBindPanel, {
|
||||
props: {
|
||||
treeData: MODULE_TREE,
|
||||
moduleTypes: TYPES,
|
||||
menuType: 'page',
|
||||
menuId: 'm1',
|
||||
modelValue: model,
|
||||
'onUpdate:modelValue': () => {},
|
||||
...props,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
describe('isBindableModule', () => {
|
||||
it('data / virtual 可绑定,module 不可', () => {
|
||||
expect(isBindableModule('data')).toBe(true)
|
||||
expect(isBindableModule('virtual')).toBe(true)
|
||||
expect(isBindableModule('module')).toBe(false)
|
||||
})
|
||||
|
||||
it('类型未知时按可绑定处理(避免误删历史绑定)', () => {
|
||||
// 模块清单没加载全时,宁可保留关系行也不当成脏数据删掉
|
||||
expect(isBindableModule(undefined)).toBe(true)
|
||||
expect(isBindableModule(null)).toBe(true)
|
||||
expect(isBindableModule('')).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
describe('filterBindableModules', () => {
|
||||
it('剔除分类节点,保留可绑定模块与原顺序', () => {
|
||||
expect(filterBindableModules(['v_order', 'sales', 'v_customer'], TYPES)).toEqual([
|
||||
'v_order',
|
||||
'v_customer',
|
||||
])
|
||||
})
|
||||
|
||||
it('勾父级带回的子树键里,只有可绑定的留下', () => {
|
||||
// 非严格模式点「销售」会把 sales / v_order / v_customer 一起回传
|
||||
expect(filterBindableModules(['sales', 'v_order', 'v_customer'], TYPES)).toEqual([
|
||||
'v_order',
|
||||
'v_customer',
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
describe('moduleBindSignature', () => {
|
||||
it('顺序无关:同集合不同顺序签名相同', () => {
|
||||
expect(moduleBindSignature(['a', 'b'])).toBe(moduleBindSignature(['b', 'a']))
|
||||
})
|
||||
|
||||
it('集合不同则签名不同', () => {
|
||||
expect(moduleBindSignature(['a'])).not.toBe(moduleBindSignature(['a', 'b']))
|
||||
})
|
||||
|
||||
it('数字与字符串编码视为同一个', () => {
|
||||
expect(moduleBindSignature([1, 2])).toBe(moduleBindSignature(['1', '2']))
|
||||
})
|
||||
})
|
||||
|
||||
describe('buildMenuModuleRows', () => {
|
||||
it('按勾选顺序生成关系行,b_xh 从 10 起步', () => {
|
||||
expect(buildMenuModuleRows('m1', ['v_order', 'v_customer'])).toEqual([
|
||||
{ b_menu_id: 'm1', b_module_id: 'v_order', b_xh: 10, b_canuse: 1 },
|
||||
{ b_menu_id: 'm1', b_module_id: 'v_customer', b_xh: 20, b_canuse: 1 },
|
||||
])
|
||||
})
|
||||
|
||||
it('菜单编码为空时返回空数组(不产出悬空关系行)', () => {
|
||||
expect(buildMenuModuleRows('', ['v_order'])).toEqual([])
|
||||
})
|
||||
|
||||
it('空绑定返回空数组', () => {
|
||||
expect(buildMenuModuleRows('m1', [])).toEqual([])
|
||||
})
|
||||
})
|
||||
|
||||
describe('normalizeMenuModulesByType', () => {
|
||||
it('页面菜单保留绑定', () => {
|
||||
expect(normalizeMenuModulesByType('page', ['v_order'])).toEqual(['v_order'])
|
||||
})
|
||||
|
||||
it('目录 / 外链一律清空(非页面不绑定模块)', () => {
|
||||
expect(normalizeMenuModulesByType('directory', ['v_order'])).toEqual([])
|
||||
expect(normalizeMenuModulesByType('external', ['v_order'])).toEqual([])
|
||||
})
|
||||
})
|
||||
|
||||
describe('ModuleBindPanel', () => {
|
||||
it('页面菜单渲染可勾选的模块树', () => {
|
||||
const wrapper = mountPanel()
|
||||
expect(wrapper.find('.biz-tree').exists()).toBe(true)
|
||||
// 树默认收起(只渲染顶层节点),所以这里只断言顶层两个节点各有复选框
|
||||
const boxes = wrapper.findAllComponents({ name: 'G3Checkbox' })
|
||||
expect(boxes.length).toBe(2)
|
||||
expect(wrapper.text()).toContain('销售')
|
||||
expect(wrapper.text()).toContain('其他')
|
||||
})
|
||||
|
||||
it('目录 / 外链不渲染树,各给一句说明', () => {
|
||||
const dir = mountPanel({ menuType: 'directory' })
|
||||
expect(dir.find('.biz-tree').exists()).toBe(false)
|
||||
expect(dir.text()).toContain('目录不绑定模块')
|
||||
|
||||
const ext = mountPanel({ menuType: 'external' })
|
||||
expect(ext.find('.biz-tree').exists()).toBe(false)
|
||||
expect(ext.text()).toContain('外链不绑定模块')
|
||||
})
|
||||
|
||||
it('初始已绑模块反映在顶层复选框上', async () => {
|
||||
// 「其他」是顶层节点:默认收起的树里只有顶层可见,用它验证已绑态回填
|
||||
const wrapper = mountPanel({}, ['v_other'])
|
||||
await nextTick()
|
||||
|
||||
const boxes = wrapper.findAllComponents({ name: 'G3Checkbox' })
|
||||
// 顶层顺序与 treeData 一致:sales、v_other
|
||||
expect(boxes[0].props('modelValue')).toBe(false)
|
||||
expect(boxes[1].props('modelValue')).toBe(true)
|
||||
})
|
||||
|
||||
it('切换菜单清掉勾选草稿', async () => {
|
||||
const wrapper = mountPanel({}, ['v_other'])
|
||||
await nextTick()
|
||||
expect(wrapper.findAllComponents({ name: 'G3Checkbox' })[1].props('modelValue')).toBe(true)
|
||||
|
||||
// 切到另一个菜单:父级尚未回填新绑定时,草稿必须清空而不是留着上一个菜单的勾
|
||||
await wrapper.setProps({ menuId: 'm2', modelValue: [] })
|
||||
await nextTick()
|
||||
expect(wrapper.findAllComponents({ name: 'G3Checkbox' })[1].props('modelValue')).toBe(false)
|
||||
})
|
||||
|
||||
it('勾选后回写模型时剔除分类节点', async () => {
|
||||
const updates: string[][] = []
|
||||
const wrapper = mountPanel({
|
||||
'onUpdate:modelValue': (v: string[]) => updates.push(v),
|
||||
})
|
||||
await nextTick()
|
||||
|
||||
// 点「销售」分类 → 级联勾选整棵子树(含分类自身)
|
||||
const boxes = wrapper.findAllComponents({ name: 'G3Checkbox' })
|
||||
await boxes[0].vm.$emit('change', true)
|
||||
await nextTick()
|
||||
|
||||
const last = updates.at(-1) ?? []
|
||||
expect(last).not.toContain('sales')
|
||||
expect(last.toSorted()).toEqual(['v_customer', 'v_order'])
|
||||
})
|
||||
|
||||
it('数量标记只算可绑定的模块', async () => {
|
||||
const wrapper = mountPanel({}, ['v_order', 'v_customer'])
|
||||
await nextTick()
|
||||
expect(wrapper.find('.g3-tag').text()).toBe('2')
|
||||
})
|
||||
|
||||
it('未绑定时不显示数量标记', () => {
|
||||
const wrapper = mountPanel({}, [])
|
||||
expect(wrapper.find('.g3-tag').exists()).toBe(false)
|
||||
})
|
||||
})
|
||||
+42
-34
@@ -5,9 +5,7 @@
|
||||
* diff 成一条 insert),只有用户首次操作才落行;且 defineModel 写入后不能立刻
|
||||
* 回读 prop(要下一轮才回传),所以建行后返回的是 reactive 代理行。
|
||||
*
|
||||
* 「启用」开关不在本面板内(已上提到页面级面板头),面板通过
|
||||
* defineExpose 的 toggleEnabled() 拨动、enabled prop 接收状态,
|
||||
* 测试走同一对口而不是找面板里的 G3Switch。
|
||||
* 「启用」开关在表单第一行,测试点面板里真实的 G3Switch 驱动。
|
||||
*/
|
||||
|
||||
import { describe, expect, it } from 'vitest'
|
||||
@@ -42,27 +40,16 @@ function row(overrides: Partial<ModuleAutoCodeRow> = {}): ModuleAutoCodeRow {
|
||||
}
|
||||
|
||||
/**
|
||||
* 模拟父级 v-model:autocode + 面板头开关:emit 回来要显式写回 prop,
|
||||
* 模拟父级 v-model:autocode:emit 回来要显式写回 prop,
|
||||
* 否则复现不了「立刻回读旧值」的问题。
|
||||
*
|
||||
* 注意 enabled 用可变对象持有、不在 mount 期间引用 wrapper:
|
||||
* 面板的 update:enabled 是 immediate 的,挂载时就会 emit,
|
||||
* 处理器里访问尚未赋值的 wrapper 会直接抛 TDZ 错误。
|
||||
*/
|
||||
function mountPanel(autocode: ModuleAutoCodeRow[] = [], enabled = false) {
|
||||
const state = { enabled }
|
||||
function mountPanel(autocode: ModuleAutoCodeRow[] = []) {
|
||||
const wrapper = mount(ModuleAutoCodePanel, {
|
||||
props: {
|
||||
moduleId: 'm1',
|
||||
fields: FIELDS,
|
||||
autocode,
|
||||
get enabled() {
|
||||
return state.enabled
|
||||
},
|
||||
'onUpdate:autocode': (value: ModuleAutoCodeRow[]) => wrapper.setProps({ autocode: value }),
|
||||
'onUpdate:enabled': (value: boolean) => {
|
||||
state.enabled = value
|
||||
},
|
||||
},
|
||||
})
|
||||
return wrapper
|
||||
@@ -73,7 +60,7 @@ describe('自动编码面板', () => {
|
||||
const wrapper = mountPanel()
|
||||
|
||||
// 模块从未配置自动编码:草稿为空,此时拨开关会走 ensureRow 建行
|
||||
wrapper.vm.toggleEnabled(true)
|
||||
await wrapper.find('[role="switch"]').trigger('click')
|
||||
await wrapper.vm.$nextTick()
|
||||
|
||||
const emitted = wrapper.emitted('update:autocode')
|
||||
@@ -90,7 +77,7 @@ describe('自动编码面板', () => {
|
||||
const draft = [row({ b_canuse: 0, b_prefix: 'A' })]
|
||||
const wrapper = mountPanel(draft)
|
||||
|
||||
wrapper.vm.toggleEnabled(true)
|
||||
await wrapper.find('[role="switch"]').trigger('click')
|
||||
await wrapper.vm.$nextTick()
|
||||
|
||||
// 已落草稿:直接改这一行的属性(父级 ref 是深度响应式,改得见)
|
||||
@@ -102,9 +89,9 @@ describe('自动编码面板', () => {
|
||||
it('把从未配置过的模块拨开又关掉,不留占位行(否则保存会 diff 出一条 insert)', async () => {
|
||||
const wrapper = mountPanel()
|
||||
|
||||
wrapper.vm.toggleEnabled(true)
|
||||
await wrapper.find('[role="switch"]').trigger('click')
|
||||
await wrapper.vm.$nextTick()
|
||||
wrapper.vm.toggleEnabled(false)
|
||||
await wrapper.find('[role="switch"]').trigger('click')
|
||||
await wrapper.vm.$nextTick()
|
||||
|
||||
// 最后一次写回的草稿必须回到空数组
|
||||
@@ -114,9 +101,9 @@ describe('自动编码面板', () => {
|
||||
|
||||
it('停用既有规则时保留该行(那是既有规则的停用,要落库)', async () => {
|
||||
const draft = [row({ b_canuse: 1 })]
|
||||
const wrapper = mountPanel(draft, true)
|
||||
const wrapper = mountPanel(draft)
|
||||
|
||||
wrapper.vm.toggleEnabled(false)
|
||||
await wrapper.find('[role="switch"]').trigger('click')
|
||||
await wrapper.vm.$nextTick()
|
||||
|
||||
expect(draft[0]?.b_canuse).toBe(0)
|
||||
@@ -124,12 +111,14 @@ describe('自动编码面板', () => {
|
||||
expect(wrapper.emitted('update:autocode')).toBeUndefined()
|
||||
})
|
||||
|
||||
it('启用态回报给父级(驱动面板头开关)', async () => {
|
||||
const wrapper = mountPanel([row({ b_canuse: 1 })])
|
||||
await wrapper.vm.$nextTick()
|
||||
it('开关的选中态跟随规则行(配过又停用的行显示为关)', async () => {
|
||||
const on = mountPanel([row({ b_canuse: 1 })])
|
||||
await on.vm.$nextTick()
|
||||
expect(on.find('[role="switch"]').attributes('aria-checked')).toBe('true')
|
||||
|
||||
expect(wrapper.emitted('update:enabled')).toBeTruthy()
|
||||
expect(wrapper.emitted('update:enabled')![0][0]).toBe(true)
|
||||
const off = mountPanel([row({ b_canuse: 0 })])
|
||||
await off.vm.$nextTick()
|
||||
expect(off.find('[role="switch"]').attributes('aria-checked')).toBe('false')
|
||||
})
|
||||
|
||||
it('紧凑网格固定竖排且标签左对齐,不跟随全局横排配置', () => {
|
||||
@@ -139,10 +128,29 @@ describe('自动编码面板', () => {
|
||||
expect(wrapper.findAll('.g3-form-item__label.is-label-right')).toHaveLength(0)
|
||||
})
|
||||
|
||||
it('面板内不再自带「启用」开关(已上提到页面级面板头)', () => {
|
||||
const wrapper = mountPanel([row()])
|
||||
it('「启用」开关独占表单第一行,未配置时也可拨', () => {
|
||||
const wrapper = mountPanel()
|
||||
|
||||
expect(wrapper.find('[role="switch"]').exists()).toBe(false)
|
||||
// 标签顺序 = 填写顺序:行内从左到右、行间从上到下
|
||||
// (启用 → 业务编号字段/重置周期 → 前缀/日期/分隔符/位数/起始值 → 编号预览)
|
||||
const labels = wrapper.findAll('.g3-form-item__label')
|
||||
expect(labels.map((item) => item.text())).toEqual([
|
||||
'启用',
|
||||
'业务编号字段',
|
||||
'重置周期',
|
||||
'前缀',
|
||||
'日期',
|
||||
'分隔符',
|
||||
'位数',
|
||||
'起始值',
|
||||
'编号预览',
|
||||
])
|
||||
|
||||
// 未配置(草稿为空)时开关也渲染、可拨:它就是配置入口
|
||||
const switchEl = wrapper.find('[role="switch"]')
|
||||
expect(switchEl.exists()).toBe(true)
|
||||
expect(switchEl.attributes('disabled')).toBeUndefined()
|
||||
expect(switchEl.attributes('aria-checked')).toBe('false')
|
||||
})
|
||||
|
||||
it('预览按 前缀 + 日期 + 补位流水号 拼接', async () => {
|
||||
@@ -157,13 +165,13 @@ describe('自动编码面板', () => {
|
||||
})
|
||||
|
||||
it('启用态下的合法规则校验通过', async () => {
|
||||
const wrapper = mountPanel([row()], true)
|
||||
const wrapper = mountPanel([row()])
|
||||
|
||||
expect(await wrapper.vm.validate()).toEqual([])
|
||||
})
|
||||
|
||||
it('启用但未选业务编号字段时报错(错误挂在对应 FormItem 上)', async () => {
|
||||
const wrapper = mountPanel([row({ b_field: null })], true)
|
||||
const wrapper = mountPanel([row({ b_field: null })])
|
||||
|
||||
const errors = await wrapper.vm.validate()
|
||||
expect(errors.map((item) => item.name)).toContain('b_field')
|
||||
@@ -171,7 +179,7 @@ describe('自动编码面板', () => {
|
||||
})
|
||||
|
||||
it('位数超出 1-18 时报错', async () => {
|
||||
const wrapper = mountPanel([row({ b_seqwidth: 20 })], true)
|
||||
const wrapper = mountPanel([row({ b_seqwidth: 20 })])
|
||||
|
||||
const errors = await wrapper.vm.validate()
|
||||
expect(errors.find((item) => item.name === 'b_seqwidth')?.errors[0]).toBe(
|
||||
@@ -187,7 +195,7 @@ describe('自动编码面板', () => {
|
||||
|
||||
it('未启用时即使参数残缺也不报错(重置周期为空同样跳过)', async () => {
|
||||
// 占位行 / 已停用的规则都不该拦保存:旧写法里 b_resettype 是硬性 required,会误报
|
||||
const wrapper = mountPanel([row({ b_canuse: 0, b_resettype: '', b_seqwidth: 0 })], false)
|
||||
const wrapper = mountPanel([row({ b_canuse: 0, b_resettype: '', b_seqwidth: 0 })])
|
||||
|
||||
expect(await wrapper.vm.validate()).toEqual([])
|
||||
})
|
||||
|
||||
@@ -1,136 +0,0 @@
|
||||
/**
|
||||
* 查询配置面板(query JSON,schemaVersion 4):只配工作队列页签。
|
||||
*
|
||||
* 这里测的是**结构与数据往返**:分组渲染、建组即建页签、编码自动派生、
|
||||
* 组名就地改要改整组、旧的查询字段配置在回写时被清掉。
|
||||
* G3Table 在 happy-dom 里没有真实尺寸,行内编辑与行拖拽是组件库自己的活,
|
||||
* 用桩替换掉(本面板只负责把列定义与数据源接上去)。
|
||||
*/
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { mount } from '@vue/test-utils'
|
||||
import ModuleQueryPanel from '@/views/module/module-management/ModuleQueryPanel.vue'
|
||||
import type { SchemaJson } from '@/utils/schemaJson'
|
||||
|
||||
function schema(views: Array<Record<string, unknown>> = []): SchemaJson {
|
||||
return { schemaVersion: 4, views }
|
||||
}
|
||||
|
||||
/**
|
||||
* 模拟父级 v-model:query:emit 回来要显式写回 prop,
|
||||
* 否则复现不了「草稿回写 → 父级再传下来」这一轮往返。
|
||||
*/
|
||||
function mountPanel(views: Array<Record<string, unknown>> = []) {
|
||||
const wrapper = mount(ModuleQueryPanel, {
|
||||
props: {
|
||||
query: schema(views),
|
||||
'onUpdate:query': (value: SchemaJson) => wrapper.setProps({ query: value }),
|
||||
},
|
||||
global: { stubs: { G3Table: true } },
|
||||
})
|
||||
return wrapper
|
||||
}
|
||||
|
||||
/** 当前草稿里的页签行(面板对外就是这份 query JSON) */
|
||||
function draftViews(wrapper: ReturnType<typeof mountPanel>): Array<Record<string, unknown>> {
|
||||
return (wrapper.props('query') as SchemaJson).views as Array<Record<string, unknown>>
|
||||
}
|
||||
|
||||
function groupNames(wrapper: ReturnType<typeof mountPanel>): string[] {
|
||||
return wrapper.findAll('.mm-groups__name').map((el) => (el.element as HTMLInputElement).value)
|
||||
}
|
||||
|
||||
/** 改组名:业务上走 change(失焦 / 回车提交),这里照同一条路触发 */
|
||||
async function renameFirstGroup(wrapper: ReturnType<typeof mountPanel>, name: string) {
|
||||
const input = wrapper.find('.mm-groups__name')
|
||||
await input.setValue(name)
|
||||
await input.trigger('change')
|
||||
await wrapper.vm.$nextTick()
|
||||
}
|
||||
|
||||
describe('查询配置面板(工作队列页签)', () => {
|
||||
it('按 group 归组:分组条上每组一个 chip,顺序跟着组内最小 order 走', () => {
|
||||
const wrapper = mountPanel([
|
||||
{ code: 'sail', label: '已开航', group: '状态', order: 30 },
|
||||
{ code: 'all', label: '全部', group: '状态', order: 10 },
|
||||
{ code: 'month', label: '本月', group: '时间', order: 20 },
|
||||
])
|
||||
|
||||
expect(groupNames(wrapper)).toEqual(['状态', '时间'])
|
||||
})
|
||||
|
||||
it('历史配置没写 group 的页签落到「默认」组(组从行反推,不存在无组的页签)', () => {
|
||||
const wrapper = mountPanel([{ code: 'all', label: '全部', order: 10 }])
|
||||
|
||||
expect(groupNames(wrapper)).toEqual(['默认'])
|
||||
})
|
||||
|
||||
it('新增页签组:建组的同时建出组内第一个页签,编码自动派生(空编码落库会被丢掉)', async () => {
|
||||
const wrapper = mountPanel()
|
||||
|
||||
await wrapper.find('.mm-query__bar button').trigger('click')
|
||||
await wrapper.vm.$nextTick()
|
||||
|
||||
expect(groupNames(wrapper)).toEqual(['分组 1'])
|
||||
const views = draftViews(wrapper)
|
||||
expect(views).toHaveLength(1)
|
||||
expect(views[0].group).toBe('分组 1')
|
||||
expect(views[0].code).toBe('view_1')
|
||||
// 组里第一个页签自动成为组内默认:一个组总要有一个默认选中的
|
||||
expect(views[0].isDefault).toBe(true)
|
||||
})
|
||||
|
||||
it('再加一组时编码继续派生,不会与已有页签撞号', async () => {
|
||||
const wrapper = mountPanel([{ code: 'view_1', label: '全部', group: '状态', order: 10 }])
|
||||
|
||||
await wrapper.find('.mm-query__bar button').trigger('click')
|
||||
await wrapper.vm.$nextTick()
|
||||
|
||||
expect(draftViews(wrapper)[1].code).toBe('view_2')
|
||||
})
|
||||
|
||||
it('组名就地改:改的是整组(组是共享实体,不能只改一行)', async () => {
|
||||
const wrapper = mountPanel([
|
||||
{ code: 'all', label: '全部', group: '状态', order: 10 },
|
||||
{ code: 'sail', label: '已开航', group: '状态', order: 20 },
|
||||
])
|
||||
|
||||
await renameFirstGroup(wrapper, '运行状态')
|
||||
|
||||
expect(groupNames(wrapper)).toEqual(['运行状态'])
|
||||
expect(draftViews(wrapper).every((row) => row.group === '运行状态')).toBe(true)
|
||||
})
|
||||
|
||||
it('组名改成已存在的组名时拒绝(否则两个组会被无声合并)', async () => {
|
||||
const wrapper = mountPanel([
|
||||
{ code: 'a', label: '全部', group: '状态', order: 10 },
|
||||
{ code: 'b', label: '本月', group: '时间', order: 20 },
|
||||
])
|
||||
|
||||
await renameFirstGroup(wrapper, '时间')
|
||||
|
||||
expect(groupNames(wrapper)).toEqual(['状态', '时间'])
|
||||
})
|
||||
|
||||
it('回写时把不再使用的 queryFields / keywordSearch / quickFilters 一并清掉', async () => {
|
||||
const wrapper = mountPanel()
|
||||
// 载入一份带旧配置的 schema:适配层只认 views,其余键由回写统一清理
|
||||
await wrapper.setProps({
|
||||
query: {
|
||||
schemaVersion: 3,
|
||||
views: [{ code: 'all', label: '全部', order: 10 }],
|
||||
keywordSearch: { fields: ['b_name'] },
|
||||
quickFilters: [{ field: 'b_name', order: 10 }],
|
||||
queryFields: { b_name: { component: 'input', operator: 'like' } },
|
||||
},
|
||||
})
|
||||
// 触发一次回写(新增一组)
|
||||
await wrapper.find('.mm-query__bar button').trigger('click')
|
||||
await wrapper.vm.$nextTick()
|
||||
|
||||
const next = wrapper.props('query') as SchemaJson
|
||||
expect(next.queryFields).toBeUndefined()
|
||||
expect(next.keywordSearch).toBeUndefined()
|
||||
expect(next.quickFilters).toBeUndefined()
|
||||
expect(next.schemaVersion).toBe(4)
|
||||
})
|
||||
})
|
||||
Reference in new issue
Block a user