<!-- 训练登记表详情 --> <script name="TrainDetail" lang="ts" setup> import { ElMessage, ElMessageBox, dayjs } from 'element-plus' import type { IStaffBasicInfo } from '../register/person-regitster' import type { IStaffListQuery, ITrainInfo } from './train-interface' import FilterRegistedStaff from '@/views/resource/common/filterRegistedStaff.vue' import { addTrainInfo, getTrainStaffList, updateTrainInfo } from '@/api/resource/train' import type { TableColumn } from '@/components/NormalTable/table_interface' import type { IDictType } from '@/commonInterface/resource-interface' const type = ref<string>('') const id = ref<string>('') const route = useRoute() const router = useRouter() // 字典值 const trainSiteDict = ref<Array<IDictType>>([]) // 训练地点 HK / XC const trainGroupDict = ref<Array<IDictType>>([]) // 培训部门 const trainContentDict = ref<Array<IDictType>>([]) // 培训内容 const trainWayDict = ref<Array<IDictType>>([]) // 培训方式 const staffListQuery = ref<IStaffListQuery>({ id: '', limit: 1200, offset: 1, }) const trainInfo = ref<ITrainInfo>({ id: '', trainNo: '', trainSite: '', trainSiteName: '', trainGroupArray: [], trainGroup: '', trainGroupName: '', trainContent: '', trainContentName: '', trainWay: '', trainWayName: '', dutyLeader: '', trainType: '', trainText: '', trainDate: '', trainLocation: '', shouldAttendCount: undefined, actualAttendCount: undefined, attendRate: '', score: '', consume: '', remark: '', trainName: '训练登记表', createTime: '', staffList: [], }) const trainStaffList = ref<Array<IStaffBasicInfo>>([]) const basicFormRef = ref() const staffFormRef = ref() const refFilterStaff = ref() const trainBasicRules = ref({ trainSite: [{ required: true, message: '训练场地不能为空,请选择', trigger: ['change', 'blur'] }], trainGroup: [{ required: true, message: '培训部门不能为空,请选择', trigger: ['change', 'blur'] }], trainContent: [{ required: true, message: '培训内容不能为空,请选择', trigger: ['change', 'blur'] }], trainWay: [{ required: true, message: '培训方式不能为空,请选择', trigger: ['change', 'blur'] }], dutyLeader: [{ required: true, message: '值班领导不能为空', trigger: 'blur' }], trainType: [{ required: true, message: '训练类别不能为空', trigger: 'blur' }], trainText: [{ required: true, message: '训练内容不能为空', trigger: 'blur' }], trainDate: [{ required: true, message: '训练时间不能为空', trigger: 'blur' }], trainLocation: [{ required: true, message: '训练地点不能为空', trigger: 'blur' }], shouldAttendCount: [{ required: true, message: '应训人数不能为空', trigger: ['blur', 'change'] }], actualAttendCount: [{ required: true, message: '实训人数不能为空', trigger: ['blur', 'change'] }], score: [{ required: true, message: '训练效果不能为空', trigger: 'blur' }], consume: [{ required: true, message: '消耗不能为空', trigger: 'blur' }], }) // 表单验证规则 const staffColumns = ref<Array<TableColumn>>([ { text: '人员编号', value: 'staffNo', align: 'center', width: '160' }, { text: '姓名', value: 'staffName', align: 'center', width: '150' }, { text: '工作部门', value: 'deptName', align: 'center' }, { text: '岗位', value: 'station', align: 'center' }, { text: '人员类别', value: 'staffTypeName', align: 'center', width: '150' }, { text: '效果(成绩)', value: 'staffScore', align: 'center', width: '150' }, ]) // 表头 // 表格被选中的行 const staffSelected = ref<IStaffBasicInfo[]>([]) // 逻辑 // 关闭 const resetForm = () => { sessionStorage.removeItem('trainInfo') router.go(-1) } const staffMultiSelect = (e: any) => { staffSelected.value = e } // 新增训练登记表 const addTrainAndStaffList = () => { trainInfo.value.createTime = dayjs(new Date()).format('YYYY-MM-DD HH:mm:ss') addTrainInfo(trainInfo.value).then((res) => { if (res.code === 200) { // 提示保存成功 ElMessage.success('保存成功') type.value = 'detail' } else { // 提示失败信息 ElMessage.error(`保存失败:${res.message}`) } }) } // 编辑登记表 const updateTrainAndStaffList = () => { updateTrainInfo(trainInfo.value).then((res) => { if (res.code === 200) { // 提示保存成功 ElMessage.success('保存成功') type.value = 'detail' } else { // 提示失败信息 ElMessage.error(`保存失败:${res.message}`) } }) } // 保存基本信息 const saveTrainForm = async () => { if (!basicFormRef) { return } await basicFormRef.value.validate((valid: boolean, fields: any) => { if (valid === true) { if (trainInfo.value.staffList !== undefined && trainInfo.value.staffList.length > 0) { ElMessageBox.confirm( '确认保存吗?', '提示', { confirmButtonText: '确认', cancelButtonText: '取消', type: 'warning', }, ).then(() => { if (type.value === 'create') { addTrainAndStaffList() } else if (type.value === 'update') { updateTrainAndStaffList() } }) } else { ElMessage.warning('实训人员不能为空') } } }) } // 从接口查询 const getActualTrainStaffList = (trainId: string) => { staffListQuery.value.id = trainId getTrainStaffList(staffListQuery.value).then((res) => { if (res.code === 200) { trainStaffList.value = res.data.rows // 添加staffList trainInfo.value.staffList = [] trainStaffList.value.forEach((item) => { trainInfo.value.staffList!.push({ staffId: item.id!, score: item.staffScore!, }) }) } }) } // 点击增加行按钮 选择人员 const addEditableRow = () => { if (trainInfo.value.actualAttendCount === 0 || trainInfo.value.actualAttendCount === null) { ElMessage.warning('请先输入实训人数') } else if (trainInfo.value.actualAttendCount! <= trainStaffList.value.length) { ElMessage.warning('实训人员列表总数不能超过实训人数') } else { refFilterStaff.value.showOrHideFilterDialog(true, trainInfo.value.actualAttendCount) } } // 选定人员 const recordSelectedHandler = (rows: Array<IStaffBasicInfo>) => { refFilterStaff.value.showOrHideFilterDialog(false) // 没有实训人员列表 则直接添加 if (trainStaffList.value.length > 0) { // 找到已有实训人员列表中不存在的记录 加到新选择的记录中 const selectedIds = rows.map(item => item.id) const notInNew = trainStaffList.value.filter(item => selectedIds.includes(item.id) === false) trainStaffList.value = notInNew } trainStaffList.value = trainStaffList.value.concat(rows) trainInfo.value.staffList = [] trainStaffList.value.forEach((row: IStaffBasicInfo) => { trainInfo.value.staffList!.push({ staffId: row.id!, score: row.staffScore!, }) }) } // 删除实训人员 const delTrainStaffRec = async () => { if (staffSelected.value.length === 0) { ElMessage.warning('请至少选择一行') return } // 前端界面删除 trainStaffList.value = trainStaffList.value.filter(item => staffSelected.value.includes(item) === false) // 将详情数据中的值也删除 trainInfo.value.staffList = [] trainStaffList.value.forEach((row: IStaffBasicInfo) => { trainInfo.value.staffList!.push({ staffId: row.id!, score: row.staffScore!, }) }) } const initDialog = (params: any) => { type.value = params.type id.value = params.id switch (params.type) { case 'create' : trainInfo.value.createTime = dayjs(new Date()).format('YYYY-MM-DD HH:mm:ss') break case 'update': trainInfo.value = JSON.parse(sessionStorage.getItem('trainInfo')!) getActualTrainStaffList(trainInfo.value.id) break case 'detail': trainInfo.value = JSON.parse(sessionStorage.getItem('trainInfo')!) getActualTrainStaffList(trainInfo.value.id) break default: break } } const initDict = () => { if (trainSiteDict.value.length === 0) { trainSiteDict.value = JSON.parse(sessionStorage.getItem('bizTrainSite')!) } if (trainGroupDict.value.length === 0) { trainGroupDict.value = JSON.parse(sessionStorage.getItem('bizGroupCode')!) } if (trainContentDict.value.length === 0) { trainContentDict.value = JSON.parse(sessionStorage.getItem('bizTrainContent')!) } if (trainWayDict.value.length === 0) { trainWayDict.value = JSON.parse(sessionStorage.getItem('bizTrainWay')!) } } // 计算参训率 const rate = computed(() => { if (trainInfo.value.shouldAttendCount === undefined || trainInfo.value.actualAttendCount === undefined || trainInfo.value.shouldAttendCount === 0 || trainInfo.value.actualAttendCount === 0) { return '0.00' } else { return ((trainInfo.value.actualAttendCount! / trainInfo.value.shouldAttendCount!) * 100).toFixed(2) } }) // 监听训练场地 显示中文 watch(() => trainInfo.value.trainSite, (newVal) => { const targetList = trainSiteDict.value.filter(item => item.value === newVal) if (targetList.length > 0) { trainInfo.value.trainSiteName = targetList[0].name } else { trainInfo.value.trainSiteName = '' } }) // 监听培训部门 显示中文 watch(() => trainInfo.value.trainGroupArray, (newVal) => { if (trainInfo.value.trainGroupArray === undefined) { return } if (newVal?.length === 0) { trainInfo.value.trainGroup = '' trainInfo.value.trainGroupName = '' } else { let nameStr = '' newVal?.forEach((val) => { const targetList = trainGroupDict.value.filter(item => item.value === val) if (targetList.length > 0) { nameStr += `${targetList[0].name}, ` } }) nameStr = nameStr.substring(0, nameStr.length - 2) trainInfo.value.trainGroup = newVal!.toString() trainInfo.value.trainGroupName = nameStr } }) // 监听培训内容 显示中文 watch(() => trainInfo.value.trainContent, (newVal) => { const targetList = trainContentDict.value.filter(item => item.value === newVal) if (targetList.length > 0) { trainInfo.value.trainContentName = targetList[0].name } else { trainInfo.value.trainContentName = '' } }) // 监听培训方式 显示中文 watch(() => trainInfo.value.trainWay, (newVal) => { const targetList = trainWayDict.value.filter(item => item.value === newVal) if (targetList.length > 0) { trainInfo.value.trainWayName = targetList[0].name } else { trainInfo.value.trainWayName = '' } }) onMounted(async () => { initDict() initDialog(route.query) }) </script> <template> <app-container> <detail-page title="训练登记表"> <template #btns> <el-button v-if="type !== 'detail'" type="primary" @click="saveTrainForm()"> 保存 </el-button> <el-button type="info" @click="resetForm()"> 关闭 </el-button> </template> <el-form ref="basicFormRef" :model="trainInfo" :rules="trainBasicRules" label-position="right" :class="[type === 'detail' ? 'isDetail' : '']" label-width="110" border stripe> <el-row :gutter="24"> <!-- 第一行 第一列 --> <el-col :span="6"> <el-form-item label="训练场地" prop="trainSite"> <el-select v-model="trainInfo.trainSite" style="width: 100%;" placeholder="请选择训练场地" :disabled="type === 'detail'"> <el-option v-for="site in trainSiteDict" :key="site.id" :value="site.value" :label="site.name" /> </el-select> <el-input v-model="trainInfo.trainSiteName" type="hidden" /> </el-form-item> <el-form-item label="登记表编号"> <el-input v-model="trainInfo.trainNo" placeholder="请输入训练登记表编号" :clearable="true" :disabled="type === 'detail'" /> </el-form-item> <el-form-item label="训练类别" prop="trainType"> <el-input v-model="trainInfo.trainType" :clearable="true" placeholder="请输入训练类别" :disabled="type === 'detail'" /> </el-form-item> <el-form-item label="应训人数" prop="shouldAttendCount"> <el-input-number v-model="trainInfo.shouldAttendCount" placeholder="请输入应训人数" :min="0" :step="1" controls-position="right" :clearable="true" :disabled="type === 'detail'" style="width: 100%;" /> </el-form-item> </el-col> <!-- 第一行 第二列 --> <el-col :span="6"> <el-form-item label="培训部门" prop="trainGroup"> <el-select v-if="type !== 'detail'" v-model="trainInfo.trainGroupArray" style="width: 100%;" multiple collapse-tags collapse-tags-tooltip placeholder="培训部门,可多选" :disabled="type === 'detail'" > <el-option v-for="site in trainGroupDict" :key="site.id" :value="site.value" :label="site.name" /> </el-select> <el-input v-model="trainInfo.trainGroup" type="hidden" /> <el-input v-if="type === 'detail'" v-model="trainInfo.trainGroupName" :disabled="true" /> </el-form-item> <el-form-item label="登记表名称"> <el-input v-model="trainInfo.trainName" :disabled="true" /> </el-form-item> <el-form-item label="训练内容" prop="trainText"> <el-input v-model="trainInfo.trainText" :clearable="true" placeholder="请输入训练内容" :disabled="type === 'detail'" /> </el-form-item> <el-form-item label="实训人数" prop="actualAttendCount"> <el-input-number v-model="trainInfo.actualAttendCount" placeholder="请输入实训人数" :min="0" :step="1" controls-position="right" :clearable="true" :disabled="type === 'detail'" style="width: 100%;" /> </el-form-item> </el-col> <!-- 第一行 第三列 --> <el-col :span="6"> <el-form-item label="培训内容" prop="trainContent"> <el-select v-model="trainInfo.trainContent" style="width: 100%;" placeholder="请选择培训内容" :disabled="type === 'detail'"> <el-option v-for="site in trainContentDict" :key="site.id" :value="site.value" :label="site.name" /> </el-select> <el-input v-model="trainInfo.trainContentName" type="hidden" /> </el-form-item> <el-form-item label="值班领导" prop="dutyLeader"> <el-input v-model="trainInfo.dutyLeader" :clearable="true" placeholder="请输入值班领导" :disabled="type === 'detail'" /> </el-form-item> <el-form-item label="训练内容" prop="trainDate"> <el-date-picker v-model="trainInfo.trainDate" type="date" format="YYYY-MM-DD" value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择训练时间" :disabled="type === 'detail'" style="width: 100%;" /> </el-form-item> <el-form-item label="参训率"> <el-input v-model="rate" :readonly="true" :disabled="type === 'detail'" placeholder="自动计算"> <template #append> % </template> </el-input> </el-form-item> </el-col> <!-- 第一行 第四列 --> <el-col :span="6"> <el-form-item label="培训方式" prop="trainWay"> <el-select v-model="trainInfo.trainWay" placeholder="请选择培训方式" style="width: 100%;" :clearable="true" :disabled="type === 'detail'"> <el-option v-for="dict in trainWayDict" :key="dict.id" :label="dict.name" :value="dict.value" /> </el-select> <el-input v-model="trainInfo.trainWayName" type="hidden" /> </el-form-item> <el-form-item label="创建时间"> <el-input v-model="trainInfo.createTime" :disabled="true" /> </el-form-item> <el-form-item label="训练地点" prop="trainLocation"> <el-input v-model="trainInfo.trainLocation" :clearable="true" :disabled="type === 'detail'" placeholder="请输入训练地点" /> </el-form-item> <el-form-item label="效果(成绩)" prop="score"> <el-input v-model="trainInfo.score" :clearable="true" :disabled="type === 'detail'" placeholder="请输入训练效果" /> </el-form-item> </el-col> </el-row> <!-- 第二行 --> <el-row :gutter="24"> <el-col :span="6"> <el-form-item label="消耗" prop="consume"> <el-input v-model="trainInfo.consume" placeholder="请输入消耗" :clearable="true" :disabled="type === 'detail'" /> </el-form-item> </el-col> <el-col :span="18"> <el-form-item label="备注"> <el-input v-model="trainInfo.remark" placeholder="请输入备注信息" :clearable="true" :disabled="type === 'detail'" /> </el-form-item> </el-col> </el-row> </el-form> </detail-page> <el-form ref="staffFormRef" label-position="right" label-width="110px" border stripe> <table-container title="实训人员" style="margin-top: 20px;"> <template v-if="type !== 'detail'" #btns-right> <el-button type="primary" @click="addEditableRow"> 增加行 </el-button> <el-button type="info" @click="delTrainStaffRec"> 删除行 </el-button> </template> <!-- 表格区域 --> <el-table :data="trainStaffList" :columns="staffColumns" border @selection-change="staffMultiSelect"> <el-table-column v-if="type !== 'detail'" type="selection" align="center" width="40" /> <el-table-column align="center" label="序号" width="55" type="index" /> <el-table-column v-for="item in staffColumns" :key="item.value" :prop="item.value" :label="item.text" align="center" > <template #header> <span>{{ item.text }}</span> </template> </el-table-column> </el-table> </table-container> </el-form> <filter-registed-staff ref="refFilterStaff" @record-selected="recordSelectedHandler" /> </app-container> </template> <style lang="scss" scoped> .isDetail { ::v-deep { .el-form-item.is-required:not(.is-no-asterisk) .el-form-item__label-wrap > .el-form-item__label::before, .el-form-item.is-required:not(.is-no-asterisk) > .el-form-item__label::before { content: ""; display: none; } } } </style>