业务级对话框实现
目录
概述
业务级对话框是LME系统中用于处理复杂业务场景的核心UI组件。本文档深入分析了三个主要的业务级对话框:工位选择对话框(WorkStationDialog)、工艺路由对话框(ProcessRouterDialog)和人工工位设置对话框(ArtificialStationDialog)。这些组件通过继承BaseDialog基类,结合Vue 3 Composition API和自定义Hook模式,实现了高度可复用和可维护的业务逻辑封装。
BaseDialog基类设计
BaseDialog作为所有业务级对话框的基础组件,提供了统一的对话框框架和通用功能。
图表来源
BaseDialog提供了以下核心功能:
- 统一的对话框头部和底部布局
- 自动化的关闭和确认事件处理
- 可配置的对话框尺寸和样式
- 国际化支持的语言文本
- 可扩展的插槽系统
章节来源
业务级对话框架构
业务级对话框采用分层架构设计,通过组件继承和Hook模式实现业务逻辑的模块化封装。
图表来源
核心业务对话框分析
工位选择对话框(WorkStationDialog)
WorkStationDialog是最基础的业务级对话框,专门用于工位的选择和管理。
组件特性
- 支持多选和单选模式
- 集成搜索功能
- 数据源动态加载
- 选中状态管理
实现要点
// 工位对话框的核心实现
const {
onClose,
onConfirm,
onCheck,
onOpen,
onSearch,
visible,
innerValue,
tableRef,
dataSource,
columns,
selections,
} = useSelectDialog(props, ctx)
数据流图
图表来源
章节来源
工艺路由对话框(ProcessRouterDialog)
ProcessRouterDialog扩展了工位选择的功能,增加了工艺路线的关联和筛选能力。
特殊功能
- 工艺路线数据预加载
- 条件过滤和筛选
- 单选模式支持
- 数据源动态关联
实现差异
// 工艺路由特有的初始化逻辑
const onOpen = async () => {
routers.value = await getProcessRouterList(props.productId)
initData()
}
const initData = async (filter?: string) => {
const ids = routers.value.map((item) => item.id) as string[]
const data = await getWorkStationList(filter)
const dataSourceItems = data.items.filter((item) =>
ids.includes(item.workSectionId)
)
dataSource.value = dataSourceItems
}
章节来源
人工工位对话框(ArtificialStationDialog)
ArtificialStationDialog是最复杂的业务级对话框,集成了表格编辑和动态表单功能。
复合功能
- 主表格展示
- 编辑对话框
- 动态表单验证
- 多用户权限管理
双对话框架构
图表来源
章节来源
Hook状态管理机制
业务级对话框采用Vue 3 Composition API和自定义Hook模式,实现了清晰的状态管理和副作用处理。
useSelectDialog Hook设计
图表来源
状态管理模式
响应式状态定义
// 基础状态定义
const visible = computed({
get() {
return props.modelValue
},
set(val) {
ctx.emit('update:modelValue', val)
},
})
const dataSource = ref<any[]>([])
const innerValue = ref('')
const checkedList = ref<any[]>([])
计算属性和响应式依赖
// 计算属性实现
const selections = computed(() => {
return props.data?.map((item: any) => item.id) ?? []
})
const columns = computed(() => [
{
title: _t('序号'),
type: 'seq',
width: '60',
},
{
field: 'workSection.name',
title: _t('工序名称'),
},
// ... 其他列定义
])
章节来源
API集成与数据流
业务级对话框通过专门的API模块实现与后端服务的通信,支持异步数据加载和错误处理。
API模块设计
图表来源
数据加载流程
异步数据初始化
// 工艺路由对话框的数据初始化
const onOpen = async () => {
routers.value = await getProcessRouterList(props.productId)
initData()
}
const initData = async (filter?: string) => {
const ids = routers.value.map((item) => item.id) as string[]
const data = await getWorkStationList(filter)
const dataSourceItems = data.items.filter((item) =>
ids.includes(item.workSectionId)
)
dataSource.value = dataSourceItems
}
API调用封装
// API模块的封装实现
export const getProcessRouterList = (id: string) => {
return request.get(`/api/v1/messuite/query/processroutes?productId=${id}`)
}
export const getWorkStationList = (v?: string) => {
const filter = v ? `&Filter=${v}` : ''
return request.get(
`/api/v1/processmanagement/workstation?SkipCount=0&MaxResultCount=999&includeDetails=true${filter}`
)
}
章节来源
复杂交互实现
业务级对话框支持多种复杂的用户交互场景,包括表格操作、表单验证和动态内容生成。
表格渲染与交互
BaseTable集成
<BaseTable
params={{
Filter: innerValue.value,
includeDetails: true,
}}
selections={selections.value}
pageSize={50}
ref={tableRef}
url="/api/v1/processmanagement/workstation"
style="margin-top:10px"
v-model:dataSource={dataSource.value}
columns={columns.value}
isChecked={true}
onCheck={onCheck}
/>
表格列配置
const columns = computed(() => [
{
title: _t('序号'),
type: 'seq',
width: '60',
},
{
field: 'workSection.name',
title: _t('工序名称'),
},
{
field: 'name',
title: _t('工位名称'),
},
{
field: 'remark',
title: _t('备注'),
},
])
动态表单生成
DyForm集成
<DyForm
ref={formRef}
v-model:formData={formData.value}
formItemProps={[
{
prop: 'ipListString',
label: _t('可访问IP'),
el: 'input',
clearable: true,
placeholder: _t('请输入可访问IP'),
icon: 'tip',
tip: _t('手动填写IP,存在多个IP访问,以“;”分隔'),
rules: [
{
message: _t('请输入可访问IP'),
pattern: /^(\d{1,3}\.){3}\d{1,3}(\s*;\s*(\d{1,3}\.){3}\d{1,3})*$/,
trigger: 'change',
},
],
},
{
prop: 'userListString',
label: _t('可访问用户'),
el: 'select',
maxCollapseTags: 999,
clearable: true,
placeholder: _t('可访问用户'),
filterable: true,
remote: true,
multiple: true,
collapseTags: true,
options: userOptions.value,
},
]}
/>
树形选择器联动
虽然在当前分析的代码中没有直接看到树形选择器,但基于系统的整体架构,可以预见树形选择器会通过类似的Hook模式实现:
章节来源
性能优化与内存管理
业务级对话框在设计时充分考虑了性能优化和内存管理,避免不必要的重新渲染和内存泄漏。
组件销毁策略
// destroy-on-close属性确保组件销毁
<BaseDialog
destroy-on-close
class={styles.drawer}
style="background: #fff"
width="664px"
height="578px"
title={props.title ? props.title : _t('工位选择')}
v-model={visible.value}
onClose={onClose}
onConfirm={onConfirm}
onOpen={onOpen}
/>
内存泄漏防护
自动清理机制
// 对话框关闭时自动清理状态
const onClose = () => {
visible.value = false
// 清理选中状态
checkedList.value = []
// 清理搜索条件
innerValue.value = ''
// 触发关闭事件
ctx.emit('close')
}
// 确认时的清理
const onConfirm = async () => {
ctx.emit('confirm', checkedList.value)
// 清理表格选中状态
tableRef.value?.clearAll()
visible.value = false
}
异步操作取消
// 使用AbortController或类似机制取消未完成的请求
let abortController: AbortController | null = null
const fetchData = async () => {
abortController = new AbortController()
try {
const response = await fetch('/api/data', {
signal: abortController.signal
})
// 处理响应...
} catch (error) {
if (error.name === 'AbortError') {
// 请求被取消,无需处理
return
}
throw error
}
}
// 在组件卸载时取消请求
onUnmounted(() => {
if (abortController) {
abortController.abort()
}
})
性能优化策略
虚拟滚动
// 对于大数据量表格启用虚拟滚动
<BaseTable
// ... 其他属性
virtual-list-props={{
height: autoHeight.value
}}
isVScroll={true}
/>
懒加载
// 按需加载对话框内容
const onOpen = async () => {
if (!hasLoaded.value) {
await loadData()
hasLoaded.value = true
}
}
最佳实践指南
基于对业务级对话框的深入分析,以下是推荐的最佳实践:
组件设计原则
1. 单一职责原则
每个业务级对话框专注于特定的业务场景,避免功能混杂。
2. 可复用性设计
通过Hook模式提取通用逻辑,减少重复代码。
3. 类型安全
充分利用TypeScript类型系统,确保组件接口的正确性。
开发规范
Hook命名规范
// 推荐的Hook命名格式
export const useSelectDialog = (props: DialogProps, ctx: SetupContext) => {
// 实现...
}
export const useWorkStation = (props: WorkStationProps, ctx: SetupContext) => {
// 实现...
}
API模块组织
// 按功能模块组织API
export const getWorkStationList = (filter?: string) => {
// 实现...
}
export const updateWorkStation = (id: string, data: WorkStationData) => {
// 实现...
}
错误处理策略
分层错误处理
// 组件层错误处理
const onConfirm = async () => {
try {
await validateForm()
await submitData()
ctx.emit('confirm', result)
} catch (error) {
handleError(error)
}
}
// Hook层错误处理
const useSelectDialog = (props: any, ctx: any) => {
const handleError = (error: Error) => {
console.error('Dialog error:', error)
ElMessage.error(_t('操作失败,请稍后重试'))
}
}
测试策略
单元测试覆盖
// Hook函数测试
describe('useSelectDialog', () => {
it('should initialize with correct props', () => {
const props = { modelValue: true, data: [] }
const ctx = createMockContext()
const result = useSelectDialog(props, ctx)
expect(result.visible.value).toBe(true)
expect(result.selections.value).toEqual([])
})
})
集成测试
// 组件集成测试
describe('WorkStationDialog', () => {
it('should render correctly with data', async () => {
const wrapper = mount(WorkStationDialog, {
props: {
modelValue: true,
data: testData
}
})
expect(wrapper.find('.workstation-table')).toBeDefined()
})
})
总结
业务级对话框是LME系统中实现复杂业务逻辑的重要组件。通过BaseDialog基类的统一框架、Hook模式的状态管理、以及完善的API集成,这些组件实现了:
- 高度可复用的架构设计:通过继承和组合模式,实现了代码的最大化复用
- 清晰的职责分离:组件、Hook、API各司其职,保持代码的整洁性
- 强大的状态管理:利用Vue 3 Composition API实现响应式状态管理
- 完善的错误处理:多层次的错误处理机制确保应用稳定性
- 优秀的用户体验:丰富的交互功能和流畅的动画效果
这种设计模式不仅提高了开发效率,也为后续的功能扩展和维护奠定了坚实的基础。开发者可以基于现有的业务级对话框快速构建新的业务场景,同时保持代码质量和一致性。
通过深入理解这些组件的设计理念和实现细节,开发团队能够更好地维护现有系统,并为未来的功能扩展制定合理的规划。