- 修复路由守卫:未登录时直接跳转,不显示提示信息 - 修复API拦截器:401错误直接跳转,无需确认 - 移除不必要的ElMessageBox确认框 - 优化Token过期处理逻辑 - 修复文件管理API引入路径和URL前缀 - 修复调拨/回收管理API端点不匹配问题 - 修复通知管理API方法不匹配问题 - 统一系统配置API路径为单数形式 影响文件: - src/router/index.ts - src/api/request.ts - src/api/file.ts - src/api/index.ts 测试状态: - 前端构建通过 - 所有API路径已验证 - 登录流程测试通过 Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
284 lines
6.6 KiB
TypeScript
284 lines
6.6 KiB
TypeScript
/**
|
|
* 字段联动管理器
|
|
* 管理字段之间的依赖关系和联动逻辑
|
|
*/
|
|
|
|
import type { FieldDependency, FormData } from '@/types/form'
|
|
|
|
/**
|
|
* 字段联动管理器类
|
|
*/
|
|
export class FieldDependencyManager {
|
|
/** 联动配置列表 */
|
|
private dependencies: FieldDependency[] = []
|
|
|
|
/** 字段变化回调 */
|
|
private callbacks: Map<string, Set<(targetField: string, action: any) => void>> = new Map()
|
|
|
|
/**
|
|
* 添加联动配置
|
|
* @param dep 联动配置
|
|
*/
|
|
addDependency(dep: FieldDependency): void {
|
|
// 检查是否已存在相同的联动配置
|
|
const existingIndex = this.dependencies.findIndex(
|
|
(d) => d.sourceField === dep.sourceField && d.targetField === dep.targetField
|
|
)
|
|
|
|
if (existingIndex >= 0) {
|
|
// 替换现有配置
|
|
this.dependencies[existingIndex] = dep
|
|
} else {
|
|
// 添加新配置
|
|
this.dependencies.push(dep)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 批量添加联动配置
|
|
* @param deps 联动配置列表
|
|
*/
|
|
addDependencies(deps: FieldDependency[]): void {
|
|
deps.forEach((dep) => this.addDependency(dep))
|
|
}
|
|
|
|
/**
|
|
* 移除联动配置
|
|
* @param sourceField 源字段
|
|
* @param targetField 目标字段
|
|
*/
|
|
removeDependency(sourceField: string, targetField: string): void {
|
|
this.dependencies = this.dependencies.filter(
|
|
(d) => !(d.sourceField === sourceField && d.targetField === targetField)
|
|
)
|
|
}
|
|
|
|
/**
|
|
* 清空所有联动配置
|
|
*/
|
|
clear(): void {
|
|
this.dependencies = []
|
|
this.callbacks.clear()
|
|
}
|
|
|
|
/**
|
|
* 触发联动
|
|
* @param sourceField 源字段名称
|
|
* @param sourceValue 源字段值
|
|
* @param allFormData 所有表单数据
|
|
* @returns 联动结果 { [targetField]: { type, value } }
|
|
*/
|
|
trigger(
|
|
sourceField: string,
|
|
sourceValue: any,
|
|
allFormData: FormData
|
|
): Record<string, { type: string; value?: any }> {
|
|
const results: Record<string, { type: string; value?: any }> = {}
|
|
|
|
// 找到所有与源字段相关的联动配置
|
|
const relatedDeps = this.dependencies.filter((dep) => dep.sourceField === sourceField)
|
|
|
|
relatedDeps.forEach((dep) => {
|
|
// 检查条件是否满足
|
|
if (dep.condition(sourceValue, allFormData)) {
|
|
let result: any = undefined
|
|
|
|
// 执行联动动作
|
|
switch (dep.type) {
|
|
case 'show':
|
|
case 'hide':
|
|
result = dep.type === 'show'
|
|
break
|
|
|
|
case 'enable':
|
|
case 'disable':
|
|
result = dep.type !== 'disable'
|
|
break
|
|
|
|
case 'setValue':
|
|
if (dep.action) {
|
|
result = dep.action(
|
|
allFormData[dep.targetField],
|
|
sourceValue,
|
|
allFormData
|
|
)
|
|
}
|
|
break
|
|
|
|
case 'setOptions':
|
|
if (dep.action) {
|
|
result = dep.action(
|
|
allFormData[dep.targetField],
|
|
sourceValue,
|
|
allFormData
|
|
)
|
|
}
|
|
break
|
|
}
|
|
|
|
results[dep.targetField] = {
|
|
type: dep.type,
|
|
value: result
|
|
}
|
|
|
|
// 触发回调
|
|
this.emit(sourceField, dep.targetField, { type: dep.type, value: result })
|
|
}
|
|
})
|
|
|
|
return results
|
|
}
|
|
|
|
/**
|
|
* 注册字段变化回调
|
|
* @param sourceField 源字段
|
|
* @param callback 回调函数
|
|
*/
|
|
on(sourceField: string, callback: (targetField: string, action: any) => void): void {
|
|
if (!this.callbacks.has(sourceField)) {
|
|
this.callbacks.set(sourceField, new Set())
|
|
}
|
|
this.callbacks.get(sourceField)!.add(callback)
|
|
}
|
|
|
|
/**
|
|
* 取消注册回调
|
|
* @param sourceField 源字段
|
|
* @param callback 回调函数
|
|
*/
|
|
off(sourceField: string, callback: (targetField: string, action: any) => void): void {
|
|
const callbacks = this.callbacks.get(sourceField)
|
|
if (callbacks) {
|
|
callbacks.delete(callback)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 触发回调
|
|
*/
|
|
private emit(sourceField: string, targetField: string, action: any): void {
|
|
const callbacks = this.callbacks.get(sourceField)
|
|
if (callbacks) {
|
|
callbacks.forEach((cb) => cb(targetField, action))
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 获取所有联动配置
|
|
*/
|
|
getDependencies(): FieldDependency[] {
|
|
return [...this.dependencies]
|
|
}
|
|
|
|
/**
|
|
* 获取与指定字段相关的所有联动
|
|
* @param fieldName 字段名称
|
|
*/
|
|
getFieldDependencies(fieldName: string): {
|
|
asSource: FieldDependency[]
|
|
asTarget: FieldDependency[]
|
|
} {
|
|
return {
|
|
asSource: this.dependencies.filter((dep) => dep.sourceField === fieldName),
|
|
asTarget: this.dependencies.filter((dep) => dep.targetField === fieldName)
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 创建常用的联动条件函数
|
|
*/
|
|
export const DependencyConditions = {
|
|
/**
|
|
* 等于某个值
|
|
*/
|
|
equals: (value: any) => (sourceValue: any) => sourceValue === value,
|
|
|
|
/**
|
|
* 不等于某个值
|
|
*/
|
|
notEquals: (value: any) => (sourceValue: any) => sourceValue !== value,
|
|
|
|
/**
|
|
* 包含某个值(用于数组)
|
|
*/
|
|
contains: (value: any) => (sourceValue: any) => {
|
|
if (Array.isArray(sourceValue)) {
|
|
return sourceValue.includes(value)
|
|
}
|
|
return sourceValue === value
|
|
},
|
|
|
|
/**
|
|
* 不包含某个值
|
|
*/
|
|
notContains: (value: any) => (sourceValue: any) => {
|
|
if (Array.isArray(sourceValue)) {
|
|
return !sourceValue.includes(value)
|
|
}
|
|
return sourceValue !== value
|
|
},
|
|
|
|
/**
|
|
* 大于某个值
|
|
*/
|
|
greaterThan: (value: any) => (sourceValue: any) => Number(sourceValue) > Number(value),
|
|
|
|
/**
|
|
* 小于某个值
|
|
*/
|
|
lessThan: (value: any) => (sourceValue: any) => Number(sourceValue) < Number(value),
|
|
|
|
/**
|
|
* 在某个范围内
|
|
*/
|
|
between: (min: number, max: number) => (sourceValue: any) => {
|
|
const num = Number(sourceValue)
|
|
return num >= min && num <= max
|
|
},
|
|
|
|
/**
|
|
* 值为真
|
|
*/
|
|
isTrue: () => (sourceValue: any) => Boolean(sourceValue),
|
|
|
|
/**
|
|
* 值为假
|
|
*/
|
|
isFalse: () => (sourceValue: any) => !Boolean(sourceValue)
|
|
}
|
|
|
|
/**
|
|
* 创建常用的联动动作函数
|
|
*/
|
|
export const DependencyActions = {
|
|
/**
|
|
* 设置为固定值
|
|
*/
|
|
setValue: (value: any) => () => value,
|
|
|
|
/**
|
|
* 清空值
|
|
*/
|
|
clearValue: () => () => undefined,
|
|
|
|
/**
|
|
* 根据源值设置目标值
|
|
*/
|
|
copyValue: () => (_target: any, source: any) => source,
|
|
|
|
/**
|
|
* 动态加载选项
|
|
*/
|
|
loadOptions: (optionsLoader: (sourceValue: any) => Array<{ label: string; value: any }>) => {
|
|
return () => async (_target: any, source: any, allData: FormData) => {
|
|
return await optionsLoader(source)
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 导出单例实例
|
|
*/
|
|
export const fieldDependencyManager = new FieldDependencyManager()
|