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)
|
and_(Course.name == course_in.name, Course.is_deleted == False)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
if existing.scalar_one_or_none():
|
existing_course = existing.scalar_one_or_none()
|
||||||
raise ConflictError(f"课程名称 '{course_in.name}' 已存在")
|
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()
|
course_data = course_in.model_dump()
|
||||||
@@ -260,8 +264,12 @@ class CourseService(BaseService[Course]):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
if existing.scalar_one_or_none():
|
existing_course = existing.scalar_one_or_none()
|
||||||
raise ConflictError(f"课程名称 '{course_in.name}' 已存在")
|
if existing_course:
|
||||||
|
raise ConflictError(
|
||||||
|
f"课程名称 '{course_in.name}' 已存在",
|
||||||
|
detail={"existing_id": existing_course.id, "existing_name": existing_course.name}
|
||||||
|
)
|
||||||
|
|
||||||
# 记录状态变更
|
# 记录状态变更
|
||||||
old_status = course.status
|
old_status = course.status
|
||||||
@@ -800,8 +808,12 @@ class GrowthPathService(BaseService[GrowthPath]):
|
|||||||
and_(GrowthPath.name == path_in.name, GrowthPath.is_deleted == False)
|
and_(GrowthPath.name == path_in.name, GrowthPath.is_deleted == False)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
if existing.scalar_one_or_none():
|
existing_path = existing.scalar_one_or_none()
|
||||||
raise ConflictError(f"成长路径名称 '{path_in.name}' 已存在")
|
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:
|
if path_in.courses:
|
||||||
|
|||||||
@@ -365,6 +365,16 @@ export const handleHttpError = (error: any): ErrorInfo => {
|
|||||||
type = ErrorType.API
|
type = ErrorType.API
|
||||||
message = '请求的资源不存在'
|
message = '请求的资源不存在'
|
||||||
break
|
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:
|
case 429:
|
||||||
type = ErrorType.API
|
type = ErrorType.API
|
||||||
level = ErrorLevel.HIGH
|
level = ErrorLevel.HIGH
|
||||||
@@ -487,4 +497,48 @@ export const handleWebSocketError = (error: Event, url: string): void => {
|
|||||||
errorHandler.handleError(errorInfo)
|
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()
|
loadPositionList()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error: any) {
|
||||||
console.error('提交失败:', error)
|
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 {
|
} finally {
|
||||||
submitLoading.value = false
|
submitLoading.value = false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1026,9 +1026,18 @@ const handleEdit = async () => {
|
|||||||
ElMessage.success('用户信息修改成功')
|
ElMessage.success('用户信息修改成功')
|
||||||
loadUserList()
|
loadUserList()
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error: any) {
|
||||||
console.error('编辑用户失败:', error)
|
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 {
|
} finally {
|
||||||
editLoading.value = false
|
editLoading.value = false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -988,7 +988,33 @@ const handleSave = async () => {
|
|||||||
router.push('/manager/course-management')
|
router.push('/manager/course-management')
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
console.error('保存课程失败:', error)
|
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