考勤记录
This commit is contained in:
		| @ -90,7 +90,7 @@ | ||||
|       <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" /> | ||||
|     </el-card> | ||||
|     <!-- 添加或修改考勤对话框 --> | ||||
|     <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body> | ||||
|     <!-- <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body> | ||||
|       <el-form ref="attendanceFormRef" :model="form" :rules="rules" label-width="80px"> | ||||
|         <el-form-item label="人员id" prop="userId"> | ||||
|           <el-input v-model="form.userId" placeholder="请输入人员id" /> | ||||
| @ -146,7 +146,7 @@ | ||||
|           <el-button @click="cancel">取 消</el-button> | ||||
|         </div> | ||||
|       </template> | ||||
|     </el-dialog> | ||||
|     </el-dialog> --> | ||||
|     <!-- 考勤详情对话框 --> | ||||
|     <el-dialog v-model="dialog.details" width="1300px"> | ||||
|       <el-calendar ref="calendar" class="h170 pos-relative"> | ||||
| @ -293,7 +293,7 @@ const workTime = computed(() => (date) => { | ||||
|  | ||||
| //下班时间 | ||||
| const workFromTime = computed(() => (date) => { | ||||
|   return calendarList.value[playCardIdx.value(date)].attendanceList[1].clockTime?.slice(10); | ||||
|   return calendarList.value[playCardIdx.value(date)].attendanceList[1]?.clockTime?.slice(10); | ||||
| }); | ||||
|  | ||||
| //考勤状态 | ||||
| @ -403,7 +403,7 @@ const incrementMonth = (dateStr: string, monthsToAdd: number) => { | ||||
|  | ||||
| /** 详情按钮操作 */ | ||||
| const handleDetails = async (row?: AttendanceVO) => { | ||||
|   const res = await listAttendanceMonth({ id: row?.id }); | ||||
|   const res = await listAttendanceMonth({ userId: row?.id }); | ||||
|   calendarList.value = res.data; | ||||
|   dialog.details = true; | ||||
|   dialog.id = row?.id; | ||||
|  | ||||
							
								
								
									
										182
									
								
								src/views/project/attendanceRecords/index.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										182
									
								
								src/views/project/attendanceRecords/index.vue
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,182 @@ | ||||
| <template> | ||||
|   <div class="p-2"> | ||||
|     <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave"> | ||||
|       <div v-show="showSearch" class="mb-[10px]"> | ||||
|         <el-card shadow="hover"> | ||||
|           <el-form ref="queryFormRef" :model="queryParams" :inline="true"> | ||||
|             <el-form-item label="人员姓名" prop="userName"> | ||||
|               <el-input v-model="queryParams.userName" placeholder="请输入人员姓名" clearable @keyup.enter="handleQuery" /> | ||||
|             </el-form-item> | ||||
|             <el-form-item label="班组" prop="teamId"> | ||||
|               <el-select v-model="queryParams.teamId" placeholder="请选择班组" clearable> | ||||
|                 <el-option v-for="dict in projectTeamOpt" :key="dict.value" :label="dict.label" :value="dict.value" /> | ||||
|               </el-select> | ||||
|             </el-form-item> | ||||
|             <el-form-item label="打卡日期" prop="clockDate"> | ||||
|               <el-date-picker clearable v-model="queryParams.clockDate" type="date" value-format="YYYY-MM-DD" placeholder="请选择打卡日期" /> | ||||
|             </el-form-item> | ||||
|             <el-form-item label="考勤状态" prop="clockStatus"> | ||||
|               <el-select v-model="queryParams.clockStatus" placeholder="请选择考勤状态" clearable> | ||||
|                 <el-option v-for="dict in clock_status_type" :key="dict.value" :label="dict.label" :value="dict.value" /> | ||||
|               </el-select> | ||||
|             </el-form-item> | ||||
|             <el-form-item> | ||||
|               <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button> | ||||
|               <el-button icon="Refresh" @click="resetQuery">重置</el-button> | ||||
|             </el-form-item> | ||||
|           </el-form> | ||||
|         </el-card> | ||||
|       </div> | ||||
|     </transition> | ||||
|  | ||||
|     <el-card shadow="never"> | ||||
|       <el-table v-loading="loading" :data="attendanceList"> | ||||
|         <el-table-column type="selection" width="55" align="center" /> | ||||
|         <el-table-column label="序号" type="index" width="60" align="center" /> | ||||
|         <el-table-column label="人员姓名" align="center" prop="userName" /> | ||||
|         <!-- <el-table-column label="上班打卡时间" align="center" prop="onClockTime" width="180"> | ||||
|           <template #default="scope"> | ||||
|             <span>{{ parseTime(scope.row.onClockTime, '{y}-{m}-{d}') }}</span> | ||||
|           </template> | ||||
|         </el-table-column> | ||||
|         <el-table-column label="下班打卡时间" align="center" prop="offClockTime" width="180"> | ||||
|           <template #default="scope"> | ||||
|             <span>{{ parseTime(scope.row.offClockTime, '{y}-{m}-{d}') }}</span> | ||||
|           </template> | ||||
|         </el-table-column> --> | ||||
|         <el-table-column label="上下班" align="center" prop="commuter"> | ||||
|           <template #default="scope"> | ||||
|             <dict-tag :options="commuter_type" :value="scope.row.commuter" /> | ||||
|           </template> | ||||
|         </el-table-column> | ||||
|         <el-table-column label="打卡日期" align="center" prop="clockDate"> | ||||
|           <template #default="scope"> | ||||
|             <span>{{ parseTime(scope.row.clockDate, '{y}-{m}-{d}') }}</span> | ||||
|           </template> | ||||
|         </el-table-column> | ||||
|         <el-table-column label="打卡时间" align="center" prop="clockTime"> | ||||
|           <template #default="scope"> | ||||
|             <span>{{ parseTime(scope.row.clockTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span> | ||||
|           </template> | ||||
|         </el-table-column> | ||||
|       </el-table> | ||||
|  | ||||
|       <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" /> | ||||
|     </el-card> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script setup name="Attendance" lang="ts"> | ||||
| import { listAttendance, getAttendance, delAttendance, addAttendance, updateAttendance } from '@/api/project/attendanceRecords'; | ||||
| import { AttendanceVO, AttendanceQuery, AttendanceForm } from '@/api/project/attendanceRecords/types'; | ||||
| import { listProjectTeam } from '@/api/project/projectTeam'; | ||||
| import { ProjectTeamVO } from '@/api/project/projectTeam/types'; | ||||
| import { useUserStoreHook } from '@/store/modules/user'; | ||||
| const { proxy } = getCurrentInstance() as ComponentInternalInstance; | ||||
| const { clock_status_type, commuter_type } = toRefs<any>(proxy?.useDict('clock_status_type', 'commuter_type')); | ||||
|  | ||||
| const attendanceList = ref<AttendanceVO[]>([]); | ||||
| const buttonLoading = ref(false); | ||||
| const loading = ref(true); | ||||
| const showSearch = ref(true); | ||||
| const ids = ref<Array<string | number>>([]); | ||||
| const single = ref(true); | ||||
| const multiple = ref(true); | ||||
| const total = ref(0); | ||||
| const projectTeamOpt = ref<any[]>([]); | ||||
| const queryFormRef = ref<ElFormInstance>(); | ||||
| const attendanceFormRef = ref<ElFormInstance>(); | ||||
|  | ||||
| const dialog = reactive<DialogOption>({ | ||||
|   visible: false, | ||||
|   title: '' | ||||
| }); | ||||
| // 获取用户 store | ||||
| const userStore = useUserStoreHook(); | ||||
| // 从 store 中获取项目列表和当前选中的项目 | ||||
| const currentProject = computed(() => userStore.selectedProject); | ||||
| const initFormData: AttendanceForm = { | ||||
|   id: undefined, | ||||
|   userId: undefined, | ||||
|   facePic: undefined, | ||||
|   projectId: undefined, | ||||
|   onClockTime: undefined, | ||||
|   offClockTime: undefined, | ||||
|   clockDate: undefined, | ||||
|   clockStatus: undefined, | ||||
|   pinchUserId: undefined, | ||||
|   clockRecord: undefined, | ||||
|   commuter: undefined, | ||||
|   dailyWage: undefined, | ||||
|   lng: undefined, | ||||
|   lat: undefined, | ||||
|   remark: undefined | ||||
| }; | ||||
| const data = reactive<PageData<AttendanceForm, AttendanceQuery>>({ | ||||
|   form: { ...initFormData }, | ||||
|   queryParams: { | ||||
|     pageNum: 1, | ||||
|     pageSize: 10, | ||||
|     userName: undefined, | ||||
|     projectId: undefined, | ||||
|     clockDate: undefined, | ||||
|     clockStatus: undefined, | ||||
|     commuter: undefined, | ||||
|     params: {}, | ||||
|     teamId: undefined | ||||
|   }, | ||||
|   rules: { | ||||
|     id: [{ required: true, message: '主键id不能为空', trigger: 'blur' }], | ||||
|     userId: [{ required: true, message: '人员id不能为空', trigger: 'blur' }], | ||||
|     facePic: [{ required: true, message: '人脸照不能为空', trigger: 'blur' }], | ||||
|     projectId: [{ required: true, message: '项目id不能为空', trigger: 'blur' }], | ||||
|     clockDate: [{ required: true, message: '打卡日期不能为空', trigger: 'blur' }], | ||||
|     clockStatus: [{ required: true, message: '1正常,2迟到,3早退,4缺勤,5补卡不能为空', trigger: 'change' }] | ||||
|   } | ||||
| }); | ||||
|  | ||||
| const { queryParams, form, rules } = toRefs(data); | ||||
|  | ||||
| /** 查询考勤列表 */ | ||||
| const getList = async () => { | ||||
|   loading.value = true; | ||||
|   const res = await listAttendance(queryParams.value); | ||||
|   attendanceList.value = res.rows; | ||||
|   total.value = res.total; | ||||
|   loading.value = false; | ||||
| }; | ||||
|  | ||||
| /** 搜索按钮操作 */ | ||||
| const handleQuery = () => { | ||||
|   queryParams.value.pageNum = 1; | ||||
|   getList(); | ||||
| }; | ||||
|  | ||||
| /** 重置按钮操作 */ | ||||
| const resetQuery = () => { | ||||
|   queryFormRef.value?.resetFields(); | ||||
|   handleQuery(); | ||||
| }; | ||||
|  | ||||
| /** 搜索班组操作 */ | ||||
| const getProjectTeamList = async () => { | ||||
|   loading.value = true; | ||||
|   const res = await listProjectTeam({ | ||||
|     pageNum: 1, | ||||
|     pageSize: 20, | ||||
|     orderByColumn: 'createTime', | ||||
|     isAsc: 'desc', | ||||
|     projectId: currentProject.value.id | ||||
|   }); | ||||
|   projectTeamOpt.value = res.rows.map((projectTeam: ProjectTeamVO) => ({ | ||||
|     value: projectTeam.id, | ||||
|     label: projectTeam.teamName | ||||
|   })); | ||||
|   loading.value = false; | ||||
| }; | ||||
|  | ||||
| onMounted(() => { | ||||
|   getList(); | ||||
|   getProjectTeamList(); | ||||
| }); | ||||
| </script> | ||||
							
								
								
									
										394
									
								
								src/views/project/leave/index.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										394
									
								
								src/views/project/leave/index.vue
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,394 @@ | ||||
| <template> | ||||
|   <div class="p-2"> | ||||
|     <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave"> | ||||
|       <div v-show="showSearch" class="mb-[10px]"> | ||||
|         <el-card shadow="hover"> | ||||
|           <el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="100px"> | ||||
|             <el-form-item label="申请人" prop="userName"> | ||||
|               <el-input v-model="queryParams.userName" placeholder="请输入申请人" clearable @keyup.enter="handleQuery" /> | ||||
|             </el-form-item> | ||||
|             <el-form-item label="所属班组" prop="leaveType"> | ||||
|               <el-select v-model="queryParams.teamId" placeholder="全部" clearable> | ||||
|                 <el-option v-for="dict in projectTeamOpt" :key="dict.value" :label="dict.label" :value="dict.value" /> | ||||
|               </el-select> | ||||
|             </el-form-item> | ||||
|             <!-- <el-form-item label="请假类型" prop="leaveType"> | ||||
|               <el-select v-model="queryParams.leaveType" placeholder="请选择请假类型" clearable> | ||||
|                 <el-option v-for="dict in user_leave_type" :key="dict.value" :label="dict.label" :value="dict.value" /> | ||||
|               </el-select> | ||||
|             </el-form-item> --> | ||||
|             <el-form-item label="班组长意见" prop="gangerOpinion"> | ||||
|               <el-select v-model="queryParams.gangerOpinion" placeholder="全部" clearable> | ||||
|                 <el-option v-for="dict in user_opinion_type" :key="dict.value" :label="dict.label" :value="dict.value" /> | ||||
|               </el-select> | ||||
|             </el-form-item> | ||||
|             <el-form-item label="管理员意见" prop="managerOpinion"> | ||||
|               <el-select v-model="queryParams.managerOpinion" placeholder="全部" clearable> | ||||
|                 <el-option v-for="dict in user_opinion_type" :key="dict.value" :label="dict.label" :value="dict.value" /> | ||||
|               </el-select> | ||||
|             </el-form-item> | ||||
|             <el-form-item> | ||||
|               <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button> | ||||
|               <el-button icon="Refresh" @click="resetQuery">重置</el-button> | ||||
|             </el-form-item> | ||||
|           </el-form> | ||||
|         </el-card> | ||||
|       </div> | ||||
|     </transition> | ||||
|  | ||||
|     <el-card shadow="never"> | ||||
|       <!-- <template #header> | ||||
|         <el-row :gutter="10" class="mb8"> | ||||
|           <el-col :span="1.5"> | ||||
|             <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['project:leave:add']">新增</el-button> | ||||
|           </el-col> | ||||
|           <el-col :span="1.5"> | ||||
|             <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['project:leave:edit']" | ||||
|               >修改</el-button | ||||
|             > | ||||
|           </el-col> | ||||
|           <el-col :span="1.5"> | ||||
|             <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['project:leave:remove']" | ||||
|               >删除</el-button | ||||
|             > | ||||
|           </el-col> | ||||
|           <el-col :span="1.5"> | ||||
|             <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['project:leave:export']">导出</el-button> | ||||
|           </el-col> | ||||
|           <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar> | ||||
|         </el-row> | ||||
|       </template> --> | ||||
|  | ||||
|       <el-table v-loading="loading" :data="leaveList"> | ||||
|         <el-table-column type="selection" width="55" align="center" /> | ||||
|         <el-table-column label="序号" align="center" type="index" width="50" /> | ||||
|         <el-table-column label="申请人" align="center" prop="userName" /> | ||||
|         <el-table-column label="申请请假说明" align="center" prop="userExplain" /> | ||||
|         <!-- <el-table-column label="请假申请时间" align="center" prop="userTime" width="180"> | ||||
|           <template #default="scope"> | ||||
|             <span>{{ parseTime(scope.row.userTime, '{y}-{m}-{d}') }}</span> | ||||
|           </template> | ||||
|         </el-table-column> --> | ||||
|         <el-table-column label="所属班组" align="center" prop="teamName"> | ||||
|           <template #default="scope"> | ||||
|             <dict-tag :options="user_leave_type" :value="scope.row.teamName" /> | ||||
|           </template> | ||||
|         </el-table-column> | ||||
|         <el-table-column label="状态" align="center" prop="status"> | ||||
|           <template #default="scope"> | ||||
|             <dict-tag :options="user_review_status_type" :value="scope.row.status" /> | ||||
|           </template> | ||||
|         </el-table-column> | ||||
|         <!-- <el-table-column label="班组长意见" align="center" prop="gangerOpinion"> | ||||
|           <template #default="scope"> | ||||
|             <dict-tag :options="user_opinion_type" :value="scope.row.gangerOpinion" /> | ||||
|           </template> | ||||
|         </el-table-column> | ||||
|         <el-table-column label="班组长说明" align="center" prop="gangerExplain" /> | ||||
|         <el-table-column label="班组长操作时间" align="center" prop="gangerTime" width="180"> | ||||
|           <template #default="scope"> | ||||
|             <span>{{ parseTime(scope.row.gangerTime, '{y}-{m}-{d}') }}</span> | ||||
|           </template> | ||||
|         </el-table-column> | ||||
|         <el-table-column label="管理员意见" align="center" prop="managerOpinion"> | ||||
|           <template #default="scope"> | ||||
|             <dict-tag :options="user_opinion_type" :value="scope.row.managerOpinion" /> | ||||
|           </template> | ||||
|         </el-table-column> | ||||
|         <el-table-column label="管理员说明" align="center" prop="managerExplain" /> | ||||
|         <el-table-column label="请假申请时间" align="center" prop="userTime" width="180"> | ||||
|           <template #default="scope"> | ||||
|             <span>{{ parseTime(scope.row.userTime) }}</span> | ||||
|           </template> | ||||
|         </el-table-column> --> | ||||
|         <el-table-column label="操作" align="center" class-name="small-padding fixed-width"> | ||||
|           <template #default="scope"> | ||||
|             <el-button link type="success" icon="View" @click="handleDetail(scope.row)">详情</el-button> | ||||
|           </template> | ||||
|         </el-table-column> | ||||
|       </el-table> | ||||
|  | ||||
|       <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" /> | ||||
|     </el-card> | ||||
|     <!-- 审批对话框 --> | ||||
|     <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body> | ||||
|       <div class="pl-xl"> | ||||
|         <el-form-item label="是否同意"> | ||||
|           <el-radio-group v-model="auditForm.managerOpinion"> | ||||
|             <el-radio value="2" size="small">同意</el-radio> | ||||
|             <el-radio value="3" size="small">拒绝</el-radio> | ||||
|           </el-radio-group> | ||||
|         </el-form-item> | ||||
|         <el-form-item label="拒绝说明" v-if="auditForm.managerOpinion == '3'"> | ||||
|           <el-input v-model="auditForm.managerExplain" placeholder="请输入拒绝说明" type="textarea" clearable></el-input> | ||||
|         </el-form-item> | ||||
|       </div> | ||||
|       <template #footer> | ||||
|         <div class="dialog-footer"> | ||||
|           <el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button> | ||||
|           <el-button @click="cancel">取 消</el-button> | ||||
|         </div> | ||||
|       </template> | ||||
|     </el-dialog> | ||||
|     <!-- 详情对话框 --> | ||||
|     <el-dialog title="审核进度" v-model="dialog.details" width="500px" append-to-body> | ||||
|       <el-steps style="max-width: 600px" :active="auditProgress" align-center finish-status="success"> | ||||
|         <el-step :title="teamStatus ? detailObj.gangerName : '班组长'" :status="teamStatus ? teamStatus : ''"> | ||||
|           <template #description> | ||||
|             <div v-if="!teamStatus">审核中</div> | ||||
|             <div v-else> | ||||
|               <span>{{ detailObj.gangerOpinion == '2' ? '同意' : '拒绝' }}</span> | ||||
|               <p>{{ detailObj.gangerExplain }}</p> | ||||
|             </div> | ||||
|           </template> | ||||
|         </el-step> | ||||
|         <el-step :title="managerStatus ? detailObj.managerName : '管理员'" :status="managerStatus ? managerStatus : ''"> | ||||
|           <template #description> | ||||
|             <div v-if="!managerStatus">审核中</div> | ||||
|             <div v-else> | ||||
|               <span>{{ detailObj.managerOpinion == '2' ? '同意' : '拒绝' }}</span> | ||||
|               <p>{{ detailObj.managerExplain }}</p> | ||||
|             </div> | ||||
|           </template> | ||||
|         </el-step> | ||||
|         <el-step title="结果" :status="resultsStatus"> | ||||
|           <template #description> | ||||
|             <div>{{ user_review_status_type[parseInt(detailObj.status) - 1].label }}</div> | ||||
|           </template> | ||||
|         </el-step> | ||||
|       </el-steps> | ||||
|     </el-dialog> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script setup name="Leave" lang="ts"> | ||||
| import { listLeave, getLeave, delLeave, addLeave, updateLeave, AuditReissueCard } from '@/api/project/leave'; | ||||
| import { LeaveVO, LeaveQuery, LeaveForm } from '@/api/project/leave/types'; | ||||
| import { listProjectTeam } from '@/api/project/projectTeam'; | ||||
| import { ProjectTeamVO } from '@/api/project/projectTeam/types'; | ||||
| import { AuditReissueCardForm, ReissueCardVO } from '@/api/project/reissueCard/types'; | ||||
| import { useUserStoreHook } from '@/store/modules/user'; | ||||
| const { proxy } = getCurrentInstance() as ComponentInternalInstance; | ||||
| const { user_leave_type, user_opinion_type, user_review_status_type } = toRefs<any>( | ||||
|   proxy?.useDict('user_leave_type', 'user_opinion_type', 'user_review_status_type') | ||||
| ); | ||||
| const detailObj = ref<ReissueCardVO>({ | ||||
|   userName: undefined, | ||||
|   id: undefined, | ||||
|   userExplain: undefined, | ||||
|   userTime: undefined, | ||||
|   gangerName: undefined, | ||||
|   gangerOpinion: undefined, | ||||
|   gangerExplain: undefined, | ||||
|   gangerTime: undefined, | ||||
|   managerOpinion: undefined, | ||||
|   managerExplain: undefined, | ||||
|   managerTime: undefined, | ||||
|   remark: undefined, | ||||
|   status: undefined, | ||||
|   managerName: undefined | ||||
| }); | ||||
|  | ||||
| const leaveList = ref<LeaveVO[]>([]); | ||||
| const buttonLoading = ref(false); | ||||
| const loading = ref(true); | ||||
| const showSearch = ref(true); | ||||
| const ids = ref<Array<string | number>>([]); | ||||
| const single = ref(true); | ||||
| const multiple = ref(true); | ||||
| const total = ref(0); | ||||
|  | ||||
| const queryFormRef = ref<ElFormInstance>(); | ||||
| const leaveFormRef = ref<ElFormInstance>(); | ||||
| const projectTeamOpt = ref<any[]>([]); | ||||
| const dialog = reactive<DialogOption>({ | ||||
|   visible: false, | ||||
|   title: '', | ||||
|   details: false | ||||
| }); | ||||
| // 获取用户 store | ||||
| const userStore = useUserStoreHook(); | ||||
| // 从 store 中获取项目列表和当前选中的项目 | ||||
| const currentProject = computed(() => userStore.selectedProject); | ||||
| const initFormData: LeaveForm = { | ||||
|   id: undefined, | ||||
|   userId: undefined, | ||||
|   userName: undefined, | ||||
|   userExplain: undefined, | ||||
|   userTime: undefined, | ||||
|   leaveType: undefined, | ||||
|   startTime: undefined, | ||||
|   endTime: undefined, | ||||
|   gangerId: undefined, | ||||
|   gangerName: undefined, | ||||
|   gangerOpinion: undefined, | ||||
|   gangerExplain: undefined, | ||||
|   gangerTime: undefined, | ||||
|   managerOpinion: undefined, | ||||
|   managerExplain: undefined, | ||||
|   managerTime: undefined, | ||||
|   projectId: undefined, | ||||
|   teamId: undefined, | ||||
|   remark: undefined | ||||
| }; | ||||
| const data = reactive<PageData<LeaveForm, LeaveQuery>>({ | ||||
|   form: { ...initFormData }, | ||||
|   queryParams: { | ||||
|     pageNum: 1, | ||||
|     pageSize: 10, | ||||
|     userName: undefined, | ||||
|     leaveType: undefined, | ||||
|     gangerOpinion: undefined, | ||||
|     managerOpinion: undefined, | ||||
|     projectId: undefined, | ||||
|     teamId: undefined, | ||||
|     params: {} | ||||
|   }, | ||||
|   rules: { | ||||
|     id: [{ required: true, message: '主键id不能为空', trigger: 'blur' }], | ||||
|     userId: [{ required: true, message: '申请人id不能为空', trigger: 'blur' }], | ||||
|     userName: [{ required: true, message: '申请人名字不能为空', trigger: 'blur' }], | ||||
|     leaveType: [{ required: true, message: '请假类型不能为空', trigger: 'change' }], | ||||
|     startTime: [{ required: true, message: '请假开始时间不能为空', trigger: 'blur' }], | ||||
|     endTime: [{ required: true, message: '请假结束时间不能为空', trigger: 'blur' }], | ||||
|     gangerOpinion: [{ required: true, message: '班组长意见不能为空', trigger: 'change' }], | ||||
|     managerOpinion: [{ required: true, message: '管理员意见不能为空', trigger: 'change' }], | ||||
|     projectId: [{ required: true, message: '项目id不能为空', trigger: 'blur' }] | ||||
|   } | ||||
| }); | ||||
| const auditForm = reactive<AuditReissueCardForm>({ | ||||
|   id: undefined, | ||||
|   managerOpinion: '2', | ||||
|   managerExplain: undefined | ||||
| }); | ||||
| const { queryParams, form, rules } = toRefs(data); | ||||
|  | ||||
| //审核进度 | ||||
| const auditProgress = computed(() => { | ||||
|   if (auditStatus.value) return 3; | ||||
|   if (managerStatus.value) return 2; | ||||
|   if (teamStatus.value) return 1; | ||||
|   return 0; | ||||
| }); | ||||
| //审核状态 | ||||
| const auditStatus = computed(() => { | ||||
|   if (detailObj.value.status == '3' || detailObj.value.status == '4') return true; | ||||
|   return false; | ||||
| }); | ||||
| //管理员审核状态 | ||||
| const managerStatus = computed(() => { | ||||
|   switch (detailObj.value.managerOpinion) { | ||||
|     case '1': | ||||
|       return false; | ||||
|     case '2': | ||||
|       return 'success'; | ||||
|     case '3': | ||||
|       return 'error'; | ||||
|   } | ||||
| }); | ||||
| //班组审核状态 | ||||
| const teamStatus = computed(() => { | ||||
|   switch (detailObj.value.gangerOpinion) { | ||||
|     case '1': | ||||
|       return false; | ||||
|     case '2': | ||||
|       return 'success'; | ||||
|     case '3': | ||||
|       return 'error'; | ||||
|   } | ||||
| }); | ||||
| //结果状态 | ||||
| const resultsStatus = computed(() => { | ||||
|   if (detailObj.value.status == '3') return 'success'; | ||||
|   if (detailObj.value.status == '4') return 'error'; | ||||
|   return ''; | ||||
| }); | ||||
|  | ||||
| /** 查询施工人员请假申请列表 */ | ||||
| const getList = async () => { | ||||
|   loading.value = true; | ||||
|   const res = await listLeave(queryParams.value); | ||||
|   leaveList.value = res.rows; | ||||
|   total.value = res.total; | ||||
|   loading.value = false; | ||||
| }; | ||||
|  | ||||
| /** 取消按钮 */ | ||||
| const cancel = () => { | ||||
|   reset(); | ||||
|   dialog.visible = false; | ||||
| }; | ||||
|  | ||||
| /** 表单重置 */ | ||||
| const reset = () => {}; | ||||
|  | ||||
| /** 搜索按钮操作 */ | ||||
| const handleQuery = () => { | ||||
|   queryParams.value.pageNum = 1; | ||||
|   getList(); | ||||
| }; | ||||
|  | ||||
| /** 重置按钮操作 */ | ||||
| const resetQuery = () => { | ||||
|   queryFormRef.value?.resetFields(); | ||||
|   handleQuery(); | ||||
| }; | ||||
|  | ||||
| /** 提交按钮 */ | ||||
| const submitForm = async () => { | ||||
|   await AuditReissueCard(auditForm); | ||||
|   proxy?.$modal.msgSuccess('审批成功'); | ||||
|   dialog.visible = false; | ||||
|  | ||||
|   await getList(); | ||||
| }; | ||||
|  | ||||
| const handleDetail = (row: ReissueCardVO) => { | ||||
|   detailObj.value = row; | ||||
|   console.log('🚀 ~ handleDetail ~ row:', row); | ||||
|  | ||||
|   dialog.details = true; | ||||
| }; | ||||
|  | ||||
| /** 审批按钮操作 */ | ||||
| const handleUpdate = async (row?: LeaveVO) => { | ||||
|   reset(); | ||||
|   const _id = row?.id || ids.value[0]; | ||||
|   auditForm.id = _id; | ||||
|   dialog.visible = true; | ||||
|   dialog.title = '修改施工人员补卡申请'; | ||||
| }; | ||||
|  | ||||
| /** 导出按钮操作 */ | ||||
| const handleExport = () => { | ||||
|   proxy?.download( | ||||
|     'project/leave/export', | ||||
|     { | ||||
|       ...queryParams.value | ||||
|     }, | ||||
|     `leave_${new Date().getTime()}.xlsx` | ||||
|   ); | ||||
| }; | ||||
|  | ||||
| /** 搜索班组操作 */ | ||||
| const getProjectTeamList = async () => { | ||||
|   loading.value = true; | ||||
|   const res = await listProjectTeam({ | ||||
|     pageNum: 1, | ||||
|     pageSize: 20, | ||||
|     orderByColumn: 'createTime', | ||||
|     isAsc: 'desc', | ||||
|     projectId: currentProject.value.id | ||||
|   }); | ||||
|   projectTeamOpt.value = res.rows.map((projectTeam: ProjectTeamVO) => ({ | ||||
|     value: projectTeam.id, | ||||
|     label: projectTeam.teamName | ||||
|   })); | ||||
|   loading.value = false; | ||||
| }; | ||||
|  | ||||
| onMounted(() => { | ||||
|   getList(); | ||||
|   getProjectTeamList(); | ||||
| }); | ||||
| </script> | ||||
							
								
								
									
										350
									
								
								src/views/project/reissueCard/index.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										350
									
								
								src/views/project/reissueCard/index.vue
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,350 @@ | ||||
| <template> | ||||
|   <div class="p-2"> | ||||
|     <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave"> | ||||
|       <div v-show="showSearch" class="mb-[10px]"> | ||||
|         <el-card shadow="hover"> | ||||
|           <el-form ref="queryFormRef" :model="queryParams" :inline="true"> | ||||
|             <el-form-item label="申请人" prop="userName"> | ||||
|               <el-input v-model="queryParams.userName" placeholder="请输入申请人" clearable @keyup.enter="handleQuery" /> | ||||
|             </el-form-item> | ||||
|             <el-form-item label="补卡类型" prop="reissueCardType"> | ||||
|               <el-select v-model="queryParams.reissueCardType" placeholder="全部" clearable> | ||||
|                 <el-option v-for="dict in commuter_type" :key="dict.value" :label="dict.label" :value="dict.value" /> | ||||
|               </el-select> | ||||
|             </el-form-item> | ||||
|             <el-form-item label="所属班组" prop="reissueCardType"> | ||||
|               <el-select v-model="queryParams.teamId" placeholder="全部" clearable> | ||||
|                 <el-option v-for="dict in projectTeamOpt" :key="dict.value" :label="dict.label" :value="dict.value" /> | ||||
|               </el-select> | ||||
|             </el-form-item> | ||||
|             <el-form-item label="班组长意见" prop="gangerOpinion" label-width="100px"> | ||||
|               <el-select v-model="queryParams.gangerOpinion" placeholder="全部" clearable> | ||||
|                 <el-option v-for="dict in user_opinion_type" :key="dict.value" :label="dict.label" :value="dict.value" /> | ||||
|               </el-select> | ||||
|             </el-form-item> | ||||
|             <el-form-item label="管理员意见" prop="managerOpinion" label-width="100px"> | ||||
|               <el-select v-model="queryParams.managerOpinion" placeholder="全部" clearable> | ||||
|                 <el-option v-for="dict in user_opinion_type" :key="dict.value" :label="dict.label" :value="dict.value" /> | ||||
|               </el-select> | ||||
|             </el-form-item> | ||||
|  | ||||
|             <el-form-item> | ||||
|               <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button> | ||||
|               <el-button icon="Refresh" @click="resetQuery">重置</el-button> | ||||
|             </el-form-item> | ||||
|           </el-form> | ||||
|         </el-card> | ||||
|       </div> | ||||
|     </transition> | ||||
|  | ||||
|     <el-card shadow="never"> | ||||
|       <el-table v-loading="loading" :data="reissueCardList"> | ||||
|         <el-table-column type="selection" width="55" align="center" /> | ||||
|         <el-table-column label="序号" align="center" width="55" type="index" /> | ||||
|         <el-table-column label="申请人" align="center" prop="userName" /> | ||||
|         <el-table-column label="申请补卡说明" align="center" prop="userExplain" /> | ||||
|         <el-table-column label="所属班组" align="center" prop="teamName" /> | ||||
|         <el-table-column label="状态" align="center" prop="status"> | ||||
|           <template #default="scope"> | ||||
|             <dict-tag :options="user_review_status_type" :value="scope.row.status" /> | ||||
|           </template> | ||||
|         </el-table-column> | ||||
|         <!-- <el-table-column label="班组长意见" align="center" prop="gangerOpinion"> | ||||
|           <template #default="scope"> | ||||
|             <dict-tag :options="user_opinion_type" :value="scope.row.gangerOpinion" /> | ||||
|           </template> | ||||
|         </el-table-column> | ||||
|         <el-table-column label="班组长说明" align="center" prop="gangerExplain" /> | ||||
|         <el-table-column label="班组长操作时间" align="center" prop="gangerTime" width="180"> | ||||
|           <template #default="scope"> | ||||
|             <span>{{ parseTime(scope.row.gangerTime, '{y}-{m}-{d}') }}</span> | ||||
|           </template> | ||||
|         </el-table-column> | ||||
|         <el-table-column label="管理员意见" align="center" prop="managerOpinion"> | ||||
|           <template #default="scope"> | ||||
|             <dict-tag :options="user_opinion_type" :value="scope.row.managerOpinion" /> | ||||
|           </template> | ||||
|         </el-table-column> | ||||
|         <el-table-column label="管理员说明" align="center" prop="managerExplain" /> | ||||
|         <el-table-column label="补卡申请时间" align="center" prop="userTime" width="180"> | ||||
|           <template #default="scope"> | ||||
|             <span>{{ parseTime(scope.row.userTime, '{y}-{m}-{d}') }}</span> | ||||
|           </template> | ||||
|         </el-table-column> | ||||
|  | ||||
|         <el-table-column label="管理员操作时间" align="center" prop="managerTime" width="180"> | ||||
|           <template #default="scope"> | ||||
|             <span>{{ parseTime(scope.row.managerTime, '{y}-{m}-{d}') }}</span> | ||||
|           </template> | ||||
|         </el-table-column> --> | ||||
|         <!-- <el-table-column label="备注" align="center" prop="remark" /> --> | ||||
|         <el-table-column label="操作" align="center" class-name="small-padding fixed-width"> | ||||
|           <template #default="scope"> | ||||
|             <el-button link type="success" icon="View" @click="handleDetail(scope.row)">详情</el-button> | ||||
|           </template> | ||||
|         </el-table-column> | ||||
|       </el-table> | ||||
|  | ||||
|       <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" /> | ||||
|     </el-card> | ||||
|     <el-dialog title="修改施工人员补卡申请" v-model="dialog.visible" width="400px"> | ||||
|       <div class="pl-xl"> | ||||
|         <el-form-item label="是否同意"> | ||||
|           <el-radio-group v-model="auditForm.managerOpinion"> | ||||
|             <el-radio value="2" size="small">同意</el-radio> | ||||
|             <el-radio value="3" size="small">拒绝</el-radio> | ||||
|           </el-radio-group> | ||||
|         </el-form-item> | ||||
|         <el-form-item label="拒绝说明" v-if="auditForm.managerOpinion == '3'"> | ||||
|           <el-input v-model="auditForm.managerExplain" placeholder="请输入拒绝说明" type="textarea" clearable></el-input> | ||||
|         </el-form-item> | ||||
|       </div> | ||||
|  | ||||
|       <template #footer> | ||||
|         <span> | ||||
|           <el-button type="primary" @click="submitAudit">确定</el-button> | ||||
|           <el-button @click="dialog.visible = false">取消</el-button> | ||||
|         </span> | ||||
|       </template> | ||||
|     </el-dialog> | ||||
|     <el-dialog title="审核进度" v-model="dialog.details" width="500px" append-to-body> | ||||
|       <el-steps style="max-width: 600px" :active="auditProgress" align-center finish-status="success"> | ||||
|         <el-step :title="teamStatus ? detailObj.gangerName : '班组长'" :status="teamStatus ? teamStatus : ''"> | ||||
|           <template #description> | ||||
|             <div v-if="!teamStatus">审核中</div> | ||||
|             <div v-else> | ||||
|               <span>{{ detailObj.gangerOpinion == '2' ? '同意' : '拒绝' }}</span> | ||||
|               <p>{{ detailObj.gangerExplain }}</p> | ||||
|             </div> | ||||
|           </template> | ||||
|         </el-step> | ||||
|         <el-step :title="managerStatus ? detailObj.managerName : '管理员'" :status="managerStatus ? managerStatus : ''"> | ||||
|           <template #description> | ||||
|             <div v-if="!managerStatus">审核中</div> | ||||
|             <div v-else> | ||||
|               <span>{{ detailObj.managerOpinion == '2' ? '同意' : '拒绝' }}</span> | ||||
|               <p>{{ detailObj.managerExplain }}</p> | ||||
|             </div> | ||||
|           </template> | ||||
|         </el-step> | ||||
|         <el-step title="结果" :status="resultsStatus"> | ||||
|           <template #description> | ||||
|             <div>{{ user_review_status_type[parseInt(detailObj.status) - 1].label }}</div> | ||||
|           </template> | ||||
|         </el-step> | ||||
|       </el-steps> | ||||
|     </el-dialog> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script setup name="ReissueCard" lang="ts"> | ||||
| import { listProjectTeam } from '@/api/project/projectTeam'; | ||||
| import { ProjectTeamVO } from '@/api/project/projectTeam/types'; | ||||
| import { listReissueCard, getReissueCard, delReissueCard, addReissueCard, updateReissueCard, AuditReissueCard } from '@/api/project/reissueCard'; | ||||
| import { ReissueCardVO, ReissueCardQuery, ReissueCardForm, AuditReissueCardForm } from '@/api/project/reissueCard/types'; | ||||
| import { useUserStoreHook } from '@/store/modules/user'; | ||||
| const { proxy } = getCurrentInstance() as ComponentInternalInstance; | ||||
| const { commuter_type, user_opinion_type, user_review_status_type } = toRefs<any>( | ||||
|   proxy?.useDict('commuter_type', 'user_opinion_type', 'user_review_status_type') | ||||
| ); | ||||
| const detailObj = ref<ReissueCardVO>({ | ||||
|   userName: undefined, | ||||
|   id: undefined, | ||||
|   userExplain: undefined, | ||||
|   userTime: undefined, | ||||
|   gangerName: undefined, | ||||
|   gangerOpinion: undefined, | ||||
|   gangerExplain: undefined, | ||||
|   gangerTime: undefined, | ||||
|   managerOpinion: undefined, | ||||
|   managerExplain: undefined, | ||||
|   managerTime: undefined, | ||||
|   remark: undefined, | ||||
|   status: undefined, | ||||
|   managerName: undefined | ||||
| }); | ||||
| const reissueCardList = ref<ReissueCardVO[]>([]); | ||||
| const buttonLoading = ref(false); | ||||
| const loading = ref(true); | ||||
| const showSearch = ref(true); | ||||
| const ids = ref<Array<string | number>>([]); | ||||
| const single = ref(true); | ||||
| const multiple = ref(true); | ||||
| const total = ref(0); | ||||
| const projectTeamOpt = ref<any[]>([]); | ||||
| const queryFormRef = ref<ElFormInstance>(); | ||||
| const reissueCardFormRef = ref<ElFormInstance>(); | ||||
| const auditForm = reactive<AuditReissueCardForm>({ | ||||
|   id: undefined, | ||||
|   managerOpinion: '2', | ||||
|   managerExplain: undefined | ||||
| }); | ||||
| const dialog = reactive<DialogOption>({ | ||||
|   visible: false, | ||||
|   title: '', | ||||
|   details: false | ||||
| }); | ||||
| // 获取用户 store | ||||
| const userStore = useUserStoreHook(); | ||||
| // 从 store 中获取项目列表和当前选中的项目 | ||||
| const currentProject = computed(() => userStore.selectedProject); | ||||
| const initFormData: ReissueCardForm = { | ||||
|   id: undefined, | ||||
|   userId: undefined, | ||||
|   userExplain: undefined, | ||||
|   gangerId: undefined, | ||||
|   gangerOpinion: undefined, | ||||
|   gangerExplain: undefined, | ||||
|   managerOpinion: undefined, | ||||
|   managerExplain: undefined, | ||||
|   projectId: undefined, | ||||
|   attendanceId: undefined, | ||||
|   remark: undefined | ||||
| }; | ||||
| const data = reactive<PageData<ReissueCardForm, ReissueCardQuery>>({ | ||||
|   form: { ...initFormData }, | ||||
|   queryParams: { | ||||
|     pageNum: 1, | ||||
|     pageSize: 10, | ||||
|     userName: undefined, | ||||
|     gangerOpinion: undefined, | ||||
|     managerOpinion: undefined, | ||||
|     projectId: undefined, | ||||
|     teamId: undefined, | ||||
|     reissueCardType: undefined, | ||||
|     params: {} | ||||
|   }, | ||||
|   rules: { | ||||
|     id: [{ required: true, message: '主键id不能为空', trigger: 'blur' }], | ||||
|     userId: [{ required: true, message: '申请人id不能为空', trigger: 'blur' }], | ||||
|     gangerId: [{ required: true, message: '班组长不能为空', trigger: 'blur' }], | ||||
|     gangerOpinion: [{ required: true, message: '班组长意见不能为空', trigger: 'blur' }], | ||||
|     managerOpinion: [{ required: true, message: '管理员意见不能为空', trigger: 'blur' }], | ||||
|     projectId: [{ required: true, message: '项目id不能为空', trigger: 'blur' }], | ||||
|     attendanceId: [{ required: true, message: '考勤表主键id不能为空', trigger: 'blur' }] | ||||
|   } | ||||
| }); | ||||
|  | ||||
| const { queryParams, form, rules } = toRefs(data); | ||||
|  | ||||
| //审核进度 | ||||
| const auditProgress = computed(() => { | ||||
|   if (auditStatus.value) return 3; | ||||
|   if (managerStatus.value) return 2; | ||||
|   if (teamStatus.value) return 1; | ||||
|   return 0; | ||||
| }); | ||||
| //审核状态 | ||||
| const auditStatus = computed(() => { | ||||
|   if (detailObj.value.status == '3' || detailObj.value.status == '4') return true; | ||||
|   return false; | ||||
| }); | ||||
| //管理员审核状态 | ||||
| const managerStatus = computed(() => { | ||||
|   switch (detailObj.value.managerOpinion) { | ||||
|     case '1': | ||||
|       return false; | ||||
|     case '2': | ||||
|       return 'success'; | ||||
|     case '3': | ||||
|       return 'error'; | ||||
|   } | ||||
| }); | ||||
| //班组审核状态 | ||||
| const teamStatus = computed(() => { | ||||
|   switch (detailObj.value.gangerOpinion) { | ||||
|     case '1': | ||||
|       return false; | ||||
|     case '2': | ||||
|       return 'success'; | ||||
|     case '3': | ||||
|       return 'error'; | ||||
|   } | ||||
| }); | ||||
| //结果状态 | ||||
| const resultsStatus = computed(() => { | ||||
|   if (detailObj.value.status == '3') return 'success'; | ||||
|   if (detailObj.value.status == '4') return 'error'; | ||||
|   return ''; | ||||
| }); | ||||
|  | ||||
| /** 查询施工人员补卡申请列表 */ | ||||
| async function getList() { | ||||
|   loading.value = true; | ||||
|   const res = await listReissueCard(queryParams.value); | ||||
|   reissueCardList.value = res.rows; | ||||
|   total.value = res.total; | ||||
|   loading.value = false; | ||||
| } | ||||
|  | ||||
| /** 表单重置 */ | ||||
| const reset = () => { | ||||
|   auditForm.managerExplain = ''; | ||||
|   auditForm.managerOpinion = '2'; | ||||
| }; | ||||
|  | ||||
| /** 搜索按钮操作 */ | ||||
| const handleQuery = () => { | ||||
|   queryParams.value.pageNum = 1; | ||||
|   getList(); | ||||
| }; | ||||
|  | ||||
| /** 重置按钮操作 */ | ||||
| const resetQuery = () => { | ||||
|   queryFormRef.value?.resetFields(); | ||||
|   handleQuery(); | ||||
| }; | ||||
|  | ||||
| /** 新增按钮操作 */ | ||||
| const handleAdd = () => { | ||||
|   reset(); | ||||
|   dialog.visible = true; | ||||
|   dialog.title = '添加施工人员补卡申请'; | ||||
| }; | ||||
|  | ||||
| /** 审批按钮操作 */ | ||||
| const handleUpdate = async (row?: ReissueCardVO) => { | ||||
|   reset(); | ||||
|   const _id = row?.id || ids.value[0]; | ||||
|   auditForm.id = _id; | ||||
|   dialog.visible = true; | ||||
|   dialog.title = '修改施工人员补卡申请'; | ||||
| }; | ||||
|  | ||||
| /** 搜索班组操作 */ | ||||
| const getProjectTeamList = async () => { | ||||
|   loading.value = true; | ||||
|   const res = await listProjectTeam({ | ||||
|     pageNum: 1, | ||||
|     pageSize: 20, | ||||
|     orderByColumn: 'createTime', | ||||
|     isAsc: 'desc', | ||||
|     projectId: currentProject.value.id | ||||
|   }); | ||||
|   projectTeamOpt.value = res.rows.map((projectTeam: ProjectTeamVO) => ({ | ||||
|     value: projectTeam.id, | ||||
|     label: projectTeam.teamName | ||||
|   })); | ||||
|   loading.value = false; | ||||
| }; | ||||
|  | ||||
| const handleDetail = (row: ReissueCardVO) => { | ||||
|   detailObj.value = row; | ||||
|   dialog.details = true; | ||||
| }; | ||||
|  | ||||
| /** 审批操作 */ | ||||
| const submitAudit = async () => { | ||||
|   await AuditReissueCard(auditForm); | ||||
|   proxy?.$modal.msgSuccess('审批成功'); | ||||
|   dialog.visible = false; | ||||
|   auditForm.managerExplain = ''; | ||||
|   auditForm.managerOpinion = '2'; | ||||
|   await getList(); | ||||
| }; | ||||
|  | ||||
| onMounted(() => { | ||||
|   getList(); | ||||
|   getProjectTeamList(); | ||||
| }); | ||||
| </script> | ||||
		Reference in New Issue
	
	Block a user