1. 后端 course_service.py: - 课程名重复时返回 existing_id 和 existing_name - 成长路径名重复时返回详细信息 2. 前端 edit-course.vue: - 处理409冲突错误,提供跳转到已存在课程的选项 3. 前端 errorHandler.ts: - 添加409错误的处理逻辑 - 添加冲突错误工具函数 4. 前端 position-management.vue, user-management.vue: - 改进错误消息提取,显示更详细的错误信息
This commit is contained in:
@@ -195,8 +195,12 @@ class CourseService(BaseService[Course]):
|
||||
and_(Course.name == course_in.name, Course.is_deleted == False)
|
||||
)
|
||||
)
|
||||
if existing.scalar_one_or_none():
|
||||
raise ConflictError(f"课程名称 '{course_in.name}' 已存在")
|
||||
existing_course = existing.scalar_one_or_none()
|
||||
if existing_course:
|
||||
raise ConflictError(
|
||||
f"课程名称 '{course_in.name}' 已存在",
|
||||
detail={"existing_id": existing_course.id, "existing_name": existing_course.name}
|
||||
)
|
||||
|
||||
# 创建课程
|
||||
course_data = course_in.model_dump()
|
||||
@@ -260,8 +264,12 @@ class CourseService(BaseService[Course]):
|
||||
)
|
||||
)
|
||||
)
|
||||
if existing.scalar_one_or_none():
|
||||
raise ConflictError(f"课程名称 '{course_in.name}' 已存在")
|
||||
existing_course = existing.scalar_one_or_none()
|
||||
if existing_course:
|
||||
raise ConflictError(
|
||||
f"课程名称 '{course_in.name}' 已存在",
|
||||
detail={"existing_id": existing_course.id, "existing_name": existing_course.name}
|
||||
)
|
||||
|
||||
# 记录状态变更
|
||||
old_status = course.status
|
||||
@@ -800,8 +808,12 @@ class GrowthPathService(BaseService[GrowthPath]):
|
||||
and_(GrowthPath.name == path_in.name, GrowthPath.is_deleted == False)
|
||||
)
|
||||
)
|
||||
if existing.scalar_one_or_none():
|
||||
raise ConflictError(f"成长路径名称 '{path_in.name}' 已存在")
|
||||
existing_path = existing.scalar_one_or_none()
|
||||
if existing_path:
|
||||
raise ConflictError(
|
||||
f"成长路径名称 '{path_in.name}' 已存在",
|
||||
detail={"existing_id": existing_path.id, "existing_name": existing_path.name, "type": "growth_path"}
|
||||
)
|
||||
|
||||
# 验证课程是否存在
|
||||
if path_in.courses:
|
||||
|
||||
@@ -365,6 +365,16 @@ export const handleHttpError = (error: any): ErrorInfo => {
|
||||
type = ErrorType.API
|
||||
message = '请求的资源不存在'
|
||||
break
|
||||
case 409:
|
||||
type = ErrorType.VALIDATION
|
||||
level = ErrorLevel.MEDIUM
|
||||
// 处理冲突错误,通常是资源重复
|
||||
if (typeof data?.detail === 'object') {
|
||||
message = data.detail.message || '资源已存在'
|
||||
} else {
|
||||
message = data?.detail || data?.message || '资源已存在'
|
||||
}
|
||||
break
|
||||
case 429:
|
||||
type = ErrorType.API
|
||||
level = ErrorLevel.HIGH
|
||||
@@ -487,4 +497,48 @@ export const handleWebSocketError = (error: Event, url: string): void => {
|
||||
errorHandler.handleError(errorInfo)
|
||||
}
|
||||
|
||||
// 冲突错误详情接口
|
||||
export interface ConflictDetail {
|
||||
existing_id?: number
|
||||
existing_name?: string
|
||||
type?: string // 'course', 'growth_path', 'user' 等
|
||||
}
|
||||
|
||||
// 检查是否为冲突错误
|
||||
export const isConflictError = (error: any): boolean => {
|
||||
const status = error?.status || error?.response?.status
|
||||
return status === 409
|
||||
}
|
||||
|
||||
// 获取冲突错误详情
|
||||
export const getConflictDetail = (error: any): ConflictDetail | null => {
|
||||
if (!isConflictError(error)) return null
|
||||
|
||||
// 尝试从不同位置获取详情
|
||||
const detail = error?.detail?.detail
|
||||
|| error?.response?.data?.detail?.detail
|
||||
|| error?.response?.data?.detail
|
||||
|| null
|
||||
|
||||
if (detail && typeof detail === 'object') {
|
||||
return {
|
||||
existing_id: detail.existing_id,
|
||||
existing_name: detail.existing_name,
|
||||
type: detail.type
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
// 获取冲突错误消息
|
||||
export const getConflictMessage = (error: any): string => {
|
||||
const detail = error?.detail?.message
|
||||
|| error?.response?.data?.detail?.message
|
||||
|| error?.message
|
||||
|| '资源已存在'
|
||||
|
||||
return typeof detail === 'string' ? detail : '资源已存在'
|
||||
}
|
||||
|
||||
// 导出类型定义
|
||||
|
||||
@@ -640,9 +640,14 @@ const handleSubmit = async () => {
|
||||
loadPositionList()
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
} catch (error: any) {
|
||||
console.error('提交失败:', error)
|
||||
ElMessage.error(isEdit.value ? '岗位编辑失败' : '岗位创建失败')
|
||||
// 提取详细错误信息
|
||||
const message = error?.detail?.message
|
||||
|| error?.response?.data?.detail?.message
|
||||
|| error?.message
|
||||
|| (isEdit.value ? '岗位编辑失败' : '岗位创建失败')
|
||||
ElMessage.error(message)
|
||||
} finally {
|
||||
submitLoading.value = false
|
||||
}
|
||||
|
||||
@@ -1026,9 +1026,18 @@ const handleEdit = async () => {
|
||||
ElMessage.success('用户信息修改成功')
|
||||
loadUserList()
|
||||
}
|
||||
} catch (error) {
|
||||
} catch (error: any) {
|
||||
console.error('编辑用户失败:', error)
|
||||
ElMessage.error('编辑用户失败')
|
||||
// 提取详细错误信息
|
||||
let errorMsg = '编辑用户失败'
|
||||
if (error?.detail?.message) {
|
||||
errorMsg = error.detail.message
|
||||
} else if (error?.response?.data?.detail?.message) {
|
||||
errorMsg = error.response.data.detail.message
|
||||
} else if (error.message) {
|
||||
errorMsg = error.message
|
||||
}
|
||||
ElMessage.error(errorMsg)
|
||||
} finally {
|
||||
editLoading.value = false
|
||||
}
|
||||
|
||||
@@ -988,7 +988,33 @@ const handleSave = async () => {
|
||||
router.push('/manager/course-management')
|
||||
} catch (error: any) {
|
||||
console.error('保存课程失败:', error)
|
||||
ElMessage.error(error.message || '保存课程失败')
|
||||
|
||||
// 处理课程名重复的409冲突错误
|
||||
const status = error?.status || error?.response?.status
|
||||
const detail = error?.detail?.detail || error?.response?.data?.detail?.detail
|
||||
|
||||
if (status === 409 && detail?.existing_id) {
|
||||
// 课程名重复,提供跳转选项
|
||||
ElMessageBox.confirm(
|
||||
`课程名称"${courseForm.name}"已存在,您可以点击下方按钮查看已有课程。`,
|
||||
'课程名称重复',
|
||||
{
|
||||
confirmButtonText: '查看已有课程',
|
||||
cancelButtonText: '修改名称',
|
||||
type: 'warning'
|
||||
}
|
||||
).then(() => {
|
||||
// 跳转到已存在的课程
|
||||
router.push(`/manager/edit-course/${detail.existing_id}`)
|
||||
}).catch(() => {
|
||||
// 用户选择修改名称,聚焦到名称输入框
|
||||
activeTab.value = 'basic'
|
||||
})
|
||||
} else {
|
||||
// 其他错误
|
||||
const message = error?.detail?.message || error?.message || '保存课程失败'
|
||||
ElMessage.error(message)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user