fix: 代码审查修复 - 前端TypeScript类型和UI优化

前端修复:
- 完善TypeScript类型定义(QuestionnairePageParams, QuestionPageParams等)
- 移除未使用的导入(Dayjs等)
- 日期格式化统一使用dateFormatter替代自定义函数
- 问题类型选项使用字典替代硬编码
- 优化API参数传递方式

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
tangweijie 2026-01-15 20:16:10 +08:00
parent 1ebf700cf2
commit fdc6bf58e0
13 changed files with 215 additions and 149 deletions

View File

@ -1,5 +1,4 @@
import request from '@/config/axios'
import type { Dayjs } from 'dayjs';
/** 监区信息信息 */
export interface Area {

View File

@ -1,55 +1,81 @@
import request from '@/config/axios'
import type { Dayjs } from 'dayjs';
/** 监室信息信息 */
export interface Cell {
id: number; // 监室ID
areaId?: number; // 所属监区ID
areaName?: string; // 所属监区名称
name?: string; // 监室名称
code?: string; // 监室编码
capacity: number; // 床位数量
currentCount: number; // 当前人数
sort: number; // 排序
status?: number; // 状态1-启用 2-禁用
remark: string; // 备注
createTime?: Date; // 创建时间
}
// ========== 监室信息类型定义 ==========
// 监室信息 API
// 监室信息响应 VO用于列表和详情展示
export interface CellVO {
id: number
areaId?: number
areaName?: string
name?: string
code?: string
capacity: number
currentCount: number
sort: number
status?: number
remark?: string
createTime?: Date
}
// 监室信息创建 Request VO
export interface CellCreateReqVO {
areaId: number
name: string
code: string
capacity: number
sort: number
status: number
remark?: string
}
// 监室信息更新 Request VO
export interface CellUpdateReqVO extends CellCreateReqVO {
id: number
}
// 监室信息分页 Request VO
export interface CellPageReqVO {
pageNo: number
pageSize: number
areaId?: number
name?: string
status?: number
}
// ========== 监室信息 API ==========
export const CellApi = {
// 查询监室信息分页
getCellPage: async (params: any) => {
return await request.get({ url: `/prison/cell/page`, params })
getCellPage: async (params: CellPageReqVO) => {
return await request.get<{ list: CellVO[]; total: number }>({ url: '/prison/cell/page', params })
},
// 查询监室信息详情
getCell: async (id: number) => {
return await request.get({ url: `/prison/cell/get?id=` + id })
return await request.get<CellVO>({ url: '/prison/cell/get', params: { id } })
},
// 新增监室信息
createCell: async (data: Cell) => {
return await request.post({ url: `/prison/cell/create`, data })
createCell: async (data: CellCreateReqVO) => {
return await request.post({ url: '/prison/cell/create', data })
},
// 修改监室信息
updateCell: async (data: Cell) => {
return await request.put({ url: `/prison/cell/update`, data })
updateCell: async (data: CellUpdateReqVO) => {
return await request.put({ url: '/prison/cell/update', data })
},
// 删除监室信息
deleteCell: async (id: number) => {
return await request.delete({ url: `/prison/cell/delete?id=` + id })
return await request.delete({ url: '/prison/cell/delete', params: { id } })
},
/** 批量删除监室信息 */
// 批量删除监室信息
deleteCellList: async (ids: number[]) => {
return await request.delete({ url: `/prison/cell/delete-list?ids=${ids.join(',')}` })
return await request.delete({ url: '/prison/cell/delete-list', params: { ids: ids.join(',') } })
},
// 导出监室信息 Excel
exportCell: async (params) => {
return await request.download({ url: `/prison/cell/export-excel`, params })
exportCell: async (params: CellPageReqVO) => {
return await request.download({ url: '/prison/cell/export-excel', params })
}
}
}

View File

@ -1,9 +1,8 @@
import request from '@/config/axios'
import type { Dayjs } from 'dayjs';
/** 问卷问题信息 */
export interface Question {
id: number // 问题ID
id?: number // 问题ID(创建时不需要)
questionnaireId?: number // 所属问卷ID
title?: string // 问题标题
type?: number // 问题类型1-单选 2-多选 3-填空 4-评分 5-日期 6-数字
@ -22,48 +21,71 @@ export interface Question {
displayCondition?: string // 显示条件JSON
minValue?: number // 最小值
maxValue?: number // 最大值
createTime?: Date // 创建时间
createTime?: string // 创建时间
}
/** 问卷问题分页参数 */
export interface QuestionPageParams {
pageNo: number
pageSize: number
questionnaireId?: number
title?: string
type?: number
partName?: string
}
/** 批量更新参数 */
export interface BatchUpdateQuestion {
id: number
partName?: string
partSort?: number
sort?: number
}
/** 批量更新请求 */
export interface BatchUpdateReq {
questions: BatchUpdateQuestion[]
}
// 问卷问题 API
export const QuestionApi = {
// 查询问卷问题分页
getQuestionPage: async (params: any) => {
getQuestionPage: async (params: QuestionPageParams) => {
return await request.get({ url: `/prison/question/page`, params })
},
// 查询问卷问题详情
getQuestion: async (id: number) => {
return await request.get({ url: `/prison/question/get?id=` + id })
return await request.get<Question>({ url: `/prison/question/get`, params: { id } })
},
// 新增问卷问题
createQuestion: async (data: Question) => {
return await request.post({ url: `/prison/question/create`, data })
return await request.post<number>({ url: `/prison/question/create`, data })
},
// 修改问卷问题
updateQuestion: async (data: Question) => {
return await request.put({ url: `/prison/question/update`, data })
return await request.put<boolean>({ url: `/prison/question/update`, data })
},
// 删除问卷问题
deleteQuestion: async (id: number) => {
return await request.delete({ url: `/prison/question/delete?id=` + id })
return await request.delete<boolean>({ url: `/prison/question/delete`, params: { id } })
},
/** 批量删除问卷问题 */
deleteQuestionList: async (ids: number[]) => {
return await request.delete({ url: `/prison/question/delete-list?ids=${ids.join(',')}` })
return await request.delete<boolean>({ url: `/prison/question/delete-list`, params: { ids: ids.join(',') } })
},
// 导出问卷问题 Excel
exportQuestion: async (params) => {
exportQuestion: async (params: QuestionPageParams) => {
return await request.download({ url: `/prison/question/export-excel`, params })
},
// 批量更新问卷问题(仅排序和分区字段)
batchUpdate: async (data: { questions: Array<{ id: number; partName?: string; partSort?: number; sort?: number }> }) => {
return await request.post({ url: `/prison/question/batch-update`, data })
batchUpdate: async (data: BatchUpdateReq) => {
return await request.post<boolean>({ url: `/prison/question/batch-update`, data })
}
}
}

View File

@ -1,51 +1,73 @@
import request from '@/config/axios'
import type { Dayjs } from 'dayjs';
/** 问卷模板信息 */
export interface Questionnaire {
id: number; // 问卷ID
title?: string; // 问卷标题
type?: number; // 问卷类型1-心理测评 2-行为评估 3-满意度调查
description: string; // 问卷说明
totalScore: number; // 总分
passScore: number; // 及格分
status?: number; // 状态1-草稿 2-已发布 3-已禁用
}
id?: number // 问卷ID创建时不需要
title: string // 问卷标题
type: number // 问卷类型1-心理测评 2-行为评估 3-满意度调查
description?: string // 问卷说明
totalScore: number // 总分
passScore: number // 及格分
status: number // 状态1-草稿 2-已发布 3-已禁用
coverImage?: string // 封面图片URL
instruction?: string // 填写说明
estimatedTime?: number // 预计耗时(分钟)
partCount?: number // 分区数量
allowAnonymous?: boolean // 是否允许匿名
creator?: string // 创建者
createTime?: string // 创建时间
updater?: string // 更新者
updateTime?: string // 更新时间
}
/** 问卷模板分页参数 */
export interface QuestionnairePageParams {
pageNo: number
pageSize: number
title?: string
type?: number
status?: number
coverImage?: string
instruction?: string
estimatedTime?: number
partCount?: number
allowAnonymous?: boolean
}
// 问卷模板 API
export const QuestionnaireApi = {
// 查询问卷模板分页
getQuestionnairePage: async (params: any) => {
getQuestionnairePage: async (params: QuestionnairePageParams) => {
return await request.get({ url: `/prison/questionnaire/page`, params })
},
// 查询问卷模板详情
getQuestionnaire: async (id: number) => {
return await request.get({ url: `/prison/questionnaire/get?id=` + id })
return await request.get<Questionnaire>({ url: `/prison/questionnaire/get`, params: { id } })
},
// 新增问卷模板
createQuestionnaire: async (data: Questionnaire) => {
return await request.post({ url: `/prison/questionnaire/create`, data })
return await request.post<number>({ url: `/prison/questionnaire/create`, data })
},
// 修改问卷模板
updateQuestionnaire: async (data: Questionnaire) => {
return await request.put({ url: `/prison/questionnaire/update`, data })
return await request.put<boolean>({ url: `/prison/questionnaire/update`, data })
},
// 删除问卷模板
deleteQuestionnaire: async (id: number) => {
return await request.delete({ url: `/prison/questionnaire/delete?id=` + id })
return await request.delete<boolean>({ url: `/prison/questionnaire/delete`, params: { id } })
},
/** 批量删除问卷模板 */
deleteQuestionnaireList: async (ids: number[]) => {
return await request.delete({ url: `/prison/questionnaire/delete-list?ids=${ids.join(',')}` })
return await request.delete<boolean>({ url: `/prison/questionnaire/delete-list`, params: { ids: ids.join(',') } })
},
// 导出问卷模板 Excel
exportQuestionnaire: async (params) => {
exportQuestionnaire: async (params: QuestionnairePageParams) => {
return await request.download({ url: `/prison/questionnaire/export-excel`, params })
}
}
}

View File

@ -1,52 +1,66 @@
import request from '@/config/axios'
import type { Dayjs } from 'dayjs';
/** 问卷答题记录信息 */
export interface QuestionnaireRecord {
id: number; // 记录ID
questionnaireId?: number; // 问卷ID
prisonerId?: number; // 罪犯ID
prisonerNo?: string; // 罪犯编号
totalScore: number; // 得分
passStatus: number; // 是否及格1-及格 2-不及格
answerTime?: string | Dayjs; // 答题时间
status?: number; // 状态1-已完成 2-已过期
}
id?: number // 记录ID创建时不需要
questionnaireId?: number // 问卷ID
prisonerId?: number // 罪犯ID
prisonerNo?: string // 罪犯编号
totalScore?: number // 得分
passStatus?: number // 是否及格0-未及格 1-及格
answerTime?: string // 答题时间
status?: number // 状态1-待评估 2-已完成
createTime?: string // 创建时间
}
/** 问卷答题记录分页参数 */
export interface QuestionnaireRecordPageParams {
pageNo: number
pageSize: number
questionnaireId?: number
prisonerId?: number
prisonerNo?: string
totalScore?: number
passStatus?: number
status?: number
answerTime?: string[]
createTime?: string[]
}
// 问卷答题记录 API
export const QuestionnaireRecordApi = {
// 查询问卷答题记录分页
getQuestionnaireRecordPage: async (params: any) => {
getQuestionnaireRecordPage: async (params: QuestionnaireRecordPageParams) => {
return await request.get({ url: `/prison/questionnaire-record/page`, params })
},
// 查询问卷答题记录详情
getQuestionnaireRecord: async (id: number) => {
return await request.get({ url: `/prison/questionnaire-record/get?id=` + id })
return await request.get<QuestionnaireRecord>({ url: `/prison/questionnaire-record/get`, params: { id } })
},
// 新增问卷答题记录
createQuestionnaireRecord: async (data: QuestionnaireRecord) => {
return await request.post({ url: `/prison/questionnaire-record/create`, data })
return await request.post<number>({ url: `/prison/questionnaire-record/create`, data })
},
// 修改问卷答题记录
updateQuestionnaireRecord: async (data: QuestionnaireRecord) => {
return await request.put({ url: `/prison/questionnaire-record/update`, data })
return await request.put<boolean>({ url: `/prison/questionnaire-record/update`, data })
},
// 删除问卷答题记录
deleteQuestionnaireRecord: async (id: number) => {
return await request.delete({ url: `/prison/questionnaire-record/delete?id=` + id })
return await request.delete<boolean>({ url: `/prison/questionnaire-record/delete`, params: { id } })
},
/** 批量删除问卷答题记录 */
deleteQuestionnaireRecordList: async (ids: number[]) => {
return await request.delete({ url: `/prison/questionnaire-record/delete-list?ids=${ids.join(',')}` })
return await request.delete<boolean>({ url: `/prison/questionnaire-record/delete-list`, params: { ids: ids.join(',') } })
},
// 导出问卷答题记录 Excel
exportQuestionnaireRecord: async (params) => {
exportQuestionnaireRecord: async (params: QuestionnaireRecordPageParams) => {
return await request.download({ url: `/prison/questionnaire-record/export-excel`, params })
}
}
}

View File

@ -458,5 +458,15 @@ export default {
btn_zoom_in: 'Zoom in',
btn_zoom_out: 'Zoom out',
preview: 'Preivew'
},
prison: {
area: {
nameRequired: 'Area name is required',
codeRequired: 'Area code is required',
levelRequired: 'Level is required',
typeRequired: 'Area type is required',
statusRequired: 'Status is required',
parentNotSelf: 'Parent area cannot be itself'
}
}
}

View File

@ -454,5 +454,15 @@ export default {
btn_zoom_out: '缩小',
preview: '预览'
},
prison: {
area: {
nameRequired: '监区名称不能为空',
codeRequired: '监区编码不能为空',
levelRequired: '级别不能为空',
typeRequired: '监区类型不能为空',
statusRequired: '状态不能为空',
parentNotSelf: '父级监区不能选择自己'
}
},
'OAuth 2.0': 'OAuth 2.0' // 避免菜单名是 OAuth 2.0 时,一直 warn 报错
}

View File

@ -86,7 +86,7 @@ import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
import { AreaApi, AreaSaveReqVO } from '@/api/prison/area'
/** 监区信息 表单 */
defineOptions({ name: 'AreaForm' })
defineOptions({ name: 'PrisonAreaForm' })
const { t } = useI18n() //
const message = useMessage() //
@ -110,11 +110,11 @@ const formData = ref({
})
const formRules = reactive({
name: [{ required: true, message: '监区名称不能为空', trigger: 'blur' }],
code: [{ required: true, message: '监区编码不能为空', trigger: 'blur' }],
level: [{ required: true, message: '级别不能为空', trigger: 'blur' }],
type: [{ required: true, message: '监区类型不能为空', trigger: 'blur' }],
status: [{ required: true, message: '状态不能为空', trigger: 'blur' }]
name: [{ required: true, message: t('prison.area.nameRequired'), trigger: 'blur' }],
code: [{ required: true, message: t('prison.area.codeRequired'), trigger: 'blur' }],
level: [{ required: true, message: t('prison.area.levelRequired'), trigger: 'blur' }],
type: [{ required: true, message: t('prison.area.typeRequired'), trigger: 'blur' }],
status: [{ required: true, message: t('prison.area.statusRequired'), trigger: 'blur' }]
})
const formRef = ref() // Ref
@ -191,7 +191,7 @@ const submitForm = async () => {
const data = formData.value as unknown as AreaSaveReqVO
//
if (data.level === 2 && data.parentId === data.id) {
message.error('父级监区不能选择自己')
message.error(t('prison.area.parentNotSelf'))
return
}
if (formType.value === 'create') {

View File

@ -221,14 +221,11 @@ import { AreaApi, AreaNode } from '@/api/prison/area'
import AreaForm from './AreaForm.vue'
import { OfficeBuilding, Files } from '@element-plus/icons-vue'
defineOptions({ name: 'Area' })
defineOptions({ name: 'PrisonArea' })
const message = useMessage()
const { t } = useI18n()
const loading = ref(true)
const list = ref<Area[]>([])
const total = ref(0)
const queryParams = reactive({
pageNo: 1,
pageSize: 10,
@ -257,12 +254,6 @@ const treeProps = {
children: 'children'
}
/** 日期格式化 */
const formatDate = (date: string | Date | undefined) => {
if (!date) return '-'
return new Date(date).toLocaleString('zh-CN')
}
/** 获取级别图标 */
const getLevelIcon = (level: number) => {
return level === 1 ? OfficeBuilding : Files
@ -319,22 +310,9 @@ const getTreeList = async () => {
}
}
/** 查询列表 */
const getList = async () => {
loading.value = true
try {
const data = await AreaApi.getAreaPage(queryParams)
list.value = data.list
total.value = data.total
} finally {
loading.value = false
}
}
/** 搜索按钮操作 */
const handleQuery = () => {
queryParams.pageNo = 1
getList()
//
getTreeListWithSearch()
}
@ -344,7 +322,6 @@ const resetQuery = () => {
queryFormRef.value.resetFields()
// 使
getTreeList()
handleQuery()
}
/** 添加/修改操作 */
@ -404,7 +381,6 @@ const handleExport = async () => {
/** 初始化 */
onMounted(() => {
getTreeList()
getList()
})
</script>

View File

@ -58,8 +58,9 @@
</template>
<script setup lang="ts">
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
import { CellApi, Cell } from '@/api/prison/cell'
import { CellApi } from '@/api/prison/cell'
import { AreaApi } from '@/api/prison/area'
import type { CellVO, CellCreateReqVO, CellUpdateReqVO } from '@/api/prison/cell'
/** 监室信息 表单 */
defineOptions({ name: 'CellForm' })
@ -75,22 +76,22 @@ const formType = ref('') // 表单的类型create - 新增update - 修改
//
const areaTreeData = ref<any[]>([])
const formData = ref({
const formData = ref<Partial<CellCreateReqVO> & { id?: number }>({
id: undefined,
areaId: undefined as number | undefined,
areaId: undefined,
name: undefined,
code: undefined,
capacity: undefined as number | undefined,
currentCount: undefined as number | undefined,
sort: undefined as number | undefined,
status: undefined as number | undefined,
capacity: undefined,
sort: undefined,
status: undefined,
remark: undefined
})
const formRules = reactive({
areaId: [{ required: true, message: '所属监区不能为空', trigger: 'change' }],
name: [{ required: true, message: '监室名称不能为空', trigger: 'blur' }],
code: [{ required: true, message: '监室编码不能为空', trigger: 'blur' }],
status: [{ required: true, message: '状态不能为空', trigger: 'blur' }]
sort: [{ required: true, message: '排序不能为空', trigger: 'blur' }],
status: [{ required: true, message: '状态不能为空', trigger: 'change' }]
})
const formRef = ref() // Ref
@ -98,7 +99,8 @@ const formRef = ref() // 表单 Ref
const loadAreaTree = async () => {
try {
areaTreeData.value = await AreaApi.getAreaTree()
} catch {
} catch (error) {
console.error('加载监区树形数据失败:', error)
areaTreeData.value = []
}
}
@ -133,17 +135,19 @@ const submitForm = async () => {
//
formLoading.value = true
try {
const data = formData.value as unknown as Cell
const data = formData.value as CellCreateReqVO & { id?: number }
if (formType.value === 'create') {
await CellApi.createCell(data)
message.success(t('common.createSuccess'))
} else {
await CellApi.updateCell(data)
await CellApi.updateCell(data as CellUpdateReqVO)
message.success(t('common.updateSuccess'))
}
dialogVisible.value = false
//
emit('success')
} catch (error) {
console.error('提交表单失败:', error)
} finally {
formLoading.value = false
}
@ -157,7 +161,6 @@ const resetForm = () => {
name: undefined,
code: undefined,
capacity: undefined,
currentCount: undefined,
sort: undefined,
status: undefined,
remark: undefined

View File

@ -139,9 +139,10 @@
<script lang="ts" setup>
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
import download from '@/utils/download'
import { CellApi, Cell } from '@/api/prison/cell'
import { CellApi } from '@/api/prison/cell'
import { AreaApi } from '@/api/prison/area'
import CellForm from './CellForm.vue'
import type { CellVO, CellPageReqVO } from '@/api/prison/cell'
defineOptions({ name: 'Cell' })
@ -149,12 +150,12 @@ const message = useMessage()
const { t } = useI18n()
const loading = ref(true)
const list = ref<Cell[]>([])
const list = ref<CellVO[]>([])
const total = ref(0)
const queryParams = reactive({
const queryParams = reactive<CellPageReqVO>({
pageNo: 1,
pageSize: 10,
areaId: undefined as number | undefined,
areaId: undefined,
name: undefined,
status: undefined
})
@ -224,7 +225,7 @@ const handleDelete = async (id: number) => {
/** 批量删除按钮操作 */
const checkedIds = ref<number[]>([])
const handleRowCheckboxChange = (rows: Cell[]) => {
const handleRowCheckboxChange = (rows: CellVO[]) => {
checkedIds.value = rows.map((row) => row.id!)
}
@ -244,7 +245,7 @@ const handleExport = async () => {
await message.exportConfirm()
exportLoading.value = true
const data = await CellApi.exportCell(queryParams)
download.excel(data, '监室信息.xls')
download.excel(data, '监室信息.xlsx')
} catch {
} finally {
exportLoading.value = false

View File

@ -96,7 +96,7 @@
</el-table-column>
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
<template #default="scope">
{{ formatDate(scope.row.createTime) }}
{{ dateFormatter(scope.row.createTime) }}
</template>
</el-table-column>
<el-table-column label="操作" align="center" width="150">
@ -157,19 +157,8 @@ const queryParams = reactive({
const queryFormRef = ref()
const exportLoading = ref(false)
// (1- 2- 3- 4-)
const questionTypeOptions = [
{ label: '单选', value: 1 },
{ label: '多选', value: 2 },
{ label: '填空', value: 3 },
{ label: '评分', value: 4 }
]
/** 日期格式化 */
const formatDate = (date: string | Date | undefined) => {
if (!date) return '-'
return new Date(date).toLocaleString('zh-CN')
}
// (使)
const questionTypeOptions = getIntDictOptions(DICT_TYPE.PRISON_QUESTION_TYPE)
/** 查询列表 */
const getList = async () => {

View File

@ -110,7 +110,7 @@
</el-table-column>
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
<template #default="scope">
{{ formatDate(scope.row.createTime) }}
{{ dateFormatter(scope.row.createTime) }}
</template>
</el-table-column>
<el-table-column label="操作" align="center" width="150">
@ -185,12 +185,6 @@ const exportLoading = ref(false)
const questionnaireTypeOptions = getIntDictOptions(DICT_TYPE.PRISON_QUESTIONNAIRE_TYPE)
const questionnaireStatusOptions = getIntDictOptions(DICT_TYPE.PRISON_QUESTIONNAIRE_STATUS)
/** 日期格式化 */
const formatDate = (date: string | Date | undefined) => {
if (!date) return '-'
return new Date(date).toLocaleString('zh-CN')
}
/** 查询列表 */
const getList = async () => {
loading.value = true