fix: 修复前端登录体验和API调用问题
- 修复路由守卫:未登录时直接跳转,不显示提示信息 - 修复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>
This commit is contained in:
283
src/utils/fieldDependency.ts
Normal file
283
src/utils/fieldDependency.ts
Normal file
@@ -0,0 +1,283 @@
|
||||
/**
|
||||
* 字段联动管理器
|
||||
* 管理字段之间的依赖关系和联动逻辑
|
||||
*/
|
||||
|
||||
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()
|
||||
Reference in New Issue
Block a user