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:
Claude
2026-01-25 00:26:33 +08:00
commit e48975f9d5
151 changed files with 39477 additions and 0 deletions

View 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()