进度计划添加计划,添加日报
This commit is contained in:
		| @ -22,19 +22,23 @@ | ||||
|                 <div style="margin-left: 45px" m="4"> | ||||
|                   <el-table | ||||
|                     :border="true" | ||||
|                     :data="props.row.detail" | ||||
|                     :data="props.row.detailList" | ||||
|                     :header-cell-style="{ 'text-align': 'center' }" | ||||
|                     :cell-style="{ 'text-align': 'center' }" | ||||
|                     highlight-current-row | ||||
|                   > | ||||
|                     <el-table-column label="序号" type="index" width="50px" /> | ||||
|                     <el-table-column label="计划日期" prop="date"> </el-table-column> | ||||
|                     <el-table-column label="数量" prop="planNum" width="60" /> | ||||
|                     <el-table-column label="完成量" prop="finishedNum" width="60" /> | ||||
|                     <el-table-column label="序号" type="index" width="60px" /> | ||||
|                     <el-table-column label="计划日期" prop="date"> | ||||
|                       <template #default="scope"> | ||||
|                         <span class="text-3">{{ scope.row.date }}</span> | ||||
|                       </template> | ||||
|                     </el-table-column> | ||||
|                     <el-table-column label="数量" prop="planNumber" width="60" /> | ||||
|                     <el-table-column label="完成量" prop="finishedNumber" width="65" /> | ||||
|                     <el-table-column label="操作" class-name="small-padding" width="80px" fixed="right"> | ||||
|                       <template #default="scope"> | ||||
|                         <el-button type="primary" link @click="handleDayAdd(scope.row, props.row)" | ||||
|                           ><el-icon><ele-Plus /></el-icon>日报</el-button | ||||
|                           ><el-icon><Plus /></el-icon>日报</el-button | ||||
|                         > | ||||
|                       </template> | ||||
|                     </el-table-column> | ||||
| @ -42,11 +46,11 @@ | ||||
|                 </div> | ||||
|               </template> | ||||
|             </el-table-column> | ||||
|             <el-table-column label="序号" type="index" :index="indexMethod" width="50px" /> | ||||
|             <el-table-column label="计划数量" prop="planNum" min-width="100px" /> | ||||
|             <el-table-column label="序号" type="index" :index="indexMethod" width="60px" /> | ||||
|             <el-table-column label="计划数量" prop="planNumber" min-width="100px" /> | ||||
|             <el-table-column label="开始时间" min-width="100px"> | ||||
|               <template #default="scope"> | ||||
|                 <span>{{ scope.row.startAt.split(' ')[0] }}</span> | ||||
|                 <span>{{ scope.row.startDate.split(' ')[0] }}</span> | ||||
|               </template> | ||||
|             </el-table-column> | ||||
|           </el-table> | ||||
| @ -62,10 +66,10 @@ | ||||
|           <div class="box_form" v-if="formDetail.submitTime"> | ||||
|             <span>{{ dayDetail.date }}</span> | ||||
|             <el-form size="large" ref="formRef" :model="formDetail" :rules="rules" label-width="110px"> | ||||
|               <el-form-item label="实际完成数量" prop="finishedNum"> | ||||
|               <el-form-item label="实际完成数量" prop="finishedNumber"> | ||||
|                 <el-row> | ||||
|                   <el-col :span="18"> | ||||
|                     <el-input type="number" :min="0" v-model="formDetail.finishedNum" placeholder="请输入实际完成数量"> </el-input | ||||
|                     <el-input type="number" :min="0" v-model="formDetail.finishedNumber" placeholder="请输入实际完成数量"> </el-input | ||||
|                   ></el-col> | ||||
|                 </el-row> </el-form-item | ||||
|             ></el-form> | ||||
| @ -85,15 +89,15 @@ | ||||
| </template> | ||||
|  | ||||
| <script lang="ts" setup> | ||||
| import { ref, reactive, toRefs, getCurrentInstance } from 'vue'; | ||||
| import { ElMessage, ElMessageBox } from 'element-plus'; | ||||
| import { workScheduleList, workScheduleDel, workScheduleSubmit } from '@/api/progress/plan'; | ||||
| import { progressPlanDetailForm, workScheduleListQuery } from '@/api/progress/plan/types'; | ||||
|  | ||||
| const { proxy } = getCurrentInstance() as any; | ||||
|  | ||||
| const menuRef = ref(); | ||||
| const formRef = ref(); | ||||
|  | ||||
| const rowData = ref(null); | ||||
| const expandRowKeys = ref([]); | ||||
| const loading = ref(false); | ||||
| const isShowDialog = ref(false); | ||||
| @ -101,26 +105,25 @@ const tableData = ref([]); | ||||
| const total = ref(0); | ||||
| const oldLength = ref(0); | ||||
|  | ||||
| const queryParams = reactive({ | ||||
| const queryParams = reactive<workScheduleListQuery>({ | ||||
|   pageSize: 10, | ||||
|   pageNum: 1, | ||||
|   workId: '' | ||||
|   progressCategoryId: '' | ||||
| }); | ||||
|  | ||||
| const infoDetail = reactive({ | ||||
|   name: '' | ||||
| }); | ||||
|  | ||||
| const formDetail = reactive({ | ||||
|   workId: '', | ||||
| const formDetail = reactive<progressPlanDetailForm>({ | ||||
|   id: '', | ||||
|   submitTime: '', | ||||
|   finishedNum: 0 | ||||
|   finishedNumber: 0 | ||||
| }); | ||||
|  | ||||
| const dayDetail = reactive({ | ||||
|   date: '', | ||||
|   finishedNum: 0 | ||||
|   finishedNumber: 0 | ||||
| }); | ||||
|  | ||||
| const rules = { | ||||
| @ -128,20 +131,20 @@ const rules = { | ||||
| }; | ||||
|  | ||||
| const openDialog = (row: any) => { | ||||
|   queryParams.workId = row.work_id; | ||||
|   formDetail.workId = row.work_id; | ||||
|   queryParams.progressCategoryId = row.id; | ||||
|   infoDetail.name = row.name; | ||||
|   isShowDialog.value = true; | ||||
|   rowData.value = row; | ||||
|   getWorkList(true); | ||||
| }; | ||||
|  | ||||
| const getWorkList = (bool = false) => { | ||||
|   loading.value = true; | ||||
|   workScheduleList(queryParams).then((res: any) => { | ||||
|     if (res.code === 0) { | ||||
|       tableData.value = res.data.list.map((item: any, index: number) => ({ ...item, index: index + 1 })); | ||||
|       if (bool) oldLength.value = res.data.list.length; | ||||
|       total.value = res.data.total; | ||||
|     if (res.code === 200) { | ||||
|       tableData.value = res.rows.map((item: any, index: number) => ({ ...item, index: index + 1 })); | ||||
|       if (bool) oldLength.value = res.rows.length; | ||||
|       total.value = res.rows.total; | ||||
|     } | ||||
|     loading.value = false; | ||||
|   }); | ||||
| @ -156,45 +159,27 @@ const onCancel = () => { | ||||
|   closeDialog(); | ||||
| }; | ||||
|  | ||||
| const handleDelete = (row: any) => { | ||||
|   ElMessageBox.confirm('你确定要删除所选计划?', '温馨提示', { | ||||
|     confirmButtonText: '确认', | ||||
|     cancelButtonText: '取消', | ||||
|     type: 'warning' | ||||
|   }) | ||||
|     .then(() => { | ||||
|       workScheduleDel({ ids: [row.id] }).then((res: any) => { | ||||
|         if (res.code === 0) { | ||||
|           ElMessage.success('删除成功'); | ||||
|           getWorkList(); | ||||
|         } else { | ||||
|           ElMessage.error(res.message); | ||||
|         } | ||||
|       }); | ||||
|     }) | ||||
|     .catch(() => {}); | ||||
| }; | ||||
|  | ||||
| const indexMethod = (index: number) => { | ||||
|   const currentPage = queryParams.pageNum - 1; | ||||
|   return index + 1 + (currentPage > 0 ? currentPage * queryParams.pageSize : 0); | ||||
| }; | ||||
|  | ||||
| const handleDayAdd = (row: any, obj: any) => { | ||||
|   formDetail.id = obj.id; | ||||
|   formDetail.id = row.id; | ||||
|   formDetail.submitTime = row.date; | ||||
|   formDetail.finishedNum = row.finishedNum; | ||||
|   formDetail.finishedNumber = row.finishedNumber; | ||||
|   Object.assign(dayDetail, row); | ||||
| }; | ||||
|  | ||||
| const onAddSubmit = () => { | ||||
|   dayDetail.finishedNum = Number(dayDetail.finishedNum); | ||||
|   dayDetail.finishedNumber = Number(dayDetail.finishedNumber); | ||||
|   workScheduleSubmit(formDetail).then((res: any) => { | ||||
|     if (res.code === 0) { | ||||
|     if (res.code === 200) { | ||||
|       ElMessage.success('添加成功'); | ||||
|       dayDetail.finishedNum = formDetail.finishedNum; | ||||
|       dayDetail.finishedNumber = formDetail.finishedNumber; | ||||
|       formDetail.submitTime = ''; | ||||
|       formDetail.finishedNum = 0; | ||||
|       formDetail.finishedNumber = 0; | ||||
|       getWorkList(); | ||||
|     } else { | ||||
|       ElMessage.error(res.message); | ||||
|     } | ||||
|  | ||||
							
								
								
									
										550
									
								
								src/views/progress/plan/component/createDailyRate.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										550
									
								
								src/views/progress/plan/component/createDailyRate.vue
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,550 @@ | ||||
| <template> | ||||
|   <div class="daily-paper-count"> | ||||
|     <el-dialog v-model="isShowDialog" @close="onCancel" width="65vw" :close-on-click-modal="false" :destroy-on-close="true"> | ||||
|       <template #header> | ||||
|         <div v-drag="['.daily-paper-count .el-dialog', '.daily-paper-count .el-dialog__header']" style="font-size: 18px"> | ||||
|           {{ infoDetail.name }} 日报填写 | ||||
|         </div> | ||||
|       </template> | ||||
|       <div class="box"> | ||||
|         <div class="box-left"> | ||||
|           <el-table | ||||
|             v-loading="loading" | ||||
|             :data="tableData" | ||||
|             height="64vh" | ||||
|             :cell-style="{ textAlign: 'center' }" | ||||
|             :header-cell-style="{ textAlign: 'center' }" | ||||
|             border | ||||
|             :row-key="tableKey" | ||||
|             :expand-row-keys="expandRowKeys" | ||||
|             @expand-change="clickOpen" | ||||
|           > | ||||
|             <el-table-column type="expand"> | ||||
|               <template #default="{ row: propsRow }"> | ||||
|                 <div style="margin-left: 45px" m="4"> | ||||
|                   <el-table | ||||
|                     :border="true" | ||||
|                     :data="propsRow.detail" | ||||
|                     :header-cell-style="{ 'text-align': 'center' }" | ||||
|                     :cell-style="{ 'text-align': 'center' }" | ||||
|                     highlight-current-row | ||||
|                   > | ||||
|                     <el-table-column label="序号" type="index" width="60px" /> | ||||
|                     <el-table-column label="计划日期" prop="date" /> | ||||
|                     <el-table-column label="数量" prop="planNum" width="60" /> | ||||
|                     <el-table-column label="完成量" prop="finishedNum" width="60" /> | ||||
|                     <el-table-column label="AI填报" prop="autoFill" width="60" /> | ||||
|                     <el-table-column label="操作" class-name="small-padding" width="200px" fixed="right"> | ||||
|                       <template #default="{ row: scopeRow, $index }"> | ||||
|                         <el-button type="primary" link @click="handleDayAdd(scopeRow, propsRow)"> | ||||
|                           <el-icon><ele-Plus /></el-icon>日报 | ||||
|                         </el-button> | ||||
|                         <el-button type="success" link @click="handleView(scopeRow, propsRow)"> | ||||
|                           <el-icon><ele-View /></el-icon>查看 | ||||
|                         </el-button> | ||||
|                       </template> | ||||
|                     </el-table-column> | ||||
|                   </el-table> | ||||
|                 </div> | ||||
|               </template> | ||||
|             </el-table-column> | ||||
|             <el-table-column label="序号" type="index" :index="indexMethod" width="60px" /> | ||||
|             <el-table-column label="计划数量" prop="planNum" min-width="100px" /> | ||||
|             <el-table-column label="完成数量" prop="finishedNum" min-width="100px" /> | ||||
|             <el-table-column label="延期量" min-width="100px"> | ||||
|               <template #default="{ row: scopeRow }"> | ||||
|                 <el-tag :type="filterW(scopeRow) ? 'danger' : 'success'"> | ||||
|                   {{ filterW(scopeRow) }} | ||||
|                 </el-tag> | ||||
|               </template> | ||||
|             </el-table-column> | ||||
|             <el-table-column label="AI填报" prop="autoFill" min-width="100px" /> | ||||
|             <el-table-column label="开始时间" min-width="100px"> | ||||
|               <template #default="{ row: scopeRow }"> | ||||
|                 <span>{{ scopeRow.startAt.split(' ')[0] }}</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="getWorkList" | ||||
|             layout="total, sizes, prev, pager, next" | ||||
|             :isSmall="5" | ||||
|           /> | ||||
|         </div> | ||||
|         <div class="box_right" v-if="showDayWork"> | ||||
|           <div class="time_submit"> | ||||
|             <span>{{ formDetail.submitTime }}</span> | ||||
|             <el-button type="primary" :disabled="!checkedList.length || flag" @click="onUploadDaily" size="large"> | ||||
|               <el-icon><ele-Upload /></el-icon>提交日报 | ||||
|             </el-button> | ||||
|           </div> | ||||
|           <el-table | ||||
|             v-loading="loading1" | ||||
|             height="58vh" | ||||
|             :data="detialList" | ||||
|             @selection-change="handleSelectionChange" | ||||
|             :row-key="(row) => row.id" | ||||
|             ref="multipleTableRef" | ||||
|           > | ||||
|             <el-table-column label="未完成工作" align="center"> | ||||
|               <el-table-column :reserve-selection="true" type="selection" width="55" align="center" /> | ||||
|               <el-table-column label="序号" align="center" type="index" width="60px" /> | ||||
|               <el-table-column label="编号" align="center" prop="name" min-width="100px" /> | ||||
|               <el-table-column label="状态" align="center" min-width="100px"> | ||||
|                 <template #default="{ row: scopeRow }"> | ||||
|                   <el-tag :type="typeList[scopeRow.status]"> | ||||
|                     {{ filterStatus(scopeRow.status) }} | ||||
|                   </el-tag> | ||||
|                 </template> | ||||
|               </el-table-column> | ||||
|             </el-table-column> | ||||
|           </el-table> | ||||
|           <pagination | ||||
|             v-show="detailTotal > 0" | ||||
|             :total="detailTotal" | ||||
|             v-model:page="detailQueryParams.pageNum" | ||||
|             v-model:limit="detailQueryParams.pageSize" | ||||
|             @pagination="getPvModuleList" | ||||
|             layout="total, sizes, prev, pager, next" | ||||
|             :isSmall="5" | ||||
|           /> | ||||
|         </div> | ||||
|         <div class="box_right" v-else> | ||||
|           <div class="time_submit"> | ||||
|             <span>{{ formDetail.submitTime }}</span> | ||||
|             <el-button type="danger" :disabled="single" @click="handleRemove(null)" size="large"> | ||||
|               <el-icon><ele-SemiSelect /></el-icon>批量移除 | ||||
|             </el-button> | ||||
|           </div> | ||||
|           <el-table | ||||
|             v-loading="loading2" | ||||
|             height="58vh" | ||||
|             :data="detialWordList" | ||||
|             @selection-change="handleSelectionChangeWork" | ||||
|             :row-key="(row) => row.id" | ||||
|             ref="multipleTableWorkRef" | ||||
|           > | ||||
|             <el-table-column label="已完成工作" align="center"> | ||||
|               <el-table-column :reserve-selection="true" type="selection" width="55" align="center" /> | ||||
|               <el-table-column label="序号" align="center" type="index" width="60px" /> | ||||
|               <el-table-column label="编号" align="center" prop="name" min-width="100px" /> | ||||
|               <el-table-column label="填报方式" align="center" prop="status" min-width="100px"> | ||||
|                 <template #default="{ row: scopeRow }"> | ||||
|                   <span v-if="scopeRow.status === 2">手动填报</span> | ||||
|                   <span v-if="scopeRow.status === 3">AI识别</span> | ||||
|                 </template> | ||||
|               </el-table-column> | ||||
|               <el-table-column label="操作" align="center" min-width="100px"> | ||||
|                 <template #default="{ row: scopeRow }"> | ||||
|                   <el-button type="danger" link @click="handleRemove(scopeRow)"> | ||||
|                     <el-icon><ele-SemiSelect /></el-icon>移除 | ||||
|                   </el-button> | ||||
|                 </template> | ||||
|               </el-table-column> | ||||
|             </el-table-column> | ||||
|           </el-table> | ||||
|           <pagination | ||||
|             v-show="detailTotalWork > 0" | ||||
|             :total="detailTotalWork" | ||||
|             v-model:page="detailQueryParamsWork.pageNum" | ||||
|             v-model:limit="detailQueryParamsWork.pageSize" | ||||
|             @pagination="getPvModuleList" | ||||
|             layout="total, sizes, prev, pager, next" | ||||
|             :isSmall="5" | ||||
|           /> | ||||
|         </div> | ||||
|       </div> | ||||
|       <template #footer> | ||||
|         <div class="dialog-footer"> | ||||
|           <el-button @click="onCancel" size="large">关 闭</el-button> | ||||
|         </div> | ||||
|       </template> | ||||
|     </el-dialog> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script setup lang="ts"> | ||||
| import { ref, reactive, computed, watch, onMounted } from 'vue'; | ||||
| import { ElMessage, ElMessageBox } from 'element-plus'; | ||||
| import { workScheduleList, pvModuleList, addDaily, getDailyBook, deleteDaily } from '@/api/progress/plan'; | ||||
| import { workScheduleListQuery } from '@/api/progress/plan/types'; | ||||
|  | ||||
| // 响应式状态 | ||||
| const state = reactive<{ | ||||
|   expandRowKeys: number[]; | ||||
|   loading: boolean; | ||||
|   isShowDialog: boolean; | ||||
|   queryParams: workScheduleListQuery; | ||||
|   infoDetail: { name: string }; | ||||
|   tableData: any[]; | ||||
|   total: number; | ||||
|   formDetail: { | ||||
|     workId: string; | ||||
|     id: string; | ||||
|     submitTime: string; | ||||
|     finishedNum: number; | ||||
|   }; | ||||
|   detialList: any[]; | ||||
|   detailTotal: number; | ||||
|   detailQueryParams: { | ||||
|     pageSize: number; | ||||
|     pageNum: number; | ||||
|   }; | ||||
|   loading1: boolean; | ||||
|   loading2: boolean; | ||||
|   typeList: ('info' | 'warning' | 'success' | 'danger')[]; | ||||
|   checkedList: number[]; | ||||
|   updateRow: any | null; | ||||
|   showDayWork: boolean; | ||||
|   detialWordList: any[]; | ||||
|   detailTotalWork: number; | ||||
|   detailQueryParamsWork: { | ||||
|     pageSize: number; | ||||
|     pageNum: number; | ||||
|   }; | ||||
|   single: boolean; | ||||
|   checkList: number[]; | ||||
|   flag: boolean; | ||||
| }>({ | ||||
|   expandRowKeys: [], | ||||
|   loading: false, | ||||
|   isShowDialog: false, | ||||
|   queryParams: { | ||||
|     pageSize: 10, | ||||
|     pageNum: 1, | ||||
|     progressCategoryId: '' | ||||
|   }, | ||||
|   infoDetail: { name: '' }, | ||||
|   tableData: [], | ||||
|   total: 0, | ||||
|   formDetail: { | ||||
|     workId: '', | ||||
|     id: '', | ||||
|     submitTime: '选择日期', | ||||
|     finishedNum: 0 | ||||
|   }, | ||||
|   detialList: [], | ||||
|   detailTotal: 0, | ||||
|   detailQueryParams: { | ||||
|     pageSize: 20, | ||||
|     pageNum: 1 | ||||
|   }, | ||||
|   loading1: false, | ||||
|   loading2: false, | ||||
|   typeList: ['info', 'warning', 'success', 'danger'], | ||||
|   checkedList: [], | ||||
|   updateRow: null, | ||||
|   showDayWork: true, | ||||
|   detialWordList: [], | ||||
|   detailTotalWork: 0, | ||||
|   detailQueryParamsWork: { | ||||
|     pageSize: 20, | ||||
|     pageNum: 1 | ||||
|   }, | ||||
|   single: true, | ||||
|   checkList: [], | ||||
|   flag: false | ||||
| }); | ||||
|  | ||||
| // 引用refs | ||||
| const multipleTableRef = ref(); | ||||
| const multipleTableWorkRef = ref(); | ||||
|  | ||||
| // 状态解包 | ||||
| const { | ||||
|   expandRowKeys, | ||||
|   loading, | ||||
|   isShowDialog, | ||||
|   queryParams, | ||||
|   infoDetail, | ||||
|   tableData, | ||||
|   total, | ||||
|   formDetail, | ||||
|   detialList, | ||||
|   detailTotal, | ||||
|   detailQueryParams, | ||||
|   loading1, | ||||
|   loading2, | ||||
|   typeList, | ||||
|   checkedList, | ||||
|   updateRow, | ||||
|   showDayWork, | ||||
|   detialWordList, | ||||
|   detailTotalWork, | ||||
|   detailQueryParamsWork, | ||||
|   single, | ||||
|   checkList, | ||||
|   flag | ||||
| } = toRefs(state); | ||||
|  | ||||
| // 状态过滤函数 | ||||
| const filterStatus = (val: number): string => { | ||||
|   switch (val) { | ||||
|     case 0: | ||||
|       return '未开始'; | ||||
|     case 1: | ||||
|       return '进行中'; | ||||
|     case 2: | ||||
|       return '已完成'; | ||||
|     case 3: | ||||
|       return '已延期'; | ||||
|     default: | ||||
|       return ''; | ||||
|   } | ||||
| }; | ||||
|  | ||||
| // 打开弹窗 | ||||
| const openDialog = (row: any) => { | ||||
|   resetForm(false); | ||||
|   formDetail.value.submitTime = ''; | ||||
|   queryParams.value.progressCategoryId = row.id; | ||||
|   formDetail.value.workId = row.work_id; | ||||
|   infoDetail.value = row; | ||||
|   state.isShowDialog = true; | ||||
|   getWorkList(true); | ||||
| }; | ||||
|  | ||||
| const resetForm = (bool: boolean) => { | ||||
|   showDayWork.value = bool; | ||||
|   detialList.value = []; | ||||
|   detialWordList.value = []; | ||||
| }; | ||||
|  | ||||
| // 获取未完成数据 | ||||
| const getPvModuleList = () => { | ||||
|   loading1.value = true; | ||||
|   pvModuleList({ | ||||
|     workId: formDetail.value.workId, | ||||
|     ...detailQueryParams.value, | ||||
|     type: infoDetail.value.work_type, | ||||
|     status: 0 | ||||
|   }).then((res: any) => { | ||||
|     loading1.value = false; | ||||
|     if (res.code === 0) { | ||||
|       detialList.value = res.data.list; | ||||
|       detailTotal.value = res.data.total; | ||||
|     } | ||||
|   }); | ||||
| }; | ||||
|  | ||||
| // 获取计划列表 | ||||
| const getWorkList = (bool = false) => { | ||||
|   loading.value = true; | ||||
|   workScheduleList(queryParams.value).then((res: any) => { | ||||
|     if (res.code === 0) { | ||||
|       state.tableData = res.data.list.map((item: any, i: number) => { | ||||
|         item.index = i + 1; | ||||
|         item.autoFill = item.detail?.reduce((sum: number, child: any) => sum + child.autoFill, 0) || 0; | ||||
|         return item; | ||||
|       }); | ||||
|       state.total = res.data.total; | ||||
|     } | ||||
|     loading.value = false; | ||||
|   }); | ||||
| }; | ||||
|  | ||||
| // 关闭弹窗 | ||||
| const onCancel = () => { | ||||
|   closeDialog(); | ||||
| }; | ||||
|  | ||||
| const closeDialog = () => { | ||||
|   isShowDialog.value = false; | ||||
|   emit('getProgressList'); | ||||
| }; | ||||
|  | ||||
| // 自定义序号 | ||||
| const indexMethod = (index: number): number => { | ||||
|   const currentPage = queryParams.value.pageNum - 1; | ||||
|   return currentPage > -1 ? index + 1 + currentPage * queryParams.value.pageSize : index + 1; | ||||
| }; | ||||
|  | ||||
| // 日报添加 | ||||
| const handleDayAdd = (row: any, obj: any) => { | ||||
|   resetForm(true); | ||||
|   formDetail.value.id = obj.id; | ||||
|   formDetail.value.submitTime = row.date; | ||||
|   state.updateRow = row; | ||||
|   getPvModuleList(); | ||||
| }; | ||||
|  | ||||
| const tableKey = (row: any) => row.id; | ||||
|  | ||||
| // 展开行处理 | ||||
| const clickOpen = (row: any) => { | ||||
|   const index = state.expandRowKeys.indexOf(row.id); | ||||
|   index === -1 ? state.expandRowKeys.push(row.id) : state.expandRowKeys.splice(index, 1); | ||||
|   state.expandRowKeys = [...new Set(state.expandRowKeys)]; | ||||
| }; | ||||
|  | ||||
| // 多选框处理 | ||||
| const handleSelectionChange = (selection: any[]) => { | ||||
|   state.checkedList = selection.map((item: any) => item.id); | ||||
| }; | ||||
|  | ||||
| // 提交日报 | ||||
| const onUploadDaily = () => { | ||||
|   if (!checkedList.value.length) { | ||||
|     ElMessage.warning('请添加完成的任务编号'); | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   const obj = { | ||||
|     ids: checkedList.value, | ||||
|     workID: formDetail.value.workId, | ||||
|     doneTime: formDetail.value.submitTime, | ||||
|     planID: formDetail.value.id | ||||
|   }; | ||||
|  | ||||
|   state.flag = true; | ||||
|   addDaily(obj).then((res: any) => { | ||||
|     if (res.code === 0) { | ||||
|       ElMessage.success('添加成功'); | ||||
|       if (state.updateRow) { | ||||
|         state.updateRow.finishedNum += checkedList.value.length; | ||||
|       } | ||||
|       checkedList.value = []; | ||||
|       multipleTableRef.value?.clearSelection(); | ||||
|       getPvModuleList(); | ||||
|     } else { | ||||
|       ElMessage.error(res.message); | ||||
|     } | ||||
|     state.flag = false; | ||||
|   }); | ||||
| }; | ||||
|  | ||||
| // 查看日报 | ||||
| const handleView = (row: any, obj: any) => { | ||||
|   resetForm(false); | ||||
|   getDailyBookList(row.date); | ||||
|   state.updateRow = row; | ||||
|   formDetail.value.id = obj.id; | ||||
|   formDetail.value.submitTime = row.date; | ||||
|   showDayWork.value = false; | ||||
| }; | ||||
|  | ||||
| // 获取已填日报 | ||||
| const getDailyBookList = (doneTime: string) => { | ||||
|   detialWordList.value = []; | ||||
|   getDailyBook({ | ||||
|     workId: formDetail.value.workId, | ||||
|     type: infoDetail.value.work_type, | ||||
|     doneTime | ||||
|   }).then((res: any) => { | ||||
|     if (res.code === 0) { | ||||
|       detialWordList.value = res.data.list || []; | ||||
|     } else { | ||||
|       ElMessage.error(res.message); | ||||
|     } | ||||
|   }); | ||||
| }; | ||||
|  | ||||
| // 选中处理(已完成) | ||||
| const handleSelectionChangeWork = (selection: any[]) => { | ||||
|   state.checkList = selection.map((item: any) => item.id); | ||||
|   state.single = selection.length === 0; | ||||
| }; | ||||
|  | ||||
| // 移除日报 | ||||
| const handleRemove = (row?: any) => { | ||||
|   const planID = row ? [row.id] : state.checkList; | ||||
|   const obj = { | ||||
|     planID, | ||||
|     id: formDetail.value.id, | ||||
|     workID: formDetail.value.workId, | ||||
|     time: formDetail.value.submitTime | ||||
|   }; | ||||
|  | ||||
|   ElMessageBox.confirm('确认移除该条数据?', '温馨提示', { | ||||
|     confirmButtonText: '确认', | ||||
|     cancelButtonText: '取消', | ||||
|     type: 'warning' | ||||
|   }) | ||||
|     .then(() => { | ||||
|       deleteDaily(obj).then((res: any) => { | ||||
|         if (res.code === 0) { | ||||
|           ElMessage.success('移除成功'); | ||||
|           if (state.updateRow) { | ||||
|             state.updateRow.finishedNum -= planID.length; | ||||
|           } | ||||
|           getDailyBookList(formDetail.value.submitTime); | ||||
|         } else { | ||||
|           ElMessage.error(res.message); | ||||
|         } | ||||
|       }); | ||||
|     }) | ||||
|     .catch(() => {}); | ||||
| }; | ||||
|  | ||||
| // 延期计算 | ||||
| const filterW = (row: any): number => { | ||||
|   const { finishedNum, planNum, endAt } = row; | ||||
|   if (!endAt) return 0; | ||||
|  | ||||
|   const endTime = new Date(endAt).getTime(); | ||||
|   const now = new Date().getTime(); | ||||
|  | ||||
|   if (endTime <= now && planNum > finishedNum) { | ||||
|     return planNum - finishedNum; | ||||
|   } | ||||
|   return 0; | ||||
| }; | ||||
|  | ||||
| // 暴露给模板的属性和方法 | ||||
| defineExpose({ | ||||
|   openDialog, | ||||
|   closeDialog | ||||
| }); | ||||
| const emit = defineEmits(['getProgressList']); | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| .daily-paper-count { | ||||
|   width: 100%; | ||||
|  | ||||
|   .box { | ||||
|     display: flex; | ||||
|     width: 100%; | ||||
|     justify-content: space-between; | ||||
|     padding: 0 10px; | ||||
|  | ||||
|     .box-left { | ||||
|       width: 50%; | ||||
|       float: left; | ||||
|     } | ||||
|  | ||||
|     .box_right { | ||||
|       width: 46%; | ||||
|       float: left; | ||||
|       border: 1px solid #ebeef5; | ||||
|       height: 64vh; | ||||
|       margin-left: 20px; | ||||
|  | ||||
|       .time_submit { | ||||
|         width: 100%; | ||||
|         padding: 10px; | ||||
|         box-sizing: border-box; | ||||
|         display: flex; | ||||
|         justify-content: space-between; | ||||
|  | ||||
|         > span { | ||||
|           font-size: 20px; | ||||
|           font-family: revert; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .pagination-container { | ||||
|     padding: 10px 10px !important; | ||||
|   } | ||||
|  | ||||
|   .el-drawer__title { | ||||
|     font-size: 18px; | ||||
|   } | ||||
| } | ||||
| </style> | ||||
| @ -19,7 +19,7 @@ | ||||
|                 value-format="YYYY-MM-DD" | ||||
|                 size="large" | ||||
|                 :disabled-date="pickerOptionsStart" | ||||
|                 :disabled="remainingNumAt.remainingNum === 0" | ||||
|                 :disabled="remainingNumAt.leftNum === 0" | ||||
|               /> | ||||
|             </el-form-item> | ||||
|             <el-form-item label="结束时间" prop="end_at"> | ||||
| @ -31,26 +31,26 @@ | ||||
|                 value-format="YYYY-MM-DD" | ||||
|                 size="large" | ||||
|                 :disabled-date="pickerOptionsEnd" | ||||
|                 :disabled="remainingNumAt.remainingNum === 0" | ||||
|                 :disabled="remainingNumAt.leftNum === 0" | ||||
|               /> | ||||
|             </el-form-item> | ||||
|             <el-form-item label="计划数量" prop="planNum"> | ||||
|             <el-form-item label="计划数量" prop="planNumber"> | ||||
|               <el-row> | ||||
|                 <el-col :span="18"> | ||||
|                   <el-input | ||||
|                     v-model="formData.planNum" | ||||
|                     v-model="formData.planNumber" | ||||
|                     type="number" | ||||
|                     :min="0" | ||||
|                     :max="remainingNumAt.remainingNum" | ||||
|                     :disabled="remainingNumAt.remainingNum === 0" | ||||
|                     :max="remainingNumAt.leftNum" | ||||
|                     :disabled="remainingNumAt.leftNum === 0" | ||||
|                     placeholder="请输入计划数量" | ||||
|                   > | ||||
|                     <template #append> | ||||
|                       <span style="font-size: 12px">最大值:{{ remainingNumAt.remainingNum }}</span> | ||||
|                       <span style="font-size: 12px">最大值:{{ remainingNumAt.leftNum }}</span> | ||||
|                     </template> | ||||
|                   </el-input> | ||||
|                 </el-col> | ||||
|                 <el-button type="primary" @click="onAverage" :disabled="!formData.planNum || tableData.length === 0" style="margin-left: 10px" | ||||
|                 <el-button type="primary" @click="onAverage" :disabled="!formData.planNumber || tableData.length === 0" style="margin-left: 10px" | ||||
|                   >均值</el-button | ||||
|                 > | ||||
|               </el-row> | ||||
| @ -70,9 +70,16 @@ | ||||
|           > | ||||
|             <el-table-column type="index" :index="indexMethod" label="序号" width="60" /> | ||||
|             <el-table-column prop="date" label="日期" width="130" /> | ||||
|             <el-table-column prop="planNum" label="数量"> | ||||
|             <el-table-column prop="planNumber" label="数量"> | ||||
|               <template #default="scope"> | ||||
|                 <el-input-number v-model="scope.row.planNum" :value-on-clear="0" :min="0" :max="scope.row.max" @change="onChangeSum" size="small" /> | ||||
|                 <el-input-number | ||||
|                   v-model="scope.row.planNumber" | ||||
|                   :value-on-clear="0" | ||||
|                   :min="0" | ||||
|                   :max="scope.row.max" | ||||
|                   @change="onChangeSum" | ||||
|                   size="small" | ||||
|                 /> | ||||
|               </template> | ||||
|             </el-table-column> | ||||
|           </el-table> | ||||
| @ -103,6 +110,7 @@ | ||||
| import { ref, reactive, watch, computed } from 'vue'; | ||||
| import { ElMessage, FormInstance } from 'element-plus'; | ||||
| import { workScheduleAddPlan, lastTime } from '@/api/progress/plan'; | ||||
| import { lastTimeVo, ProgressCategoryVO, ProgressPlanForm } from '@/api/progress/plan/types'; | ||||
|  | ||||
| // Form refs | ||||
| const formRef = ref<FormInstance | null>(null); | ||||
| @ -115,27 +123,40 @@ const pageSize = 10; | ||||
| const formData = reactive({ | ||||
|   start_at: '', | ||||
|   end_at: '', | ||||
|   planNum: 0 | ||||
|   planNumber: 0 | ||||
| }); | ||||
|  | ||||
| const rules = { | ||||
|   start_at: [{ required: true, message: '开始时间不能为空', trigger: 'blur' }], | ||||
|   end_at: [{ required: true, message: '结束时间不能为空', trigger: 'blur' }], | ||||
|   planNum: [{ required: true, message: '计划数量不能为空', trigger: 'blur' }] | ||||
|   planNumber: [ | ||||
|     { | ||||
|       trigger: 'input', // 用户输入时触发校验 | ||||
|       validator: (_rule: any, value: string, callback: any) => { | ||||
|         const numberValue = Number(value); | ||||
|         console.log(numberValue); | ||||
|  | ||||
|         if (value === '') { | ||||
|           callback(new Error('请输入值')); | ||||
|         } else if (numberValue > remainingNumAt.leftNum) { | ||||
|           callback(new Error(`数字不能大于 ${remainingNumAt.leftNum}`)); | ||||
|         } else { | ||||
|           callback(); | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     { required: true, message: '计划数量不能为空', trigger: 'blur' } | ||||
|   ] | ||||
| }; | ||||
|  | ||||
| const infoDetail = reactive({ | ||||
|   name: '', | ||||
|   work_id: '', | ||||
|   is_delay: 0 | ||||
| const infoDetail = reactive<ProgressCategoryVO>({} as ProgressCategoryVO); | ||||
|  | ||||
| const remainingNumAt = reactive<lastTimeVo>({ | ||||
|   endDate: '', | ||||
|   leftNum: 100 | ||||
| }); | ||||
|  | ||||
| const remainingNumAt = reactive({ | ||||
|   endAt: '', | ||||
|   remainingNum: 100 | ||||
| }); | ||||
|  | ||||
| const tableData = ref<{ date: string; planNum: number; max: number }[]>([]); | ||||
| const tableData = ref<{ date: string; planNumber: number; max: number }[]>([]); | ||||
|  | ||||
| // Computed paginated data | ||||
| const paginatedData = computed(() => { | ||||
| @ -151,8 +172,8 @@ watch( | ||||
|       const dates = generateDateRange(start, end); | ||||
|       tableData.value = dates.map((date) => ({ | ||||
|         date, | ||||
|         planNum: 0, | ||||
|         max: remainingNumAt.remainingNum | ||||
|         planNumber: 0, | ||||
|         max: remainingNumAt.leftNum | ||||
|       })); | ||||
|     } else { | ||||
|       tableData.value = []; | ||||
| @ -175,38 +196,38 @@ const generateDateRange = (start: string, end: string): string[] => { | ||||
| // Picker rules | ||||
| const pickerOptionsStart = (date: Date) => { | ||||
|   if (formData.end_at) return date.getTime() > new Date(formData.end_at).getTime(); | ||||
|   if (remainingNumAt.endAt) return date.getTime() < new Date(remainingNumAt.endAt).getTime(); | ||||
|   if (remainingNumAt.endDate) return date.getTime() < new Date(remainingNumAt.endDate).getTime(); | ||||
|   return false; | ||||
| }; | ||||
|  | ||||
| const pickerOptionsEnd = (date: Date) => { | ||||
|   if (formData.start_at) return date.getTime() < new Date(formData.start_at).getTime(); | ||||
|   if (remainingNumAt.endAt) return date.getTime() < new Date(remainingNumAt.endAt).getTime(); | ||||
|   if (remainingNumAt.endDate) return date.getTime() < new Date(remainingNumAt.endDate).getTime(); | ||||
|   return false; | ||||
| }; | ||||
|  | ||||
| // Average calculation | ||||
| const onAverage = () => { | ||||
|   const total = formData.planNum; | ||||
|   const total = formData.planNumber; | ||||
|   const len = tableData.value.length; | ||||
|   const avg = Math.floor(total / len); | ||||
|   let remainder = total % len; | ||||
|  | ||||
|   tableData.value.forEach((row) => { | ||||
|     row.planNum = avg + (remainder > 0 ? 1 : 0); | ||||
|     row.planNumber = avg + (remainder > 0 ? 1 : 0); | ||||
|     remainder--; | ||||
|   }); | ||||
| }; | ||||
|  | ||||
| // Total sum validation | ||||
| const onChangeSum = () => { | ||||
|   let total = tableData.value.reduce((sum, item) => sum + item.planNum, 0); | ||||
|   if (total > remainingNumAt.remainingNum) { | ||||
|   let total = tableData.value.reduce((sum, item) => sum + item.planNumber, 0); | ||||
|   if (total > remainingNumAt.leftNum) { | ||||
|     tableData.value.forEach((item) => { | ||||
|       item.max = item.planNum; | ||||
|       item.max = item.planNumber; | ||||
|     }); | ||||
|   } | ||||
|   formData.planNum = total; | ||||
|   formData.planNumber = total; | ||||
| }; | ||||
|  | ||||
| // Index method | ||||
| @ -219,16 +240,18 @@ const onSubmit = () => { | ||||
|   if (!formRef.value) return; | ||||
|   formRef.value.validate((valid) => { | ||||
|     if (!valid) return; | ||||
|  | ||||
|     const payload = { | ||||
|       workId: infoDetail.work_id, | ||||
|       planNum: formData.planNum, | ||||
|       scheduledTime: tableData.value, | ||||
|       is_delay: infoDetail.is_delay === 1 ? 1 : undefined | ||||
|     const payload: ProgressPlanForm = { | ||||
|       projectId: infoDetail.projectId, | ||||
|       planNumber: formData.planNumber, | ||||
|       detailList: tableData.value, | ||||
|       startDate: formData.start_at, | ||||
|       endDate: formData.end_at, | ||||
|       progressCategoryId: infoDetail.id, | ||||
|       matrixId: infoDetail.matrixId | ||||
|     }; | ||||
|  | ||||
|     workScheduleAddPlan(payload).then((res: any) => { | ||||
|       if (res.code === 0) { | ||||
|       if (res.code === 200) { | ||||
|         ElMessage.success('添加成功'); | ||||
|         closeDialog(); | ||||
|       } else { | ||||
| @ -253,13 +276,15 @@ const closeDialog = () => { | ||||
| const resetForm = () => { | ||||
|   formData.start_at = ''; | ||||
|   formData.end_at = ''; | ||||
|   formData.planNum = 0; | ||||
|   formData.planNumber = 0; | ||||
|   tableData.value = []; | ||||
| }; | ||||
|  | ||||
| const fetchLastTime = (row: typeof infoDetail) => { | ||||
|   lastTime({ workId: row.work_id, is_delay: row.is_delay }).then((res: any) => { | ||||
|     if (res.code === 0) { | ||||
|   console.log(row); | ||||
|  | ||||
|   lastTime(row.id).then((res: any) => { | ||||
|     if (res.code === 200) { | ||||
|       Object.assign(remainingNumAt, res.data); | ||||
|     } | ||||
|   }); | ||||
|  | ||||
| @ -6,13 +6,16 @@ | ||||
|           <el-form ref="queryFormRef" :model="queryParams" :inline="true"> | ||||
|             <el-form-item label="请选择方阵:" prop="pid" label-width="100"> | ||||
|               <!-- <el-input v-model="queryParams.pid" placeholder="请选择" clearable /> --> | ||||
|               <el-cascader | ||||
|               <!-- <el-cascader | ||||
|                 :options="matrixOptions" | ||||
|                 placeholder="请选择" | ||||
|                 @change="handleChange" | ||||
|                 :props="{ value: 'id', label: 'matrixName' }" | ||||
|                 clearable | ||||
|               /> | ||||
|               /> --> | ||||
|               <el-select v-model="matrixValue" placeholder="请选择" @change="handleChange" clearable> | ||||
|                 <el-option v-for="item in matrixOptions" :key="item.id" :label="item.matrixName" :value="item.id" /> | ||||
|               </el-select> | ||||
|             </el-form-item> | ||||
|             <el-form-item> | ||||
|               <el-button type="primary" icon="Download" @click="handleQuery">导出周报</el-button> | ||||
| @ -117,7 +120,7 @@ | ||||
|                       icon="Plus" | ||||
|                       link | ||||
|                       size="small" | ||||
|                       @click="dailyRef.openDialog(scope.row)" | ||||
|                       @click="handleDayAdd(scope.row)" | ||||
|                       v-hasPermi="['progress:progressCategory:add']" | ||||
|                     > | ||||
|                       日报 | ||||
| @ -162,8 +165,9 @@ | ||||
|       </template> | ||||
|     </el-dialog> | ||||
|     <!-- 创建计划对话框 --> | ||||
|     <CreatePlan ref="planRef"></CreatePlan> | ||||
|     <CreateDaily ref="dailyRef"></CreateDaily> | ||||
|     <CreatePlan ref="planRef" @getProgressList="getList"></CreatePlan> | ||||
|     <CreateDaily ref="dailyRef" @getProgressList="getList"></CreateDaily> | ||||
|     <CreateDailyRate ref="dailyRateRef" @getProgressList="getList"></CreateDailyRate> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| @ -183,6 +187,7 @@ const { progress_unit_type, progress_status } = toRefs<any>(proxy?.useDict('prog | ||||
| import { useUserStoreHook } from '@/store/modules/user'; | ||||
| import CreatePlan from './component/createPlan.vue'; | ||||
| import CreateDaily from './component/createDaily.vue'; | ||||
| import CreateDailyRate from './component/createDailyRate.vue'; | ||||
| type ProgressCategoryOption = { | ||||
|   id: number; | ||||
|   name: string; | ||||
| @ -201,16 +206,11 @@ const isExpandAll = ref(true); | ||||
| const loading = ref(false); | ||||
| const planRef = ref<InstanceType<typeof CreatePlan>>(); | ||||
| const dailyRef = ref<InstanceType<typeof CreateDaily>>(); | ||||
| const dailyRateRef = ref<InstanceType<typeof CreateDailyRate>>(); | ||||
| const queryFormRef = ref<ElFormInstance>(); | ||||
| const progressCategoryFormRef = ref<ElFormInstance>(); | ||||
| const progressCategoryTableRef = ref<ElTableInstance>(); | ||||
| const matrixOptions = ref([ | ||||
|   { | ||||
|     id: currentProject.value.id, | ||||
|     matrixName: currentProject.value.name, | ||||
|     children: [] | ||||
|   } | ||||
| ]); | ||||
| const matrixOptions = ref([]); | ||||
| const dialog = reactive<any>({ | ||||
|   dailyStatus: false, | ||||
|   planStatus: false, | ||||
| @ -219,7 +219,7 @@ const dialog = reactive<any>({ | ||||
|   title: '', | ||||
|   file: '' | ||||
| }); | ||||
|  | ||||
| const matrixValue = ref<number | undefined>(matrixOptions.value.length > 0 ? matrixOptions.value[0].id : undefined); | ||||
| const initFormData: ProgressCategoryForm = { | ||||
|   id: undefined, | ||||
|   pid: undefined, | ||||
| @ -254,9 +254,8 @@ const { queryParams, form, rules } = toRefs(data); | ||||
| const getList = async () => { | ||||
|   if (!queryParams.value.matrixId) { | ||||
|     const res = await getProjectSquare(currentProject.value.id); | ||||
|     console.log('🚀 ~ getList ~ res:', res); | ||||
|  | ||||
|     matrixOptions.value[0].children = res.rows; | ||||
|     if (!matrixValue.value) matrixValue.value = res.rows[0].id; | ||||
|     matrixOptions.value = res.rows; | ||||
|     queryParams.value.matrixId = res.rows[0].id; | ||||
|   } | ||||
|   loading.value = true; | ||||
| @ -295,12 +294,20 @@ const handleQuery = () => { | ||||
| }; | ||||
|  | ||||
| /** 级联选择器改变事件 */ | ||||
| const handleChange = (value: number[]) => { | ||||
|   queryParams.value.matrixId = value[1]; | ||||
| const handleChange = (value: number) => { | ||||
|   queryParams.value.matrixId = value; | ||||
|  | ||||
|   getList(); | ||||
| }; | ||||
|  | ||||
| const handleDayAdd = (row: ProgressCategoryVO) => { | ||||
|   if (row.unitType === '2') { | ||||
|     dailyRef.value.openDialog(row); | ||||
|   } else { | ||||
|     dailyRateRef.value.openDialog(row); | ||||
|   } | ||||
| }; | ||||
|  | ||||
| /** 导入按钮操作 */ | ||||
| const openDialog = (row: ProgressCategoryVO, status: string, title: string) => { | ||||
|   reset(); | ||||
|  | ||||
		Reference in New Issue
	
	Block a user