合并
This commit is contained in:
		| @ -69,7 +69,8 @@ | |||||||
|     "vue-types": "5.1.3", |     "vue-types": "5.1.3", | ||||||
|     "vue3-print-nb": "^0.1.4", |     "vue3-print-nb": "^0.1.4", | ||||||
|     "vue3-scroll-seamless": "^1.0.6", |     "vue3-scroll-seamless": "^1.0.6", | ||||||
|     "vxe-table": "4.5.22" |     "vxe-table": "4.5.22", | ||||||
|  |     "xlsx": "^0.18.5" | ||||||
|   }, |   }, | ||||||
|   "devDependencies": { |   "devDependencies": { | ||||||
|     "@eslint/js": "9.15.0", |     "@eslint/js": "9.15.0", | ||||||
|  | |||||||
										
											Binary file not shown.
										
									
								
							| @ -24,3 +24,11 @@ export const exportWord = (params) => { | |||||||
|     method: 'post' |     method: 'post' | ||||||
|   }); |   }); | ||||||
| }; | }; | ||||||
|  | // 导出模版 | ||||||
|  | export const exportExcel = (params) => { | ||||||
|  |   return request({ | ||||||
|  |     url: '/design/collect/exportExcel', | ||||||
|  |     method: 'post', | ||||||
|  |     params: params | ||||||
|  |   }); | ||||||
|  | }; | ||||||
|  | |||||||
| @ -127,6 +127,17 @@ export const majorList = (params) => { | |||||||
|     params: params |     params: params | ||||||
|   }); |   }); | ||||||
| }; | }; | ||||||
|  | /** | ||||||
|  |  * 获取人员列表 | ||||||
|  |  * @param query | ||||||
|  |  */ | ||||||
|  | export const copyUserList = (params) => { | ||||||
|  |   return request({ | ||||||
|  |     url: '/design/volumeCatalog/copyUserList', | ||||||
|  |     method: 'get', | ||||||
|  |     params: params | ||||||
|  |   }); | ||||||
|  | }; | ||||||
| /** | /** | ||||||
|  * 获取二维码信息 |  * 获取二维码信息 | ||||||
|  * @param query |  * @param query | ||||||
|  | |||||||
| @ -75,3 +75,11 @@ export const inventoryList = (id: any) => { | |||||||
|     method: 'get' |     method: 'get' | ||||||
|   }); |   }); | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | //获取材料表信息 | ||||||
|  | export const getMaterialInfo = (id: any) => { | ||||||
|  |   return request({ | ||||||
|  |     url: '/materials/materials/listByFormCode/' + id, | ||||||
|  |     method: 'get' | ||||||
|  |   }); | ||||||
|  | }; | ||||||
|  | |||||||
| @ -195,3 +195,35 @@ export const changeProject = (id: string | number) => { | |||||||
|     method: 'get' |     method: 'get' | ||||||
|   }); |   }); | ||||||
| }; | }; | ||||||
|  | /** | ||||||
|  |  * 打卡规则 | ||||||
|  |  * @param id | ||||||
|  |  */ | ||||||
|  | export const attendanceRuleEdit = (data) => { | ||||||
|  |   return request({ | ||||||
|  |     url: '/project/attendanceRule', | ||||||
|  |     method: 'put', | ||||||
|  |     data | ||||||
|  |   }); | ||||||
|  | }; | ||||||
|  | /** | ||||||
|  |  * 打卡规则 | ||||||
|  |  * @param id | ||||||
|  |  */ | ||||||
|  | export const attendanceRuleAdd = (data) => { | ||||||
|  |   return request({ | ||||||
|  |     url: '/project/attendanceRule', | ||||||
|  |     method: 'post', | ||||||
|  |     data | ||||||
|  |   }); | ||||||
|  | }; | ||||||
|  | /** | ||||||
|  |  * 获取规则 | ||||||
|  |  * @param id | ||||||
|  |  */ | ||||||
|  | export const byProjectIdDetail = (id) => { | ||||||
|  |   return request({ | ||||||
|  |     url: '/project/attendanceRule/byProjectId/' + id, | ||||||
|  |     method: 'get' | ||||||
|  |   }); | ||||||
|  | }; | ||||||
|  | |||||||
| @ -71,7 +71,7 @@ export function getRoleList(deptId?: number | string): AxiosPromise<any[]> { | |||||||
|     url: '/system/role/listNoPage', |     url: '/system/role/listNoPage', | ||||||
|     method: 'get', |     method: 'get', | ||||||
|     params: { |     params: { | ||||||
|       deptId |       deptId, | ||||||
|     } |     } | ||||||
|   }); |   }); | ||||||
| } | } | ||||||
|  | |||||||
| @ -5,8 +5,6 @@ import { ProjectTeamVO } from '@/api/project/projectTeam/types'; | |||||||
| import useUserStore from '@/store/modules/user'; | import useUserStore from '@/store/modules/user'; | ||||||
| export const getProjectTeam = async () => { | export const getProjectTeam = async () => { | ||||||
|   const isPermission = useUserStore().permissions.some((item) => item == 'project:team:list'); |   const isPermission = useUserStore().permissions.some((item) => item == 'project:team:list'); | ||||||
|   console.log(useUserStore().permissions); |  | ||||||
|  |  | ||||||
|   if (!isPermission && useUserStore().permissions[0] != '*:*:*') return; |   if (!isPermission && useUserStore().permissions[0] != '*:*:*') return; | ||||||
|  |  | ||||||
|   const { id } = $cache.local.getJSON('selectedProject'); |   const { id } = $cache.local.getJSON('selectedProject'); | ||||||
|  | |||||||
| @ -5,7 +5,7 @@ | |||||||
|         <el-form :model="queryForm" :inline="true"> |         <el-form :model="queryForm" :inline="true"> | ||||||
|           <el-form-item label="版本号" prop="versions"> |           <el-form-item label="版本号" prop="versions"> | ||||||
|             <el-select v-model="queryForm.versions" placeholder="选择版本号" @change="changeVersions"> |             <el-select v-model="queryForm.versions" placeholder="选择版本号" @change="changeVersions"> | ||||||
|               <el-option v-for="item in options" :key="item.id" :label="item.versions" :value="item.id" /> |               <el-option v-for="item in options" :key="item.id" :label="item.versions" :value="item.versions" /> | ||||||
|             </el-select> |             </el-select> | ||||||
|           </el-form-item> |           </el-form-item> | ||||||
|           <el-form-item label="表名" prop="sheet"> |           <el-form-item label="表名" prop="sheet"> | ||||||
| @ -166,7 +166,8 @@ const getTableData = async () => { | |||||||
|   const params = { |   const params = { | ||||||
|     projectId: currentProject.value?.id, |     projectId: currentProject.value?.id, | ||||||
|     sheet: queryForm.value.sheet, |     sheet: queryForm.value.sheet, | ||||||
|     versions: queryForm.value.versions |     versions: queryForm.value.versions, | ||||||
|  |     type: '1' | ||||||
|   }; |   }; | ||||||
|   const res = await getTreeLimit(params); |   const res = await getTreeLimit(params); | ||||||
|   loading.value = false; |   loading.value = false; | ||||||
|  | |||||||
| @ -210,7 +210,8 @@ const getListTable = async () => { | |||||||
|   const res = await getTreeLimit({ |   const res = await getTreeLimit({ | ||||||
|     projectId: currentProject.value?.id, |     projectId: currentProject.value?.id, | ||||||
|     versions: form.value.versions, |     versions: form.value.versions, | ||||||
|     sheet: form.value.sheet |     sheet: form.value.sheet, | ||||||
|  |     type: '0' | ||||||
|   }); |   }); | ||||||
|   if (res.code == 200) { |   if (res.code == 200) { | ||||||
|     tableData.value = res.data; |     tableData.value = res.data; | ||||||
|  | |||||||
| @ -5,7 +5,7 @@ | |||||||
|         <el-form :model="queryForm" :inline="true"> |         <el-form :model="queryForm" :inline="true"> | ||||||
|           <el-form-item label="版本号" prop="versions"> |           <el-form-item label="版本号" prop="versions"> | ||||||
|             <el-select v-model="queryForm.versions" placeholder="选择版本号" @change="changeVersions"> |             <el-select v-model="queryForm.versions" placeholder="选择版本号" @change="changeVersions"> | ||||||
|               <el-option v-for="item in options" :key="item.id" :label="item.versions" :value="item.id" /> |               <el-option v-for="item in options" :key="item.id" :label="item.versions" :value="item.versions" /> | ||||||
|             </el-select> |             </el-select> | ||||||
|           </el-form-item> |           </el-form-item> | ||||||
|           <el-form-item label="表名" prop="sheet"> |           <el-form-item label="表名" prop="sheet"> | ||||||
| @ -184,7 +184,8 @@ const getTableData = async () => { | |||||||
|   const params = { |   const params = { | ||||||
|     projectId: currentProject.value?.id, |     projectId: currentProject.value?.id, | ||||||
|     sheet: queryForm.value.sheet, |     sheet: queryForm.value.sheet, | ||||||
|     versions: queryForm.value.versions |     versions: queryForm.value.versions, | ||||||
|  |     type: '0' | ||||||
|   }; |   }; | ||||||
|   const res = await getTreeLimit(params); |   const res = await getTreeLimit(params); | ||||||
|   loading.value = false; |   loading.value = false; | ||||||
| @ -288,7 +289,7 @@ const handleExport = () => { | |||||||
|       projectId: currentProject.value?.id, |       projectId: currentProject.value?.id, | ||||||
|       sheet: queryForm.value.sheet |       sheet: queryForm.value.sheet | ||||||
|     }, |     }, | ||||||
|     `限价一览表${queryForm.value.sheet}.xlsx` |     `投标成本核算${queryForm.value.sheet}.xlsx` | ||||||
|   ); |   ); | ||||||
| }; | }; | ||||||
| // 审核 | // 审核 | ||||||
|  | |||||||
| @ -138,9 +138,14 @@ | |||||||
|             <el-table-column prop="useQuantity" label="剩余量" align="center"> |             <el-table-column prop="useQuantity" label="剩余量" align="center"> | ||||||
|               <template #default="scope"> |               <template #default="scope"> | ||||||
|                 {{ |                 {{ | ||||||
|                   (scope.row.quantity ? Number(scope.row.quantity) : 0) - (scope.row.useQuantity ? Number(scope.row.useQuantity) : 0) == 0 |                   (scope.row.quantity ? Number(scope.row.quantity) : 0) - | ||||||
|  |                     (scope.row.useQuantity ? Number(scope.row.useQuantity) : 0) - | ||||||
|  |                     (scope.row.selectNum ? Number(scope.row.selectNum) : 0) == | ||||||
|  |                   0 | ||||||
|                     ? '' |                     ? '' | ||||||
|                     : (scope.row.quantity ? Number(scope.row.quantity) : 0) - (scope.row.useQuantity ? Number(scope.row.useQuantity) : 0) |                     : (scope.row.quantity ? Number(scope.row.quantity) : 0) - | ||||||
|  |                       (scope.row.selectNum ? Number(scope.row.selectNum) : 0) - | ||||||
|  |                       (scope.row.useQuantity ? Number(scope.row.useQuantity) : 0) | ||||||
|                 }} |                 }} | ||||||
|               </template> |               </template> | ||||||
|             </el-table-column> |             </el-table-column> | ||||||
| @ -149,12 +154,16 @@ | |||||||
|             <el-table-column prop="price" label="总价" align="center"> |             <el-table-column prop="price" label="总价" align="center"> | ||||||
|               <template #default="scope"> |               <template #default="scope"> | ||||||
|                 {{ |                 {{ | ||||||
|                   ((scope.row.quantity ? Number(scope.row.quantity) : 0) - (scope.row.useQuantity ? Number(scope.row.useQuantity) : 0)) * |                   ((scope.row.quantity ? Number(scope.row.quantity) : 0) - | ||||||
|  |                     (scope.row.useQuantity ? Number(scope.row.useQuantity) : 0) - | ||||||
|  |                     (scope.row.selectNum ? Number(scope.row.selectNum) : 0)) * | ||||||
|                     Number(scope.row.unitPrice) == |                     Number(scope.row.unitPrice) == | ||||||
|                   0 |                   0 | ||||||
|                     ? '' |                     ? '' | ||||||
|                     : ( |                     : ( | ||||||
|                         ((scope.row.quantity ? Number(scope.row.quantity) : 0) - (scope.row.useQuantity ? Number(scope.row.useQuantity) : 0)) * |                         ((scope.row.quantity ? Number(scope.row.quantity) : 0) - | ||||||
|  |                           (scope.row.useQuantity ? Number(scope.row.useQuantity) : 0) - | ||||||
|  |                           (scope.row.selectNum ? Number(scope.row.selectNum) : 0)) * | ||||||
|                         Number(scope.row.unitPrice) |                         Number(scope.row.unitPrice) | ||||||
|                       ).toFixed(2) |                       ).toFixed(2) | ||||||
|                 }} |                 }} | ||||||
| @ -328,18 +337,10 @@ const getVersionNums = async () => { | |||||||
|         getSheetName(); |         getSheetName(); | ||||||
|       } else { |       } else { | ||||||
|         treeForm.value.versions = ''; |         treeForm.value.versions = ''; | ||||||
|         ElMessage({ |  | ||||||
|           message: '获取版本号失败', |  | ||||||
|           type: 'warning' |  | ||||||
|         }); |  | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|   } catch (error) { |   } catch (error) { | ||||||
|     console.log(error); |     console.log(error); | ||||||
|     ElMessage({ |  | ||||||
|       message: '获取版本号失败', |  | ||||||
|       type: 'warning' |  | ||||||
|     }); |  | ||||||
|   } |   } | ||||||
| }; | }; | ||||||
| //获取表名 | //获取表名 | ||||||
| @ -356,19 +357,11 @@ const getSheetName = async () => { | |||||||
|         treeForm.value.sheet = res.data[0]; |         treeForm.value.sheet = res.data[0]; | ||||||
|       } else { |       } else { | ||||||
|         treeForm.value.sheet = ''; |         treeForm.value.sheet = ''; | ||||||
|         ElMessage({ |  | ||||||
|           message: '获取表名失败', |  | ||||||
|           type: 'warning' |  | ||||||
|         }); |  | ||||||
|       } |       } | ||||||
|       getTreeList(); |       getTreeList(); | ||||||
|     } |     } | ||||||
|   } catch (error) { |   } catch (error) { | ||||||
|     console.log(error); |     console.log(error); | ||||||
|     ElMessage({ |  | ||||||
|       message: '获取表名失败', |  | ||||||
|       type: 'warning' |  | ||||||
|     }); |  | ||||||
|   } |   } | ||||||
| }; | }; | ||||||
| const handleSelection = (selection: any) => { | const handleSelection = (selection: any) => { | ||||||
|  | |||||||
| @ -124,7 +124,7 @@ const loading = ref(false); | |||||||
| const options = ref<any[]>([]); | const options = ref<any[]>([]); | ||||||
| const sheets = ref<any[]>([]); | const sheets = ref<any[]>([]); | ||||||
| const tableData = ref<any[]>([]); | const tableData = ref<any[]>([]); | ||||||
| const isExpandAll = ref(false); | const isExpandAll = ref(true); | ||||||
| const reviewStatus = ref(''); | const reviewStatus = ref(''); | ||||||
| const versionObj: any = ref({}); | const versionObj: any = ref({}); | ||||||
| const versionMap = new Map(); | const versionMap = new Map(); | ||||||
| @ -150,18 +150,10 @@ const getVersionNums = async () => { | |||||||
|         getSheetName(); |         getSheetName(); | ||||||
|       } else { |       } else { | ||||||
|         queryForm.value.versions = ''; |         queryForm.value.versions = ''; | ||||||
|         ElMessage({ |  | ||||||
|           message: '获取版本号失败', |  | ||||||
|           type: 'warning' |  | ||||||
|         }); |  | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|   } catch (error) { |   } catch (error) { | ||||||
|     console.log(error); |     console.log(error); | ||||||
|     ElMessage({ |  | ||||||
|       message: '获取版本号失败', |  | ||||||
|       type: 'warning' |  | ||||||
|     }); |  | ||||||
|   } |   } | ||||||
| }; | }; | ||||||
| //选择版本号 | //选择版本号 | ||||||
| @ -193,19 +185,11 @@ const getSheetName = async () => { | |||||||
|         queryForm.value.sheet = res.data[0]; |         queryForm.value.sheet = res.data[0]; | ||||||
|       } else { |       } else { | ||||||
|         queryForm.value.sheet = ''; |         queryForm.value.sheet = ''; | ||||||
|         ElMessage({ |  | ||||||
|           message: '获取表名失败', |  | ||||||
|           type: 'warning' |  | ||||||
|         }); |  | ||||||
|       } |       } | ||||||
|       getTableData(); |       getTableData(); | ||||||
|     } |     } | ||||||
|   } catch (error) { |   } catch (error) { | ||||||
|     console.log(error); |     console.log(error); | ||||||
|     ElMessage({ |  | ||||||
|       message: '获取表名失败', |  | ||||||
|       type: 'warning' |  | ||||||
|     }); |  | ||||||
|   } |   } | ||||||
| }; | }; | ||||||
| //获取表格 | //获取表格 | ||||||
|  | |||||||
| @ -65,7 +65,7 @@ | |||||||
|             > |             > | ||||||
|               <el-row :gutter="8" class="items-top"> |               <el-row :gutter="8" class="items-top"> | ||||||
|                 <!-- 1. 专业选择(核心:统一所有角色的专业来源) --> |                 <!-- 1. 专业选择(核心:统一所有角色的专业来源) --> | ||||||
|                 <el-col :span="3" class="mb-4 sm:mb-0 pl-4" style="margin-top:8px;"> |                 <el-col :span="3" class="mb-4 sm:mb-0 pl-4" style="margin-top: 8px"> | ||||||
|                   <el-form-item |                   <el-form-item | ||||||
|                     :prop="`designers.${configIndex}.userMajor`" |                     :prop="`designers.${configIndex}.userMajor`" | ||||||
|                     :rules="[ |                     :rules="[ | ||||||
| @ -76,7 +76,8 @@ | |||||||
|                     label-width="60px" |                     label-width="60px" | ||||||
|                     label="专业" |                     label="专业" | ||||||
|                   > |                   > | ||||||
|                     <el-select filterable |                     <el-select | ||||||
|  |                       filterable | ||||||
|                       v-model="form.designers[configIndex].userMajor" |                       v-model="form.designers[configIndex].userMajor" | ||||||
|                       placeholder="请选择专业" |                       placeholder="请选择专业" | ||||||
|                       class="w-full transition-all duration-300 border-gray-300" |                       class="w-full transition-all duration-300 border-gray-300" | ||||||
| @ -109,7 +110,8 @@ | |||||||
|                           label="设计" |                           label="设计" | ||||||
|                           label-width="50px" |                           label-width="50px" | ||||||
|                         > |                         > | ||||||
|                           <el-select filterable |                           <el-select | ||||||
|  |                             filterable | ||||||
|                             v-model="person.userId" |                             v-model="person.userId" | ||||||
|                             placeholder="选择人员" |                             placeholder="选择人员" | ||||||
|                             class="w-full transition-all duration-300 border-gray-300" |                             class="w-full transition-all duration-300 border-gray-300" | ||||||
| @ -165,7 +167,8 @@ | |||||||
|                           label="校审" |                           label="校审" | ||||||
|                           label-width="50px" |                           label-width="50px" | ||||||
|                         > |                         > | ||||||
|                           <el-select filterable |                           <el-select | ||||||
|  |                             filterable | ||||||
|                             v-model="person.userId" |                             v-model="person.userId" | ||||||
|                             placeholder="选择人员" |                             placeholder="选择人员" | ||||||
|                             class="w-full transition-all duration-300 border-gray-300" |                             class="w-full transition-all duration-300 border-gray-300" | ||||||
| @ -221,7 +224,8 @@ | |||||||
|                           label="审定" |                           label="审定" | ||||||
|                           label-width="50px" |                           label-width="50px" | ||||||
|                         > |                         > | ||||||
|                           <el-select filterable |                           <el-select | ||||||
|  |                             filterable | ||||||
|                             v-model="person.userId" |                             v-model="person.userId" | ||||||
|                             placeholder="选择人员" |                             placeholder="选择人员" | ||||||
|                             class="w-full transition-all duration-300 border-gray-300" |                             class="w-full transition-all duration-300 border-gray-300" | ||||||
| @ -277,7 +281,8 @@ | |||||||
|                           label="审核" |                           label="审核" | ||||||
|                           label-width="50px" |                           label-width="50px" | ||||||
|                         > |                         > | ||||||
|                           <el-select filterable |                           <el-select | ||||||
|  |                             filterable | ||||||
|                             v-model="person.userId" |                             v-model="person.userId" | ||||||
|                             placeholder="选择人员" |                             placeholder="选择人员" | ||||||
|                             class="w-full transition-all duration-300 border-gray-300" |                             class="w-full transition-all duration-300 border-gray-300" | ||||||
| @ -318,7 +323,7 @@ | |||||||
|                 </el-col> |                 </el-col> | ||||||
|  |  | ||||||
|                 <!-- 操作列 --> |                 <!-- 操作列 --> | ||||||
|                 <el-col :span="2" class="text-right pr-4"> |                 <el-col :span="2" class="pr-4 mt-2 text-right"> | ||||||
|                   <el-button |                   <el-button | ||||||
|                     type="text" |                     type="text" | ||||||
|                     class="text-red-500 hover:text-red-700 transition-colors" |                     class="text-red-500 hover:text-red-700 transition-colors" | ||||||
|  | |||||||
| @ -6,7 +6,7 @@ | |||||||
|         <el-card v-if="index < 3" shadow="always"> |         <el-card v-if="index < 3" shadow="always"> | ||||||
|           <el-form :model="state.queryForm" :inline="true"> |           <el-form :model="state.queryForm" :inline="true"> | ||||||
|             <el-form-item label="版本号" prop="versions"> |             <el-form-item label="版本号" prop="versions"> | ||||||
|               <el-select v-model="state.queryForm.versions" placeholder="选择版本号"> |               <el-select v-model="state.queryForm.versions" placeholder="选择版本号" @change="handleChangeVersion"> | ||||||
|                 <el-option v-for="item in state.options" :key="item.versions" :label="item.versions" :value="item.versions" /> |                 <el-option v-for="item in state.options" :key="item.versions" :label="item.versions" :value="item.versions" /> | ||||||
|               </el-select> |               </el-select> | ||||||
|             </el-form-item> |             </el-form-item> | ||||||
| @ -16,7 +16,7 @@ | |||||||
|               </el-select> |               </el-select> | ||||||
|             </el-form-item> |             </el-form-item> | ||||||
|             <el-form-item> |             <el-form-item> | ||||||
|             <el-button type="primary" @click="openTable(index)">{{ isExpandAll ? '一键收起' : '一键展开' }}</el-button> |               <el-button type="primary" @click="openTable(index)">{{ isExpandAll ? '一键收起' : '一键展开' }}</el-button> | ||||||
|             </el-form-item> |             </el-form-item> | ||||||
|             <el-form-item> |             <el-form-item> | ||||||
|               <el-button type="success" @click="downloadTemplate(1)">下载模板</el-button> |               <el-button type="success" @click="downloadTemplate(1)">下载模板</el-button> | ||||||
| @ -62,15 +62,10 @@ | |||||||
|               </el-upload> |               </el-upload> | ||||||
|             </el-form-item> |             </el-form-item> | ||||||
|             <el-form-item v-if="state.versionsData.status == 'draft'"> |             <el-form-item v-if="state.versionsData.status == 'draft'"> | ||||||
|               <el-button  type="primary" con="edit" @click="clickApprovalSheet()">审核</el-button> |               <el-button type="primary" con="edit" @click="clickApprovalSheet()">审核</el-button> | ||||||
|             </el-form-item> |             </el-form-item> | ||||||
|             <el-form-item v-if="state.versionsData.status == 'waiting' || state.versionsData.status == 'finish'"> |             <el-form-item v-if="state.versionsData.status == 'waiting' || state.versionsData.status == 'finish'"> | ||||||
|               <el-button |               <el-button icon="view" @click="lookApprovalFlow()" type="warning">查看流程</el-button> | ||||||
|                 icon="view" |  | ||||||
|                 @click="lookApprovalFlow()" |  | ||||||
|                 type="warning" |  | ||||||
|                 >查看流程</el-button |  | ||||||
|               > |  | ||||||
|             </el-form-item> |             </el-form-item> | ||||||
|           </el-form> |           </el-form> | ||||||
|         </el-card> |         </el-card> | ||||||
| @ -171,6 +166,7 @@ const handleTabChange = (tab) => { | |||||||
| onMounted(async () => { | onMounted(async () => { | ||||||
|   await getVersionNums(); |   await getVersionNums(); | ||||||
| }); | }); | ||||||
|  |  | ||||||
| // 获取版本号 | // 获取版本号 | ||||||
| async function getVersionNums(isSheet = true) { | async function getVersionNums(isSheet = true) { | ||||||
|   try { |   try { | ||||||
| @ -247,10 +243,10 @@ async function handleSheetName() { | |||||||
|  |  | ||||||
| // 获取列表 | // 获取列表 | ||||||
| async function handleQueryList(isSheet = true) { | async function handleQueryList(isSheet = true) { | ||||||
|   if (isSheet && !state.queryForm.sheet) { |   // if (isSheet && !state.queryForm) { | ||||||
|     console.warn('表名不存在,无法获取列表数据'); |   //   console.warn('表名不存在,无法获取列表数据'); | ||||||
|     return; |   //   return; | ||||||
|   } |   // } | ||||||
|  |  | ||||||
|   try { |   try { | ||||||
|     state.loading.list = true; |     state.loading.list = true; | ||||||
| @ -308,12 +304,12 @@ function handleChange(sheet) { | |||||||
| function handleChangeVersion(versions) { | function handleChangeVersion(versions) { | ||||||
|   state.queryForm.versions = versions; |   state.queryForm.versions = versions; | ||||||
|   state.versionsData = state.options.find((e) => e.versions == versions); |   state.versionsData = state.options.find((e) => e.versions == versions); | ||||||
|   console.log('state.versionsData', state.versionsData); |   // console.log('state.versionsData', state.versionsData); | ||||||
|   state.sheets = []; |   state.sheets = []; | ||||||
|   handleQueryList(); |   handleQueryList(); | ||||||
| } | } | ||||||
| // 在 openTable 方法中通过索引获取对应的表格实例 | // 在 openTable 方法中通过索引获取对应的表格实例 | ||||||
| function openTable( index) { | function openTable(index) { | ||||||
|   isExpandAll.value = !isExpandAll.value; |   isExpandAll.value = !isExpandAll.value; | ||||||
|   nextTick(() => { |   nextTick(() => { | ||||||
|     // 通过索引获取当前标签页的表格实例 |     // 通过索引获取当前标签页的表格实例 | ||||||
| @ -358,12 +354,12 @@ function lookApprovalFlow(row) { | |||||||
| const downloadTemplate = (type) => { | const downloadTemplate = (type) => { | ||||||
|   // 导出模版文件 |   // 导出模版文件 | ||||||
|   try { |   try { | ||||||
|     let linkurl =  ''; |     let linkurl = ''; | ||||||
|     let name = ''; |     let name = ''; | ||||||
|     if (type==1) { |     if (type == 1) { | ||||||
|       linkurl = '/billOfQuantities.xlsx'; |       linkurl = '/billOfQuantities.xlsx'; | ||||||
|       name = '工程量清单模板.xlsx'; |       name = '工程量清单模板.xlsx'; | ||||||
|     }else{ |     } else { | ||||||
|       linkurl = '/materialsEquipment.xlsx'; |       linkurl = '/materialsEquipment.xlsx'; | ||||||
|       name = '物资设备清单模板.xlsx'; |       name = '物资设备清单模板.xlsx'; | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -16,7 +16,7 @@ | |||||||
|       <!-- 表单区域 --> |       <!-- 表单区域 --> | ||||||
|       <el-card class="rounded-lg shadow-sm bg-white border border-gray-100 transition-all hover:shadow-md overflow-hidden"> |       <el-card class="rounded-lg shadow-sm bg-white border border-gray-100 transition-all hover:shadow-md overflow-hidden"> | ||||||
|         <div class="p-4 bg-gradient-to-r from-blue-50 to-indigo-50 border-b border-gray-100"> |         <div class="p-4 bg-gradient-to-r from-blue-50 to-indigo-50 border-b border-gray-100"> | ||||||
|           <h3 class="text-lg font-semibold text-gray-800">投标工程清单</h3> |           <h3 class="text-lg font-semibold text-gray-800">招标工程清单</h3> | ||||||
|         </div> |         </div> | ||||||
|         <div class="p-6"> |         <div class="p-6"> | ||||||
|           <el-form |           <el-form | ||||||
|  | |||||||
| @ -49,7 +49,32 @@ | |||||||
|         <!-- 资料文件区域 --> |         <!-- 资料文件区域 --> | ||||||
|         <div class="mb-8"> |         <div class="mb-8"> | ||||||
|           <div class="flex items-center justify-between mb-5"> |           <div class="flex items-center justify-between mb-5"> | ||||||
|             <h3 class="text-lg font-semibold text-blue-700">资料文件清单</h3> |             <div style="display: flex; align-items: center"> | ||||||
|  |               <h3 class="text-lg font-semibold text-blue-700" style="margin-right: 20px">资料文件清单</h3> | ||||||
|  |               <el-upload | ||||||
|  |                 class="upload-excel" | ||||||
|  |                 action="#" | ||||||
|  |                 v-if="!form.id || form.status == 'draft'" | ||||||
|  |                 ref="uploadRef" | ||||||
|  |                 :auto-upload="false" | ||||||
|  |                 :on-change="importTemplate" | ||||||
|  |                 :show-file-list="false" | ||||||
|  |                 :accept="'.xlsx,.xls'" | ||||||
|  |                 :limit="1" | ||||||
|  |               > | ||||||
|  |                 <el-button type="primary" icon="Upload">导入文件</el-button> | ||||||
|  |               </el-upload> | ||||||
|  |               <el-button | ||||||
|  |                 v-if="!form.id || form.status == 'draft'" | ||||||
|  |                 type="primary" | ||||||
|  |                 style="margin-left: 20px" | ||||||
|  |                 icon="Download" | ||||||
|  |                 @click="exportTemplate" | ||||||
|  |                 class="transition-all hover:bg-blue-600" | ||||||
|  |               > | ||||||
|  |                 导出模版 | ||||||
|  |               </el-button> | ||||||
|  |             </div> | ||||||
|             <el-button type="primary" size="small" @click="addDocumentItem" v-if="!disabledAll" icon="Plus" class="transition-all hover:bg-blue-600"> |             <el-button type="primary" size="small" @click="addDocumentItem" v-if="!disabledAll" icon="Plus" class="transition-all hover:bg-blue-600"> | ||||||
|               添加资料 |               添加资料 | ||||||
|             </el-button> |             </el-button> | ||||||
| @ -180,11 +205,11 @@ import { ref, reactive, computed, onMounted, onUnmounted, watch, getCurrentInsta | |||||||
| import { useUserStoreHook } from '@/store/modules/user'; | import { useUserStoreHook } from '@/store/modules/user'; | ||||||
| import { ElMessage, ElLoading, FormRules } from 'element-plus'; | import { ElMessage, ElLoading, FormRules } from 'element-plus'; | ||||||
| import { systemUserList } from '@/api/design/appointment'; | import { systemUserList } from '@/api/design/appointment'; | ||||||
| import { collectBatch, byProjectId, exportWord } from '@/api/design/received'; | import { collectBatch, byProjectId, exportWord, exportExcel } from '@/api/design/received'; | ||||||
| import { getUser } from '@/api/system/user'; | import { getUser } from '@/api/system/user'; | ||||||
| import type { ComponentInternalInstance, ElFormInstance } from 'element-plus'; | import type { ComponentInternalInstance, ElFormInstance } from 'element-plus'; | ||||||
| import { getInfo } from '@/api/login'; | import { getInfo } from '@/api/login'; | ||||||
|  | import * as XLSX from 'xlsx'; | ||||||
| // 全局实例与状态管理 | // 全局实例与状态管理 | ||||||
| const { proxy } = getCurrentInstance() as ComponentInternalInstance; | const { proxy } = getCurrentInstance() as ComponentInternalInstance; | ||||||
| const userStore = useUserStoreHook(); | const userStore = useUserStoreHook(); | ||||||
| @ -200,7 +225,7 @@ const documentsFormRef = ref<ElFormInstance>(); | |||||||
| const userList = ref<any[]>([]); | const userList = ref<any[]>([]); | ||||||
| const userMap = new Map<string, string>(); // 存储用户ID与昵称映射 | const userMap = new Map<string, string>(); // 存储用户ID与昵称映射 | ||||||
| const disabledAll = ref(false); // 表单是否全部禁用 | const disabledAll = ref(false); // 表单是否全部禁用 | ||||||
|  | const uploadRef = ref<any>(); | ||||||
| // 表单核心数据 | // 表单核心数据 | ||||||
| const form = reactive({ | const form = reactive({ | ||||||
|   projectId: currentProject.value?.id, |   projectId: currentProject.value?.id, | ||||||
| @ -445,7 +470,66 @@ const onLoad = async () => { | |||||||
|     console.error('文件导出错误:', error); |     console.error('文件导出错误:', error); | ||||||
|   } |   } | ||||||
| }; | }; | ||||||
|  | const exportTemplate = async () => { | ||||||
|  |   // 导出模版 | ||||||
|  |   proxy?.download( | ||||||
|  |     'design/collect/exportExcel', | ||||||
|  |     { | ||||||
|  |       deptId: userStore.deptId | ||||||
|  |     }, | ||||||
|  |     `收资清单表格.xlsx` | ||||||
|  |   ); | ||||||
|  | }; | ||||||
|  | const importTemplate = async (files, fileList) => { | ||||||
|  |   // 导入表格数据 | ||||||
|  |   const file = fileList[0].raw; // 获取原始文件对象 | ||||||
|  |   const reader = new FileReader(); | ||||||
|  |   let obj = { | ||||||
|  |     id: '编码', | ||||||
|  |     name: '人员', | ||||||
|  |     fliename: '目录名', | ||||||
|  |     remark: '备注' | ||||||
|  |   }; | ||||||
|  |   reader.onload = (e) => { | ||||||
|  |     try { | ||||||
|  |       // 读取文件内容 | ||||||
|  |       const data = new Uint8Array(e.target.result); | ||||||
|  |       // 解析Excel | ||||||
|  |       const workbook = XLSX.read(data, { type: 'array' }); | ||||||
|  |  | ||||||
|  |       // 获取第一个工作表名称 | ||||||
|  |       const firstSheetName = workbook.SheetNames[0]; | ||||||
|  |       // 获取第一个工作表内容 | ||||||
|  |       const worksheet = workbook.Sheets[firstSheetName]; | ||||||
|  |  | ||||||
|  |       // 转换为JSON格式 | ||||||
|  |       const jsonData = XLSX.utils.sheet_to_json(worksheet); | ||||||
|  |  | ||||||
|  |       if (jsonData.length === 0) { | ||||||
|  |         ElMessage.info('Excel文件中没有数据'); | ||||||
|  |         return; | ||||||
|  |       } | ||||||
|  |       let arr = []; | ||||||
|  |       // 判断form.documents 是否对象 | ||||||
|  |       jsonData.forEach((item, index) => { | ||||||
|  |         if (item[obj.id]) { | ||||||
|  |           arr.push({ | ||||||
|  |             id: Date.now() + index, | ||||||
|  |             catalogueName: item[obj.fliename], | ||||||
|  |             remark: item[obj.remark], | ||||||
|  |             userId: item[obj.id] | ||||||
|  |           }); | ||||||
|  |         } | ||||||
|  |       }); | ||||||
|  |       form.documents = arr; | ||||||
|  |       uploadRef.value.clearFiles(); | ||||||
|  |       console.log(arr); | ||||||
|  |     } catch (err) {} | ||||||
|  |   }; | ||||||
|  |  | ||||||
|  |   // 以ArrayBuffer方式读取文件 | ||||||
|  |   reader.readAsArrayBuffer(file); | ||||||
|  | }; | ||||||
| /** 页面挂载初始化 */ | /** 页面挂载初始化 */ | ||||||
| onMounted(() => { | onMounted(() => { | ||||||
|   // 先获取当前用户信息,再获取部门用户列表,最后回显表单数据 |   // 先获取当前用户信息,再获取部门用户列表,最后回显表单数据 | ||||||
|  | |||||||
| @ -153,6 +153,11 @@ | |||||||
|         <el-form-item v-if="uploadForm.type == '3'" label="蓝图" prop="fileIds"> |         <el-form-item v-if="uploadForm.type == '3'" label="蓝图" prop="fileIds"> | ||||||
|           <file-upload :fileType="['pdf']" :isShowTip="false" :fileSize="100" v-model="uploadForm.fileIds"></file-upload> |           <file-upload :fileType="['pdf']" :isShowTip="false" :fileSize="100" v-model="uploadForm.fileIds"></file-upload> | ||||||
|         </el-form-item> |         </el-form-item> | ||||||
|  |         <el-form-item v-if="uploadForm.type == '3'" label="抄送人"> | ||||||
|  |           <el-select multiple filterable clearable v-model="form.userIds" placeholder="请选择抄送人"> | ||||||
|  |             <el-option :value="item.userId" v-for="item in userCoryList" :key="item.userId" :label="item.nickName + '-' + item.phonenumber" /> | ||||||
|  |           </el-select> | ||||||
|  |         </el-form-item> | ||||||
|         <el-form-item v-if="uploadForm.type == '1'" label="过程图纸" prop="cancellationIds"> |         <el-form-item v-if="uploadForm.type == '1'" label="过程图纸" prop="cancellationIds"> | ||||||
|           <file-upload :fileType="['pdf']" :isShowTip="false" :fileSize="100" v-model="uploadForm.cancellationIds"></file-upload> |           <file-upload :fileType="['pdf']" :isShowTip="false" :fileSize="100" v-model="uploadForm.cancellationIds"></file-upload> | ||||||
|         </el-form-item> |         </el-form-item> | ||||||
| @ -255,7 +260,8 @@ import { | |||||||
|   uploadVolumeFile, |   uploadVolumeFile, | ||||||
|   majorList, |   majorList, | ||||||
|   getVolumeCatafileList, |   getVolumeCatafileList, | ||||||
|   volumeFileList |   volumeFileList, | ||||||
|  |   copyUserList | ||||||
| } from '@/api/design/volumeCatalog'; | } from '@/api/design/volumeCatalog'; | ||||||
| import { VolumeCatalogVO } from '@/api/design/volumeCatalog/types'; | import { VolumeCatalogVO } from '@/api/design/volumeCatalog/types'; | ||||||
| import { useUserStoreHook } from '@/store/modules/user'; | import { useUserStoreHook } from '@/store/modules/user'; | ||||||
| @ -281,6 +287,7 @@ const uploadOpinionVisible = ref(false); | |||||||
| const design = ref(''); | const design = ref(''); | ||||||
| const total = ref(0); | const total = ref(0); | ||||||
| const dialogHistory = ref(false); | const dialogHistory = ref(false); | ||||||
|  | const userCoryList = ref([]); | ||||||
| const opinion = ref(''); | const opinion = ref(''); | ||||||
| const updateRow = ref({ | const updateRow = ref({ | ||||||
|   opinion: [] |   opinion: [] | ||||||
| @ -416,7 +423,13 @@ const cancel = () => { | |||||||
|   reset(); |   reset(); | ||||||
|   dialog.visible = false; |   dialog.visible = false; | ||||||
| }; | }; | ||||||
|  | // 获取人员列表 | ||||||
|  | const getDesignUserList = async () => { | ||||||
|  |   const res = await copyUserList({ projectId: currentProject.value?.id, userType: 2 }); | ||||||
|  |   if (res.code === 200) { | ||||||
|  |     userCoryList.value = res.data; | ||||||
|  |   } | ||||||
|  | }; | ||||||
| /** 表单重置 */ | /** 表单重置 */ | ||||||
| const reset = () => { | const reset = () => { | ||||||
|   form.value = { ...initFormData }; |   form.value = { ...initFormData }; | ||||||
| @ -546,7 +559,7 @@ const onSubmit = async () => { | |||||||
|     type: uploadForm.type |     type: uploadForm.type | ||||||
|   }; |   }; | ||||||
|   try { |   try { | ||||||
|     await uploadVolumeFile(obj); |     await uploadVolumeFile({ ...obj, userIds: form.value.userIds }); | ||||||
|     proxy?.$modal.msgSuccess('文件上传成功'); |     proxy?.$modal.msgSuccess('文件上传成功'); | ||||||
|     uploadVisible.value = false; |     uploadVisible.value = false; | ||||||
|     await getList(); |     await getList(); | ||||||
| @ -656,6 +669,7 @@ const handleAuditInfo = (row) => { | |||||||
|   // 审核图纸 |   // 审核图纸 | ||||||
| }; | }; | ||||||
| onMounted(() => { | onMounted(() => { | ||||||
|  |   getDesignUserList(); | ||||||
|   getSpecialtyList(); |   getSpecialtyList(); | ||||||
|   getList(); |   getList(); | ||||||
| }); | }); | ||||||
| @ -666,6 +680,7 @@ const listeningProject = watch( | |||||||
|   (nid, oid) => { |   (nid, oid) => { | ||||||
|     queryParams.value.projectId = nid; |     queryParams.value.projectId = nid; | ||||||
|     form.value.projectId = nid; |     form.value.projectId = nid; | ||||||
|  |     getDesignUserList(); | ||||||
|     getSpecialtyList(); |     getSpecialtyList(); | ||||||
|     getList(); |     getList(); | ||||||
|   } |   } | ||||||
|  | |||||||
| @ -81,7 +81,7 @@ | |||||||
|       <el-table v-loading="loading" :data="formalitiesAreConsolidatedList" @selection-change="handleSelectionChange" row-key="id" default-expand-all> |       <el-table v-loading="loading" :data="formalitiesAreConsolidatedList" @selection-change="handleSelectionChange" row-key="id" default-expand-all> | ||||||
|         <el-table-column type="selection" width="55" align="center" /> |         <el-table-column type="selection" width="55" align="center" /> | ||||||
|         <!-- <el-table-column label="手续办理清单模板父级" align="center" prop="formalitiesPname" /> --> |         <!-- <el-table-column label="手续办理清单模板父级" align="center" prop="formalitiesPname" /> --> | ||||||
|         <el-table-column label="手续办理清单" align="center" prop="formalitiesName" /> |         <el-table-column label="手续办理清单" align="left" prop="formalitiesName" /> | ||||||
|         <el-table-column label="计划开始时间" align="center" prop="planTheStartTime" width="180"> |         <el-table-column label="计划开始时间" align="center" prop="planTheStartTime" width="180"> | ||||||
|           <template #default="scope"> |           <template #default="scope"> | ||||||
|             <span>{{ parseTime(scope.row.planTheStartTime, '{y}-{m}-{d}') }}</span> |             <span>{{ parseTime(scope.row.planTheStartTime, '{y}-{m}-{d}') }}</span> | ||||||
|  | |||||||
| @ -1,13 +1,11 @@ | |||||||
| <template> | <template> | ||||||
|   <div class="p-2"> |   <div class="p-2"> | ||||||
|     <transition :enter-active-class="proxy?.animate.searchAnimate.enter" |     <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave"> | ||||||
|       :leave-active-class="proxy?.animate.searchAnimate.leave"> |  | ||||||
|       <div v-show="showSearch" class="mb-[10px]"> |       <div v-show="showSearch" class="mb-[10px]"> | ||||||
|         <el-card shadow="hover"> |         <el-card shadow="hover"> | ||||||
|           <el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="auto"> |           <el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="auto"> | ||||||
|             <el-form-item label="材料名称" prop="materialsName"> |             <el-form-item label="材料名称" prop="materialsName"> | ||||||
|               <el-input v-model="queryParams.materialsName" placeholder="请输入材料名称" clearable |               <el-input v-model="queryParams.materialsName" placeholder="请输入材料名称" clearable @keyup.enter="handleQuery" /> | ||||||
|                 @keyup.enter="handleQuery" /> |  | ||||||
|             </el-form-item> |             </el-form-item> | ||||||
|             <el-form-item label="材料提供商" prop="companyId"> |             <el-form-item label="材料提供商" prop="companyId"> | ||||||
|               <el-select v-model="queryParams.companyId" clearable placeholder="全部"> |               <el-select v-model="queryParams.companyId" clearable placeholder="全部"> | ||||||
| @ -27,22 +25,20 @@ | |||||||
|       <template #header> |       <template #header> | ||||||
|         <el-row :gutter="10" class="mb8"> |         <el-row :gutter="10" class="mb8"> | ||||||
|           <el-col :span="1.5"> |           <el-col :span="1.5"> | ||||||
|             <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['materials:materials:add']"> 新增 |             <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['materials:materials:add']"> 新增 </el-button> | ||||||
|  |           </el-col> | ||||||
|  |           <el-col :span="1.5"> | ||||||
|  |             <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['materials:materials:edit']" | ||||||
|  |               >修改 | ||||||
|             </el-button> |             </el-button> | ||||||
|           </el-col> |           </el-col> | ||||||
|           <el-col :span="1.5"> |           <el-col :span="1.5"> | ||||||
|             <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" |             <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['materials:materials:remove']" | ||||||
|               v-hasPermi="['materials:materials:edit']">修改 |               >删除 | ||||||
|             </el-button> |             </el-button> | ||||||
|           </el-col> |           </el-col> | ||||||
|           <el-col :span="1.5"> |           <el-col :span="1.5"> | ||||||
|             <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" |             <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['materials:materials:export']">导出 </el-button> | ||||||
|               v-hasPermi="['materials:materials:remove']">删除 |  | ||||||
|             </el-button> |  | ||||||
|           </el-col> |  | ||||||
|           <el-col :span="1.5"> |  | ||||||
|             <el-button type="warning" plain icon="Download" @click="handleExport" |  | ||||||
|               v-hasPermi="['materials:materials:export']">导出 </el-button> |  | ||||||
|           </el-col> |           </el-col> | ||||||
|           <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar> |           <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar> | ||||||
|         </el-row> |         </el-row> | ||||||
| @ -72,25 +68,28 @@ | |||||||
|         <el-table-column fixed="right" label="操作" align="center" class-name="small-padding fixed-width" width="320"> |         <el-table-column fixed="right" label="操作" align="center" class-name="small-padding fixed-width" width="320"> | ||||||
|           <template #default="scope"> |           <template #default="scope"> | ||||||
|             <el-space> |             <el-space> | ||||||
|               <el-button link type="primary" icon="View" @click="handleShowDrawer(scope.row)" |               <el-button link type="primary" icon="View" @click="handleShowDrawer(scope.row)" v-hasPermi="['materials:materials:query']"> | ||||||
|                 v-hasPermi="['materials:materials:query']"> |  | ||||||
|                 详情 |                 详情 | ||||||
|               </el-button> |               </el-button> | ||||||
|               <el-button link type="success" icon="Edit" @click="handleUpdate(scope.row)" |               <el-button link type="success" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['materials:materials:edit']"> 修改 </el-button> | ||||||
|                 v-hasPermi="['materials:materials:edit']"> 修改 </el-button> |               <el-button link type="danger" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['materials:materials:remove']"> | ||||||
|               <el-button link type="danger" icon="Delete" @click="handleDelete(scope.row)" |  | ||||||
|                 v-hasPermi="['materials:materials:remove']"> |  | ||||||
|                 删除 |                 删除 | ||||||
|               </el-button> |               </el-button> | ||||||
|               <el-button v-hasPermi="['materials:materialsInventory:edit']" link type="primary" icon="Plus" |               <el-button | ||||||
|                 @click="handleAddMaterialsInventory(scope.row)"> 出入库 </el-button> |                 v-hasPermi="['materials:materialsInventory:edit']" | ||||||
|  |                 link | ||||||
|  |                 type="primary" | ||||||
|  |                 icon="Plus" | ||||||
|  |                 @click="handleAddMaterialsInventory(scope.row)" | ||||||
|  |               > | ||||||
|  |                 出入库 | ||||||
|  |               </el-button> | ||||||
|             </el-space> |             </el-space> | ||||||
|           </template> |           </template> | ||||||
|         </el-table-column> |         </el-table-column> | ||||||
|       </el-table> |       </el-table> | ||||||
|  |  | ||||||
|       <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" |       <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" /> | ||||||
|         v-model:limit="queryParams.pageSize" @pagination="getList" /> |  | ||||||
|     </el-card> |     </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> | ||||||
| @ -121,12 +120,17 @@ | |||||||
|         <el-form-item label="材料文件" prop="fileOssIdMap"> |         <el-form-item label="材料文件" prop="fileOssIdMap"> | ||||||
|           <div :key="item.value" v-for="item in materials_file_type"> |           <div :key="item.value" v-for="item in materials_file_type"> | ||||||
|             <h3>{{ item.label }}</h3> |             <h3>{{ item.label }}</h3> | ||||||
|             <file-upload v-model="ossIdMap[item.value]" :limit="1" :file-size="50" :file-type="['pdf']" |             <file-upload | ||||||
|  |               v-model="ossIdMap[item.value]" | ||||||
|  |               :limit="1" | ||||||
|  |               :file-size="50" | ||||||
|  |               :file-type="['pdf']" | ||||||
|               @update:model-value=" |               @update:model-value=" | ||||||
|                 (args) => { |                 (args) => { | ||||||
|                   handleOssUpdate(args, item.value); |                   handleOssUpdate(args, item.value); | ||||||
|                 } |                 } | ||||||
|               " /> |               " | ||||||
|  |             /> | ||||||
|           </div> |           </div> | ||||||
|         </el-form-item> |         </el-form-item> | ||||||
|       </el-form> |       </el-form> | ||||||
| @ -137,8 +141,7 @@ | |||||||
|         </div> |         </div> | ||||||
|       </template> |       </template> | ||||||
|     </el-dialog> |     </el-dialog> | ||||||
|     <materials-inventory-add-dialog :materials-id="currentMaterialsId" :project-id="currentProject.id" ref="dialogRef" |     <materials-inventory-add-dialog :materials-id="currentMaterialsId" :project-id="currentProject.id" ref="dialogRef" @submit="getList" /> | ||||||
|       @submit="getList" /> |  | ||||||
|     <el-dialog title="材料详情" v-model="showDetailDrawer" width="700px"> |     <el-dialog title="材料详情" v-model="showDetailDrawer" width="700px"> | ||||||
|       <materials-detail-drawer :materials-id="currentMaterialsId" /> |       <materials-detail-drawer :materials-id="currentMaterialsId" /> | ||||||
|     </el-dialog> |     </el-dialog> | ||||||
|  | |||||||
| @ -73,7 +73,10 @@ | |||||||
|         <el-row> |         <el-row> | ||||||
|           <el-col :span="12"> |           <el-col :span="12"> | ||||||
|             <el-form-item label="表单编号" prop="formCode"> |             <el-form-item label="表单编号" prop="formCode"> | ||||||
|               <el-input v-model="form.formCode" placeholder="请输入表单编号" /> |               <!-- <el-input v-model="form.formCode" placeholder="请输入表单编号" /> --> | ||||||
|  |               <el-select v-model="form.formCode" placeholder="请选择表单编号" @change="(value) => formCodeChange(value)"> | ||||||
|  |                 <el-option v-for="item in options" :key="item.formCode" :label="item.formCode" :value="item.formCode" /> | ||||||
|  |               </el-select> | ||||||
|             </el-form-item> |             </el-form-item> | ||||||
|           </el-col> |           </el-col> | ||||||
|           <el-col :span="12"> |           <el-col :span="12"> | ||||||
| @ -123,11 +126,11 @@ | |||||||
|                   <el-col :span="12"> |                   <el-col :span="12"> | ||||||
|                     <el-form-item |                     <el-form-item | ||||||
|                       label="名称" |                       label="名称" | ||||||
|                       :prop="`itemList.${index}.name`" |                       :prop="`itemList.${index}.materialsId`" | ||||||
|                       :rules="[{ required: true, message: '名称不能为空', trigger: 'blur' }]" |                       :rules="[{ required: true, message: '名称不能为空', trigger: 'blur' }]" | ||||||
|                     > |                     > | ||||||
|                       <el-select v-model="item.inventoryId" placeholder="请选择名称" @change="(value) => getNameChange(value, index, item)"> |                       <el-select v-model="item.materialsId" placeholder="请选择名称" @change="(value) => getNameChange(value, index, item)"> | ||||||
|                         <el-option v-for="opt in optionsName" :key="opt.id" :label="opt.materialsName" :value="opt.id" /> |                         <el-option v-for="opt in optionsName" :key="opt.id" :label="`${opt.materialsName}_${opt.createTime}`" :value="opt.id" /> | ||||||
|                       </el-select> |                       </el-select> | ||||||
|                     </el-form-item> |                     </el-form-item> | ||||||
|                   </el-col> |                   </el-col> | ||||||
| @ -168,13 +171,9 @@ | |||||||
|                   </el-col> --> |                   </el-col> --> | ||||||
|                   <el-col :span="12"> |                   <el-col :span="12"> | ||||||
|                     <el-form-item label="领取" :prop="`itemList.${index}.issuedQuantity`"> |                     <el-form-item label="领取" :prop="`itemList.${index}.issuedQuantity`"> | ||||||
|                       <el-input |                       <el-select v-model="item.issuedQuantity" placeholder="请选择数量"> | ||||||
|                         v-model.number="item.issuedQuantity" |                         <el-option v-for="opt in item.outList" :key="opt.id" :label="opt.number" :value="opt.number" /> | ||||||
|                         disabled |                       </el-select> | ||||||
|                         placeholder="请输入领取数量" |  | ||||||
|                         @input="handleIssuedChange(index)" |  | ||||||
|                         @blur="handleIssuedChange(index)" |  | ||||||
|                       /> |  | ||||||
|                     </el-form-item> |                     </el-form-item> | ||||||
|                   </el-col> |                   </el-col> | ||||||
|                   <!-- <el-col :span="12"> |                   <!-- <el-col :span="12"> | ||||||
| @ -247,7 +246,8 @@ import { | |||||||
|   addMaterialIssue, |   addMaterialIssue, | ||||||
|   updateMaterialIssue, |   updateMaterialIssue, | ||||||
|   inventoryList, |   inventoryList, | ||||||
|   getMaterialName |   getMaterialName, | ||||||
|  |   getMaterialInfo | ||||||
| } from '@/api/materials/materialIssue'; | } from '@/api/materials/materialIssue'; | ||||||
|  |  | ||||||
| import { MaterialIssueVO, MaterialIssueQuery, MaterialIssueForm } from '@/api/materials/materialIssue/types'; | import { MaterialIssueVO, MaterialIssueQuery, MaterialIssueForm } from '@/api/materials/materialIssue/types'; | ||||||
| @ -307,6 +307,7 @@ const getInitFormData = () => { | |||||||
|     itemList: [ |     itemList: [ | ||||||
|       { |       { | ||||||
|         id: undefined, |         id: undefined, | ||||||
|  |  | ||||||
|         specification: undefined, |         specification: undefined, | ||||||
|         unit: undefined, |         unit: undefined, | ||||||
|         stockQuantity: undefined, |         stockQuantity: undefined, | ||||||
| @ -314,7 +315,8 @@ const getInitFormData = () => { | |||||||
|         remainingQuantity: undefined, |         remainingQuantity: undefined, | ||||||
|         name: undefined, // 数量验收的名称 |         name: undefined, // 数量验收的名称 | ||||||
|         remark: undefined, |         remark: undefined, | ||||||
|         materialsId: undefined |         materialsId: undefined, | ||||||
|  |         outList: [] | ||||||
|       } |       } | ||||||
|     ] |     ] | ||||||
|   }; |   }; | ||||||
| @ -365,7 +367,7 @@ const computeMaterialName = () => { | |||||||
|     .map((item) => item.name.trim()) |     .map((item) => item.name.trim()) | ||||||
|     .filter((name, index, self) => self.indexOf(name) === index); // 去重(如需保留重复则删除这行) |     .filter((name, index, self) => self.indexOf(name) === index); // 去重(如需保留重复则删除这行) | ||||||
|  |  | ||||||
|   form.value.materialName = validNames.join(','); |   // form.value.materialName = validNames.join(','); | ||||||
| }; | }; | ||||||
|  |  | ||||||
| /** 查询物料领料单列表 */ | /** 查询物料领料单列表 */ | ||||||
| @ -404,6 +406,7 @@ const getNameChange = (value, index, item) => { | |||||||
|     item.unit = selected.weightId; |     item.unit = selected.weightId; | ||||||
|     item.issuedQuantity = selected.number; |     item.issuedQuantity = selected.number; | ||||||
|     item.stockQuantity = Number(selected.inventoryNumber) || 0; |     item.stockQuantity = Number(selected.inventoryNumber) || 0; | ||||||
|  |     item.outList = selected.outList || []; | ||||||
|     // calculateRemaining(index); // 计算剩余数量 |     // calculateRemaining(index); // 计算剩余数量 | ||||||
|   } |   } | ||||||
| }; | }; | ||||||
| @ -529,8 +532,27 @@ const handleAdd = () => { | |||||||
|   dialog.title = '添加物料领料单'; |   dialog.title = '添加物料领料单'; | ||||||
|   // 新增时初始计算材料名称 |   // 新增时初始计算材料名称 | ||||||
|   computeMaterialName(); |   computeMaterialName(); | ||||||
|  |   getFormData(); | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | const options = ref([]); | ||||||
|  | //新增获取表单数据 | ||||||
|  | const getFormData = async () => { | ||||||
|  |   const res = await getMaterialInfo(currentProject.value.id); | ||||||
|  |   if (res.code == 200) { | ||||||
|  |     options.value = res.data; | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  | const formCodeChange = (value) => { | ||||||
|  |   console.log(value); | ||||||
|  |   const selected = options.value.find((opt) => opt.formCode === value); | ||||||
|  |   if (selected) { | ||||||
|  |     form.value.materialName = selected.materialName; | ||||||
|  |     form.value.orderingUnit = selected.orderingUnit; | ||||||
|  |     form.value.supplierUnit = selected.supplierUnit; | ||||||
|  |     optionsName.value = selected.materials; | ||||||
|  |   } | ||||||
|  | }; | ||||||
| /** 修改按钮操作 */ | /** 修改按钮操作 */ | ||||||
| const handleUpdate = async (row?: MaterialIssueVO) => { | const handleUpdate = async (row?: MaterialIssueVO) => { | ||||||
|   reset(); |   reset(); | ||||||
| @ -597,6 +619,7 @@ const submitForm = () => { | |||||||
|             remainingQuantity: Number(item.remainingQuantity) |             remainingQuantity: Number(item.remainingQuantity) | ||||||
|           })) |           })) | ||||||
|         }; |         }; | ||||||
|  |         console.log('提交数据:', submitData); | ||||||
|  |  | ||||||
|         if (form.value.id) { |         if (form.value.id) { | ||||||
|           await updateMaterialIssue(submitData); |           await updateMaterialIssue(submitData); | ||||||
| @ -638,10 +661,13 @@ const addItem = () => { | |||||||
| // 删除数量验收条目 | // 删除数量验收条目 | ||||||
| const removeItem = (index: number) => { | const removeItem = (index: number) => { | ||||||
|   if (form.value.itemList.length > 1) { |   if (form.value.itemList.length > 1) { | ||||||
|  |     console.log(111111); | ||||||
|  |     console.log(itemWatchStopFns.value[index]); | ||||||
|  |  | ||||||
|     // 停止该条目的监听 |     // 停止该条目的监听 | ||||||
|     if (itemWatchStopFns.value[index]) { |     // if (itemWatchStopFns.value[index]) { | ||||||
|       itemWatchStopFns.value[index](); |     //   itemWatchStopFns.value[index](); | ||||||
|     } |     // } | ||||||
|     form.value.itemList.splice(index, 1); |     form.value.itemList.splice(index, 1); | ||||||
|     itemWatchStopFns.value.splice(index, 1); |     itemWatchStopFns.value.splice(index, 1); | ||||||
|     // 删除后重新计算材料名称 |     // 删除后重新计算材料名称 | ||||||
| @ -682,7 +708,7 @@ watch( | |||||||
|  |  | ||||||
| onMounted(() => { | onMounted(() => { | ||||||
|   getList(); |   getList(); | ||||||
|   getName(); |   // getName(); | ||||||
| }); | }); | ||||||
|  |  | ||||||
| // 监听项目id刷新数据 | // 监听项目id刷新数据 | ||||||
| @ -692,7 +718,7 @@ const listeningProject = watch( | |||||||
|     queryParams.value.projectId = nid; |     queryParams.value.projectId = nid; | ||||||
|     form.value.projectId = nid; |     form.value.projectId = nid; | ||||||
|     getList(); |     getList(); | ||||||
|     getName(); |     // getName(); | ||||||
|   } |   } | ||||||
| ); | ); | ||||||
|  |  | ||||||
|  | |||||||
| @ -42,7 +42,7 @@ | |||||||
|             <thead> |             <thead> | ||||||
|               <tr> |               <tr> | ||||||
|                 <th colspan="2">领料单位</th> |                 <th colspan="2">领料单位</th> | ||||||
|                 <td class="th-bg" colspan="2">{{ formData.placeholder }}</td> |                 <td class="th-bg" colspan="2">{{ formData.issueUnit }}</td> | ||||||
|                 <th colspan="2">保管单位</th> |                 <th colspan="2">保管单位</th> | ||||||
|                 <td class="th-bg" colspan="2">{{ formData.storageUnit }}</td> |                 <td class="th-bg" colspan="2">{{ formData.storageUnit }}</td> | ||||||
|               </tr> |               </tr> | ||||||
|  | |||||||
| @ -30,6 +30,9 @@ | |||||||
|                 >一键全部保存</el-button |                 >一键全部保存</el-button | ||||||
|               > |               > | ||||||
|             </el-form-item> |             </el-form-item> | ||||||
|  |             <el-form-item> | ||||||
|  |               <el-button type="primary" @click="toggleExpandAll">{{ isExpandAll ? '一键收起' : '一键展开' }}</el-button> | ||||||
|  |             </el-form-item> | ||||||
|           </el-form> |           </el-form> | ||||||
|           <right-toolbar @queryTable="getMasterDataList"></right-toolbar> |           <right-toolbar @queryTable="getMasterDataList"></right-toolbar> | ||||||
|         </el-row> |         </el-row> | ||||||
| @ -38,6 +41,7 @@ | |||||||
|     <el-table |     <el-table | ||||||
|       :data="state.tableData" |       :data="state.tableData" | ||||||
|       v-loading="state.loading.list" |       v-loading="state.loading.list" | ||||||
|  |       ref="tableRef" | ||||||
|       stripe |       stripe | ||||||
|       style="width: 100%; margin-bottom: 20px; height: calc(100vh - 230px)" |       style="width: 100%; margin-bottom: 20px; height: calc(100vh - 230px)" | ||||||
|       row-key="id" |       row-key="id" | ||||||
| @ -264,6 +268,17 @@ const formRules = reactive({ | |||||||
|   ], |   ], | ||||||
|   compileDate: [{ required: true, message: '请选择编制日期', trigger: 'change' }] |   compileDate: [{ required: true, message: '请选择编制日期', trigger: 'change' }] | ||||||
| }); | }); | ||||||
|  | // 展开状态 | ||||||
|  | const isExpandAll = ref(false); | ||||||
|  | const tableRef = ref(null); | ||||||
|  | // 切换展开状态 | ||||||
|  | const toggleExpandAll = () => { | ||||||
|  |   isExpandAll.value = !isExpandAll.value; | ||||||
|  |   console.log(isExpandAll.value); | ||||||
|  |   state.tableData.forEach((row) => { | ||||||
|  |     tableRef.value.toggleRowExpansion(row, isExpandAll.value); | ||||||
|  |   }); | ||||||
|  | }; | ||||||
| // 获取主表数据 | // 获取主表数据 | ||||||
| async function getMasterDataList() { | async function getMasterDataList() { | ||||||
|   try { |   try { | ||||||
|  | |||||||
| @ -36,7 +36,6 @@ | |||||||
|           <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar> |           <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar> | ||||||
|         </el-row> |         </el-row> | ||||||
|       </template> |       </template> | ||||||
|  |  | ||||||
|       <el-table v-loading="loading" :data="monthPlanList"> |       <el-table v-loading="loading" :data="monthPlanList"> | ||||||
|         <el-table-column type="index" label="序号" width="55" align="center" /> |         <el-table-column type="index" label="序号" width="55" align="center" /> | ||||||
|         <el-table-column label="计划月份" align="center" prop="planMonth" /> |         <el-table-column label="计划月份" align="center" prop="planMonth" /> | ||||||
| @ -82,7 +81,7 @@ | |||||||
|         <el-form-item label="计划产值(元)" prop="planValue"> |         <el-form-item label="计划产值(元)" prop="planValue"> | ||||||
|           <el-input v-model="form.planValue" placeholder="请输入计划产值" type="number" /> |           <el-input v-model="form.planValue" placeholder="请输入计划产值" type="number" /> | ||||||
|         </el-form-item> |         </el-form-item> | ||||||
|         <el-form-item label="计划月份(元)" prop="planMonth"> |         <el-form-item label="计划月份" prop="planMonth"> | ||||||
|           <el-date-picker v-model="form.planMonth" type="month" value-format="YYYY-MM" placeholder="请选择计划月份" /> |           <el-date-picker v-model="form.planMonth" type="month" value-format="YYYY-MM" placeholder="请选择计划月份" /> | ||||||
|         </el-form-item> |         </el-form-item> | ||||||
|         <el-form-item label="产值类型" prop="valueType"> |         <el-form-item label="产值类型" prop="valueType"> | ||||||
|  | |||||||
| @ -175,7 +175,7 @@ const getInfo = () => { | |||||||
|     form.value = res.data as any; |     form.value = res.data as any; | ||||||
|  |  | ||||||
|     console.log('🚀 ~ getInfo ~ form.value:', form.value[0].projectId); |     console.log('🚀 ~ getInfo ~ form.value:', form.value[0].projectId); | ||||||
|  |     form.value[0].mid = form.value[0].id; | ||||||
|     form.value[0].id = form.value[0].projectId + '_' + form.value[0].planMonth; |     form.value[0].id = form.value[0].projectId + '_' + form.value[0].planMonth; | ||||||
|     loading.value = false; |     loading.value = false; | ||||||
|     buttonLoading.value = false; |     buttonLoading.value = false; | ||||||
| @ -231,13 +231,15 @@ const approvalVerifyOpen = async () => { | |||||||
| // 图纸上传成功之后 开始提交 | // 图纸上传成功之后 开始提交 | ||||||
| const submit = async (status, data) => { | const submit = async (status, data) => { | ||||||
|   form.value = data; |   form.value = data; | ||||||
|  |   console.log(form.value); | ||||||
|  |  | ||||||
|   if (status === 'draft') { |   if (status === 'draft') { | ||||||
|     buttonLoading.value = false; |     buttonLoading.value = false; | ||||||
|     proxy?.$modal.msgSuccess('暂存成功'); |     proxy?.$modal.msgSuccess('暂存成功'); | ||||||
|     proxy.$tab.closePage(proxy.$route); |     proxy.$tab.closePage(proxy.$route); | ||||||
|     proxy.$router.go(-1); |     proxy.$router.go(-1); | ||||||
|   } else { |   } else { | ||||||
|     const res = await isSubmit(data[1]?.id); |     const res = await isSubmit(data[0]?.mid); | ||||||
|  |  | ||||||
|     if (!res.data) { |     if (!res.data) { | ||||||
|       proxy?.$modal.msgError('三种计划产值必须填写'); |       proxy?.$modal.msgError('三种计划产值必须填写'); | ||||||
|  | |||||||
| @ -78,6 +78,7 @@ | |||||||
|       </el-table> |       </el-table> | ||||||
|       <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" /> |       <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" /> | ||||||
|     </el-card> |     </el-card> | ||||||
|  |  | ||||||
|     <!-- 地块表单弹窗 --> |     <!-- 地块表单弹窗 --> | ||||||
|     <el-dialog draggable :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body> |     <el-dialog draggable :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body> | ||||||
|       <el-form ref="landBlockFormRef" :model="form" :rules="rules" label-width="100px"> |       <el-form ref="landBlockFormRef" :model="form" :rules="rules" label-width="100px"> | ||||||
| @ -107,20 +108,22 @@ | |||||||
|         </div> |         </div> | ||||||
|       </template> |       </template> | ||||||
|     </el-dialog> |     </el-dialog> | ||||||
|     <!-- 关联方阵弹窗(核心修改区域) --> |  | ||||||
|  |     <!-- 关联方阵弹窗(核心修复区域) --> | ||||||
|     <el-dialog draggable :title="dialogMatrix.title" v-model="dialogMatrix.visible" width="900px" append-to-body> |     <el-dialog draggable :title="dialogMatrix.title" v-model="dialogMatrix.visible" width="900px" append-to-body> | ||||||
|       <el-button type="primary" plain icon="Plus" @click="addUnitBoItem" style="margin-bottom: 15px">添加</el-button> |       <el-button type="primary" plain icon="Plus" @click="addUnitBoItem" style="margin-bottom: 15px">添加</el-button> | ||||||
|       <!-- 方阵表单:绑定unitBoList的索引,实现动态校验 --> |       <!-- 修复1:表单模型绑定formM(根模型),确保嵌套字段校验生效 --> | ||||||
|       <el-form ref="landBlockFormMatrixRef" :model="formM" label-width="100px"> |       <el-form ref="landBlockFormMatrixRef" :model="formM" label-width="100px"> | ||||||
|         <el-row v-for="(item, i) of unitBoList" :key="i" class="mb-4"> |         <!-- 修复2:循环formM.unitBoList(而非独立ref),保证数据双向绑定 --> | ||||||
|           <!-- 方阵选择:必填校验 --> |         <el-row v-for="(item, i) of formM.unitBoList" :key="i" class="mb-4"> | ||||||
|  |           <!-- 方阵选择:修复校验规则(移除min:2,改为min:1,适配单层级选择) --> | ||||||
|           <el-col :span="8"> |           <el-col :span="8"> | ||||||
|             <el-form-item |             <el-form-item | ||||||
|               label="方阵" |               label="方阵" | ||||||
|               :prop="`unitBoList[${i}].unitProjectId`" |               :prop="`unitBoList[${i}].unitProjectId`" | ||||||
|               :rules="[ |               :rules="[ | ||||||
|                 { required: true, message: '请选择方阵', trigger: 'change' }, |                 { required: true, message: '请选择方阵', trigger: 'change' }, | ||||||
|                 { type: 'array', min: 2, message: '请选择完整的方阵层级', trigger: 'change' } |                 { type: 'array', min: 1, message: '请选择完整的方阵', trigger: 'change' } | ||||||
|               ]" |               ]" | ||||||
|             > |             > | ||||||
|               <el-cascader |               <el-cascader | ||||||
| @ -133,7 +136,7 @@ | |||||||
|               /> |               /> | ||||||
|             </el-form-item> |             </el-form-item> | ||||||
|           </el-col> |           </el-col> | ||||||
|           <!-- 所属工区:必填校验 --> |           <!-- 所属工区:保留原有规则 --> | ||||||
|           <el-col :span="8"> |           <el-col :span="8"> | ||||||
|             <el-form-item |             <el-form-item | ||||||
|               label="所属工区" |               label="所属工区" | ||||||
| @ -143,7 +146,7 @@ | |||||||
|               <el-input v-model="item.unitProjectArea" placeholder="请输入所属工区" /> |               <el-input v-model="item.unitProjectArea" placeholder="请输入所属工区" /> | ||||||
|             </el-form-item> |             </el-form-item> | ||||||
|           </el-col> |           </el-col> | ||||||
|           <!-- 方阵状态:必填校验 --> |           <!-- 方阵状态:保留原有规则 --> | ||||||
|           <el-col :span="6"> |           <el-col :span="6"> | ||||||
|             <el-form-item |             <el-form-item | ||||||
|               label="方阵状态" |               label="方阵状态" | ||||||
| @ -153,8 +156,15 @@ | |||||||
|               <el-input v-model="item.unitProjectStatus" placeholder="请输入方阵状态" /> |               <el-input v-model="item.unitProjectStatus" placeholder="请输入方阵状态" /> | ||||||
|             </el-form-item> |             </el-form-item> | ||||||
|           </el-col> |           </el-col> | ||||||
|  |           <!-- 删除按钮:禁用逻辑优化(至少保留1项) --> | ||||||
|           <el-col :span="1" style="margin-left: 15px; display: flex; align-items: flex-end"> |           <el-col :span="1" style="margin-left: 15px; display: flex; align-items: flex-end"> | ||||||
|             <el-button style="margin-bottom: 18px" type="danger" icon="Delete" @click="removeUnitBoItem(i)"></el-button> |             <el-button | ||||||
|  |               style="margin-bottom: 18px" | ||||||
|  |               type="danger" | ||||||
|  |               icon="Delete" | ||||||
|  |               @click="removeUnitBoItem(i)" | ||||||
|  |               :disabled="formM.unitBoList.length <= 1" | ||||||
|  |             ></el-button> | ||||||
|           </el-col> |           </el-col> | ||||||
|         </el-row> |         </el-row> | ||||||
|       </el-form> |       </el-form> | ||||||
| @ -181,21 +191,35 @@ import { | |||||||
| } from '@/api/system/landTransfer/landBlock'; | } from '@/api/system/landTransfer/landBlock'; | ||||||
| import { LandBlockVO, LandBlockQuery, LandBlockForm } from '@/api/system/landTransfer/landBlock/types'; | import { LandBlockVO, LandBlockQuery, LandBlockForm } from '@/api/system/landTransfer/landBlock/types'; | ||||||
| import { useUserStoreHook } from '@/store/modules/user'; | import { useUserStoreHook } from '@/store/modules/user'; | ||||||
| import { getCurrentInstance, ComponentInternalInstance, onMounted, onUnmounted, watch } from 'vue'; | import { getCurrentInstance, ComponentInternalInstance, onMounted, onUnmounted, watch, reactive, ref, toRefs, computed } from 'vue'; | ||||||
| import { ElFormInstance, ElMessage } from 'element-plus'; | import { ElFormInstance } from 'element-plus'; | ||||||
|  |  | ||||||
| // 类型定义补充(避免any) | // 类型定义补充 | ||||||
| interface DialogOption { | interface DialogOption { | ||||||
|   visible: boolean; |   visible: boolean; | ||||||
|   title: string; |   title: string; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // 方阵级联选择器选项类型 | ||||||
|  | interface FangzhenOption { | ||||||
|  |   matrixId: string | number; | ||||||
|  |   name: string; | ||||||
|  |   children?: FangzhenOption[]; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // 方阵表单项类型 | ||||||
| interface UnitBoItem { | interface UnitBoItem { | ||||||
|   unitProjectArea: string; |   unitProjectArea: string; | ||||||
|   unitProjectStatus: string; |   unitProjectStatus: string; | ||||||
|   unitProjectId: (string | number)[]; // 级联选择值(数组) |   unitProjectId: (string | number)[]; // 级联选择值(数组) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // 方阵表单根模型类型(关键:显式声明unitBoList) | ||||||
|  | interface MatrixForm { | ||||||
|  |   landId?: string | number; // 关联的地块ID | ||||||
|  |   unitBoList: UnitBoItem[]; // 方阵列表 | ||||||
|  | } | ||||||
|  |  | ||||||
| // 基础实例与Store | // 基础实例与Store | ||||||
| const { proxy } = getCurrentInstance() as ComponentInternalInstance; | const { proxy } = getCurrentInstance() as ComponentInternalInstance; | ||||||
| const userStore = useUserStoreHook(); | const userStore = useUserStoreHook(); | ||||||
| @ -203,14 +227,17 @@ const currentProject = computed(() => userStore.selectedProject); | |||||||
|  |  | ||||||
| // 响应式数据 | // 响应式数据 | ||||||
| const landBlockList = ref<LandBlockVO[]>([]); | const landBlockList = ref<LandBlockVO[]>([]); | ||||||
| const fangzhenList = ref<any[]>([]); // 方阵列表(实际项目建议定义具体类型) | const fangzhenList = ref<FangzhenOption[]>([]); | ||||||
| const buttonLoading = ref(false); | const buttonLoading = ref(false); | ||||||
| const loading = ref(true); | const loading = ref(true); | ||||||
| const showSearch = ref(true); | const showSearch = ref(true); | ||||||
| const uploadRef = ref<any>(null); // upload组件ref | const uploadRef = ref<any>(null); | ||||||
|  |  | ||||||
| // 方阵表单数据(核心修改:初始值为空,避免默认填充无效数据) | // 方阵表单模型(核心修复:使用reactive并显式声明结构) | ||||||
| const unitBoList = ref<UnitBoItem[]>([{ unitProjectArea: '', unitProjectStatus: '', unitProjectId: [] }]); | const formM = reactive<MatrixForm>({ | ||||||
|  |   landId: undefined, | ||||||
|  |   unitBoList: [{ unitProjectArea: '', unitProjectStatus: '', unitProjectId: [] }] | ||||||
|  | }); | ||||||
|  |  | ||||||
| // 表格选择相关 | // 表格选择相关 | ||||||
| const ids = ref<Array<string | number>>([]); | const ids = ref<Array<string | number>>([]); | ||||||
| @ -243,7 +270,6 @@ const initFormData: LandBlockForm = { | |||||||
| // 核心数据(含表单规则) | // 核心数据(含表单规则) | ||||||
| const data = reactive({ | const data = reactive({ | ||||||
|   form: { ...initFormData }, |   form: { ...initFormData }, | ||||||
|   formM: { landId: undefined }, // 方阵关联表单(仅存地块ID) |  | ||||||
|   queryParams: { |   queryParams: { | ||||||
|     pageNum: 1, |     pageNum: 1, | ||||||
|     pageSize: 10, |     pageSize: 10, | ||||||
| @ -256,7 +282,7 @@ const data = reactive({ | |||||||
|     farmerCount: undefined, |     farmerCount: undefined, | ||||||
|     params: {} |     params: {} | ||||||
|   }, |   }, | ||||||
|   // 地块表单规则(原有规则保留) |   // 地块表单规则 | ||||||
|   rules: { |   rules: { | ||||||
|     id: [{ required: true, message: '主键ID不能为空', trigger: 'blur' }], |     id: [{ required: true, message: '主键ID不能为空', trigger: 'blur' }], | ||||||
|     projectId: [{ required: true, message: '项目ID不能为空', trigger: 'blur' }], |     projectId: [{ required: true, message: '项目ID不能为空', trigger: 'blur' }], | ||||||
| @ -265,7 +291,7 @@ const data = reactive({ | |||||||
|   } |   } | ||||||
| }); | }); | ||||||
|  |  | ||||||
| const { queryParams, form, rules, formM } = toRefs(data); | const { queryParams, form, rules } = toRefs(data); | ||||||
|  |  | ||||||
| /** 查询地块列表 */ | /** 查询地块列表 */ | ||||||
| const getList = async () => { | const getList = async () => { | ||||||
| @ -381,10 +407,10 @@ const getfangzhenList = async () => { | |||||||
|   loading.value = true; |   loading.value = true; | ||||||
|   try { |   try { | ||||||
|     const res = await subMatrix(currentProject.value.id); |     const res = await subMatrix(currentProject.value.id); | ||||||
|     // 处理方阵数据(级联选择需父子结构,此处保留原有逻辑) |     // 处理方阵数据(级联选择需父子结构) | ||||||
|     res.data.forEach((item: any) => { |     res.data.forEach((item: any) => { | ||||||
|       item.children?.forEach((item2: any) => { |       item.children?.forEach((item2: any) => { | ||||||
|         item2.matrixId = `${item2.name}_${item2.matrixId}`; // 拼接名称+ID,便于后续拆分 |         item2.matrixId = `${item2.name}_${item2.matrixId}`; | ||||||
|       }); |       }); | ||||||
|     }); |     }); | ||||||
|     fangzhenList.value = res.data; |     fangzhenList.value = res.data; | ||||||
| @ -395,68 +421,75 @@ const getfangzhenList = async () => { | |||||||
|   } |   } | ||||||
| }; | }; | ||||||
|  |  | ||||||
| /** 关联方阵(核心修改:打开弹窗前强制重置表单) */ | /** 关联方阵 */ | ||||||
| const handleView = async (row: LandBlockVO) => { | const handleView = async (row: LandBlockVO) => { | ||||||
|   if (!row?.id) return proxy?.$modal.msgWarning('请选择有效的地块'); |   if (!row?.id) return proxy?.$modal.msgWarning('请选择有效的地块'); | ||||||
|  |  | ||||||
|   // 1. 重置方阵表单(清空历史数据) |   // 重置方阵表单 | ||||||
|   resetMatrix(); |   resetMatrix(); | ||||||
|   // 2. 绑定当前地块ID |   // 绑定当前地块ID | ||||||
|   formM.value.landId = row.id; |   formM.landId = row.id; | ||||||
|   // 3. 打开弹窗 |   // 打开弹窗 | ||||||
|   dialogMatrix.visible = true; |   dialogMatrix.visible = true; | ||||||
|  |  | ||||||
|   dialogMatrix.title = `关联方阵(地块:${row.landName || row.landCode})`; |   dialogMatrix.title = `关联方阵(地块:${row.landName || row.landCode})`; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| /** 新增方阵表单项 */ | /** 新增方阵表单项 */ | ||||||
| const addUnitBoItem = () => { | const addUnitBoItem = () => { | ||||||
|   unitBoList.value.push({ |   formM.unitBoList.push({ | ||||||
|     unitProjectArea: '', |     unitProjectArea: '', | ||||||
|     unitProjectStatus: '', |     unitProjectStatus: '', | ||||||
|     unitProjectId: [] // 级联选择初始为空数组 |     unitProjectId: [] | ||||||
|   }); |   }); | ||||||
|  |   // 重置校验状态 | ||||||
|  |   landBlockFormMatrixRef.value?.clearValidate(); | ||||||
| }; | }; | ||||||
|  |  | ||||||
| /** 删除方阵表单项 */ | /** 删除方阵表单项 */ | ||||||
| const removeUnitBoItem = (index: number) => { | const removeUnitBoItem = (index: number) => { | ||||||
|   if (unitBoList.value.length <= 1) { |   if (formM.unitBoList.length <= 1) { | ||||||
|     return proxy?.$modal.msgWarning('至少保留一项方阵配置'); |     return proxy?.$modal.msgWarning('至少保留一项方阵配置'); | ||||||
|   } |   } | ||||||
|   unitBoList.value.splice(index, 1); |   formM.unitBoList.splice(index, 1); | ||||||
|   // 重置表单校验状态(避免删除后残留校验提示) |  | ||||||
|   landBlockFormMatrixRef.value?.clearValidate(); |   landBlockFormMatrixRef.value?.clearValidate(); | ||||||
| }; | }; | ||||||
|  |  | ||||||
| /** 提交方阵关联表单 */ | /** 提交方阵关联表单(核心修复:数据处理逻辑) */ | ||||||
| const submitFormMatrix = () => { | const submitFormMatrix = () => { | ||||||
|   landBlockFormMatrixRef.value?.validate(async (valid: boolean) => { |   landBlockFormMatrixRef.value?.validate(async (valid: boolean) => { | ||||||
|     if (!valid) return; |     if (!valid) return; | ||||||
|     if (!formM.value.landId) return proxy?.$modal.msgWarning('地块ID异常,请重新选择地块'); |     if (!formM.landId) return proxy?.$modal.msgWarning('地块ID异常,请重新选择地块'); | ||||||
|  |  | ||||||
|     try { |     try { | ||||||
|       // 处理方阵数据(拆分名称+ID) |       // 处理方阵数据(修复ID拆分逻辑) | ||||||
|       const unitBoListParams = unitBoList.value.map((item) => { |       const unitBoListParams = formM.unitBoList.map((item) => { | ||||||
|         const [unitProjectName, unitProjectId] = item.unitProjectId[1]?.split('_') || []; |         // 取级联选择的最后一层值 | ||||||
|         if (!unitProjectId) throw new Error('方阵ID解析失败,请重新选择方阵'); |         const lastLevelValue = item.unitProjectId[item.unitProjectId.length - 1]; | ||||||
|  |         if (!lastLevelValue) throw new Error('请选择完整的方阵'); | ||||||
|  |  | ||||||
|  |         // 拆分名称和ID | ||||||
|  |         const [unitProjectName, unitProjectId] = String(lastLevelValue).split('_'); | ||||||
|  |         if (!unitProjectId) throw new Error('方阵ID解析失败,请重新选择'); | ||||||
|  |  | ||||||
|         return { |         return { | ||||||
|           unitProjectArea: item.unitProjectArea.trim(), |           unitProjectArea: item.unitProjectArea.trim(), | ||||||
|           unitProjectStatus: item.unitProjectStatus.trim(), |           unitProjectStatus: item.unitProjectStatus.trim(), | ||||||
|           unitProjectId: unitProjectId, // 纯ID(后端需要) |           unitProjectId: unitProjectId, | ||||||
|           unitProjectName: unitProjectName // 名称(可选,用于显示) |           unitProjectName: unitProjectName | ||||||
|         }; |         }; | ||||||
|       }); |       }); | ||||||
|  |  | ||||||
|       // 调用关联接口 |       // 调用关联接口 | ||||||
|       const res = await LandUnit({ |       const res = await LandUnit({ | ||||||
|         landId: formM.value.landId, |         landId: formM.landId, | ||||||
|         unitBoList: unitBoListParams |         unitBoList: unitBoListParams | ||||||
|       }); |       }); | ||||||
|  |  | ||||||
|       if (res.code === 200) { |       if (res.code === 200) { | ||||||
|         proxy?.$modal.msgSuccess('关联方阵成功'); |         proxy?.$modal.msgSuccess('关联方阵成功'); | ||||||
|         dialogMatrix.visible = false; |         dialogMatrix.visible = false; | ||||||
|         await getList(); // 刷新地块列表 |         await getList(); | ||||||
|       } else { |       } else { | ||||||
|         proxy?.$modal.msgError(res.msg || '关联失败'); |         proxy?.$modal.msgError(res.msg || '关联失败'); | ||||||
|       } |       } | ||||||
| @ -472,13 +505,10 @@ const cancelMatrix = () => { | |||||||
|   dialogMatrix.visible = false; |   dialogMatrix.visible = false; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| /** 方阵表单重置(核心修改:清空所有数据+重置校验) */ | /** 方阵表单重置 */ | ||||||
| const resetMatrix = () => { | const resetMatrix = () => { | ||||||
|   // 1. 清空地块ID |   formM.landId = undefined; | ||||||
|   formM.value.landId = undefined; |   formM.unitBoList = [{ unitProjectArea: '', unitProjectStatus: '', unitProjectId: [] }]; | ||||||
|   // 2. 重置方阵列表(仅保留一个空项) |  | ||||||
|   unitBoList.value = [{ unitProjectArea: '', unitProjectStatus: '', unitProjectId: [] }]; |  | ||||||
|   // 3. 重置表单校验状态 |  | ||||||
|   if (landBlockFormMatrixRef.value) { |   if (landBlockFormMatrixRef.value) { | ||||||
|     landBlockFormMatrixRef.value.resetFields(); |     landBlockFormMatrixRef.value.resetFields(); | ||||||
|     landBlockFormMatrixRef.value.clearValidate(); |     landBlockFormMatrixRef.value.clearValidate(); | ||||||
| @ -491,11 +521,11 @@ const listeningProject = watch( | |||||||
|   (newId) => { |   (newId) => { | ||||||
|     if (newId) { |     if (newId) { | ||||||
|       queryParams.value.projectId = newId; |       queryParams.value.projectId = newId; | ||||||
|       getfangzhenList(); // 刷新方阵列表 |       getfangzhenList(); | ||||||
|       getList(); // 刷新地块列表 |       getList(); | ||||||
|     } |     } | ||||||
|   }, |   }, | ||||||
|   { immediate: true } // 初始加载时执行一次 |   { immediate: true } | ||||||
| ); | ); | ||||||
|  |  | ||||||
| /** 导入Excel */ | /** 导入Excel */ | ||||||
| @ -524,36 +554,34 @@ const handleImport = (options: { file: File }) => { | |||||||
|       loading.value = false; |       loading.value = false; | ||||||
|     }); |     }); | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | /** 导出模板 */ | ||||||
| const exportFile = () => { | const exportFile = () => { | ||||||
|   // 导出模版文件 |  | ||||||
|   try { |   try { | ||||||
|     // 创建a标签 |  | ||||||
|     const link = document.createElement('a'); |     const link = document.createElement('a'); | ||||||
|     // 设置PDF文件路径 - 相对于public目录 |  | ||||||
|     link.href = '/dikuai.xlsx'; |     link.href = '/dikuai.xlsx'; | ||||||
|     // 设置下载后的文件名 |  | ||||||
|     link.download = '地块信息导入模版.xlsx'; |     link.download = '地块信息导入模版.xlsx'; | ||||||
|     // 触发点击 |  | ||||||
|     document.body.appendChild(link); |     document.body.appendChild(link); | ||||||
|     link.click(); |     link.click(); | ||||||
|     // 清理 |  | ||||||
|     document.body.removeChild(link); |     document.body.removeChild(link); | ||||||
|   } catch (error) { |   } catch (error) { | ||||||
|     alert('下载失败,请重试'); |     alert('下载失败,请重试'); | ||||||
|   } |   } | ||||||
| }; | }; | ||||||
|  |  | ||||||
| /** 下载导入模板 */ | /** 下载导入模板 */ | ||||||
| const downloadTemplate = () => { | const downloadTemplate = () => { | ||||||
|   try { |   try { | ||||||
|     const link = document.createElement('a'); |     const link = document.createElement('a'); | ||||||
|     link.href = '/landBlock.xlsx'; // 模板路径(需确保public目录下存在该文件) |     link.href = '/landBlock.xlsx'; | ||||||
|     link.download = '地块信息导入模板.xlsx'; // 下载后文件名 |     link.download = '地块信息导入模板.xlsx'; | ||||||
|     document.body.appendChild(link); |     document.body.appendChild(link); | ||||||
|     link.click(); // 触发下载 |     link.click(); | ||||||
|   } catch (err) { |   } catch (err) { | ||||||
|     proxy?.$modal.msgError('模板下载失败,请重试'); |     proxy?.$modal.msgError('模板下载失败,请重试'); | ||||||
|   } finally { |   } finally { | ||||||
|     document.body.removeChild(link); // 清理DOM |     const link = document.querySelector('a[download="地块信息导入模板.xlsx"]'); | ||||||
|  |     if (link) document.body.removeChild(link); | ||||||
|   } |   } | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | |||||||
| @ -144,13 +144,16 @@ | |||||||
|         </el-table-column> --> |         </el-table-column> --> | ||||||
|         <el-table-column label="备注" align="center" prop="remark" /> |         <el-table-column label="备注" align="center" prop="remark" /> | ||||||
|         <el-table-column label="创建时间" align="center" prop="createTime" width="180" /> |         <el-table-column label="创建时间" align="center" prop="createTime" width="180" /> | ||||||
|         <el-table-column fixed="right" label="操作" align="center" class-name="small-padding fixed-width" width="400"> |         <el-table-column fixed="right" label="操作" align="center" width="500"> | ||||||
|           <template #default="scope"> |           <template #default="scope"> | ||||||
|             <el-space> |             <el-space> | ||||||
|  |               <el-button link type="primary" icon="Edit" @click="handleCheckRules(scope.row)" v-hasPermi="['project:attendanceRule:byProjectId']" | ||||||
|  |                 >打卡规则 | ||||||
|  |               </el-button> | ||||||
|  |               <!-- <el-button link type="primary" icon="Edit" @click="handleScope(scope.row)" v-hasPermi="['project:project:edit']">打卡范围 </el-button> --> | ||||||
|               <el-button link type="primary" icon="FolderOpened" @click="handleShowUpload(scope.row)" v-hasPermi="['project:project:edit']" |               <el-button link type="primary" icon="FolderOpened" @click="handleShowUpload(scope.row)" v-hasPermi="['project:project:edit']" | ||||||
|                 >导入安全协议书 |                 >导入安全协议书 | ||||||
|               </el-button> |               </el-button> | ||||||
|  |  | ||||||
|               <el-button link type="success" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['project:project:edit']">修改 </el-button> |               <el-button link type="success" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['project:project:edit']">修改 </el-button> | ||||||
|               <el-button link type="danger" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['project:project:remove']">删除 </el-button> |               <el-button link type="danger" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['project:project:remove']">删除 </el-button> | ||||||
|               <el-button link type="primary" icon="upload" @click="handleUpload(scope.row)" v-hasPermi="['project:project:saveTenderFile']" |               <el-button link type="primary" icon="upload" @click="handleUpload(scope.row)" v-hasPermi="['project:project:saveTenderFile']" | ||||||
| @ -160,7 +163,6 @@ | |||||||
|           </template> |           </template> | ||||||
|         </el-table-column> |         </el-table-column> | ||||||
|       </el-table> |       </el-table> | ||||||
|  |  | ||||||
|       <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" /> |       <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" /> | ||||||
|     </el-card> |     </el-card> | ||||||
|     <!-- 添加或修改项目对话框 --> |     <!-- 添加或修改项目对话框 --> | ||||||
| @ -253,78 +255,6 @@ | |||||||
|             </el-col> |             </el-col> | ||||||
|           </el-row> |           </el-row> | ||||||
|         </div> |         </div> | ||||||
|         <div class="block-box"> |  | ||||||
|           <div class="">打卡设置</div> |  | ||||||
|           <el-row :gutter="20"> |  | ||||||
|             <el-col :span="12" :offset="0"> |  | ||||||
|               <el-form-item label="打卡开始时间" prop="playCardStart" label-width="110px"> |  | ||||||
|                 <!-- <el-time-picker value-format="HH:mm" v-model="form.playCardStart" placeholder="请输入打卡开始时间" /> --> |  | ||||||
|                 <el-time-select |  | ||||||
|                   v-model="form.playCardStart" |  | ||||||
|                   style="width: 100%" |  | ||||||
|                   class="mr-4" |  | ||||||
|                   placeholder="请输入打卡开始时间" |  | ||||||
|                   value-format="HH:mm" |  | ||||||
|                   start="00:00" |  | ||||||
|                   step="00:15" |  | ||||||
|                   end="23:59" |  | ||||||
|                 /> |  | ||||||
|               </el-form-item> |  | ||||||
|             </el-col> |  | ||||||
|             <el-col :span="12" :offset="0"> |  | ||||||
|               <el-form-item label="打卡结束时间" prop="playCardEnd" label-width="110px"> |  | ||||||
|                 <!-- <el-time-picker value-format="HH:mm" v-model="form.playCardEnd" placeholder="请输入打卡结束时间" /> --> |  | ||||||
|                 <el-time-select |  | ||||||
|                   v-model="form.playCardEnd" |  | ||||||
|                   style="width: 100%" |  | ||||||
|                   :min-time="form.playCardStart" |  | ||||||
|                   class="mr-4" |  | ||||||
|                   placeholder="请输入打卡结束时间" |  | ||||||
|                   value-format="HH:mm" |  | ||||||
|                   start="00:00" |  | ||||||
|                   step="00:15" |  | ||||||
|                   end="23:59" |  | ||||||
|                 /> |  | ||||||
|               </el-form-item> |  | ||||||
|             </el-col> |  | ||||||
|             <el-col :span="12" :offset="0"> |  | ||||||
|               <el-form-item label="打卡类型" prop="playCardStart" label-width="110px"> |  | ||||||
|                 <!-- <el-time-picker value-format="HH:mm" v-model="form.playCardStart" placeholder="请输入打卡开始时间" /> --> |  | ||||||
|                 <el-time-select |  | ||||||
|                   v-model="form.playCardStart" |  | ||||||
|                   style="width: 100%" |  | ||||||
|                   class="mr-4" |  | ||||||
|                   placeholder="请输入打卡开始时间" |  | ||||||
|                   value-format="HH:mm" |  | ||||||
|                   start="00:00" |  | ||||||
|                   step="00:15" |  | ||||||
|                   end="23:59" |  | ||||||
|                 /> |  | ||||||
|               </el-form-item> |  | ||||||
|             </el-col> |  | ||||||
|             <el-col :span="12" :offset="0"> |  | ||||||
|               <el-form-item label="工作日" prop="playCardEnd" label-width="110px"> |  | ||||||
|                 <!-- <el-time-picker value-format="HH:mm" v-model="form.playCardEnd" placeholder="请输入打卡结束时间" /> --> |  | ||||||
|                 <el-time-select |  | ||||||
|                   v-model="form.playCardEnd" |  | ||||||
|                   style="width: 100%" |  | ||||||
|                   :min-time="form.playCardStart" |  | ||||||
|                   class="mr-4" |  | ||||||
|                   placeholder="请输入打卡结束时间" |  | ||||||
|                   value-format="HH:mm" |  | ||||||
|                   start="00:00" |  | ||||||
|                   step="00:15" |  | ||||||
|                   end="23:59" |  | ||||||
|                 /> |  | ||||||
|               </el-form-item> |  | ||||||
|             </el-col> |  | ||||||
|             <!-- <el-col :span="24" :offset="0"> |  | ||||||
|               <el-form-item label="安全协议书" prop="securityAgreement"> |  | ||||||
|                 <file-upload v-model="form.securityAgreement" :limit="1" :file-type="['pdf']" :file-size="50" /> |  | ||||||
|               </el-form-item> |  | ||||||
|             </el-col> --> |  | ||||||
|           </el-row> |  | ||||||
|         </div> |  | ||||||
|       </el-form> |       </el-form> | ||||||
|       <template #footer> |       <template #footer> | ||||||
|         <div class="dialog-footer"> |         <div class="dialog-footer"> | ||||||
| @ -342,13 +272,12 @@ | |||||||
|         </div> |         </div> | ||||||
|       </template> |       </template> | ||||||
|     </el-dialog> |     </el-dialog> | ||||||
|  |  | ||||||
|     <!-- //选取项目地址弹窗 --> |     <!-- //选取项目地址弹窗 --> | ||||||
|     <el-dialog v-model="amapStatus" :title="form.projectName + '-获取经纬度'" width="80%"> |     <el-dialog draggable v-model="amapStatus" :title="form.projectName + '-获取经纬度'" width="80%"> | ||||||
|       <amap height="620px" @setLocation="setPoi"></amap> |       <amap height="620px" @setLocation="setPoi"></amap> | ||||||
|     </el-dialog> |     </el-dialog> | ||||||
|     <!-- 选取方阵地址 --> |     <!-- 选取方阵地址 --> | ||||||
|     <el-dialog title="设置方阵" v-model="polygonStatus" width="1400px" :close-on-click-modal="false"> |     <el-dialog draggable title="设置方阵" v-model="polygonStatus" width="1400px" :close-on-click-modal="false"> | ||||||
|       <open-layers-map |       <open-layers-map | ||||||
|         :project-id="projectId" |         :project-id="projectId" | ||||||
|         :design-id="designId" |         :design-id="designId" | ||||||
| @ -356,7 +285,7 @@ | |||||||
|         @close="polygonStatus = false" |         @close="polygonStatus = false" | ||||||
|       ></open-layers-map> |       ></open-layers-map> | ||||||
|     </el-dialog> |     </el-dialog> | ||||||
|     <el-dialog title="添加子项目" v-model="childProjectStatus" width="400"> |     <el-dialog draggable title="添加子项目" v-model="childProjectStatus" width="400"> | ||||||
|       <span>填写子项目名称</span> |       <span>填写子项目名称</span> | ||||||
|       <el-input v-model="childProjectForm.projectName"></el-input> |       <el-input v-model="childProjectForm.projectName"></el-input> | ||||||
|       <template #footer> |       <template #footer> | ||||||
| @ -366,7 +295,7 @@ | |||||||
|         </span> |         </span> | ||||||
|       </template> |       </template> | ||||||
|     </el-dialog> |     </el-dialog> | ||||||
|     <el-dialog title="上传文件" v-model="fileVisble" width="400"> |     <el-dialog draggable title="上传文件" v-model="fileVisble" width="400"> | ||||||
|       <file-upload v-model="fileForm.tenderFiles" :limit="10" :file-type="['pdf']" :file-size="50" /> |       <file-upload v-model="fileForm.tenderFiles" :limit="10" :file-type="['pdf']" :file-size="50" /> | ||||||
|       <template #footer> |       <template #footer> | ||||||
|         <div class="dialog-footer"> |         <div class="dialog-footer"> | ||||||
| @ -375,6 +304,86 @@ | |||||||
|         </div> |         </div> | ||||||
|       </template> |       </template> | ||||||
|     </el-dialog> |     </el-dialog> | ||||||
|  |     <el-dialog draggable title="打卡规则" v-model="ruleFlag" width="800"> | ||||||
|  |       <template #footer> | ||||||
|  |         <el-form ref="projectFormRef" :model="form" :rules="rules" label-width="100px"> | ||||||
|  |           <el-row :gutter="20"> | ||||||
|  |             <el-col :span="12" :offset="0"> | ||||||
|  |               <el-form-item label="上班时间" prop="clockInTime"> | ||||||
|  |                 <el-time-select | ||||||
|  |                   v-model="form.clockInTime" | ||||||
|  |                   style="width: 100%" | ||||||
|  |                   class="mr-4" | ||||||
|  |                   placeholder="请输入打卡开始时间" | ||||||
|  |                   value-format="HH:mm" | ||||||
|  |                   start="00:00" | ||||||
|  |                   step="00:15" | ||||||
|  |                   end="23:59" | ||||||
|  |                 /> | ||||||
|  |               </el-form-item> | ||||||
|  |             </el-col> | ||||||
|  |             <el-col :span="12" :offset="0"> | ||||||
|  |               <el-form-item label="下班时间" prop="clockOutTime"> | ||||||
|  |                 <el-time-select | ||||||
|  |                   v-model="form.clockOutTime" | ||||||
|  |                   style="width: 100%" | ||||||
|  |                   :min-time="form.clockInTime" | ||||||
|  |                   class="mr-4" | ||||||
|  |                   placeholder="请输入打卡结束时间" | ||||||
|  |                   value-format="HH:mm" | ||||||
|  |                   start="00:00" | ||||||
|  |                   step="00:15" | ||||||
|  |                   end="23:59" | ||||||
|  |                 /> | ||||||
|  |               </el-form-item> | ||||||
|  |             </el-col> | ||||||
|  |             <el-col :span="24" :offset="0"> | ||||||
|  |               <el-form-item label="打卡类型" prop="type"> | ||||||
|  |                 <el-radio-group v-model="form.type"> | ||||||
|  |                   <el-radio value="1" size="large">无限制</el-radio> | ||||||
|  |                   <el-radio value="2" size="large">范围内打卡</el-radio> | ||||||
|  |                 </el-radio-group> | ||||||
|  |               </el-form-item> | ||||||
|  |             </el-col> | ||||||
|  |             <el-col :span="24"> | ||||||
|  |               <el-form-item label="打卡类型" prop="weekday"> | ||||||
|  |                 <el-checkbox-group v-model="form.weekday" size="small"> | ||||||
|  |                   <el-checkbox label="星期一" value="1" /> | ||||||
|  |                   <el-checkbox label="星期二" value="2" /> | ||||||
|  |                   <el-checkbox label="星期三" value="3" /> | ||||||
|  |                   <el-checkbox label="星期四" value="4" /> | ||||||
|  |                   <el-checkbox label="星期五" value="5" /> | ||||||
|  |                   <el-checkbox label="星期六" value="6" /> | ||||||
|  |                   <el-checkbox label="星期日" value="7" /> | ||||||
|  |                 </el-checkbox-group> | ||||||
|  |               </el-form-item> | ||||||
|  |             </el-col> </el-row | ||||||
|  |         ></el-form> | ||||||
|  |         <div class="dialog-footer"> | ||||||
|  |           <el-button type="primary" @click="ruleSubmit"> 提交</el-button> | ||||||
|  |           <el-button @click="ruleFlag = false">取消</el-button> | ||||||
|  |         </div> | ||||||
|  |       </template> | ||||||
|  |     </el-dialog> | ||||||
|  |     <el-dialog draggable title="打卡范围" v-model="ScopeFlag" width="600"> | ||||||
|  |       <div v-for="(item, i) of punchRangeList" :key="i" class="options_item"> | ||||||
|  |         <el-row> | ||||||
|  |           <el-col :span="1"> <el-color-picker v-model="item.punchColor" show-alpha /></el-col> | ||||||
|  |           <el-col :span="12"> <el-input v-model="item.punchName" placeholder="请输入打卡范围名称" class="ml-8" /></el-col> | ||||||
|  |           <el-col :span="10" style="text-align: right; margin-top: 5px"> | ||||||
|  |             <el-button link type="primary" icon="view">预览</el-button> | ||||||
|  |             <el-button link type="primary" icon="plus">添加</el-button> | ||||||
|  |             <el-button link type="primary" icon="delete">移除</el-button> | ||||||
|  |           </el-col> | ||||||
|  |         </el-row> | ||||||
|  |       </div> | ||||||
|  |       <template #footer> | ||||||
|  |         <div class="dialog-footer"> | ||||||
|  |           <el-button type="primary" @click="scopeSubmit"> 提交</el-button> | ||||||
|  |           <el-button @click="ScopeFlag = false">取消</el-button> | ||||||
|  |         </div> | ||||||
|  |       </template> | ||||||
|  |     </el-dialog> | ||||||
|   </div> |   </div> | ||||||
| </template> | </template> | ||||||
|  |  | ||||||
| @ -382,14 +391,14 @@ | |||||||
| import { | import { | ||||||
|   addChildProject, |   addChildProject, | ||||||
|   addProject, |   addProject, | ||||||
|   addProjectFacilities, |  | ||||||
|   addProjectPilePoint, |  | ||||||
|   addProjectSquare, |  | ||||||
|   delProject, |   delProject, | ||||||
|   uploadProjectFile, |   uploadProjectFile, | ||||||
|   getProject, |   getProject, | ||||||
|   listProject, |   listProject, | ||||||
|   updateProject |   updateProject, | ||||||
|  |   attendanceRuleAdd, | ||||||
|  |   attendanceRuleEdit, | ||||||
|  |   byProjectIdDetail | ||||||
| } from '@/api/project/project'; | } from '@/api/project/project'; | ||||||
| import { ProjectForm, ProjectQuery, ProjectVO, childProjectQuery, locationType } from '@/api/project/project/types'; | import { ProjectForm, ProjectQuery, ProjectVO, childProjectQuery, locationType } from '@/api/project/project/types'; | ||||||
| import amap from '@/components/amap/index.vue'; | import amap from '@/components/amap/index.vue'; | ||||||
| @ -413,6 +422,14 @@ const polygonStatus = ref(false); | |||||||
| const dxfFile = ref(null); | const dxfFile = ref(null); | ||||||
| const projectId = ref<string>(''); | const projectId = ref<string>(''); | ||||||
| const designId = ref<string>(''); | const designId = ref<string>(''); | ||||||
|  | const ruleFlag = ref(false); | ||||||
|  | const ScopeFlag = ref(false); | ||||||
|  | const punchRangeList = ref<any>([ | ||||||
|  |   { | ||||||
|  |     punchName: '', | ||||||
|  |     punchColor: '#1983ff' | ||||||
|  |   } | ||||||
|  | ]); | ||||||
| const childProjectForm = reactive<childProjectQuery>({ | const childProjectForm = reactive<childProjectQuery>({ | ||||||
|   projectName: '', |   projectName: '', | ||||||
|   pid: '', |   pid: '', | ||||||
| @ -432,7 +449,7 @@ const fileForm = ref({ | |||||||
| const jsonData = ref(null); | const jsonData = ref(null); | ||||||
| const fullscreenLoading = ref(false); | const fullscreenLoading = ref(false); | ||||||
|  |  | ||||||
| const initFormData: ProjectForm = { | const initFormData = { | ||||||
|   id: undefined, |   id: undefined, | ||||||
|   projectName: undefined, |   projectName: undefined, | ||||||
|   shortName: undefined, |   shortName: undefined, | ||||||
| @ -451,13 +468,15 @@ const initFormData: ProjectForm = { | |||||||
|   lat: undefined, |   lat: undefined, | ||||||
|   plan: undefined, |   plan: undefined, | ||||||
|   onStreamTime: undefined, |   onStreamTime: undefined, | ||||||
|   playCardStart: undefined, |   clockInTime: undefined, | ||||||
|   playCardEnd: undefined, |   clockOutTime: undefined, | ||||||
|   designTotal: undefined, |   designTotal: undefined, | ||||||
|   securityAgreement: undefined, |   securityAgreement: undefined, | ||||||
|   sort: 0, |   sort: 0, | ||||||
|   showHidden: undefined, |   showHidden: undefined, | ||||||
|   isDelete: undefined |   isDelete: undefined, | ||||||
|  |   type: '1', | ||||||
|  |   weekday: [] | ||||||
| }; | }; | ||||||
| const data = reactive<PageData<ProjectForm, ProjectQuery>>({ | const data = reactive<PageData<ProjectForm, ProjectQuery>>({ | ||||||
|   form: { ...initFormData }, |   form: { ...initFormData }, | ||||||
| @ -480,8 +499,6 @@ const data = reactive<PageData<ProjectForm, ProjectQuery>>({ | |||||||
|     lat: undefined, |     lat: undefined, | ||||||
|     plan: undefined, |     plan: undefined, | ||||||
|     onStreamTime: undefined, |     onStreamTime: undefined, | ||||||
|     playCardStart: undefined, |  | ||||||
|     playCardEnd: undefined, |  | ||||||
|     designTotal: undefined, |     designTotal: undefined, | ||||||
|     securityAgreement: undefined, |     securityAgreement: undefined, | ||||||
|     sort: undefined, |     sort: undefined, | ||||||
| @ -490,8 +507,8 @@ const data = reactive<PageData<ProjectForm, ProjectQuery>>({ | |||||||
|     params: {} |     params: {} | ||||||
|   }, |   }, | ||||||
|   rules: { |   rules: { | ||||||
|     playCardStart: [{ required: true, message: '打卡开始时间不能为空', trigger: 'blur' }], |     clockInTime: [{ required: true, message: '打卡开始时间不能为空', trigger: 'blur' }], | ||||||
|     playCardEnd: [{ required: true, message: '打卡结束时间不能为空', trigger: 'blur' }], |     clockOutTime: [{ required: true, message: '打卡结束时间不能为空', trigger: 'blur' }], | ||||||
|     projectName: [{ required: true, message: '项目名称不能为空', trigger: 'blur' }], |     projectName: [{ required: true, message: '项目名称不能为空', trigger: 'blur' }], | ||||||
|     shortName: [{ required: true, message: '项目简称不能为空', trigger: 'blur' }], |     shortName: [{ required: true, message: '项目简称不能为空', trigger: 'blur' }], | ||||||
|     principalPhone: [{ required: true, message: '负责人电话不能为空', trigger: 'blur' }], |     principalPhone: [{ required: true, message: '负责人电话不能为空', trigger: 'blur' }], | ||||||
| @ -692,7 +709,48 @@ const handleSetChild = async () => { | |||||||
|     } |     } | ||||||
|   } |   } | ||||||
| }; | }; | ||||||
|  | const handleScope = (row) => { | ||||||
|  |   // 打卡范围 | ||||||
|  |   ScopeFlag.value = true; | ||||||
|  |   projectId.value = row.id; | ||||||
|  | }; | ||||||
|  | const scopeSubmit = () => { | ||||||
|  |   // 提交打卡范围 | ||||||
|  | }; | ||||||
|  | // 添加规则 | ||||||
|  | const handleCheckRules = async (row?: ProjectVO) => { | ||||||
|  |   reset(); | ||||||
|  |   const _id = row?.id || ids.value[0]; | ||||||
|  |   const res = await byProjectIdDetail(_id); | ||||||
|  |   if (res.data) { | ||||||
|  |     res.data.weekday = res.data.weekday.split(','); | ||||||
|  |     Object.assign(form.value, res.data); | ||||||
|  |   } | ||||||
|  |   projectId.value = row.id; | ||||||
|  |   ruleFlag.value = true; | ||||||
|  | }; | ||||||
|  | const ruleSubmit = async () => { | ||||||
|  |   console.log(form.value); | ||||||
|  |   projectFormRef.value?.validate(async (valid: boolean) => { | ||||||
|  |     if (valid) { | ||||||
|  |       let obj = { | ||||||
|  |         weekday: form.value.weekday.join(','), | ||||||
|  |         projectId: projectId.value, | ||||||
|  |         id: projectId.value, | ||||||
|  |         clockInTime: form.value.clockInTime, | ||||||
|  |         clockOutTime: form.value.clockOutTime, | ||||||
|  |         type: form.value.type | ||||||
|  |       }; | ||||||
|  |       if (form.value.id) { | ||||||
|  |         await attendanceRuleEdit(obj); | ||||||
|  |       } else { | ||||||
|  |         await attendanceRuleAdd(obj); | ||||||
|  |       } | ||||||
|  |       ruleFlag.value = false; | ||||||
|  |       await getList(); | ||||||
|  |     } | ||||||
|  |   }); | ||||||
|  | }; | ||||||
| /** 导出按钮操作 */ | /** 导出按钮操作 */ | ||||||
| const handleExport = () => { | const handleExport = () => { | ||||||
|   proxy?.download( |   proxy?.download( | ||||||
|  | |||||||
							
								
								
									
										258
									
								
								src/views/system/user/comm/editInfo.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										258
									
								
								src/views/system/user/comm/editInfo.vue
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,258 @@ | |||||||
|  | <template> | ||||||
|  |   <div class="p-2 editInfo"> | ||||||
|  |     <el-form label-position="top" ref="userFormRef" :model="form" :rules="rules" label-width="80px"> | ||||||
|  |       <el-row> | ||||||
|  |         <el-col :span="10"> | ||||||
|  |           <el-form-item label="用户昵称" prop="nickName"> | ||||||
|  |             <el-input v-model="form.nickName" placeholder="请输入用户昵称" maxlength="30" /> | ||||||
|  |           </el-form-item> | ||||||
|  |         </el-col> | ||||||
|  |         <el-col :span="2"></el-col> | ||||||
|  |         <el-col :span="10"> | ||||||
|  |           <el-form-item label="归属部门" prop="deptId"> | ||||||
|  |             <el-tree-select | ||||||
|  |               v-model="form.deptId" | ||||||
|  |               :data="enabledDeptOptions" | ||||||
|  |               :props="{ value: 'id', label: 'label', children: 'children' }" | ||||||
|  |               value-key="id" | ||||||
|  |               placeholder="请选择归属部门" | ||||||
|  |               check-strictly | ||||||
|  |               @change="handleDeptChange" | ||||||
|  |             /> | ||||||
|  |           </el-form-item> | ||||||
|  |         </el-col> | ||||||
|  |         <el-col :span="10"> | ||||||
|  |           <el-form-item label="手机号码" prop="phonenumber"> | ||||||
|  |             <el-input v-model="form.phonenumber" placeholder="请输入手机号码" maxlength="11" /> | ||||||
|  |           </el-form-item> </el-col | ||||||
|  |         ><el-col :span="2"></el-col> | ||||||
|  |         <el-col :span="10"> | ||||||
|  |           <el-form-item label="邮箱" prop="email"> | ||||||
|  |             <el-input v-model="form.email" placeholder="请输入邮箱" maxlength="50" /> | ||||||
|  |           </el-form-item> | ||||||
|  |         </el-col> | ||||||
|  |         <el-col :span="10"> | ||||||
|  |           <el-form-item v-if="form.userId == undefined" label="用户名称" prop="userName"> | ||||||
|  |             <el-input v-model="form.userName" placeholder="请输入用户名称" maxlength="30" /> | ||||||
|  |           </el-form-item> </el-col | ||||||
|  |         ><el-col :span="2"></el-col> | ||||||
|  |         <el-col :span="10"> | ||||||
|  |           <el-form-item v-if="form.userId == undefined" label="用户密码" prop="password"> | ||||||
|  |             <el-input v-model="form.password" placeholder="请输入用户密码" type="password" maxlength="20" show-password /> | ||||||
|  |           </el-form-item> | ||||||
|  |         </el-col> | ||||||
|  |         <el-col :span="10"> | ||||||
|  |           <el-form-item label="用户性别"> | ||||||
|  |             <el-select v-model="form.sex" placeholder="请选择"> | ||||||
|  |               <el-option v-for="dict in sys_user_sex" :key="dict.value" :label="dict.label" :value="dict.value"></el-option> | ||||||
|  |             </el-select> | ||||||
|  |           </el-form-item> </el-col | ||||||
|  |         ><el-col :span="2"></el-col> | ||||||
|  |         <el-col :span="10"> | ||||||
|  |           <el-form-item label="岗位"> | ||||||
|  |             <el-select v-model="form.postIds" multiple placeholder="请选择"> | ||||||
|  |               <el-option | ||||||
|  |                 v-for="item in postOptions" | ||||||
|  |                 :key="item.postId" | ||||||
|  |                 :label="item.postName" | ||||||
|  |                 :value="item.postId" | ||||||
|  |                 :disabled="item.status == '1'" | ||||||
|  |               ></el-option> | ||||||
|  |             </el-select> | ||||||
|  |           </el-form-item> </el-col | ||||||
|  |         ><el-col :span="2"></el-col> | ||||||
|  |         <el-col :span="10"> | ||||||
|  |           <el-form-item label="状态"> | ||||||
|  |             <el-radio-group v-model="form.status"> | ||||||
|  |               <el-radio v-for="dict in sys_normal_disable" :key="dict.value" :value="dict.value">{{ dict.label }} </el-radio> | ||||||
|  |             </el-radio-group> | ||||||
|  |           </el-form-item> | ||||||
|  |         </el-col> | ||||||
|  |         <el-col :span="24"> | ||||||
|  |           <el-form-item label="备注"> | ||||||
|  |             <el-input v-model="form.remark" type="textarea" placeholder="请输入内容"></el-input> | ||||||
|  |           </el-form-item> | ||||||
|  |         </el-col> | ||||||
|  |       </el-row> | ||||||
|  |     </el-form> | ||||||
|  |     <!-- <div class="box_submit"> | ||||||
|  |       <el-button type="primary" @click="submitForm">确 定</el-button> | ||||||
|  |       <el-button @click="cancel()">取 消</el-button> | ||||||
|  |     </div> --> | ||||||
|  |   </div> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script setup name="Profile" lang="ts"> | ||||||
|  | import api from '@/api/system/user'; | ||||||
|  | import { listProject } from '@/api/project/project'; | ||||||
|  | import { getProjectByDeptId, getRoleList, optionselect } from '@/api/system/post'; | ||||||
|  | const { proxy } = getCurrentInstance() as ComponentInternalInstance; | ||||||
|  | const { sys_normal_disable, sys_user_sex } = toRefs<any>(proxy?.useDict('sys_normal_disable', 'sys_user_sex')); | ||||||
|  | const enabledDeptOptions = ref([]); | ||||||
|  | const deptOptions = ref([]); | ||||||
|  | const projectOptions = ref<any[]>([]); | ||||||
|  | const postOptions = ref([]); | ||||||
|  | const roleOptions = ref([]); | ||||||
|  | const userFormRef = ref<ElFormInstance>(); | ||||||
|  | const initFormData = { | ||||||
|  |   userId: undefined, | ||||||
|  |   deptId: undefined, | ||||||
|  |   userName: '', | ||||||
|  |   nickName: undefined, | ||||||
|  |   password: '', | ||||||
|  |   phonenumber: undefined, | ||||||
|  |   email: undefined, | ||||||
|  |   sex: undefined, | ||||||
|  |   projectRoles: [ | ||||||
|  |     { | ||||||
|  |       projectId: '', | ||||||
|  |       roleIds: [] | ||||||
|  |     } | ||||||
|  |   ], | ||||||
|  |   status: '0', | ||||||
|  |   remark: '', | ||||||
|  |   postIds: [], | ||||||
|  |   filePath: undefined | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | const initData = { | ||||||
|  |   form: { ...initFormData }, | ||||||
|  |   rules: { | ||||||
|  |     userName: [ | ||||||
|  |       { required: true, message: '用户名称不能为空', trigger: 'blur' }, | ||||||
|  |       { | ||||||
|  |         min: 2, | ||||||
|  |         max: 20, | ||||||
|  |         message: '用户名称长度必须介于 2 和 20 之间', | ||||||
|  |         trigger: 'blur' | ||||||
|  |       } | ||||||
|  |     ], | ||||||
|  |     nickName: [{ required: true, message: '用户昵称不能为空', trigger: 'blur' }], | ||||||
|  |     password: [ | ||||||
|  |       { required: true, message: '用户密码不能为空', trigger: 'blur' }, | ||||||
|  |       { | ||||||
|  |         min: 5, | ||||||
|  |         max: 20, | ||||||
|  |         message: '用户密码长度必须介于 5 和 20 之间', | ||||||
|  |         trigger: 'blur' | ||||||
|  |       }, | ||||||
|  |       { pattern: /^[^<>"'|\\]+$/, message: '不能包含非法字符:< > " \' \\ |', trigger: 'blur' } | ||||||
|  |     ], | ||||||
|  |     email: [ | ||||||
|  |       { | ||||||
|  |         type: 'email', | ||||||
|  |         message: '请输入正确的邮箱地址', | ||||||
|  |         trigger: ['blur', 'change'] | ||||||
|  |       } | ||||||
|  |     ], | ||||||
|  |     phonenumber: [ | ||||||
|  |       { required: true, message: '请输入手机号码', trigger: 'blur' }, | ||||||
|  |       { | ||||||
|  |         pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/, | ||||||
|  |         message: '请输入正确的手机号码', | ||||||
|  |         trigger: 'blur' | ||||||
|  |       } | ||||||
|  |     ] | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  | const data = reactive(initData); | ||||||
|  | const { form, rules } = toRefs(data); | ||||||
|  | /** 查询部门下拉树结构 */ | ||||||
|  | const getDeptTree = async () => { | ||||||
|  |   const res = await api.deptTreeSelect({ isShow: '1' }); | ||||||
|  |   deptOptions.value = res.data; | ||||||
|  |   enabledDeptOptions.value = filterDisabledDept(res.data); | ||||||
|  |   const projectList = await listProject(); | ||||||
|  |   projectOptions.value = projectList.rows; | ||||||
|  | }; | ||||||
|  | /** 过滤禁用的部门 */ | ||||||
|  | const filterDisabledDept = (deptList) => { | ||||||
|  |   return deptList.filter((dept) => { | ||||||
|  |     if (dept.disabled) { | ||||||
|  |       return false; | ||||||
|  |     } | ||||||
|  |     if (dept.children && dept.children.length) { | ||||||
|  |       dept.children = filterDisabledDept(dept.children); | ||||||
|  |     } | ||||||
|  |     return true; | ||||||
|  |   }); | ||||||
|  | }; | ||||||
|  | async function handleDeptChange(value: number | string) { | ||||||
|  |   proxy?.$emit('setDeptId', value); | ||||||
|  |   const response = await optionselect(value); | ||||||
|  |   const roleList = await getRoleList(value); | ||||||
|  |   roleOptions.value = roleList.data; | ||||||
|  |   postOptions.value = response.data; | ||||||
|  |   form.value.postIds = []; | ||||||
|  |   form.value.projectRoles = [ | ||||||
|  |     { | ||||||
|  |       projectId: '', | ||||||
|  |       roleIds: [] | ||||||
|  |     } | ||||||
|  |   ]; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const submitForm = () => { | ||||||
|  |   userFormRef.value?.validate(async (valid: boolean) => { | ||||||
|  |     if (valid) { | ||||||
|  |       form.value.userId ? await api.updateUser(form.value) : await api.addUser(form.value); | ||||||
|  |       proxy?.$modal.msgSuccess('操作成功'); | ||||||
|  |       proxy?.$emit('submit', false); | ||||||
|  |     } | ||||||
|  |   }); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | const cancel = () => { | ||||||
|  |   proxy?.$emit('close', false); | ||||||
|  | }; | ||||||
|  | /** 重置操作表单 */ | ||||||
|  | const reset = () => { | ||||||
|  |   form.value = { ...initFormData }; | ||||||
|  |   form.value.projectRoles = [ | ||||||
|  |     { | ||||||
|  |       projectId: '', | ||||||
|  |       roleIds: [] | ||||||
|  |     } | ||||||
|  |   ]; | ||||||
|  |  | ||||||
|  |   userFormRef.value?.resetFields(); | ||||||
|  | }; | ||||||
|  | // 打开弹框调用参数 | ||||||
|  | const open = async (row?: any) => { | ||||||
|  |   reset(); | ||||||
|  |   if (row) { | ||||||
|  |     // 编辑 | ||||||
|  |     const { data } = await api.getUser(row.userId); | ||||||
|  |     Object.assign(form.value, data.user); | ||||||
|  |     postOptions.value = data.posts; | ||||||
|  |     roleOptions.value = data.roles; | ||||||
|  |     form.value.postIds = data.postIds; | ||||||
|  |     form.value.projectRoles = data.projectRoles; | ||||||
|  |     form.value.password = ''; | ||||||
|  |     const roleList = await getRoleList(form.value.deptId); | ||||||
|  |     roleOptions.value = roleList.data; | ||||||
|  |   } else { | ||||||
|  |     // 新增 | ||||||
|  |     const { data } = await api.getUser(); | ||||||
|  |     postOptions.value = data.posts; | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  | const getInfoForm = () => { | ||||||
|  |   return form.value; | ||||||
|  | }; | ||||||
|  | onMounted(() => { | ||||||
|  |   getDeptTree(); | ||||||
|  | }); | ||||||
|  | defineExpose({ open, getInfoForm }); | ||||||
|  | </script> | ||||||
|  | <style lang="scss" scoped> | ||||||
|  | .editInfo { | ||||||
|  |   position: relative; | ||||||
|  |   height: 100%; | ||||||
|  |   .box_submit { | ||||||
|  |     position: absolute; | ||||||
|  |     right: 10px; | ||||||
|  |     bottom: 10px; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </style> | ||||||
							
								
								
									
										477
									
								
								src/views/system/user/comm/roleInfo.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										477
									
								
								src/views/system/user/comm/roleInfo.vue
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,477 @@ | |||||||
|  | <template> | ||||||
|  |   <div class="roleInfo"> | ||||||
|  |     <div class="title_detail"> | ||||||
|  |       <span>当前选定角色信息预览</span> | ||||||
|  |       <div style="margin-top: 10px"> | ||||||
|  |         <el-table :data="roleList" border height="150"> | ||||||
|  |           <el-table-column label="所属部门" align="center" prop="deptName" /> | ||||||
|  |           <el-table-column label="关联项目" align="center" prop="projectName" /> | ||||||
|  |           <el-table-column label="web端担任角色" align="center" prop="webRoles" /> | ||||||
|  |           <el-table-column label="APP端担任角色" align="center" prop="appRoles" /> | ||||||
|  |         </el-table> | ||||||
|  |       </div> | ||||||
|  |     </div> | ||||||
|  |     <div class="title_detail" style="margin-top: 20px"> | ||||||
|  |       <span>选择或修改当前角色信息</span> | ||||||
|  |       <div style="margin-top: 10px" class="box_detail"> | ||||||
|  |         <!-- 项目列表选择区 --> | ||||||
|  |         <div class="project_list"> | ||||||
|  |           <span>关联项目模块</span> | ||||||
|  |           <div class="project-items"> | ||||||
|  |             <div | ||||||
|  |               v-for="item in projectOptions" | ||||||
|  |               :key="item.id" | ||||||
|  |               class="project-item" | ||||||
|  |               :class="{ 'project-item-selected': isProjectSelected(item.id) }" | ||||||
|  |               @click="toggleProjectSelection(item)" | ||||||
|  |             > | ||||||
|  |               <div class="project-item-content"> | ||||||
|  |                 <el-checkbox v-model="item.checked" :value="item.id" class="project-checkbox" @change="handleProjectCheck(item, $event)" /> | ||||||
|  |                 <span class="project-name">{{ item.projectName }}</span> | ||||||
|  |               </div> | ||||||
|  |             </div> | ||||||
|  |           </div> | ||||||
|  |         </div> | ||||||
|  |         <!-- 角色分配区 --> | ||||||
|  |         <div class="post_list"> | ||||||
|  |           <span>关联项目角色分配</span> | ||||||
|  |           <div v-if="selectedProjects.length === 0" class="no-selection">请从左侧选择项目进行角色分配</div> | ||||||
|  |           <div v-for="(project, index) in selectedProjects" :key="project.id" class="project-role-container"> | ||||||
|  |             <div class="project-header"> | ||||||
|  |               <span class="project-title">{{ project.projectName }}</span> | ||||||
|  |               <el-button type="text" class="remove-project" @click="removeProject(project.id)"> 移除 </el-button> | ||||||
|  |             </div> | ||||||
|  |             <div class="role-assignment"> | ||||||
|  |               <div class="role-group"> | ||||||
|  |                 <label class="role-label">web端角色:</label> | ||||||
|  |                 <el-checkbox-group v-model="project.webRoles" @change="updateRoleList"> | ||||||
|  |                   <el-checkbox v-for="role in allRoles" :key="role.roleId" :value="role.roleId"> | ||||||
|  |                     {{ role.roleName }} | ||||||
|  |                   </el-checkbox> | ||||||
|  |                 </el-checkbox-group> | ||||||
|  |               </div> | ||||||
|  |               <div class="role-group"> | ||||||
|  |                 <label class="role-label">APP端角色:</label> | ||||||
|  |                 <el-checkbox-group v-model="project.appRoles" @change="updateRoleList"> | ||||||
|  |                   <el-checkbox v-for="role in AppRoles" :key="role.roleId" :value="role.roleId"> | ||||||
|  |                     {{ role.roleName }} | ||||||
|  |                   </el-checkbox> | ||||||
|  |                 </el-checkbox-group> | ||||||
|  |               </div> | ||||||
|  |             </div> | ||||||
|  |           </div> | ||||||
|  |         </div> | ||||||
|  |       </div> | ||||||
|  |     </div> | ||||||
|  |     <div class="box_submit"> | ||||||
|  |       <el-button type="primary" @click="submitForm">确 定</el-button> | ||||||
|  |       <el-button @click="cancel()">取 消</el-button> | ||||||
|  |     </div> | ||||||
|  |   </div> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script setup name="RoleProjectManagement" lang="ts"> | ||||||
|  | import { ref, reactive, toRefs, getCurrentInstance, ComponentInternalInstance, defineExpose, watch } from 'vue'; | ||||||
|  | import { ElFormInstance } from 'element-plus'; | ||||||
|  | import api from '@/api/system/user'; | ||||||
|  | import { listProject } from '@/api/project/project'; | ||||||
|  | import { getRoleList } from '@/api/system/post'; | ||||||
|  |  | ||||||
|  | // 类型定义 | ||||||
|  | interface Project { | ||||||
|  |   id: number | string; | ||||||
|  |   projectName: string; | ||||||
|  |   checked: boolean; | ||||||
|  |   webRoles: string[]; | ||||||
|  |   appRoles: string[]; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | interface Role { | ||||||
|  |   roleId: number | string; | ||||||
|  |   roleName: string; | ||||||
|  |   roleSort?: number; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | interface RoleInfo { | ||||||
|  |   userNick: string; | ||||||
|  |   deptName: string; | ||||||
|  |   postName: string; | ||||||
|  |   projectName: string; | ||||||
|  |   webRoles: string; | ||||||
|  |   appRoles: string; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // 组件实例 | ||||||
|  | const { proxy } = getCurrentInstance() as ComponentInternalInstance; | ||||||
|  |  | ||||||
|  | // 响应式数据 | ||||||
|  | const projectOptions = ref<Project[]>([]); | ||||||
|  | const selectedProjects = ref<Project[]>([]); | ||||||
|  | const allRoles = ref<Role[]>([]); // web端角色 | ||||||
|  | const AppRoles = ref<Role[]>([]); // APP端角色 | ||||||
|  | const roleList = ref<RoleInfo[]>([]); | ||||||
|  | // 表单初始数据 | ||||||
|  | const initFormData = { | ||||||
|  |   userId: undefined, | ||||||
|  |   deptId: undefined, | ||||||
|  |   userName: '', | ||||||
|  |   nickName: undefined, | ||||||
|  |   password: '', | ||||||
|  |   phonenumber: undefined, | ||||||
|  |   email: undefined, | ||||||
|  |   sex: undefined, | ||||||
|  |   projectRoles: [] as Array<{ projectId: number | string; webRoles: string[]; appRoles: string[] }>, | ||||||
|  |   status: '0', | ||||||
|  |   remark: '', | ||||||
|  |   postIds: [], | ||||||
|  |   filePath: undefined, | ||||||
|  |   deptName: '' // 新增部门名称字段 | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | const data = reactive({ | ||||||
|  |   form: { ...initFormData } | ||||||
|  | }); | ||||||
|  | const deptName = ref(''); | ||||||
|  | const { form } = toRefs(data); | ||||||
|  |  | ||||||
|  | // 核心方法:更新预览列表 | ||||||
|  | const updateRoleList = () => { | ||||||
|  |   if (selectedProjects.value.length === 0) { | ||||||
|  |     roleList.value = []; | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |   roleList.value = selectedProjects.value.map((project) => { | ||||||
|  |     // 处理web端角色名称 | ||||||
|  |     var webRoleNames = project.webRoles | ||||||
|  |       .map((roleId) => { | ||||||
|  |         const role = allRoles.value.find((r) => r.roleId === roleId); | ||||||
|  |         return role ? role.roleName : ''; | ||||||
|  |       }) | ||||||
|  |       .filter(Boolean); | ||||||
|  |  | ||||||
|  |     // 处理APP端角色名称 | ||||||
|  |     var appRoleNames = project.appRoles | ||||||
|  |       .map((roleId) => { | ||||||
|  |         const role = AppRoles.value.find((r) => r.roleId === roleId); | ||||||
|  |         return role ? role.roleName : ''; | ||||||
|  |       }) | ||||||
|  |       .filter(Boolean); | ||||||
|  |     webRoleNames = [...new Set(webRoleNames)]; | ||||||
|  |     appRoleNames = [...new Set(appRoleNames)]; | ||||||
|  |     return { | ||||||
|  |       deptName: deptName.value, | ||||||
|  |       projectName: project.projectName, | ||||||
|  |       webRoles: webRoleNames.length > 0 ? webRoleNames.join(',') : '无', | ||||||
|  |       appRoles: appRoleNames.length > 0 ? appRoleNames.join(',') : '无' | ||||||
|  |     }; | ||||||
|  |   }); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | // 监听已选项目变化,自动更新预览列表 | ||||||
|  | watch( | ||||||
|  |   selectedProjects, | ||||||
|  |   () => { | ||||||
|  |     updateRoleList(); | ||||||
|  |   }, | ||||||
|  |   { deep: true } | ||||||
|  | ); | ||||||
|  |  | ||||||
|  | // 检查项目是否被选中 | ||||||
|  | const isProjectSelected = (projectId: number | string) => { | ||||||
|  |   return selectedProjects.value.some((p) => p.id === projectId); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | // 切换项目选择状态 | ||||||
|  | const toggleProjectSelection = (project: Project) => { | ||||||
|  |   // handleProjectCheck(project, !project.checked); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | // 处理项目勾选状态变化 | ||||||
|  | const handleProjectCheck = (project: Project, checked: boolean) => { | ||||||
|  |   // project.checked = checked; | ||||||
|  |   const index = selectedProjects.value.findIndex((p) => p.id === project.id); | ||||||
|  |  | ||||||
|  |   if (checked && index === -1) { | ||||||
|  |     // 添加选中的项目 | ||||||
|  |     selectedProjects.value.push({ | ||||||
|  |       ...project, | ||||||
|  |       webRoles: [], | ||||||
|  |       appRoles: [] | ||||||
|  |     }); | ||||||
|  |   } else if (!checked && index !== -1) { | ||||||
|  |     // 移除取消选中的项目 | ||||||
|  |     selectedProjects.value.splice(index, 1); | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | // 移除项目 | ||||||
|  | const removeProject = (projectId: number | string) => { | ||||||
|  |   // 更新选中项目列表 | ||||||
|  |   selectedProjects.value = selectedProjects.value.filter((p) => p.id !== projectId); | ||||||
|  |  | ||||||
|  |   // 更新项目选项的勾选状态 | ||||||
|  |   const project = projectOptions.value.find((p) => p.id === projectId); | ||||||
|  |   if (project) { | ||||||
|  |     project.checked = false; | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | // 提交表单 | ||||||
|  | const submitForm = async () => { | ||||||
|  |   // 整理项目角色数据 | ||||||
|  |   form.value.projectRoles = selectedProjects.value.map((project) => ({ | ||||||
|  |     projectId: project.id, | ||||||
|  |     roleIds: [...new Set(project.webRoles), ...new Set(project.appRoles)] | ||||||
|  |   })); | ||||||
|  |   // 提交数据 | ||||||
|  |   try { | ||||||
|  |     if (form.value.userId) { | ||||||
|  |       await api.updateUser(form.value); | ||||||
|  |     } else { | ||||||
|  |       await api.addUser(form.value); | ||||||
|  |     } | ||||||
|  |     proxy?.$modal.msgSuccess('操作成功'); | ||||||
|  |     proxy?.$emit('submit', form.value); | ||||||
|  |     cancel(); | ||||||
|  |   } catch (error) { | ||||||
|  |     proxy?.$modal.msgError('操作失败,请重试'); | ||||||
|  |     console.error('提交失败:', error); | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | // 取消操作 | ||||||
|  | const cancel = () => { | ||||||
|  |   resetForm(); | ||||||
|  |   proxy?.$emit('close'); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | // 重置表单 | ||||||
|  | const resetForm = () => { | ||||||
|  |   data.form = { ...initFormData }; | ||||||
|  |   projectOptions.value.forEach((p) => (p.checked = false)); | ||||||
|  |   selectedProjects.value = []; | ||||||
|  |   roleList.value = []; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | // 初始化数据 | ||||||
|  | const initData = async () => { | ||||||
|  |   try { | ||||||
|  |     // 获取项目列表 | ||||||
|  |     const projectRes = await listProject(); | ||||||
|  |     projectOptions.value = projectRes.rows.map((item: any) => ({ | ||||||
|  |       id: item.id, | ||||||
|  |       projectName: item.projectName, | ||||||
|  |       checked: false | ||||||
|  |     })); | ||||||
|  |   } catch (error) { | ||||||
|  |     proxy?.$modal.msgError('数据加载失败'); | ||||||
|  |     console.error('初始化数据失败:', error); | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  | // 打开弹窗时调用 | ||||||
|  | const open = async (row?: any, deptId?: any) => { | ||||||
|  |   resetForm(); | ||||||
|  |   await initData(); | ||||||
|  |   deptName.value = row.deptName; | ||||||
|  |   console.log(row); | ||||||
|  |   if (row) { | ||||||
|  |     try { | ||||||
|  |       if (!row.createTime) { | ||||||
|  |         form.value = { ...row }; | ||||||
|  |         // 获取角色列表 | ||||||
|  |         if (form.value.deptId) { | ||||||
|  |           deptId = form.value.deptId; | ||||||
|  |         } | ||||||
|  |         const roleRes = await getRoleList(deptId); | ||||||
|  |         allRoles.value = roleRes.data.filter((item: Role) => item.roleSort === 1); | ||||||
|  |         AppRoles.value = roleRes.data.filter((item: Role) => item.roleSort !== 1); | ||||||
|  |       } else { | ||||||
|  |         const { data } = await api.getUser(row.userId); | ||||||
|  |         Object.assign(form.value, data.user); | ||||||
|  |         // 获取角色列表 | ||||||
|  |         if (form.value.deptId) { | ||||||
|  |           deptId = form.value.deptId; | ||||||
|  |         } | ||||||
|  |         const roleRes = await getRoleList(deptId); | ||||||
|  |         // 区分web端和app端角色 | ||||||
|  |         allRoles.value = roleRes.data.filter((item: Role) => item.roleSort === 1); | ||||||
|  |         AppRoles.value = roleRes.data.filter((item: Role) => item.roleSort !== 1); | ||||||
|  |         // 加载项目角色数据 | ||||||
|  |         if (data.projectRoles && data.projectRoles.length) { | ||||||
|  |           data.projectRoles.forEach((pr: any) => { | ||||||
|  |             const project = projectOptions.value.find((p) => p.id === pr.projectId); | ||||||
|  |             if (project) { | ||||||
|  |               project.checked = true; | ||||||
|  |               selectedProjects.value.push({ | ||||||
|  |                 ...project, | ||||||
|  |                 webRoles: pr.roleIds || [], | ||||||
|  |                 appRoles: pr.roleIds || [] | ||||||
|  |               }); | ||||||
|  |             } | ||||||
|  |           }); | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } catch (error) { | ||||||
|  |       proxy?.$modal.msgError('加载用户数据失败'); | ||||||
|  |       console.error('加载用户数据失败:', error); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | // 暴露方法 | ||||||
|  | defineExpose({ open }); | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style lang="scss"> | ||||||
|  | .roleInfo { | ||||||
|  |   position: relative; | ||||||
|  |   height: 100%; | ||||||
|  |   padding-bottom: 60px; | ||||||
|  |   box-sizing: border-box; | ||||||
|  |  | ||||||
|  |   .title_detail { | ||||||
|  |     > span { | ||||||
|  |       font-size: 16px; | ||||||
|  |       font-weight: 600; | ||||||
|  |       color: #333; | ||||||
|  |       display: inline-block; | ||||||
|  |       padding-bottom: 5px; | ||||||
|  |       border-bottom: 2px solid #409eff; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     .box_detail { | ||||||
|  |       display: flex; | ||||||
|  |       gap: 15px; | ||||||
|  |       margin-top: 15px; | ||||||
|  |  | ||||||
|  |       > div { | ||||||
|  |         height: 350px; | ||||||
|  |         padding: 15px; | ||||||
|  |         border-radius: 4px; | ||||||
|  |         box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); | ||||||
|  |         overflow-y: auto; | ||||||
|  |         box-sizing: border-box; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       .project_list { | ||||||
|  |         width: 320px; | ||||||
|  |         background-color: #fff; | ||||||
|  |  | ||||||
|  |         .project-items { | ||||||
|  |           margin-top: 10px; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         .project-item { | ||||||
|  |           padding: 10px 12px; | ||||||
|  |           margin-bottom: 8px; | ||||||
|  |           border-radius: 4px; | ||||||
|  |           cursor: pointer; | ||||||
|  |           transition: all 0.2s ease; | ||||||
|  |           border: 1px solid #eee; | ||||||
|  |  | ||||||
|  |           &:hover { | ||||||
|  |             background-color: #f5f7fa; | ||||||
|  |             border-color: #e4e7ed; | ||||||
|  |           } | ||||||
|  |  | ||||||
|  |           .project-item-content { | ||||||
|  |             display: flex; | ||||||
|  |             align-items: center; | ||||||
|  |           } | ||||||
|  |  | ||||||
|  |           .project-checkbox { | ||||||
|  |             margin-right: 8px; | ||||||
|  |           } | ||||||
|  |  | ||||||
|  |           .project-name { | ||||||
|  |             flex: 1; | ||||||
|  |             white-space: nowrap; | ||||||
|  |             overflow: hidden; | ||||||
|  |             text-overflow: ellipsis; | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         .project-item-selected { | ||||||
|  |           background-color: #ecf5ff; | ||||||
|  |           border-color: #c6e2ff; | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       .post_list { | ||||||
|  |         flex: 1; | ||||||
|  |         background-color: #fff; | ||||||
|  |  | ||||||
|  |         .no-selection { | ||||||
|  |           height: 100%; | ||||||
|  |           display: flex; | ||||||
|  |           align-items: center; | ||||||
|  |           justify-content: center; | ||||||
|  |           color: #909399; | ||||||
|  |           font-size: 14px; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         .project-role-container { | ||||||
|  |           padding: 15px; | ||||||
|  |           margin-bottom: 15px; | ||||||
|  |           background-color: #f9f9f9; | ||||||
|  |           border-radius: 4px; | ||||||
|  |           border: 1px solid #f0f0f0; | ||||||
|  |  | ||||||
|  |           .project-header { | ||||||
|  |             display: flex; | ||||||
|  |             justify-content: space-between; | ||||||
|  |             align-items: center; | ||||||
|  |             margin-bottom: 15px; | ||||||
|  |  | ||||||
|  |             .project-title { | ||||||
|  |               font-weight: 500; | ||||||
|  |               color: #333; | ||||||
|  |               font-size: 14px; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             .remove-project { | ||||||
|  |               color: #f56c6c; | ||||||
|  |               padding: 0 5px; | ||||||
|  |  | ||||||
|  |               &:hover { | ||||||
|  |                 color: #e4393c; | ||||||
|  |               } | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |  | ||||||
|  |           .role-assignment { | ||||||
|  |             .role-group { | ||||||
|  |               margin-bottom: 15px; | ||||||
|  |  | ||||||
|  |               .role-label { | ||||||
|  |                 display: inline-block; | ||||||
|  |                 width: 110px; | ||||||
|  |                 color: #606266; | ||||||
|  |                 font-size: 14px; | ||||||
|  |               } | ||||||
|  |  | ||||||
|  |               .el-checkbox-group { | ||||||
|  |                 display: inline-block; | ||||||
|  |                 margin-left: 10px; | ||||||
|  |  | ||||||
|  |                 .el-checkbox { | ||||||
|  |                   margin-right: 15px; | ||||||
|  |                   margin-bottom: 8px; | ||||||
|  |                 } | ||||||
|  |               } | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   .box_submit { | ||||||
|  |     position: absolute; | ||||||
|  |     right: 20px; | ||||||
|  |     bottom: 0px; | ||||||
|  |     display: flex; | ||||||
|  |     gap: 10px; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </style> | ||||||
							
								
								
									
										788
									
								
								src/views/system/user/index copy.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										788
									
								
								src/views/system/user/index copy.vue
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,788 @@ | |||||||
|  | <template> | ||||||
|  |   <div class="p-2"> | ||||||
|  |     <el-row :gutter="20"> | ||||||
|  |       <!-- 部门树 --> | ||||||
|  |       <el-col :lg="4" :xs="24" style=""> | ||||||
|  |         <el-card shadow="hover"> | ||||||
|  |           <el-input v-model="deptName" placeholder="请输入部门名称" prefix-icon="Search" clearable /> | ||||||
|  |           <el-tree | ||||||
|  |             ref="deptTreeRef" | ||||||
|  |             class="mt-2" | ||||||
|  |             node-key="id" | ||||||
|  |             :data="deptOptions" | ||||||
|  |             :props="{ label: 'label', children: 'children' }" | ||||||
|  |             :expand-on-click-node="false" | ||||||
|  |             :filter-node-method="filterNode" | ||||||
|  |             highlight-current | ||||||
|  |             default-expand-all | ||||||
|  |             @node-click="handleNodeClick" | ||||||
|  |           /> | ||||||
|  |         </el-card> | ||||||
|  |       </el-col> | ||||||
|  |       <el-col :lg="20" :xs="24"> | ||||||
|  |         <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="phonenumber"> | ||||||
|  |                   <el-input v-model="queryParams.phonenumber" placeholder="请输入手机号码" clearable @keyup.enter="handleQuery" /> | ||||||
|  |                 </el-form-item> | ||||||
|  |  | ||||||
|  |                 <el-form-item label="状态" prop="status"> | ||||||
|  |                   <el-select v-model="queryParams.status" placeholder="用户状态" clearable> | ||||||
|  |                     <el-option v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" /> | ||||||
|  |                   </el-select> | ||||||
|  |                 </el-form-item> | ||||||
|  |                 <el-form-item label="创建时间" style="width: 308px"> | ||||||
|  |                   <el-date-picker | ||||||
|  |                     v-model="dateRange" | ||||||
|  |                     value-format="YYYY-MM-DD HH:mm:ss" | ||||||
|  |                     type="daterange" | ||||||
|  |                     range-separator="-" | ||||||
|  |                     start-placeholder="开始日期" | ||||||
|  |                     end-placeholder="结束日期" | ||||||
|  |                     :default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]" | ||||||
|  |                   ></el-date-picker> | ||||||
|  |                 </el-form-item> | ||||||
|  |                 <el-form-item> | ||||||
|  |                   <el-button type="primary" icon="Search" @click="handleQuery" @v-has-permi="['system:user:query']">搜索</el-button> | ||||||
|  |  | ||||||
|  |                   <el-button icon="Refresh" @click="resetQuery">重置</el-button> | ||||||
|  |                 </el-form-item> | ||||||
|  |               </el-form> | ||||||
|  |             </el-card> | ||||||
|  |           </div> | ||||||
|  |         </transition> | ||||||
|  |  | ||||||
|  |         <el-card shadow="hover"> | ||||||
|  |           <template #header> | ||||||
|  |             <el-row :gutter="10"> | ||||||
|  |               <el-col :span="1.5"> | ||||||
|  |                 <el-button v-has-permi="['system:user:add']" type="primary" plain icon="Plus" @click="handleAdd()"> 新增 </el-button> | ||||||
|  |               </el-col> | ||||||
|  |               <el-col :span="1.5"> | ||||||
|  |                 <el-button v-has-permi="['system:user:edit']" type="success" plain :disabled="single" icon="Edit" @click="handleUpdate()"> | ||||||
|  |                   修改 | ||||||
|  |                 </el-button> | ||||||
|  |               </el-col> | ||||||
|  |               <el-col :span="1.5"> | ||||||
|  |                 <el-button v-has-permi="['system:user:remove']" type="danger" plain :disabled="multiple" icon="Delete" @click="handleDelete()"> | ||||||
|  |                   删除 | ||||||
|  |                 </el-button> | ||||||
|  |               </el-col> | ||||||
|  |               <el-col :span="1.5"> | ||||||
|  |                 <el-dropdown class="mt-[1px]"> | ||||||
|  |                   <el-button plain type="info"> | ||||||
|  |                     更多 | ||||||
|  |                     <el-icon class="el-icon--right"> | ||||||
|  |                       <arrow-down /> | ||||||
|  |                     </el-icon> | ||||||
|  |                   </el-button> | ||||||
|  |                   <template #dropdown> | ||||||
|  |                     <el-dropdown-menu> | ||||||
|  |                       <el-dropdown-item icon="Download" @click="importTemplate">下载模板</el-dropdown-item> | ||||||
|  |                       <el-dropdown-item v-has-permi="['system:user:import']" icon="Top" @click="handleImport">导入数据 </el-dropdown-item> | ||||||
|  |                       <el-dropdown-item v-has-permi="['system:user:export']" icon="Download" @click="handleExport"> 导出数据 </el-dropdown-item> | ||||||
|  |                     </el-dropdown-menu> | ||||||
|  |                   </template> | ||||||
|  |                 </el-dropdown> | ||||||
|  |               </el-col> | ||||||
|  |               <right-toolbar v-model:show-search="showSearch" :columns="columns" :search="true" @query-table="getList"></right-toolbar> | ||||||
|  |             </el-row> | ||||||
|  |           </template> | ||||||
|  |  | ||||||
|  |           <el-table v-loading="loading" :data="userList" @selection-change="handleSelectionChange"> | ||||||
|  |             <el-table-column type="selection" width="50" align="center" /> | ||||||
|  |             <el-table-column v-if="columns[0].visible" key="userId" label="用户编号" align="center" prop="userId" /> | ||||||
|  |             <el-table-column v-if="columns[1].visible" key="userName" label="用户名称" align="center" prop="userName" :show-overflow-tooltip="true" /> | ||||||
|  |             <el-table-column v-if="columns[2].visible" key="nickName" label="用户昵称" align="center" prop="nickName" :show-overflow-tooltip="true" /> | ||||||
|  |             <el-table-column v-if="columns[3].visible" key="deptName" label="部门" align="center" prop="deptName" :show-overflow-tooltip="true" /> | ||||||
|  |             <el-table-column v-if="columns[4].visible" key="phonenumber" label="手机号码" align="center" prop="phonenumber" width="120" /> | ||||||
|  |             <el-table-column v-if="columns[5].visible" key="status" label="状态" align="center"> | ||||||
|  |               <template #default="scope"> | ||||||
|  |                 <el-switch v-model="scope.row.status" active-value="0" inactive-value="1" @change="handleStatusChange(scope.row)"></el-switch> | ||||||
|  |               </template> | ||||||
|  |             </el-table-column> | ||||||
|  |  | ||||||
|  |             <el-table-column v-if="columns[6].visible" label="创建时间" align="center" prop="createTime" width="160"> | ||||||
|  |               <template #default="scope"> | ||||||
|  |                 <span>{{ scope.row.createTime }}</span> | ||||||
|  |               </template> | ||||||
|  |             </el-table-column> | ||||||
|  |  | ||||||
|  |             <el-table-column label="操作" fixed="right" width="230" class-name="small-padding fixed-width"> | ||||||
|  |               <template #default="scope"> | ||||||
|  |                 <el-tooltip v-if="scope.row.userId !== 1" content="修改" placement="top"> | ||||||
|  |                   <el-button v-hasPermi="['system:user:edit']" link type="primary" icon="Edit" @click="handleUpdate(scope.row)"></el-button> | ||||||
|  |                 </el-tooltip> | ||||||
|  |                 <el-tooltip v-if="scope.row.userId !== 1" content="删除" placement="top"> | ||||||
|  |                   <el-button v-hasPermi="['system:user:remove']" link type="primary" icon="Delete" @click="handleDelete(scope.row)"></el-button> | ||||||
|  |                 </el-tooltip> | ||||||
|  |  | ||||||
|  |                 <el-tooltip v-if="scope.row.userId !== 1" content="重置密码" placement="top"> | ||||||
|  |                   <el-button v-hasPermi="['system:user:resetPwd']" link type="primary" icon="Key" @click="handleResetPwd(scope.row)"></el-button> | ||||||
|  |                 </el-tooltip> | ||||||
|  |  | ||||||
|  |                 <el-tooltip v-if="scope.row.userId !== 1" content="分配角色" placement="top"> | ||||||
|  |                   <el-button v-hasPermi="['system:user:edit']" link type="primary" icon="CircleCheck" @click="handleAuthRole(scope.row)"></el-button> | ||||||
|  |                 </el-tooltip> | ||||||
|  |                 <el-tooltip v-if="scope.row.userId !== 1" content="编辑关联项目" placement="top"> | ||||||
|  |                   <el-button v-hasPermi="['system:user:edit']" link type="primary" icon="Edit" @click="handleUpdateProject(scope.row)"></el-button> | ||||||
|  |                 </el-tooltip> | ||||||
|  |                 <el-tooltip v-if="scope.row.userId !== 1" content="上传证书目录" placement="top"> | ||||||
|  |                   <el-button v-hasPermi="['system:user:edit']" link type="primary" icon="Upload" @click="handleUploadCert(scope.row)"></el-button> | ||||||
|  |                 </el-tooltip> | ||||||
|  |               </template> | ||||||
|  |             </el-table-column> | ||||||
|  |           </el-table> | ||||||
|  |           <el-dialog v-model="shuttleVisible" title="编辑关联项目" width="auto" destroy-on-close> | ||||||
|  |             <shuttle-frame :userId="selectedUserId" @close="shuttleVisible = false" /> | ||||||
|  |           </el-dialog> | ||||||
|  |  | ||||||
|  |           <pagination | ||||||
|  |             v-show="total > 0" | ||||||
|  |             v-model:page="queryParams.pageNum" | ||||||
|  |             v-model:limit="queryParams.pageSize" | ||||||
|  |             :total="total" | ||||||
|  |             @pagination="getList" | ||||||
|  |           /> | ||||||
|  |         </el-card> | ||||||
|  |       </el-col> | ||||||
|  |     </el-row> | ||||||
|  |  | ||||||
|  |     <!-- 添加或修改用户配置对话框 --> | ||||||
|  |     <el-dialog draggable ref="formDialogRef" v-model="dialog.visible" :title="dialog.title" width="600px" append-to-body @close="closeDialog"> | ||||||
|  |       <el-form ref="userFormRef" :model="form" :rules="rules" label-width="80px"> | ||||||
|  |         <el-row> | ||||||
|  |           <el-col :span="12"> | ||||||
|  |             <el-form-item label="用户昵称" prop="nickName"> | ||||||
|  |               <el-input v-model="form.nickName" placeholder="请输入用户昵称" maxlength="30" /> | ||||||
|  |             </el-form-item> | ||||||
|  |           </el-col> | ||||||
|  |           <el-col :span="12"> | ||||||
|  |             <el-form-item label="归属部门" prop="deptId"> | ||||||
|  |               <el-tree-select | ||||||
|  |                 v-model="form.deptId" | ||||||
|  |                 :data="enabledDeptOptions" | ||||||
|  |                 :props="{ value: 'id', label: 'label', children: 'children' }" | ||||||
|  |                 value-key="id" | ||||||
|  |                 placeholder="请选择归属部门" | ||||||
|  |                 check-strictly | ||||||
|  |                 @change="handleDeptChange" | ||||||
|  |               /> | ||||||
|  |             </el-form-item> | ||||||
|  |           </el-col> | ||||||
|  |           <el-col :span="12"> | ||||||
|  |             <el-form-item label="手机号码" prop="phonenumber"> | ||||||
|  |               <el-input v-model="form.phonenumber" placeholder="请输入手机号码" maxlength="11" /> | ||||||
|  |             </el-form-item> | ||||||
|  |           </el-col> | ||||||
|  |           <el-col :span="12"> | ||||||
|  |             <el-form-item label="邮箱" prop="email"> | ||||||
|  |               <el-input v-model="form.email" placeholder="请输入邮箱" maxlength="50" /> | ||||||
|  |             </el-form-item> | ||||||
|  |           </el-col> | ||||||
|  |           <el-col :span="12"> | ||||||
|  |             <el-form-item v-if="form.userId == undefined" label="用户名称" prop="userName"> | ||||||
|  |               <el-input v-model="form.userName" placeholder="请输入用户名称" maxlength="30" /> | ||||||
|  |             </el-form-item> | ||||||
|  |           </el-col> | ||||||
|  |           <el-col :span="12"> | ||||||
|  |             <el-form-item v-if="form.userId == undefined" label="用户密码" prop="password"> | ||||||
|  |               <el-input v-model="form.password" placeholder="请输入用户密码" type="password" maxlength="20" show-password /> | ||||||
|  |             </el-form-item> | ||||||
|  |           </el-col> | ||||||
|  |           <el-col :span="12"> | ||||||
|  |             <el-form-item label="用户性别"> | ||||||
|  |               <el-select v-model="form.sex" placeholder="请选择"> | ||||||
|  |                 <el-option v-for="dict in sys_user_sex" :key="dict.value" :label="dict.label" :value="dict.value"></el-option> | ||||||
|  |               </el-select> | ||||||
|  |             </el-form-item> | ||||||
|  |           </el-col> | ||||||
|  |           <el-col :span="12"> | ||||||
|  |             <el-form-item label="岗位"> | ||||||
|  |               <el-select v-model="form.postIds" multiple placeholder="请选择"> | ||||||
|  |                 <el-option | ||||||
|  |                   v-for="item in postOptions" | ||||||
|  |                   :key="item.postId" | ||||||
|  |                   :label="item.postName" | ||||||
|  |                   :value="item.postId" | ||||||
|  |                   :disabled="item.status == '1'" | ||||||
|  |                 ></el-option> | ||||||
|  |               </el-select> | ||||||
|  |             </el-form-item> | ||||||
|  |           </el-col> | ||||||
|  |           <el-col :span="24"> | ||||||
|  |             <el-row :gutter="20" v-for="(item, index) in form.projectRoles"> | ||||||
|  |               <el-col :span="11" :offset="0"> | ||||||
|  |                 <el-form-item label="项目列表"> | ||||||
|  |                   <el-select v-model="item.projectId" placeholder="请选择"> | ||||||
|  |                     <el-option v-for="dict in projectOptions" :key="dict.id" :label="dict.shortName" :value="dict.id"></el-option> | ||||||
|  |                   </el-select> | ||||||
|  |                 </el-form-item> | ||||||
|  |               </el-col> | ||||||
|  |               <el-col :span="11" :offset="0"> | ||||||
|  |                 <el-form-item label="角色"> | ||||||
|  |                   <el-select v-model="item.roleIds" filterable multiple placeholder="请选择"> | ||||||
|  |                     <el-option | ||||||
|  |                       v-for="item in roleOptions" | ||||||
|  |                       :key="item.roleId" | ||||||
|  |                       :label="item.roleName" | ||||||
|  |                       :value="item.roleId" | ||||||
|  |                       :disabled="item.status == '1'" | ||||||
|  |                     ></el-option> | ||||||
|  |                   </el-select> | ||||||
|  |                 </el-form-item> | ||||||
|  |               </el-col> | ||||||
|  |               <el-col :span="1" :offset="0"> | ||||||
|  |                 <el-button type="primary" circle icon="Plus" @click="handleAddProject" v-if="index == 0"></el-button> | ||||||
|  |                 <el-button type="danger" circle icon="Delete" @click="delProject(index)" v-else></el-button> | ||||||
|  |               </el-col> | ||||||
|  |             </el-row> | ||||||
|  |           </el-col> | ||||||
|  |           <el-col :span="12"> | ||||||
|  |             <el-form-item label="状态"> | ||||||
|  |               <el-radio-group v-model="form.status"> | ||||||
|  |                 <el-radio v-for="dict in sys_normal_disable" :key="dict.value" :value="dict.value">{{ dict.label }} </el-radio> | ||||||
|  |               </el-radio-group> | ||||||
|  |             </el-form-item> | ||||||
|  |           </el-col> | ||||||
|  |           <el-col :span="24"> | ||||||
|  |             <el-form-item label="备注"> | ||||||
|  |               <el-input v-model="form.remark" type="textarea" placeholder="请输入内容"></el-input> | ||||||
|  |             </el-form-item> | ||||||
|  |           </el-col> | ||||||
|  |         </el-row> | ||||||
|  |       </el-form> | ||||||
|  |       <template #footer> | ||||||
|  |         <div class="dialog-footer"> | ||||||
|  |           <el-button type="primary" @click="submitForm">确 定</el-button> | ||||||
|  |           <el-button @click="cancel()">取 消</el-button> | ||||||
|  |         </div> | ||||||
|  |       </template> | ||||||
|  |     </el-dialog> | ||||||
|  |  | ||||||
|  |     <!-- 用户导入对话框 --> | ||||||
|  |     <el-dialog draggable v-model="upload.open" :title="upload.title" width="400px" append-to-body> | ||||||
|  |       <el-upload | ||||||
|  |         ref="uploadRef" | ||||||
|  |         :limit="1" | ||||||
|  |         accept=".xlsx, .xls" | ||||||
|  |         :headers="upload.headers" | ||||||
|  |         :action="upload.url + '?updateSupport=' + upload.updateSupport" | ||||||
|  |         :disabled="upload.isUploading" | ||||||
|  |         :on-progress="handleFileUploadProgress" | ||||||
|  |         :on-success="handleFileSuccess" | ||||||
|  |         :auto-upload="false" | ||||||
|  |         drag | ||||||
|  |       > | ||||||
|  |         <el-icon class="el-icon--upload"> | ||||||
|  |           <i-ep-upload-filled /> | ||||||
|  |         </el-icon> | ||||||
|  |         <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div> | ||||||
|  |         <template #tip> | ||||||
|  |           <div class="text-center el-upload__tip"> | ||||||
|  |             <div class="el-upload__tip"> | ||||||
|  |               <el-checkbox v-model="upload.updateSupport" /> | ||||||
|  |               是否更新已经存在的用户数据 | ||||||
|  |             </div> | ||||||
|  |             <span>仅允许导入xls、xlsx格式文件。</span> | ||||||
|  |             <el-link type="primary" :underline="false" style="font-size: 12px; vertical-align: baseline" @click="importTemplate">下载模板 </el-link> | ||||||
|  |           </div> | ||||||
|  |         </template> | ||||||
|  |       </el-upload> | ||||||
|  |       <template #footer> | ||||||
|  |         <div class="dialog-footer"> | ||||||
|  |           <el-button type="primary" @click="submitFileForm">确 定</el-button> | ||||||
|  |           <el-button @click="upload.open = false">取 消</el-button> | ||||||
|  |         </div> | ||||||
|  |       </template> | ||||||
|  |     </el-dialog> | ||||||
|  |  | ||||||
|  |     <el-dialog title="上传证书目录" v-model="certDialog" width="30%" destroy-on-close> | ||||||
|  |       <!-- <File-upload v-model="fileUpload" :limit="5"></File-upload> --> | ||||||
|  |       <ImageUpload v-model="fileUpload" :limit="5"></ImageUpload> | ||||||
|  |       <template #footer> | ||||||
|  |         <span> | ||||||
|  |           <el-button @click="certDialog = false">取消</el-button> | ||||||
|  |           <el-button type="primary" @click="uploadCert">确定</el-button> | ||||||
|  |         </span> | ||||||
|  |       </template> | ||||||
|  |     </el-dialog> | ||||||
|  |   </div> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script setup name="User" lang="ts"> | ||||||
|  | import api, { uploadCertList } from '@/api/system/user'; | ||||||
|  | import { UserForm, UserQuery, UserVO } from '@/api/system/user/types'; | ||||||
|  | import { DeptTreeVO, DeptVO } from '@/api/system/dept/types'; | ||||||
|  | import { RoleVO } from '@/api/system/role/types'; | ||||||
|  | import { PostVO } from '@/api/system/post/types'; | ||||||
|  | import { globalHeaders } from '@/utils/request'; | ||||||
|  | import { to } from 'await-to-js'; | ||||||
|  | import { getProjectByDeptId, getRoleList, optionselect } from '@/api/system/post'; | ||||||
|  | import ShuttleFrame from '../../project/projectRelevancy/component/ShuttleFrame.vue'; | ||||||
|  | import { listProject } from '@/api/project/project'; | ||||||
|  | import editInfo from './comm/editInfo.vue'; | ||||||
|  | const router = useRouter(); | ||||||
|  | const { proxy } = getCurrentInstance() as ComponentInternalInstance; | ||||||
|  | const { sys_normal_disable, sys_user_sex } = toRefs<any>(proxy?.useDict('sys_normal_disable', 'sys_user_sex')); | ||||||
|  | const userList = ref<UserVO[]>(); | ||||||
|  | const loading = ref(true); | ||||||
|  | const showSearch = ref(true); | ||||||
|  | const ids = ref<Array<number | string>>([]); | ||||||
|  | const single = ref(true); | ||||||
|  | const multiple = ref(true); | ||||||
|  | const total = ref(0); | ||||||
|  | const dateRange = ref<[DateModelType, DateModelType]>(['', '']); | ||||||
|  | const deptName = ref(''); | ||||||
|  | const deptOptions = ref<DeptTreeVO[]>([]); | ||||||
|  | const enabledDeptOptions = ref<DeptTreeVO[]>([]); | ||||||
|  | const initPassword = ref<string>(''); | ||||||
|  | const postOptions = ref<PostVO[]>([]); | ||||||
|  | const roleOptions = ref<RoleVO[]>([]); | ||||||
|  | const projectOptions = ref<any[]>([]); | ||||||
|  |  | ||||||
|  | /*** 用户导入参数 */ | ||||||
|  | const upload = reactive<ImportOption>({ | ||||||
|  |   // 是否显示弹出层(用户导入) | ||||||
|  |   open: false, | ||||||
|  |   // 弹出层标题(用户导入) | ||||||
|  |   title: '', | ||||||
|  |   // 是否禁用上传 | ||||||
|  |   isUploading: false, | ||||||
|  |   // 是否更新已经存在的用户数据 | ||||||
|  |   updateSupport: 0, | ||||||
|  |   // 设置上传的请求头部 | ||||||
|  |   headers: globalHeaders(), | ||||||
|  |   // 上传的地址 | ||||||
|  |   url: import.meta.env.VITE_APP_BASE_API + '/system/user/importData' | ||||||
|  | }); | ||||||
|  | // 列显隐信息 | ||||||
|  | const columns = ref<FieldOption[]>([ | ||||||
|  |   { key: 0, label: `用户编号`, visible: false, children: [] }, | ||||||
|  |   { key: 1, label: `用户名称`, visible: true, children: [] }, | ||||||
|  |   { key: 2, label: `用户昵称`, visible: true, children: [] }, | ||||||
|  |   { key: 3, label: `部门`, visible: true, children: [] }, | ||||||
|  |   { key: 4, label: `手机号码`, visible: true, children: [] }, | ||||||
|  |   { key: 5, label: `状态`, visible: true, children: [] }, | ||||||
|  |   { key: 6, label: `创建时间`, visible: true, children: [] } | ||||||
|  | ]); | ||||||
|  |  | ||||||
|  | const deptTreeRef = ref<ElTreeInstance>(); | ||||||
|  | const queryFormRef = ref<ElFormInstance>(); | ||||||
|  | const userFormRef = ref<ElFormInstance>(); | ||||||
|  | const uploadRef = ref<ElUploadInstance>(); | ||||||
|  | const formDialogRef = ref<ElDialogInstance>(); | ||||||
|  |  | ||||||
|  | const dialog = reactive<DialogOption>({ | ||||||
|  |   visible: false, | ||||||
|  |   title: '' | ||||||
|  | }); | ||||||
|  |  | ||||||
|  | const initFormData: UserForm = { | ||||||
|  |   userId: undefined, | ||||||
|  |   deptId: undefined, | ||||||
|  |   userName: '', | ||||||
|  |   nickName: undefined, | ||||||
|  |   password: '', | ||||||
|  |   phonenumber: undefined, | ||||||
|  |   email: undefined, | ||||||
|  |   sex: undefined, | ||||||
|  |   projectRoles: [ | ||||||
|  |     { | ||||||
|  |       projectId: '', | ||||||
|  |       roleIds: [] | ||||||
|  |     } | ||||||
|  |   ], | ||||||
|  |   status: '0', | ||||||
|  |   remark: '', | ||||||
|  |   postIds: [], | ||||||
|  |   filePath: undefined | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | const initData: PageData<UserForm, UserQuery> = { | ||||||
|  |   form: { ...initFormData }, | ||||||
|  |   queryParams: { | ||||||
|  |     pageNum: 1, | ||||||
|  |     pageSize: 10, | ||||||
|  |     userName: '', | ||||||
|  |     phonenumber: '', | ||||||
|  |     status: '', | ||||||
|  |     deptId: '', | ||||||
|  |     roleId: '' | ||||||
|  |   }, | ||||||
|  |   rules: { | ||||||
|  |     userName: [ | ||||||
|  |       { required: true, message: '用户名称不能为空', trigger: 'blur' }, | ||||||
|  |       { | ||||||
|  |         min: 2, | ||||||
|  |         max: 20, | ||||||
|  |         message: '用户名称长度必须介于 2 和 20 之间', | ||||||
|  |         trigger: 'blur' | ||||||
|  |       } | ||||||
|  |     ], | ||||||
|  |     nickName: [{ required: true, message: '用户昵称不能为空', trigger: 'blur' }], | ||||||
|  |     password: [ | ||||||
|  |       { required: true, message: '用户密码不能为空', trigger: 'blur' }, | ||||||
|  |       { | ||||||
|  |         min: 5, | ||||||
|  |         max: 20, | ||||||
|  |         message: '用户密码长度必须介于 5 和 20 之间', | ||||||
|  |         trigger: 'blur' | ||||||
|  |       }, | ||||||
|  |       { pattern: /^[^<>"'|\\]+$/, message: '不能包含非法字符:< > " \' \\ |', trigger: 'blur' } | ||||||
|  |     ], | ||||||
|  |     email: [ | ||||||
|  |       { | ||||||
|  |         type: 'email', | ||||||
|  |         message: '请输入正确的邮箱地址', | ||||||
|  |         trigger: ['blur', 'change'] | ||||||
|  |       } | ||||||
|  |     ], | ||||||
|  |     phonenumber: [ | ||||||
|  |       { required: true, message: '请输入手机号码', trigger: 'blur' }, | ||||||
|  |       { | ||||||
|  |         pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/, | ||||||
|  |         message: '请输入正确的手机号码', | ||||||
|  |         trigger: 'blur' | ||||||
|  |       } | ||||||
|  |     ] | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  | const data = reactive<PageData<UserForm, UserQuery>>(initData); | ||||||
|  |  | ||||||
|  | const { queryParams, form, rules } = toRefs<PageData<UserForm, UserQuery>>(data); | ||||||
|  |  | ||||||
|  | /** 通过条件过滤节点  */ | ||||||
|  | const filterNode = (value: string, data: any) => { | ||||||
|  |   if (!value) return true; | ||||||
|  |   return data.label.indexOf(value) !== -1; | ||||||
|  | }; | ||||||
|  | /** 根据名称筛选部门树 */ | ||||||
|  | watchEffect( | ||||||
|  |   () => { | ||||||
|  |     deptTreeRef.value?.filter(deptName.value); | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     flush: 'post' // watchEffect会在DOM挂载或者更新之前就会触发,此属性控制在DOM元素更新后运行 | ||||||
|  |   } | ||||||
|  | ); | ||||||
|  |  | ||||||
|  | /** 查询用户列表 */ | ||||||
|  | const getList = async () => { | ||||||
|  |   loading.value = true; | ||||||
|  |   const res = await api.listUser(proxy?.addDateRange(queryParams.value, dateRange.value)); | ||||||
|  |   loading.value = false; | ||||||
|  |   userList.value = res.rows; | ||||||
|  |   total.value = res.total; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | /** 查询部门下拉树结构 */ | ||||||
|  | const getDeptTree = async () => { | ||||||
|  |   const res = await api.deptTreeSelect({ isShow: '1' }); | ||||||
|  |   deptOptions.value = res.data; | ||||||
|  |   enabledDeptOptions.value = filterDisabledDept(res.data); | ||||||
|  |   const projectList = await listProject(); | ||||||
|  |   projectOptions.value = projectList.rows; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | /** 过滤禁用的部门 */ | ||||||
|  | const filterDisabledDept = (deptList: DeptTreeVO[]) => { | ||||||
|  |   return deptList.filter((dept) => { | ||||||
|  |     if (dept.disabled) { | ||||||
|  |       return false; | ||||||
|  |     } | ||||||
|  |     if (dept.children && dept.children.length) { | ||||||
|  |       dept.children = filterDisabledDept(dept.children); | ||||||
|  |     } | ||||||
|  |     return true; | ||||||
|  |   }); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | /** 节点单击事件 */ | ||||||
|  | const handleNodeClick = (data: DeptVO) => { | ||||||
|  |   queryParams.value.deptId = data.id; | ||||||
|  |   handleQuery(); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | /** 部门选择变化 */ | ||||||
|  | const handleAddProject = () => { | ||||||
|  |   form.value.projectRoles.push({ | ||||||
|  |     projectId: '', | ||||||
|  |     roleIds: [] | ||||||
|  |   }); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | /** 删除项目 */ | ||||||
|  | const delProject = (index: number) => { | ||||||
|  |   form.value.projectRoles.splice(index, 1); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | /** 搜索按钮操作 */ | ||||||
|  | const handleQuery = () => { | ||||||
|  |   queryParams.value.pageNum = 1; | ||||||
|  |   getList(); | ||||||
|  | }; | ||||||
|  | /** 重置按钮操作 */ | ||||||
|  | const resetQuery = () => { | ||||||
|  |   dateRange.value = ['', '']; | ||||||
|  |   queryFormRef.value?.resetFields(); | ||||||
|  |   queryParams.value.pageNum = 1; | ||||||
|  |   queryParams.value.deptId = undefined; | ||||||
|  |   deptTreeRef.value?.setCurrentKey(undefined); | ||||||
|  |   handleQuery(); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | /** 删除按钮操作 */ | ||||||
|  | const handleDelete = async (row?: UserVO) => { | ||||||
|  |   const userIds = row?.userId || ids.value; | ||||||
|  |   const [err] = await to(proxy?.$modal.confirm('是否确认删除用户编号为"' + userIds + '"的数据项?') as any); | ||||||
|  |   if (!err) { | ||||||
|  |     await api.delUser(userIds); | ||||||
|  |     await getList(); | ||||||
|  |     proxy?.$modal.msgSuccess('删除成功'); | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | /** 用户状态修改  */ | ||||||
|  | const handleStatusChange = async (row: UserVO) => { | ||||||
|  |   let text = row.status === '0' ? '启用' : '停用'; | ||||||
|  |   try { | ||||||
|  |     await proxy?.$modal.confirm('确认要"' + text + '""' + row.userName + '"用户吗?'); | ||||||
|  |     await api.changeUserStatus(row.userId, row.status); | ||||||
|  |     proxy?.$modal.msgSuccess(text + '成功'); | ||||||
|  |   } catch (err) { | ||||||
|  |     row.status = row.status === '0' ? '1' : '0'; | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  | /** 跳转角色分配 */ | ||||||
|  | const handleAuthRole = (row: UserVO) => { | ||||||
|  |   const userId = row.userId; | ||||||
|  |   router.push('/system/user-auth/role/' + userId); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | /** 重置密码按钮操作 */ | ||||||
|  | const handleResetPwd = async (row: UserVO) => { | ||||||
|  |   const [err, res] = await to( | ||||||
|  |     ElMessageBox.prompt('请输入"' + row.userName + '"的新密码', '提示', { | ||||||
|  |       confirmButtonText: '确定', | ||||||
|  |       cancelButtonText: '取消', | ||||||
|  |       closeOnClickModal: false, | ||||||
|  |       inputPattern: /^.{5,20}$/, | ||||||
|  |       inputErrorMessage: '用户密码长度必须介于 5 和 20 之间', | ||||||
|  |       inputValidator: (value) => { | ||||||
|  |         if (/<|>|"|'|\||\\/.test(value)) { | ||||||
|  |           return '不能包含非法字符:< > " \' \\ |'; | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     }) | ||||||
|  |   ); | ||||||
|  |   if (!err && res) { | ||||||
|  |     await api.resetUserPwd(row.userId, res.value); | ||||||
|  |     proxy?.$modal.msgSuccess('修改成功,新密码是:' + res.value); | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | /** 选择条数  */ | ||||||
|  | const handleSelectionChange = (selection: UserVO[]) => { | ||||||
|  |   ids.value = selection.map((item) => item.userId); | ||||||
|  |   single.value = selection.length != 1; | ||||||
|  |   multiple.value = !selection.length; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | /** 导入按钮操作 */ | ||||||
|  | const handleImport = () => { | ||||||
|  |   upload.title = '用户导入'; | ||||||
|  |   upload.open = true; | ||||||
|  | }; | ||||||
|  | /** 导出按钮操作 */ | ||||||
|  | const handleExport = () => { | ||||||
|  |   proxy?.download( | ||||||
|  |     'system/user/export', | ||||||
|  |     { | ||||||
|  |       ...queryParams.value | ||||||
|  |     }, | ||||||
|  |     `user_${new Date().getTime()}.xlsx` | ||||||
|  |   ); | ||||||
|  | }; | ||||||
|  | /** 下载模板操作 */ | ||||||
|  | const importTemplate = () => { | ||||||
|  |   proxy?.download('system/user/importTemplate', {}, `user_template_${new Date().getTime()}.xlsx`); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | /**文件上传中处理 */ | ||||||
|  | const handleFileUploadProgress = () => { | ||||||
|  |   upload.isUploading = true; | ||||||
|  | }; | ||||||
|  | /** 文件上传成功处理 */ | ||||||
|  | const handleFileSuccess = (response: any, file: UploadFile) => { | ||||||
|  |   upload.open = false; | ||||||
|  |   upload.isUploading = false; | ||||||
|  |   uploadRef.value?.handleRemove(file); | ||||||
|  |   ElMessageBox.alert("<div style='overflow: auto;overflow-x: hidden;max-height: 70vh;padding: 10px 20px 0;'>" + response.msg + '</div>', '导入结果', { | ||||||
|  |     dangerouslyUseHTMLString: true | ||||||
|  |   }); | ||||||
|  |   getList(); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | /** 提交上传文件 */ | ||||||
|  | function submitFileForm() { | ||||||
|  |   uploadRef.value?.submit(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** 重置操作表单 */ | ||||||
|  | const reset = () => { | ||||||
|  |   form.value = { ...initFormData }; | ||||||
|  |   form.value.projectRoles = [ | ||||||
|  |     { | ||||||
|  |       projectId: '', | ||||||
|  |       roleIds: [] | ||||||
|  |     } | ||||||
|  |   ]; | ||||||
|  |  | ||||||
|  |   userFormRef.value?.resetFields(); | ||||||
|  | }; | ||||||
|  | /** 取消按钮 */ | ||||||
|  | const cancel = () => { | ||||||
|  |   dialog.visible = false; | ||||||
|  |   reset(); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | /** 新增按钮操作 */ | ||||||
|  | const handleAdd = async () => { | ||||||
|  |   reset(); | ||||||
|  |   const { data } = await api.getUser(); | ||||||
|  |   dialog.visible = true; | ||||||
|  |   dialog.title = '新增用户'; | ||||||
|  |   postOptions.value = data.posts; | ||||||
|  |   form.value.password = initPassword.value.toString(); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | /** 修改按钮操作 */ | ||||||
|  | const handleUpdate = async (row?: UserForm) => { | ||||||
|  |   reset(); | ||||||
|  |   const userId = row?.userId || ids.value[0]; | ||||||
|  |   const { data } = await api.getUser(userId); | ||||||
|  |   dialog.visible = true; | ||||||
|  |   dialog.title = '修改用户'; | ||||||
|  |   Object.assign(form.value, data.user); | ||||||
|  |   postOptions.value = data.posts; | ||||||
|  |   roleOptions.value = data.roles; | ||||||
|  |   form.value.postIds = data.postIds; | ||||||
|  |   form.value.projectRoles = data.projectRoles; | ||||||
|  |   form.value.password = ''; | ||||||
|  |   const roleList = await getRoleList(form.value.deptId); | ||||||
|  |  | ||||||
|  |   roleOptions.value = roleList.data; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | const validate = () => { | ||||||
|  |   for (let i = 0; i < form.value.projectRoles.length; i++) { | ||||||
|  |     const item = form.value.projectRoles[i]; | ||||||
|  |     if (!item.projectId || item.projectId.length === 0) { | ||||||
|  |       proxy?.$modal.msgError(`第 ${i + 1} 行“项目列表”未填写`); | ||||||
|  |       return false; // 阻止提交 | ||||||
|  |     } | ||||||
|  |     if (!item.roleIds || item.roleIds.length === 0) { | ||||||
|  |       proxy?.$modal.msgError(`第 ${i + 1} 行“角色”未填写`); | ||||||
|  |       return false; // 阻止提交 | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   return true; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | /** 提交按钮 */ | ||||||
|  | const submitForm = () => { | ||||||
|  |   const isValid = validate(); | ||||||
|  |   if (!isValid) return; | ||||||
|  |   userFormRef.value?.validate(async (valid: boolean) => { | ||||||
|  |     if (valid) { | ||||||
|  |       form.value.userId ? await api.updateUser(form.value) : await api.addUser(form.value); | ||||||
|  |       proxy?.$modal.msgSuccess('操作成功'); | ||||||
|  |       dialog.visible = false; | ||||||
|  |       await getList(); | ||||||
|  |     } | ||||||
|  |   }); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * 关闭用户弹窗 | ||||||
|  |  */ | ||||||
|  | const closeDialog = () => { | ||||||
|  |   dialog.visible = false; | ||||||
|  |   resetForm(); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * 重置表单 | ||||||
|  |  */ | ||||||
|  | const resetForm = () => { | ||||||
|  |   userFormRef.value?.resetFields(); | ||||||
|  |   userFormRef.value?.clearValidate(); | ||||||
|  |  | ||||||
|  |   form.value.id = undefined; | ||||||
|  |   form.value.status = '1'; | ||||||
|  | }; | ||||||
|  | onMounted(() => { | ||||||
|  |   getDeptTree(); // 初始化部门数据 | ||||||
|  |   getList(); // 初始化列表数据 | ||||||
|  |   proxy?.getConfigKey('sys.user.initPassword').then((response) => { | ||||||
|  |     initPassword.value = response.data; | ||||||
|  |   }); | ||||||
|  | }); | ||||||
|  |  | ||||||
|  | async function handleDeptChange(value: number | string) { | ||||||
|  |   const response = await optionselect(value); | ||||||
|  |   const roleList = await getRoleList(value); | ||||||
|  |  | ||||||
|  |   roleOptions.value = roleList.data; | ||||||
|  |   postOptions.value = response.data; | ||||||
|  |   form.value.postIds = []; | ||||||
|  |   form.value.projectRoles = [ | ||||||
|  |     { | ||||||
|  |       projectId: [], | ||||||
|  |       roleIds: [] | ||||||
|  |     } | ||||||
|  |   ]; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const shuttleVisible = ref(false); | ||||||
|  | const selectedUserId = ref<number>(); | ||||||
|  | const handleUpdateProject = (row) => { | ||||||
|  |   if (row) { | ||||||
|  |     selectedUserId.value = row.userId; | ||||||
|  |     shuttleVisible.value = true; | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | const certDialog = ref(false); | ||||||
|  | const certId = ref<string | number>(undefined); | ||||||
|  | const fileUpload = ref<string>(); | ||||||
|  | //上传证书 | ||||||
|  | const handleUploadCert = (row: UserVO) => { | ||||||
|  |   certId.value = row.userId; | ||||||
|  |   fileUpload.value = row.filePath; | ||||||
|  |   certDialog.value = true; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | const uploadCert = async () => { | ||||||
|  |   if (!fileUpload.value) { | ||||||
|  |     proxy?.$modal.msgError('请上传证书目录'); | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |   let res = await uploadCertList({ | ||||||
|  |     userId: certId.value, | ||||||
|  |     fileId: fileUpload.value | ||||||
|  |   }); | ||||||
|  |   console.log(res); | ||||||
|  |  | ||||||
|  |   certDialog.value = false; | ||||||
|  |   proxy?.$modal.msgSuccess('上传证书目录成功'); | ||||||
|  | }; | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style lang="scss" scoped></style> | ||||||
| @ -5,14 +5,22 @@ | |||||||
|       <el-col :lg="4" :xs="24" style=""> |       <el-col :lg="4" :xs="24" style=""> | ||||||
|         <el-card shadow="hover"> |         <el-card shadow="hover"> | ||||||
|           <el-input v-model="deptName" placeholder="请输入部门名称" prefix-icon="Search" clearable /> |           <el-input v-model="deptName" placeholder="请输入部门名称" prefix-icon="Search" clearable /> | ||||||
|           <el-tree ref="deptTreeRef" class="mt-2" node-key="id" :data="deptOptions" |           <el-tree | ||||||
|             :props="{ label: 'label', children: 'children' }" :expand-on-click-node="false" |             ref="deptTreeRef" | ||||||
|             :filter-node-method="filterNode" highlight-current default-expand-all @node-click="handleNodeClick" /> |             class="mt-2" | ||||||
|  |             node-key="id" | ||||||
|  |             :data="deptOptions" | ||||||
|  |             :props="{ label: 'label', children: 'children' }" | ||||||
|  |             :expand-on-click-node="false" | ||||||
|  |             :filter-node-method="filterNode" | ||||||
|  |             highlight-current | ||||||
|  |             default-expand-all | ||||||
|  |             @node-click="handleNodeClick" | ||||||
|  |           /> | ||||||
|         </el-card> |         </el-card> | ||||||
|       </el-col> |       </el-col> | ||||||
|       <el-col :lg="20" :xs="24"> |       <el-col :lg="20" :xs="24"> | ||||||
|         <transition :enter-active-class="proxy?.animate.searchAnimate.enter" |         <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave"> | ||||||
|           :leave-active-class="proxy?.animate.searchAnimate.leave"> |  | ||||||
|           <div v-show="showSearch" class="mb-[10px]"> |           <div v-show="showSearch" class="mb-[10px]"> | ||||||
|             <el-card shadow="hover"> |             <el-card shadow="hover"> | ||||||
|               <el-form ref="queryFormRef" :model="queryParams" :inline="true"> |               <el-form ref="queryFormRef" :model="queryParams" :inline="true"> | ||||||
| @ -20,24 +28,27 @@ | |||||||
|                   <el-input v-model="queryParams.userName" placeholder="请输入用户名称" clearable @keyup.enter="handleQuery" /> |                   <el-input v-model="queryParams.userName" placeholder="请输入用户名称" clearable @keyup.enter="handleQuery" /> | ||||||
|                 </el-form-item> |                 </el-form-item> | ||||||
|                 <el-form-item label="手机号码" prop="phonenumber"> |                 <el-form-item label="手机号码" prop="phonenumber"> | ||||||
|                   <el-input v-model="queryParams.phonenumber" placeholder="请输入手机号码" clearable |                   <el-input v-model="queryParams.phonenumber" placeholder="请输入手机号码" clearable @keyup.enter="handleQuery" /> | ||||||
|                     @keyup.enter="handleQuery" /> |  | ||||||
|                 </el-form-item> |                 </el-form-item> | ||||||
|  |  | ||||||
|                 <el-form-item label="状态" prop="status"> |                 <el-form-item label="状态" prop="status"> | ||||||
|                   <el-select v-model="queryParams.status" placeholder="用户状态" clearable> |                   <el-select v-model="queryParams.status" placeholder="用户状态" clearable> | ||||||
|                     <el-option v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.label" |                     <el-option v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" /> | ||||||
|                       :value="dict.value" /> |  | ||||||
|                   </el-select> |                   </el-select> | ||||||
|                 </el-form-item> |                 </el-form-item> | ||||||
|                 <el-form-item label="创建时间" style="width: 308px"> |                 <el-form-item label="创建时间" style="width: 308px"> | ||||||
|                   <el-date-picker v-model="dateRange" value-format="YYYY-MM-DD HH:mm:ss" type="daterange" |                   <el-date-picker | ||||||
|                     range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" |                     v-model="dateRange" | ||||||
|                     :default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"></el-date-picker> |                     value-format="YYYY-MM-DD HH:mm:ss" | ||||||
|  |                     type="daterange" | ||||||
|  |                     range-separator="-" | ||||||
|  |                     start-placeholder="开始日期" | ||||||
|  |                     end-placeholder="结束日期" | ||||||
|  |                     :default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]" | ||||||
|  |                   ></el-date-picker> | ||||||
|                 </el-form-item> |                 </el-form-item> | ||||||
|                 <el-form-item> |                 <el-form-item> | ||||||
|                   <el-button type="primary" icon="Search" @click="handleQuery" |                   <el-button type="primary" icon="Search" @click="handleQuery" @v-has-permi="['system:user:query']">搜索</el-button> | ||||||
|                     @v-has-permi="['system:user:query']">搜索</el-button> |  | ||||||
|  |  | ||||||
|                   <el-button icon="Refresh" @click="resetQuery">重置</el-button> |                   <el-button icon="Refresh" @click="resetQuery">重置</el-button> | ||||||
|                 </el-form-item> |                 </el-form-item> | ||||||
| @ -50,18 +61,15 @@ | |||||||
|           <template #header> |           <template #header> | ||||||
|             <el-row :gutter="10"> |             <el-row :gutter="10"> | ||||||
|               <el-col :span="1.5"> |               <el-col :span="1.5"> | ||||||
|                 <el-button v-has-permi="['system:user:add']" type="primary" plain icon="Plus" @click="handleAdd()"> 新增 |                 <el-button v-has-permi="['system:user:add']" type="primary" plain icon="Plus" @click="handleAdd()"> 新增 </el-button> | ||||||
|                 </el-button> |  | ||||||
|               </el-col> |               </el-col> | ||||||
|               <el-col :span="1.5"> |               <el-col :span="1.5"> | ||||||
|                 <el-button v-has-permi="['system:user:edit']" type="success" plain :disabled="single" icon="Edit" |                 <el-button v-has-permi="['system:user:edit']" type="success" plain :disabled="single" icon="Edit" @click="handleUpdate()"> | ||||||
|                   @click="handleUpdate()"> |  | ||||||
|                   修改 |                   修改 | ||||||
|                 </el-button> |                 </el-button> | ||||||
|               </el-col> |               </el-col> | ||||||
|               <el-col :span="1.5"> |               <el-col :span="1.5"> | ||||||
|                 <el-button v-has-permi="['system:user:remove']" type="danger" plain :disabled="multiple" icon="Delete" |                 <el-button v-has-permi="['system:user:remove']" type="danger" plain :disabled="multiple" icon="Delete" @click="handleDelete()"> | ||||||
|                   @click="handleDelete()"> |  | ||||||
|                   删除 |                   删除 | ||||||
|                 </el-button> |                 </el-button> | ||||||
|               </el-col> |               </el-col> | ||||||
| @ -76,34 +84,26 @@ | |||||||
|                   <template #dropdown> |                   <template #dropdown> | ||||||
|                     <el-dropdown-menu> |                     <el-dropdown-menu> | ||||||
|                       <el-dropdown-item icon="Download" @click="importTemplate">下载模板</el-dropdown-item> |                       <el-dropdown-item icon="Download" @click="importTemplate">下载模板</el-dropdown-item> | ||||||
|                       <el-dropdown-item v-has-permi="['system:user:import']" icon="Top" @click="handleImport">导入数据 |                       <el-dropdown-item v-has-permi="['system:user:import']" icon="Top" @click="handleImport">导入数据 </el-dropdown-item> | ||||||
|                       </el-dropdown-item> |                       <el-dropdown-item v-has-permi="['system:user:export']" icon="Download" @click="handleExport"> 导出数据 </el-dropdown-item> | ||||||
|                       <el-dropdown-item v-has-permi="['system:user:export']" icon="Download" @click="handleExport"> 导出数据 |  | ||||||
|                       </el-dropdown-item> |  | ||||||
|                     </el-dropdown-menu> |                     </el-dropdown-menu> | ||||||
|                   </template> |                   </template> | ||||||
|                 </el-dropdown> |                 </el-dropdown> | ||||||
|               </el-col> |               </el-col> | ||||||
|               <right-toolbar v-model:show-search="showSearch" :columns="columns" :search="true" |               <right-toolbar v-model:show-search="showSearch" :columns="columns" :search="true" @query-table="getList"></right-toolbar> | ||||||
|                 @query-table="getList"></right-toolbar> |  | ||||||
|             </el-row> |             </el-row> | ||||||
|           </template> |           </template> | ||||||
|  |  | ||||||
|           <el-table v-loading="loading" :data="userList" @selection-change="handleSelectionChange"> |           <el-table v-loading="loading" :data="userList" @selection-change="handleSelectionChange"> | ||||||
|             <el-table-column type="selection" width="50" align="center" /> |             <el-table-column type="selection" width="50" align="center" /> | ||||||
|             <el-table-column v-if="columns[0].visible" key="userId" label="用户编号" align="center" prop="userId" /> |             <el-table-column v-if="columns[0].visible" key="userId" label="用户编号" align="center" prop="userId" /> | ||||||
|             <el-table-column v-if="columns[1].visible" key="userName" label="用户名称" align="center" prop="userName" |             <el-table-column v-if="columns[1].visible" key="userName" label="用户名称" align="center" prop="userName" :show-overflow-tooltip="true" /> | ||||||
|               :show-overflow-tooltip="true" /> |             <el-table-column v-if="columns[2].visible" key="nickName" label="用户昵称" align="center" prop="nickName" :show-overflow-tooltip="true" /> | ||||||
|             <el-table-column v-if="columns[2].visible" key="nickName" label="用户昵称" align="center" prop="nickName" |             <el-table-column v-if="columns[3].visible" key="deptName" label="部门" align="center" prop="deptName" :show-overflow-tooltip="true" /> | ||||||
|               :show-overflow-tooltip="true" /> |             <el-table-column v-if="columns[4].visible" key="phonenumber" label="手机号码" align="center" prop="phonenumber" width="120" /> | ||||||
|             <el-table-column v-if="columns[3].visible" key="deptName" label="部门" align="center" prop="deptName" |  | ||||||
|               :show-overflow-tooltip="true" /> |  | ||||||
|             <el-table-column v-if="columns[4].visible" key="phonenumber" label="手机号码" align="center" prop="phonenumber" |  | ||||||
|               width="120" /> |  | ||||||
|             <el-table-column v-if="columns[5].visible" key="status" label="状态" align="center"> |             <el-table-column v-if="columns[5].visible" key="status" label="状态" align="center"> | ||||||
|               <template #default="scope"> |               <template #default="scope"> | ||||||
|                 <el-switch v-model="scope.row.status" active-value="0" inactive-value="1" |                 <el-switch v-model="scope.row.status" active-value="0" inactive-value="1" @change="handleStatusChange(scope.row)"></el-switch> | ||||||
|                   @change="handleStatusChange(scope.row)"></el-switch> |  | ||||||
|               </template> |               </template> | ||||||
|             </el-table-column> |             </el-table-column> | ||||||
|  |  | ||||||
| @ -116,30 +116,24 @@ | |||||||
|             <el-table-column label="操作" fixed="right" width="230" class-name="small-padding fixed-width"> |             <el-table-column label="操作" fixed="right" width="230" class-name="small-padding fixed-width"> | ||||||
|               <template #default="scope"> |               <template #default="scope"> | ||||||
|                 <el-tooltip v-if="scope.row.userId !== 1" content="修改" placement="top"> |                 <el-tooltip v-if="scope.row.userId !== 1" content="修改" placement="top"> | ||||||
|                   <el-button v-hasPermi="['system:user:edit']" link type="primary" icon="Edit" |                   <el-button v-hasPermi="['system:user:edit']" link type="primary" icon="Edit" @click="handleUpdate(scope.row)"></el-button> | ||||||
|                     @click="handleUpdate(scope.row)"></el-button> |  | ||||||
|                 </el-tooltip> |                 </el-tooltip> | ||||||
|                 <el-tooltip v-if="scope.row.userId !== 1" content="删除" placement="top"> |                 <el-tooltip v-if="scope.row.userId !== 1" content="删除" placement="top"> | ||||||
|                   <el-button v-hasPermi="['system:user:remove']" link type="primary" icon="Delete" |                   <el-button v-hasPermi="['system:user:remove']" link type="primary" icon="Delete" @click="handleDelete(scope.row)"></el-button> | ||||||
|                     @click="handleDelete(scope.row)"></el-button> |  | ||||||
|                 </el-tooltip> |                 </el-tooltip> | ||||||
|  |  | ||||||
|                 <el-tooltip v-if="scope.row.userId !== 1" content="重置密码" placement="top"> |                 <el-tooltip v-if="scope.row.userId !== 1" content="重置密码" placement="top"> | ||||||
|                   <el-button v-hasPermi="['system:user:resetPwd']" link type="primary" icon="Key" |                   <el-button v-hasPermi="['system:user:resetPwd']" link type="primary" icon="Key" @click="handleResetPwd(scope.row)"></el-button> | ||||||
|                     @click="handleResetPwd(scope.row)"></el-button> |  | ||||||
|                 </el-tooltip> |                 </el-tooltip> | ||||||
|  |  | ||||||
|                 <el-tooltip v-if="scope.row.userId !== 1" content="分配角色" placement="top"> |                 <el-tooltip v-if="scope.row.userId !== 1" content="分配角色" placement="top"> | ||||||
|                   <el-button v-hasPermi="['system:user:edit']" link type="primary" icon="CircleCheck" |                   <el-button v-hasPermi="['system:user:edit']" link type="primary" icon="CircleCheck" @click="handleAuthRole(scope.row)"></el-button> | ||||||
|                     @click="handleAuthRole(scope.row)"></el-button> |  | ||||||
|                 </el-tooltip> |                 </el-tooltip> | ||||||
|                 <el-tooltip v-if="scope.row.userId !== 1" content="编辑关联项目" placement="top"> |                 <el-tooltip v-if="scope.row.userId !== 1" content="编辑关联项目" placement="top"> | ||||||
|                   <el-button v-hasPermi="['system:user:edit']" link type="primary" icon="Edit" |                   <el-button v-hasPermi="['system:user:edit']" link type="primary" icon="Edit" @click="handleUpdateProject(scope.row)"></el-button> | ||||||
|                     @click="handleUpdateProject(scope.row)"></el-button> |  | ||||||
|                 </el-tooltip> |                 </el-tooltip> | ||||||
|                 <el-tooltip v-if="scope.row.userId !== 1" content="上传证书目录" placement="top"> |                 <el-tooltip v-if="scope.row.userId !== 1" content="上传证书目录" placement="top"> | ||||||
|                   <el-button v-hasPermi="['system:user:edit']" link type="primary" icon="Upload" |                   <el-button v-hasPermi="['system:user:edit']" link type="primary" icon="Upload" @click="handleUploadCert(scope.row)"></el-button> | ||||||
|                     @click="handleUploadCert(scope.row)"></el-button> |  | ||||||
|                 </el-tooltip> |                 </el-tooltip> | ||||||
|               </template> |               </template> | ||||||
|             </el-table-column> |             </el-table-column> | ||||||
| @ -148,117 +142,47 @@ | |||||||
|             <shuttle-frame :userId="selectedUserId" @close="shuttleVisible = false" /> |             <shuttle-frame :userId="selectedUserId" @close="shuttleVisible = false" /> | ||||||
|           </el-dialog> |           </el-dialog> | ||||||
|  |  | ||||||
|           <pagination v-show="total > 0" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" |           <pagination | ||||||
|             :total="total" @pagination="getList" /> |             v-show="total > 0" | ||||||
|  |             v-model:page="queryParams.pageNum" | ||||||
|  |             v-model:limit="queryParams.pageSize" | ||||||
|  |             :total="total" | ||||||
|  |             @pagination="getList" | ||||||
|  |           /> | ||||||
|         </el-card> |         </el-card> | ||||||
|       </el-col> |       </el-col> | ||||||
|     </el-row> |     </el-row> | ||||||
|  |  | ||||||
|     <!-- 添加或修改用户配置对话框 --> |     <!-- 添加或修改用户配置对话框 --> | ||||||
|     <el-dialog ref="formDialogRef" v-model="dialog.visible" :title="dialog.title" width="600px" append-to-body |     <el-dialog draggable ref="formDialogRef" v-model="dialog.visible" :title="dialog.title" width="1300px" append-to-body @close="closeDialog"> | ||||||
|       @close="closeDialog"> |       <div class="boxDetial"> | ||||||
|       <el-form ref="userFormRef" :model="form" :rules="rules" label-width="80px"> |         <div class="tab_info"> | ||||||
|         <el-row> |           <span @click="onTab(1)" :class="{ active: type == 1 }">基本资料</span> | ||||||
|           <el-col :span="12"> |           <span @click="onTab(2)" :class="{ active: type == 2 }">角色信息</span> | ||||||
|             <el-form-item label="用户昵称" prop="nickName"> |  | ||||||
|               <el-input v-model="form.nickName" placeholder="请输入用户昵称" maxlength="30" /> |  | ||||||
|             </el-form-item> |  | ||||||
|           </el-col> |  | ||||||
|           <el-col :span="12"> |  | ||||||
|             <el-form-item label="归属部门" prop="deptId"> |  | ||||||
|               <el-tree-select v-model="form.deptId" :data="enabledDeptOptions" |  | ||||||
|                 :props="{ value: 'id', label: 'label', children: 'children' }" value-key="id" placeholder="请选择归属部门" |  | ||||||
|                 check-strictly @change="handleDeptChange" /> |  | ||||||
|             </el-form-item> |  | ||||||
|           </el-col> |  | ||||||
|           <el-col :span="12"> |  | ||||||
|             <el-form-item label="手机号码" prop="phonenumber"> |  | ||||||
|               <el-input v-model="form.phonenumber" placeholder="请输入手机号码" maxlength="11" /> |  | ||||||
|             </el-form-item> |  | ||||||
|           </el-col> |  | ||||||
|           <el-col :span="12"> |  | ||||||
|             <el-form-item label="邮箱" prop="email"> |  | ||||||
|               <el-input v-model="form.email" placeholder="请输入邮箱" maxlength="50" /> |  | ||||||
|             </el-form-item> |  | ||||||
|           </el-col> |  | ||||||
|           <el-col :span="12"> |  | ||||||
|             <el-form-item v-if="form.userId == undefined" label="用户名称" prop="userName"> |  | ||||||
|               <el-input v-model="form.userName" placeholder="请输入用户名称" maxlength="30" /> |  | ||||||
|             </el-form-item> |  | ||||||
|           </el-col> |  | ||||||
|           <el-col :span="12"> |  | ||||||
|             <el-form-item v-if="form.userId == undefined" label="用户密码" prop="password"> |  | ||||||
|               <el-input v-model="form.password" placeholder="请输入用户密码" type="password" maxlength="20" show-password /> |  | ||||||
|             </el-form-item> |  | ||||||
|           </el-col> |  | ||||||
|           <el-col :span="12"> |  | ||||||
|             <el-form-item label="用户性别"> |  | ||||||
|               <el-select v-model="form.sex" placeholder="请选择"> |  | ||||||
|                 <el-option v-for="dict in sys_user_sex" :key="dict.value" :label="dict.label" |  | ||||||
|                   :value="dict.value"></el-option> |  | ||||||
|               </el-select> |  | ||||||
|             </el-form-item> |  | ||||||
|           </el-col> |  | ||||||
|           <el-col :span="12"> |  | ||||||
|             <el-form-item label="岗位"> |  | ||||||
|               <el-select v-model="form.postIds" multiple placeholder="请选择"> |  | ||||||
|                 <el-option v-for="item in postOptions" :key="item.postId" :label="item.postName" :value="item.postId" |  | ||||||
|                   :disabled="item.status == '1'"></el-option> |  | ||||||
|               </el-select> |  | ||||||
|             </el-form-item> |  | ||||||
|           </el-col> |  | ||||||
|           <el-col :span="24"> |  | ||||||
|             <el-row :gutter="20" v-for="(item, index) in form.projectRoles"> |  | ||||||
|               <el-col :span="11" :offset="0"> |  | ||||||
|                 <el-form-item label="项目列表"> |  | ||||||
|                   <el-select v-model="item.projectId" placeholder="请选择"> |  | ||||||
|                     <el-option v-for="dict in projectOptions" :key="dict.id" :label="dict.shortName" |  | ||||||
|                       :value="dict.id"></el-option> |  | ||||||
|                   </el-select> |  | ||||||
|                 </el-form-item> |  | ||||||
|               </el-col> |  | ||||||
|               <el-col :span="11" :offset="0"> |  | ||||||
|                 <el-form-item label="角色"> |  | ||||||
|                   <el-select v-model="item.roleIds" filterable multiple placeholder="请选择"> |  | ||||||
|                     <el-option v-for="item in roleOptions" :key="item.roleId" :label="item.roleName" |  | ||||||
|                       :value="item.roleId" :disabled="item.status == '1'"></el-option> |  | ||||||
|                   </el-select> |  | ||||||
|                 </el-form-item> |  | ||||||
|               </el-col> |  | ||||||
|               <el-col :span="1" :offset="0"> |  | ||||||
|                 <el-button type="primary" circle icon="Plus" @click="handleAddProject" v-if="index == 0"></el-button> |  | ||||||
|                 <el-button type="danger" circle icon="Delete" @click="delProject(index)" v-else></el-button> |  | ||||||
|               </el-col> |  | ||||||
|             </el-row> |  | ||||||
|           </el-col> |  | ||||||
|           <el-col :span="12"> |  | ||||||
|             <el-form-item label="状态"> |  | ||||||
|               <el-radio-group v-model="form.status"> |  | ||||||
|                 <el-radio v-for="dict in sys_normal_disable" :key="dict.value" :value="dict.value">{{ dict.label }} |  | ||||||
|                 </el-radio> |  | ||||||
|               </el-radio-group> |  | ||||||
|             </el-form-item> |  | ||||||
|           </el-col> |  | ||||||
|           <el-col :span="24"> |  | ||||||
|             <el-form-item label="备注"> |  | ||||||
|               <el-input v-model="form.remark" type="textarea" placeholder="请输入内容"></el-input> |  | ||||||
|             </el-form-item> |  | ||||||
|           </el-col> |  | ||||||
|         </el-row> |  | ||||||
|       </el-form> |  | ||||||
|       <template #footer> |  | ||||||
|         <div class="dialog-footer"> |  | ||||||
|           <el-button type="primary" @click="submitForm">确 定</el-button> |  | ||||||
|           <el-button @click="cancel()">取 消</el-button> |  | ||||||
|         </div> |         </div> | ||||||
|       </template> |         <div class="tab_content" v-show="type == 1"> | ||||||
|  |           <editInfo ref="editInfoRef" @close="dialog.visible = false" @submit="getList" @setDeptId="setDeptId"></editInfo> | ||||||
|  |         </div> | ||||||
|  |         <div class="tab_content" v-show="type == 2"> | ||||||
|  |           <roleInfo ref="roleInfoRef" @close="dialog.visible = false" @submit="getList"></roleInfo> | ||||||
|  |         </div> | ||||||
|  |       </div> | ||||||
|     </el-dialog> |     </el-dialog> | ||||||
|  |  | ||||||
|     <!-- 用户导入对话框 --> |     <!-- 用户导入对话框 --> | ||||||
|     <el-dialog draggable v-model="upload.open" :title="upload.title" width="400px" append-to-body> |     <el-dialog draggable v-model="upload.open" :title="upload.title" width="400px" append-to-body> | ||||||
|       <el-upload ref="uploadRef" :limit="1" accept=".xlsx, .xls" :headers="upload.headers" |       <el-upload | ||||||
|         :action="upload.url + '?updateSupport=' + upload.updateSupport" :disabled="upload.isUploading" |         ref="uploadRef" | ||||||
|         :on-progress="handleFileUploadProgress" :on-success="handleFileSuccess" :auto-upload="false" drag> |         :limit="1" | ||||||
|  |         accept=".xlsx, .xls" | ||||||
|  |         :headers="upload.headers" | ||||||
|  |         :action="upload.url + '?updateSupport=' + upload.updateSupport" | ||||||
|  |         :disabled="upload.isUploading" | ||||||
|  |         :on-progress="handleFileUploadProgress" | ||||||
|  |         :on-success="handleFileSuccess" | ||||||
|  |         :auto-upload="false" | ||||||
|  |         drag | ||||||
|  |       > | ||||||
|         <el-icon class="el-icon--upload"> |         <el-icon class="el-icon--upload"> | ||||||
|           <i-ep-upload-filled /> |           <i-ep-upload-filled /> | ||||||
|         </el-icon> |         </el-icon> | ||||||
| @ -270,8 +194,7 @@ | |||||||
|               是否更新已经存在的用户数据 |               是否更新已经存在的用户数据 | ||||||
|             </div> |             </div> | ||||||
|             <span>仅允许导入xls、xlsx格式文件。</span> |             <span>仅允许导入xls、xlsx格式文件。</span> | ||||||
|             <el-link type="primary" :underline="false" style="font-size: 12px; vertical-align: baseline" |             <el-link type="primary" :underline="false" style="font-size: 12px; vertical-align: baseline" @click="importTemplate">下载模板 </el-link> | ||||||
|               @click="importTemplate">下载模板 </el-link> |  | ||||||
|           </div> |           </div> | ||||||
|         </template> |         </template> | ||||||
|       </el-upload> |       </el-upload> | ||||||
| @ -307,7 +230,8 @@ import { to } from 'await-to-js'; | |||||||
| import { getProjectByDeptId, getRoleList, optionselect } from '@/api/system/post'; | import { getProjectByDeptId, getRoleList, optionselect } from '@/api/system/post'; | ||||||
| import ShuttleFrame from '../../project/projectRelevancy/component/ShuttleFrame.vue'; | import ShuttleFrame from '../../project/projectRelevancy/component/ShuttleFrame.vue'; | ||||||
| import { listProject } from '@/api/project/project'; | import { listProject } from '@/api/project/project'; | ||||||
|  | import editInfo from './comm/editInfo.vue'; | ||||||
|  | import roleInfo from './comm/roleInfo.vue'; | ||||||
| const router = useRouter(); | const router = useRouter(); | ||||||
| const { proxy } = getCurrentInstance() as ComponentInternalInstance; | const { proxy } = getCurrentInstance() as ComponentInternalInstance; | ||||||
| const { sys_normal_disable, sys_user_sex } = toRefs<any>(proxy?.useDict('sys_normal_disable', 'sys_user_sex')); | const { sys_normal_disable, sys_user_sex } = toRefs<any>(proxy?.useDict('sys_normal_disable', 'sys_user_sex')); | ||||||
| @ -326,7 +250,8 @@ const initPassword = ref<string>(''); | |||||||
| const postOptions = ref<PostVO[]>([]); | const postOptions = ref<PostVO[]>([]); | ||||||
| const roleOptions = ref<RoleVO[]>([]); | const roleOptions = ref<RoleVO[]>([]); | ||||||
| const projectOptions = ref<any[]>([]); | const projectOptions = ref<any[]>([]); | ||||||
|  | const editInfoRef = ref<InstanceType<typeof editInfo> | null>(null); | ||||||
|  | const roleInfoRef = ref<InstanceType<typeof roleInfo> | null>(null); | ||||||
| /*** 用户导入参数 */ | /*** 用户导入参数 */ | ||||||
| const upload = reactive<ImportOption>({ | const upload = reactive<ImportOption>({ | ||||||
|   // 是否显示弹出层(用户导入) |   // 是否显示弹出层(用户导入) | ||||||
| @ -358,7 +283,8 @@ const queryFormRef = ref<ElFormInstance>(); | |||||||
| const userFormRef = ref<ElFormInstance>(); | const userFormRef = ref<ElFormInstance>(); | ||||||
| const uploadRef = ref<ElUploadInstance>(); | const uploadRef = ref<ElUploadInstance>(); | ||||||
| const formDialogRef = ref<ElDialogInstance>(); | const formDialogRef = ref<ElDialogInstance>(); | ||||||
|  | const deptIdRole = ref<number>(); | ||||||
|  | const type = ref(1); | ||||||
| const dialog = reactive<DialogOption>({ | const dialog = reactive<DialogOption>({ | ||||||
|   visible: false, |   visible: false, | ||||||
|   title: '' |   title: '' | ||||||
| @ -452,7 +378,9 @@ watchEffect( | |||||||
|     flush: 'post' // watchEffect会在DOM挂载或者更新之前就会触发,此属性控制在DOM元素更新后运行 |     flush: 'post' // watchEffect会在DOM挂载或者更新之前就会触发,此属性控制在DOM元素更新后运行 | ||||||
|   } |   } | ||||||
| ); | ); | ||||||
|  | const setDeptId = (deptId: number) => { | ||||||
|  |   deptIdRole.value = deptId; | ||||||
|  | }; | ||||||
| /** 查询用户列表 */ | /** 查询用户列表 */ | ||||||
| const getList = async () => { | const getList = async () => { | ||||||
|   loading.value = true; |   loading.value = true; | ||||||
| @ -637,8 +565,12 @@ const cancel = () => { | |||||||
| const handleAdd = async () => { | const handleAdd = async () => { | ||||||
|   reset(); |   reset(); | ||||||
|   const { data } = await api.getUser(); |   const { data } = await api.getUser(); | ||||||
|  |   type.value = 1; | ||||||
|   dialog.visible = true; |   dialog.visible = true; | ||||||
|   dialog.title = '新增用户'; |   dialog.title = '新增用户'; | ||||||
|  |   nextTick(() => { | ||||||
|  |     editInfoRef.value?.open(); | ||||||
|  |   }); | ||||||
|   postOptions.value = data.posts; |   postOptions.value = data.posts; | ||||||
|   form.value.password = initPassword.value.toString(); |   form.value.password = initPassword.value.toString(); | ||||||
| }; | }; | ||||||
| @ -646,19 +578,13 @@ const handleAdd = async () => { | |||||||
| /** 修改按钮操作 */ | /** 修改按钮操作 */ | ||||||
| const handleUpdate = async (row?: UserForm) => { | const handleUpdate = async (row?: UserForm) => { | ||||||
|   reset(); |   reset(); | ||||||
|   const userId = row?.userId || ids.value[0]; |  | ||||||
|   const { data } = await api.getUser(userId); |  | ||||||
|   dialog.visible = true; |   dialog.visible = true; | ||||||
|   dialog.title = '修改用户'; |   dialog.title = '修改用户'; | ||||||
|   Object.assign(form.value, data.user); |   type.value = 1; | ||||||
|   postOptions.value = data.posts; |   form.value = row; | ||||||
|   roleOptions.value = data.roles; |   nextTick(() => { | ||||||
|   form.value.postIds = data.postIds; |     editInfoRef.value?.open(row); | ||||||
|   form.value.projectRoles = data.projectRoles; |   }); | ||||||
|   form.value.password = ''; |  | ||||||
|   const roleList = await getRoleList(form.value.deptId); |  | ||||||
|  |  | ||||||
|   roleOptions.value = roleList.data; |  | ||||||
| }; | }; | ||||||
|  |  | ||||||
| const validate = () => { | const validate = () => { | ||||||
| @ -764,6 +690,46 @@ const uploadCert = async () => { | |||||||
|   certDialog.value = false; |   certDialog.value = false; | ||||||
|   proxy?.$modal.msgSuccess('上传证书目录成功'); |   proxy?.$modal.msgSuccess('上传证书目录成功'); | ||||||
| }; | }; | ||||||
|  | const onTab = (val) => { | ||||||
|  |   type.value = val; | ||||||
|  |   if (val == 2) { | ||||||
|  |     let obj = editInfoRef.value?.getInfoForm(); | ||||||
|  |     form.value = obj; | ||||||
|  |     nextTick(() => { | ||||||
|  |       roleInfoRef.value?.open(form.value, deptIdRole.value); | ||||||
|  |     }); | ||||||
|  |   } | ||||||
|  | }; | ||||||
| </script> | </script> | ||||||
|  |  | ||||||
| <style lang="scss" scoped></style> | <style lang="scss" scoped> | ||||||
|  | .boxDetial { | ||||||
|  |   display: flex; | ||||||
|  |   justify-content: space-between; | ||||||
|  |   align-items: center; | ||||||
|  |   height: 680px; | ||||||
|  |   .tab_info { | ||||||
|  |     height: 100%; | ||||||
|  |     width: 200px; | ||||||
|  |     background: #f0f2f5; | ||||||
|  |     padding: 10px; | ||||||
|  |     text-align: center; | ||||||
|  |     display: flex; | ||||||
|  |     flex-direction: column; | ||||||
|  |     font-size: 18px; | ||||||
|  |     > span { | ||||||
|  |       margin-bottom: 10px; | ||||||
|  |       cursor: pointer; | ||||||
|  |     } | ||||||
|  |     .active { | ||||||
|  |       color: #1890ff; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   .tab_content { | ||||||
|  |     height: 100%; | ||||||
|  |     width: calc(100% - 200px); | ||||||
|  |     padding: 20px 10px; | ||||||
|  |     background: #ccc; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </style> | ||||||
|  | |||||||
| @ -10,7 +10,7 @@ | |||||||
|                   <el-option v-for="item in options" :key="item.versions" :label="item.versions" :value="item.versions" /> |                   <el-option v-for="item in options" :key="item.versions" :label="item.versions" :value="item.versions" /> | ||||||
|                 </el-select> |                 </el-select> | ||||||
|               </el-form-item> |               </el-form-item> | ||||||
|               <el-form-item label="表名" prop="sheet"> |               <el-form-item label="表名" prop="sheet" v-if="activeTab != '3'"> | ||||||
|                 <el-select v-model="queryForm.sheet" placeholder="选择表名" @change="changeSheet"> |                 <el-select v-model="queryForm.sheet" placeholder="选择表名" @change="changeSheet"> | ||||||
|                   <el-option v-for="item in sheets" :key="item" :label="item" :value="item" /> |                   <el-option v-for="item in sheets" :key="item" :label="item" :value="item" /> | ||||||
|                 </el-select> |                 </el-select> | ||||||
| @ -139,7 +139,7 @@ const sheets = ref([]); | |||||||
| const options = ref([]); | const options = ref([]); | ||||||
| const tableData = ref([]); | const tableData = ref([]); | ||||||
| const tableRef = ref(); | const tableRef = ref(); | ||||||
| const isExpandAll = ref(false); | const isExpandAll = ref(true); | ||||||
| const loading = ref(false); | const loading = ref(false); | ||||||
| const versionMap = new Map(); | const versionMap = new Map(); | ||||||
|  |  | ||||||
|  | |||||||
| @ -191,9 +191,14 @@ | |||||||
|             <el-table-column prop="useQuantity" label="剩余量" align="center"> |             <el-table-column prop="useQuantity" label="剩余量" align="center"> | ||||||
|               <template #default="scope"> |               <template #default="scope"> | ||||||
|                 {{ |                 {{ | ||||||
|                   (scope.row.quantity ? Number(scope.row.quantity) : 0) - (scope.row.useQuantity ? Number(scope.row.useQuantity) : 0) == 0 |                   (scope.row.quantity ? Number(scope.row.quantity) : 0) - | ||||||
|  |                     (scope.row.useQuantity ? Number(scope.row.useQuantity) : 0) - | ||||||
|  |                     (scope.row.selectNum ? Number(scope.row.selectNum) : 0) == | ||||||
|  |                   0 | ||||||
|                     ? '' |                     ? '' | ||||||
|                     : (scope.row.quantity ? Number(scope.row.quantity) : 0) - (scope.row.useQuantity ? Number(scope.row.useQuantity) : 0) |                     : (scope.row.quantity ? Number(scope.row.quantity) : 0) - | ||||||
|  |                       (scope.row.selectNum ? Number(scope.row.selectNum) : 0) - | ||||||
|  |                       (scope.row.useQuantity ? Number(scope.row.useQuantity) : 0) | ||||||
|                 }} |                 }} | ||||||
|               </template> |               </template> | ||||||
|             </el-table-column> |             </el-table-column> | ||||||
| @ -219,12 +224,16 @@ | |||||||
|             <el-table-column prop="price" label="总价" align="center"> |             <el-table-column prop="price" label="总价" align="center"> | ||||||
|               <template #default="scope"> |               <template #default="scope"> | ||||||
|                 {{ |                 {{ | ||||||
|                   ((scope.row.quantity ? Number(scope.row.quantity) : 0) - (scope.row.useQuantity ? Number(scope.row.useQuantity) : 0)) * |                   ((scope.row.quantity ? Number(scope.row.quantity) : 0) - | ||||||
|  |                     (scope.row.useQuantity ? Number(scope.row.useQuantity) : 0) - | ||||||
|  |                     (scope.row.selectNum ? Number(scope.row.selectNum) : 0)) * | ||||||
|                     Number(scope.row.unitPrice) == |                     Number(scope.row.unitPrice) == | ||||||
|                   0 |                   0 | ||||||
|                     ? '' |                     ? '' | ||||||
|                     : ( |                     : ( | ||||||
|                         ((scope.row.quantity ? Number(scope.row.quantity) : 0) - (scope.row.useQuantity ? Number(scope.row.useQuantity) : 0)) * |                         ((scope.row.quantity ? Number(scope.row.quantity) : 0) - | ||||||
|  |                           (scope.row.useQuantity ? Number(scope.row.useQuantity) : 0) - | ||||||
|  |                           (scope.row.selectNum ? Number(scope.row.selectNum) : 0)) * | ||||||
|                         Number(scope.row.unitPrice) |                         Number(scope.row.unitPrice) | ||||||
|                       ).toFixed(2) |                       ).toFixed(2) | ||||||
|                 }} |                 }} | ||||||
| @ -459,19 +468,11 @@ const getSheetName = async () => { | |||||||
|         treeForm.value.sheet = res.data[0]; |         treeForm.value.sheet = res.data[0]; | ||||||
|       } else { |       } else { | ||||||
|         treeForm.value.sheet = ''; |         treeForm.value.sheet = ''; | ||||||
|         ElMessage({ |  | ||||||
|           message: '获取表名失败', |  | ||||||
|           type: 'warning' |  | ||||||
|         }); |  | ||||||
|       } |       } | ||||||
|       getTreeList(); |       getTreeList(); | ||||||
|     } |     } | ||||||
|   } catch (error) { |   } catch (error) { | ||||||
|     console.log(error); |     console.log(error); | ||||||
|     ElMessage({ |  | ||||||
|       message: '获取表名失败', |  | ||||||
|       type: 'warning' |  | ||||||
|     }); |  | ||||||
|   } |   } | ||||||
| }; | }; | ||||||
| const handleSelection = (selection: any) => { | const handleSelection = (selection: any) => { | ||||||
|  | |||||||
| @ -234,17 +234,17 @@ | |||||||
|         <!-- 第十一行:注册人员数量(仅劳务类型显示) --> |         <!-- 第十一行:注册人员数量(仅劳务类型显示) --> | ||||||
|         <el-row :gutter="20" class="mb-4" v-if="form.supplierType === '劳务'"> |         <el-row :gutter="20" class="mb-4" v-if="form.supplierType === '劳务'"> | ||||||
|           <el-col :span="12"> |           <el-col :span="12"> | ||||||
|             <el-form-item label="一建建造师" prop="build1"> |             <el-form-item label="一建建造师" prop="firstBuildingNumber"> | ||||||
|               <el-input v-model="form.build1" placeholder="请输入一建建造师数量" clearable /> |               <el-input v-model="form.firstBuildingNumber" placeholder="请输入一建建造师数量" clearable /> | ||||||
|             </el-form-item> |             </el-form-item> | ||||||
|             <el-form-item label="二建建造师" prop="build2"> |             <el-form-item label="二建建造师" prop="secondBuildingNumber"> | ||||||
|               <el-input v-model="form.build2" placeholder="请输入二建建造师数量" clearable /> |               <el-input v-model="form.secondBuildingNumber" placeholder="请输入二建建造师数量" clearable /> | ||||||
|             </el-form-item> |             </el-form-item> | ||||||
|             <el-form-item label="注册造价工程师" prop="build3"> |             <el-form-item label="注册造价工程师" prop="registeredEngineerNumber"> | ||||||
|               <el-input v-model="form.build3" placeholder="请输入注册造价工程师数量" clearable /> |               <el-input v-model="form.registeredEngineerNumber" placeholder="请输入注册造价工程师数量" clearable /> | ||||||
|             </el-form-item> |             </el-form-item> | ||||||
|             <el-form-item label="其他(分别写)" prop="build4"> |             <el-form-item label="其他(分别写)" prop="otherBuildingNumber"> | ||||||
|               <el-input v-model="form.build4" placeholder="请输入其他人员数量" clearable /> |               <el-input v-model="form.otherBuildingNumber" placeholder="请输入其他人员数量" clearable /> | ||||||
|             </el-form-item> |             </el-form-item> | ||||||
|           </el-col> |           </el-col> | ||||||
|           <el-col :span="12"> |           <el-col :span="12"> | ||||||
| @ -254,17 +254,17 @@ | |||||||
|         <!-- 第十二行:职称人员数量(仅劳务类型显示) --> |         <!-- 第十二行:职称人员数量(仅劳务类型显示) --> | ||||||
|         <el-row :gutter="20" class="mb-4" v-if="form.supplierType === '劳务'"> |         <el-row :gutter="20" class="mb-4" v-if="form.supplierType === '劳务'"> | ||||||
|           <el-col :span="12"> |           <el-col :span="12"> | ||||||
|             <el-form-item label="高级工程师人数" prop="personnelNumber1"> |             <el-form-item label="高级工程师人数" prop="seniorEngineerNumber"> | ||||||
|               <el-input v-model="form.personnelNumber1" placeholder="请输高级工程师数量" clearable /> |               <el-input v-model="form.seniorEngineerNumber" placeholder="请输高级工程师数量" clearable /> | ||||||
|             </el-form-item> |             </el-form-item> | ||||||
|             <el-form-item label="工程师数量" prop="personnelNumber2"> |             <el-form-item label="工程师数量" prop="engineerNumber"> | ||||||
|               <el-input v-model="form.personnelNumber2" placeholder="请输入工程师数量" clearable /> |               <el-input v-model="form.engineerNumber" placeholder="请输入工程师数量" clearable /> | ||||||
|             </el-form-item> |             </el-form-item> | ||||||
|             <el-form-item label="助理工程师数量" prop="personnelNumber3"> |             <el-form-item label="助理工程师数量" prop="assistantEngineerNumber"> | ||||||
|               <el-input v-model="form.personnelNumber3" placeholder="请输入助理工程师数量" clearable /> |               <el-input v-model="form.assistantEngineerNumber" placeholder="请输入助理工程师数量" clearable /> | ||||||
|             </el-form-item> |             </el-form-item> | ||||||
|             <el-form-item label="其他人员数量" prop="personnelNumber4"> |             <el-form-item label="其他人员数量" prop="otherPersonnelNumber"> | ||||||
|               <el-input v-model="form.personnelNumber4" placeholder="请输入其他人员数量" clearable /> |               <el-input v-model="form.otherPersonnelNumber" placeholder="请输入其他人员数量" clearable /> | ||||||
|             </el-form-item> |             </el-form-item> | ||||||
|           </el-col> |           </el-col> | ||||||
|           <el-col :span="12"> |           <el-col :span="12"> | ||||||
| @ -285,8 +285,8 @@ | |||||||
|                 :data="form" |                 :data="form" | ||||||
|                 uploadUrl="/supplierInput/supplierInput" |                 uploadUrl="/supplierInput/supplierInput" | ||||||
|                 :limit="1" |                 :limit="1" | ||||||
|                 :onUploadSuccess="handleUploadSuccess" |                 @handleChange="handleFileChange" | ||||||
|                 @handleChange="change" |                 @handleRemove="handleFileRemove" | ||||||
|                 showFileList |                 showFileList | ||||||
|               > |               > | ||||||
|                 <div><el-button type="primary">上传文件</el-button><br /></div> |                 <div><el-button type="primary">上传文件</el-button><br /></div> | ||||||
| @ -309,7 +309,7 @@ | |||||||
| <script setup name="SupplierInput" lang="ts"> | <script setup name="SupplierInput" lang="ts"> | ||||||
| import { ComponentInternalInstance, getCurrentInstance, onMounted, ref, reactive, toRefs, computed } from 'vue'; | import { ComponentInternalInstance, getCurrentInstance, onMounted, ref, reactive, toRefs, computed } from 'vue'; | ||||||
| import { ElFormInstance } from 'element-plus'; | import { ElFormInstance } from 'element-plus'; | ||||||
| import { listSupplierInput, getSupplierInput, delSupplierInput } from '@/api/supplierInput/supplierInput/index'; | import { listSupplierInput, getSupplierInput, delSupplierInput, updateSupplierInput } from '@/api/supplierInput/supplierInput/index'; | ||||||
| import { SupplierInputVO, SupplierInputQuery, SupplierInputForm, PageData, DialogOption } from '@/api/supplierInput/supplierInput/types'; | import { SupplierInputVO, SupplierInputQuery, SupplierInputForm, PageData, DialogOption } from '@/api/supplierInput/supplierInput/types'; | ||||||
| import Pagination from '@/components/Pagination/index.vue'; | import Pagination from '@/components/Pagination/index.vue'; | ||||||
| import RightToolbar from '@/components/RightToolbar/index.vue'; | import RightToolbar from '@/components/RightToolbar/index.vue'; | ||||||
| @ -369,14 +369,14 @@ const initFormData: any = { | |||||||
|   inputFile: undefined, |   inputFile: undefined, | ||||||
|   // state: '0', // 新增默认待审核 |   // state: '0', // 新增默认待审核 | ||||||
|   // 新增:用于表单输入的单独字段 |   // 新增:用于表单输入的单独字段 | ||||||
|   build1: undefined, // 一建建造师 |   firstBuildingNumber: undefined, // 一建建造师 | ||||||
|   build2: undefined, // 二建建造师 |   secondBuildingNumber: undefined, // 二建建造师 | ||||||
|   build3: undefined, // 注册造价工程师 |   registeredEngineerNumber: undefined, // 注册造价工程师 | ||||||
|   build4: undefined, // 其他注册人员 |   otherBuildingNumber: undefined, // 其他注册人员 | ||||||
|   personnelNumber1: undefined, // 高级工程师 |   seniorEngineerNumber: undefined, // 高级工程师 | ||||||
|   personnelNumber2: undefined, // 工程师 |   engineerNumber: undefined, // 工程师 | ||||||
|   personnelNumber3: undefined, // 助理工程师 |   assistantEngineerNumber: undefined, // 助理工程师 | ||||||
|   personnelNumber4: undefined // 其他职称人员 |   otherPersonnelNumber: undefined // 其他职称人员 | ||||||
| }; | }; | ||||||
| // 核心数据(表单+查询参数) | // 核心数据(表单+查询参数) | ||||||
| const data = reactive<PageData<SupplierInputForm, SupplierInputQuery>>({ | const data = reactive<PageData<SupplierInputForm, SupplierInputQuery>>({ | ||||||
| @ -411,14 +411,14 @@ const rules = computed(() => { | |||||||
|       { pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号格式', trigger: 'blur' } |       { pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号格式', trigger: 'blur' } | ||||||
|     ], |     ], | ||||||
|     id: [{ required: true, message: 'ID不能为空', trigger: 'blur' }], |     id: [{ required: true, message: 'ID不能为空', trigger: 'blur' }], | ||||||
|     build1: [{ required: true, message: '请输入一建建造师数量', trigger: 'change' }], |     firstBuildingNumber: [{ required: true, message: '请输入一建建造师数量', trigger: 'change' }], | ||||||
|     build2: [{ required: true, message: '请输入二建建造师数量', trigger: 'change' }], |     secondBuildingNumber: [{ required: true, message: '请输入二建建造师数量', trigger: 'change' }], | ||||||
|     build3: [{ required: true, message: '请输入注册造价工程师数量', trigger: 'change' }], |     registeredEngineerNumber: [{ required: true, message: '请输入注册造价工程师数量', trigger: 'change' }], | ||||||
|     build4: [{ required: true, message: '请输入其他数量', trigger: 'change' }], |     otherBuildingNumber: [{ required: true, message: '请输入其他数量', trigger: 'change' }], | ||||||
|     personnelNumber1: [{ required: true, message: '请输入高级工程师数量', trigger: 'change' }], |     seniorEngineerNumber: [{ required: true, message: '请输入高级工程师数量', trigger: 'change' }], | ||||||
|     personnelNumber2: [{ required: true, message: '请输入工程师数量', trigger: 'change' }], |     engineerNumber: [{ required: true, message: '请输入工程师数量', trigger: 'change' }], | ||||||
|     personnelNumber3: [{ required: true, message: '请输入助理工程师数量', trigger: 'change' }], |     assistantEngineerNumber: [{ required: true, message: '请输入助理工程师数量', trigger: 'change' }], | ||||||
|     personnelNumber4: [{ required: true, message: '请输入其他数量', trigger: 'change' }] |     otherPersonnelNumber: [{ required: true, message: '请输入其他数量', trigger: 'change' }] | ||||||
|   }; |   }; | ||||||
|  |  | ||||||
|   // 仅当类型为"劳务"时,添加安全生产许可证+人员数量校验 |   // 仅当类型为"劳务"时,添加安全生产许可证+人员数量校验 | ||||||
| @ -430,15 +430,15 @@ const rules = computed(() => { | |||||||
|       safeCodeData: [{ required: true, message: '请选择安全生产许可证发证日期', trigger: 'change' }], |       safeCodeData: [{ required: true, message: '请选择安全生产许可证发证日期', trigger: 'change' }], | ||||||
|       safeCertificateValidity: [{ required: true, message: '请选择安全生产许可证有效期', trigger: 'change' }], |       safeCertificateValidity: [{ required: true, message: '请选择安全生产许可证有效期', trigger: 'change' }], | ||||||
|       // 注册人员数量校验 |       // 注册人员数量校验 | ||||||
|       build1: [{ required: true, message: '请输入一建建造师数量', trigger: 'blur' }], |       firstBuildingNumber: [{ required: true, message: '请输入一建建造师数量', trigger: 'blur' }], | ||||||
|       build2: [{ required: true, message: '请输入二建建造师数量', trigger: 'blur' }], |       secondBuildingNumber: [{ required: true, message: '请输入二建建造师数量', trigger: 'blur' }], | ||||||
|       build3: [{ required: true, message: '请输入注册造价工程师数量', trigger: 'blur' }], |       registeredEngineerNumber: [{ required: true, message: '请输入注册造价工程师数量', trigger: 'blur' }], | ||||||
|       build4: [{ required: true, message: '请输入其他注册人员数量', trigger: 'blur' }], |       otherBuildingNumber: [{ required: true, message: '请输入其他注册人员数量', trigger: 'blur' }], | ||||||
|       // 职称人员数量校验 |       // 职称人员数量校验 | ||||||
|       personnelNumber1: [{ required: true, message: '请输入高级工程师数量', trigger: 'blur' }], |       seniorEngineerNumber: [{ required: true, message: '请输入高级工程师数量', trigger: 'blur' }], | ||||||
|       personnelNumber2: [{ required: true, message: '请输入工程师数量', trigger: 'blur' }], |       engineerNumber: [{ required: true, message: '请输入工程师数量', trigger: 'blur' }], | ||||||
|       personnelNumber3: [{ required: true, message: '请输入助理工程师数量', trigger: 'blur' }], |       assistantEngineerNumber: [{ required: true, message: '请输入助理工程师数量', trigger: 'blur' }], | ||||||
|       personnelNumber4: [{ required: true, message: '请输入其他职称人员数量', trigger: 'blur' }] |       otherPersonnelNumber: [{ required: true, message: '请输入其他职称人员数量', trigger: 'blur' }] | ||||||
|     }; |     }; | ||||||
|   } |   } | ||||||
|  |  | ||||||
| @ -455,22 +455,26 @@ const handleTypeChange = () => { | |||||||
|     form.value.registeredNumber = undefined; |     form.value.registeredNumber = undefined; | ||||||
|     form.value.personnelNumber = undefined; |     form.value.personnelNumber = undefined; | ||||||
|     // 清空表单单独字段 |     // 清空表单单独字段 | ||||||
|     form.value.build1 = form.value.build2 = form.value.build3 = form.value.build4 = undefined; |     form.value.firstBuildingNumber = | ||||||
|     form.value.personnelNumber1 = form.value.personnelNumber2 = form.value.personnelNumber3 = form.value.personnelNumber4 = undefined; |       form.value.secondBuildingNumber = | ||||||
|  |       form.value.registeredEngineerNumber = | ||||||
|  |       form.value.otherBuildingNumber = | ||||||
|  |         undefined; | ||||||
|  |     form.value.seniorEngineerNumber = form.value.engineerNumber = form.value.assistantEngineerNumber = form.value.otherPersonnelNumber = undefined; | ||||||
|   } |   } | ||||||
|   // 重置隐藏字段的校验状态,避免错误提示残留 |   // 重置隐藏字段的校验状态,避免错误提示残留 | ||||||
|   supplierInputFormRef.value?.clearValidate([ |   supplierInputFormRef.value?.clearValidate([ | ||||||
|     'safeCode', |     'safeCode', | ||||||
|     'safeCodeData', |     'safeCodeData', | ||||||
|     'safeCertificateValidity', |     'safeCertificateValidity', | ||||||
|     'build1', |     'firstBuildingNumber', | ||||||
|     'build2', |     'secondBuildingNumber', | ||||||
|     'build3', |     'registeredEngineerNumber', | ||||||
|     'build4', |     'otherBuildingNumber', | ||||||
|     'personnelNumber1', |     'seniorEngineerNumber', | ||||||
|     'personnelNumber2', |     'engineerNumber', | ||||||
|     'personnelNumber3', |     'assistantEngineerNumber', | ||||||
|     'personnelNumber4' |     'otherPersonnelNumber' | ||||||
|   ]); |   ]); | ||||||
| }; | }; | ||||||
|  |  | ||||||
| @ -517,18 +521,18 @@ const resetQuery = () => { | |||||||
| const splitBackEndStrToForm = (resData: any) => { | const splitBackEndStrToForm = (resData: any) => { | ||||||
|   if (resData.registeredNumber) { |   if (resData.registeredNumber) { | ||||||
|     const registeredArr = resData.registeredNumber.split(','); |     const registeredArr = resData.registeredNumber.split(','); | ||||||
|     form.value.build1 = registeredArr[0] || undefined; // 一建建造师 |     form.value.firstBuildingNumber = registeredArr[0] || undefined; // 一建建造师 | ||||||
|     form.value.build2 = registeredArr[1] || undefined; // 二建建造师 |     form.value.secondBuildingNumber = registeredArr[1] || undefined; // 二建建造师 | ||||||
|     form.value.build3 = registeredArr[2] || undefined; // 注册造价工程师 |     form.value.registeredEngineerNumber = registeredArr[2] || undefined; // 注册造价工程师 | ||||||
|     form.value.build4 = registeredArr[3] || undefined; // 其他注册人员 |     form.value.otherBuildingNumber = registeredArr[3] || undefined; // 其他注册人员 | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   if (resData.personnelNumber) { |   if (resData.personnelNumber) { | ||||||
|     const personnelArr = resData.personnelNumber.split(','); |     const personnelArr = resData.personnelNumber.split(','); | ||||||
|     form.value.personnelNumber1 = personnelArr[0] || undefined; // 高级工程师 |     form.value.seniorEngineerNumber = personnelArr[0] || undefined; // 高级工程师 | ||||||
|     form.value.personnelNumber2 = personnelArr[1] || undefined; // 工程师 |     form.value.engineerNumber = personnelArr[1] || undefined; // 工程师 | ||||||
|     form.value.personnelNumber3 = personnelArr[2] || undefined; // 助理工程师 |     form.value.assistantEngineerNumber = personnelArr[2] || undefined; // 助理工程师 | ||||||
|     form.value.personnelNumber4 = personnelArr[3] || undefined; // 其他职称人员 |     form.value.otherPersonnelNumber = personnelArr[3] || undefined; // 其他职称人员 | ||||||
|   } |   } | ||||||
| }; | }; | ||||||
| /** 审核过程按钮操作 */ | /** 审核过程按钮操作 */ | ||||||
| @ -572,6 +576,7 @@ const handleAdd = () => { | |||||||
|   dialog.title = '添加供应商入库'; |   dialog.title = '添加供应商入库'; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | const editFileId = ref(''); | ||||||
| const handleUpdate = async (row?: SupplierInputVO) => { | const handleUpdate = async (row?: SupplierInputVO) => { | ||||||
|   reset(); |   reset(); | ||||||
|   const _id = row?.id || ids.value[0]; |   const _id = row?.id || ids.value[0]; | ||||||
| @ -579,7 +584,8 @@ const handleUpdate = async (row?: SupplierInputVO) => { | |||||||
|  |  | ||||||
|   try { |   try { | ||||||
|     const res = await getSupplierInput(_id); |     const res = await getSupplierInput(_id); | ||||||
|     const resData = res.data || {}; |     const resData: any = res.data || {}; | ||||||
|  |     editFileId.value = resData.fileId; | ||||||
|     // 1. 基础字段回显 |     // 1. 基础字段回显 | ||||||
|     form.value = { ...form.value, ...resData, inputFile: '' }; |     form.value = { ...form.value, ...resData, inputFile: '' }; | ||||||
|     // 2. 核心修复:拆分后端拼接字符串到表单单独字段 |     // 2. 核心修复:拆分后端拼接字符串到表单单独字段 | ||||||
| @ -594,32 +600,61 @@ const handleUpdate = async (row?: SupplierInputVO) => { | |||||||
|   } |   } | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | const fileStatus = ref(false); | ||||||
|  | const updateFileStatus = ref(true); | ||||||
|  | const isUpdateFile = ref(false); //记录是否在修改页面时是否有新上传的文件 | ||||||
|  | const handleFileChange = (file, fileList) => { | ||||||
|  |   if (form.value.id) { | ||||||
|  |     updateFileStatus.value = true; | ||||||
|  |     isUpdateFile.value = true; //记录是否在修改页面时是否有新上传的文件 | ||||||
|  |   } | ||||||
|  |   fileStatus.value = true; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | const handleFileRemove = (file, fileList) => { | ||||||
|  |   if (form.value.id) { | ||||||
|  |     updateFileStatus.value = false; | ||||||
|  |     isUpdateFile.value = false; //记录是否在修改页面时是否有新上传的文件 | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   fileStatus.value = false; | ||||||
|  | }; | ||||||
| /** 提交表单 */ | /** 提交表单 */ | ||||||
| const submitForm = () => { | const submitForm = () => { | ||||||
|   supplierInputFormRef.value?.validate(async (valid: boolean) => { |   supplierInputFormRef.value?.validate(async (valid: boolean) => { | ||||||
|     if (!valid) return; |     if (!valid) return; | ||||||
|     if (form.value.supplierType === '劳务') { |     if (form.value.supplierType === '劳务') { | ||||||
|       form.value.registeredNumber = [form.value.build1, form.value.build2, form.value.build3, form.value.build4].join(','); |       form.value.registeredNumber = [ | ||||||
|  |         form.value.firstBuildingNumber, | ||||||
|  |         form.value.secondBuildingNumber, | ||||||
|  |         form.value.registeredEngineerNumber, | ||||||
|  |         form.value.otherBuildingNumber | ||||||
|  |       ].join(','); | ||||||
|       form.value.personnelNumber = [ |       form.value.personnelNumber = [ | ||||||
|         form.value.personnelNumber1, |         form.value.seniorEngineerNumber, | ||||||
|         form.value.personnelNumber2, |         form.value.engineerNumber, | ||||||
|         form.value.personnelNumber3, |         form.value.assistantEngineerNumber, | ||||||
|         form.value.personnelNumber4 |         form.value.otherPersonnelNumber | ||||||
|       ].join(','); |       ].join(','); | ||||||
|     } |     } | ||||||
|     buttonLoading.value = true; |     buttonLoading.value = true; | ||||||
|     try { |     try { | ||||||
|       if (fileUploadRef.value) { |       if (fileUploadRef.value) { | ||||||
|         await fileUploadRef.value.submitUpload().then((res) => { |         if (form.value.fileId === editFileId.value && !isUpdateFile.value) { | ||||||
|           console.log(res); |           console.log(1111111111); | ||||||
|           if (res == 'noFile') { |  | ||||||
|             proxy?.$modal.msgError('请上传文件'); |           editFormData(); | ||||||
|             return; |         } else { | ||||||
|           } |           fileUploadRef.value.submitUpload().then((res) => { | ||||||
|           proxy?.$modal.msgSuccess('操作成功'); |             if (res == 'noFile') { | ||||||
|           dialog.visible = false; |               proxy?.$modal.msgError('请上传文件'); | ||||||
|           getList(); |               return; | ||||||
|         }); |             } | ||||||
|  |             proxy?.$modal.msgSuccess('操作成功'); | ||||||
|  |             dialog.visible = false; | ||||||
|  |             getList(); | ||||||
|  |           }); | ||||||
|  |         } | ||||||
|       } |       } | ||||||
|     } catch (error) { |     } catch (error) { | ||||||
|       proxy?.$modal.msgError('提交失败,请重试'); |       proxy?.$modal.msgError('提交失败,请重试'); | ||||||
| @ -628,7 +663,14 @@ const submitForm = () => { | |||||||
|     } |     } | ||||||
|   }); |   }); | ||||||
| }; | }; | ||||||
|  | const editFormData = async () => { | ||||||
|  |   const res = await updateSupplierInput(form.value); | ||||||
|  |   if ((res.code = 200)) { | ||||||
|  |     proxy?.$modal.msgSuccess('操作成功'); | ||||||
|  |     dialog.visible = false; | ||||||
|  |     getList(); | ||||||
|  |   } | ||||||
|  | }; | ||||||
| /** 删除操作 */ | /** 删除操作 */ | ||||||
| const handleDelete = async (row?: SupplierInputVO) => { | const handleDelete = async (row?: SupplierInputVO) => { | ||||||
|   const _ids = row?.id || ids.value; |   const _ids = row?.id || ids.value; | ||||||
|  | |||||||
| @ -122,41 +122,41 @@ | |||||||
|               </el-row> |               </el-row> | ||||||
|               <el-row class="mb-4" v-if="form.supplierType === '劳务'"> |               <el-row class="mb-4" v-if="form.supplierType === '劳务'"> | ||||||
|                 <el-col :span="12"> |                 <el-col :span="12"> | ||||||
|                   <el-form-item label="一建建造师" prop="build1"> |                   <el-form-item label="一建建造师" prop="firstBuildingNumber"> | ||||||
|                     <el-input v-model="form.build1" placeholder="请输入一建建造师数量" clearable /> |                     <el-input v-model="form.firstBuildingNumber" placeholder="请输入一建建造师数量" clearable /> | ||||||
|                   </el-form-item> |                   </el-form-item> | ||||||
|                 </el-col> |                 </el-col> | ||||||
|                 <el-col :span="12"> |                 <el-col :span="12"> | ||||||
|                   <el-form-item label="二建建造师" prop="build2"> |                   <el-form-item label="二建建造师" prop="secondBuildingNumber"> | ||||||
|                     <el-input v-model="form.build2" placeholder="请输入二建建造师数量" clearable /> |                     <el-input v-model="form.secondBuildingNumber" placeholder="请输入二建建造师数量" clearable /> | ||||||
|                   </el-form-item> |                   </el-form-item> | ||||||
|                 </el-col> |                 </el-col> | ||||||
|                 <el-col :span="12"> |                 <el-col :span="12"> | ||||||
|                   <el-form-item label="其他(分别写)" prop="build4"> |                   <el-form-item label="其他(分别写)" prop="otherBuildingNumber"> | ||||||
|                     <el-input v-model="form.build3" placeholder="请输入其他人员数量" clearable /> |                     <el-input v-model="form.otherBuildingNumber" placeholder="请输入其他人员数量" clearable /> | ||||||
|                   </el-form-item> </el-col |                   </el-form-item> </el-col | ||||||
|                 ><el-col :span="12"> |                 ><el-col :span="12"> | ||||||
|                   <el-form-item label="注册造价工程师" prop="build3"> |                   <el-form-item label="注册造价工程师" prop="registeredEngineerNumber"> | ||||||
|                     <el-input v-model="form.build4" placeholder="请输入注册造价工程师数量" clearable /> |                     <el-input v-model="form.registeredEngineerNumber" placeholder="请输入注册造价工程师数量" clearable /> | ||||||
|                   </el-form-item> |                   </el-form-item> | ||||||
|                 </el-col> |                 </el-col> | ||||||
|               </el-row> |               </el-row> | ||||||
|               <el-row :gutter="24" class="mb-4" v-if="form.supplierType === '劳务'"> |               <el-row :gutter="24" class="mb-4" v-if="form.supplierType === '劳务'"> | ||||||
|                 <el-col :span="12"> |                 <el-col :span="12"> | ||||||
|                   <el-form-item label="高级工程师人数" prop="personnelNumber1"> |                   <el-form-item label="高级工程师人数" prop="seniorEngineerNumber"> | ||||||
|                     <el-input v-model="form.personnelNumber1" placeholder="请输高级工程师数量" clearable /> |                     <el-input v-model="form.seniorEngineerNumber" placeholder="请输高级工程师数量" clearable /> | ||||||
|                   </el-form-item> </el-col |                   </el-form-item> </el-col | ||||||
|                 ><el-col :span="12"> |                 ><el-col :span="12"> | ||||||
|                   <el-form-item label="工程师数量" prop="personnelNumber2"> |                   <el-form-item label="工程师数量" prop="engineerNumber"> | ||||||
|                     <el-input v-model="form.personnelNumber2" placeholder="请输入工程师数量" clearable /> |                     <el-input v-model="form.engineerNumber" placeholder="请输入工程师数量" clearable /> | ||||||
|                   </el-form-item> </el-col |                   </el-form-item> </el-col | ||||||
|                 ><el-col :span="12"> |                 ><el-col :span="12"> | ||||||
|                   <el-form-item label="助理工程师数量" prop="personnelNumber3"> |                   <el-form-item label="助理工程师数量" prop="assistantEngineerNumber"> | ||||||
|                     <el-input v-model="form.personnelNumber3" placeholder="请输入助理工程师数量" clearable /> |                     <el-input v-model="form.assistantEngineerNumber" placeholder="请输入助理工程师数量" clearable /> | ||||||
|                   </el-form-item> </el-col |                   </el-form-item> </el-col | ||||||
|                 ><el-col :span="12"> |                 ><el-col :span="12"> | ||||||
|                   <el-form-item label="其他人员数量" prop="personnelNumber4"> |                   <el-form-item label="其他人员数量" prop="otherPersonnelNumber"> | ||||||
|                     <el-input v-model="form.personnelNumber4" placeholder="请输入其他人员数量" clearable /> |                     <el-input v-model="form.otherPersonnelNumber" placeholder="请输入其他人员数量" clearable /> | ||||||
|                   </el-form-item> |                   </el-form-item> | ||||||
|                 </el-col> |                 </el-col> | ||||||
|               </el-row> |               </el-row> | ||||||
| @ -270,14 +270,14 @@ const initFormData = { | |||||||
|   inputFile: undefined, |   inputFile: undefined, | ||||||
|   state: '0', // 新增默认待审核 |   state: '0', // 新增默认待审核 | ||||||
|   // 新增:用于表单输入的单独字段 |   // 新增:用于表单输入的单独字段 | ||||||
|   build1: undefined, // 一建建造师 |   firstBuildingNumber: undefined, // 一建建造师 | ||||||
|   build2: undefined, // 二建建造师 |   secondBuildingNumber: undefined, // 二建建造师 | ||||||
|   build3: undefined, // 注册造价工程师 |   registeredEngineerNumber: undefined, // 注册造价工程师 | ||||||
|   build4: undefined, // 其他注册人员 |   otherBuildingNumber: undefined, // 其他注册人员 | ||||||
|   personnelNumber1: undefined, // 高级工程师 |   seniorEngineerNumber: undefined, // 高级工程师 | ||||||
|   personnelNumber2: undefined, // 工程师 |   engineerNumber: undefined, // 工程师 | ||||||
|   personnelNumber3: undefined, // 助理工程师 |   assistantEngineerNumber: undefined, // 助理工程师 | ||||||
|   personnelNumber4: undefined // 其他职称人员 |   otherPersonnelNumber: undefined | ||||||
| }; | }; | ||||||
| const data = reactive<PageData<LeaveForm, LeaveQuery>>({ | const data = reactive<PageData<LeaveForm, LeaveQuery>>({ | ||||||
|   form: { ...initFormData }, |   form: { ...initFormData }, | ||||||
| @ -332,17 +332,27 @@ const getInfo = () => { | |||||||
|   buttonLoading.value = false; |   buttonLoading.value = false; | ||||||
|   nextTick(async () => { |   nextTick(async () => { | ||||||
|     const res = await getSupplierInput(routeParams.value.id); |     const res = await getSupplierInput(routeParams.value.id); | ||||||
|  |     console.log(res, '------------------res'); | ||||||
|  |  | ||||||
|     Object.assign(form.value, res.data); |     Object.assign(form.value, res.data); | ||||||
|     form.value.registeredNumber = form.value.registeredNumber?.split(','); |     //  form.value.firstBuildingNumber=res.data.firstBuildingNumber, // 一建建造师 | ||||||
|     form.value.build1 = form.value.registeredNumber[0] || ''; |     // secondBuildingNumber: undefined, // 二建建造师 | ||||||
|     form.value.build2 = form.value.registeredNumber[1] || ''; |     // registeredEngineerNumber: undefined, // 注册造价工程师 | ||||||
|     form.value.build3 = form.value.registeredNumber[2] || ''; |     // otherBuildingNumber: undefined, // 其他注册人员 | ||||||
|     form.value.build4 = form.value.registeredNumber[3] || ''; |     // seniorEngineerNumber: undefined, // 高级工程师 | ||||||
|     form.value.personnelNumber = form.value.personnelNumber?.split(','); |     // engineerNumber: undefined, // 工程师 | ||||||
|     form.value.personnelNumber1 = form.value.personnelNumber[0] || ''; |     // assistantEngineerNumber: undefined, // 助理工程师 | ||||||
|     form.value.personnelNumber2 = form.value.personnelNumber[1] || ''; |     // otherPersonnelNumber: undefined | ||||||
|     form.value.personnelNumber3 = form.value.personnelNumber[2] || ''; |     //   form.value.registeredNumber = form.value.registeredNumber?.split(','); | ||||||
|     form.value.personnelNumber4 = form.value.personnelNumber[3] || ''; |     //   form.value.build1 = form.value.registeredNumber[0] || ''; | ||||||
|  |     //   form.value.build2 = form.value.registeredNumber[1] || ''; | ||||||
|  |     //   form.value.build3 = form.value.registeredNumber[2] || ''; | ||||||
|  |     //   form.value.build4 = form.value.registeredNumber[3] || ''; | ||||||
|  |     //   form.value.personnelNumber = form.value.personnelNumber?.split(','); | ||||||
|  |     //   form.value.personnelNumber1 = form.value.personnelNumber[0] || ''; | ||||||
|  |     //   form.value.personnelNumber2 = form.value.personnelNumber[1] || ''; | ||||||
|  |     //   form.value.personnelNumber3 = form.value.personnelNumber[2] || ''; | ||||||
|  |     //   form.value.personnelNumber4 = form.value.personnelNumber[3] || ''; | ||||||
|  |  | ||||||
|     loading.value = false; |     loading.value = false; | ||||||
|     buttonLoading.value = false; |     buttonLoading.value = false; | ||||||
|  | |||||||
							
								
								
									
										230
									
								
								vite.config.ts.timestamp-1756887630311-9edbd99a3287f.mjs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										230
									
								
								vite.config.ts.timestamp-1756887630311-9edbd99a3287f.mjs
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
		Reference in New Issue
	
	Block a user