Bladeren bron

refactor: 整理配分管理页面逻辑,新增组织信息获取接口

1.  新增用户和部门组织信息获取API接口
2.  重构部门/队室/通道/责任人选择逻辑,使用精准的禁用判断
3.  替换预警页面路由路径,新增部门页面初始化顶级节点
4.  优化员工档案标签显示,重构用户编辑页标签输入组件
5.  注释导入页面部分冗余的导入项
huoyi 2 weken geleden
bovenliggende
commit
1256a498bc

+ 17 - 0
src/api/system/user.js

@@ -152,3 +152,20 @@ export function getDeptUserTree(params) {
152 152
     params: params
153 153
   })
154 154
 }
155
+//通过用户ID获取用户组织信息
156
+export function getUserOrgInfo(params) {
157
+  return request({
158
+    url: '/system/dept/userOrgInfo',
159
+    method: 'get',
160
+    params: params
161
+  })
162
+}
163
+
164
+//通过部门ID获取部门组织信息及上级链
165
+export function getDeptOrgInfo(params) {
166
+  return request({
167
+    url: '/system/dept/deptOrgInfo',
168
+    method: 'get',
169
+    params: params
170
+  })
171
+}

+ 1 - 1
src/router/index.js

@@ -91,7 +91,7 @@ export const constantRoutes = [
91 91
     meta: { title: '监控中心', icon: 'dashboard', affix: true },
92 92
     children: [
93 93
       {
94
-        path: '/warningPage',
94
+        path: '/index',
95 95
         component: () => import('@/views/warningPage'),
96 96
         name: 'WarningPage',
97 97
         meta: { title: '预警页面', icon: 'dashboard' }

+ 54 - 54
src/views/ledger/import/index.vue

@@ -251,15 +251,15 @@ const importItems = reactive([
251 251
     loading: false,
252 252
     lastResult: null
253 253
   },
254
-  {
255
-    key: 'patrolInspection',
256
-    title: '队室三级质控巡查记录',
257
-    desc: '队室层级巡查问题记录',
258
-    icon: 'DocumentChecked',
259
-    api: importPatrolInspection,
260
-    loading: false,
261
-    lastResult: null
262
-  },
254
+  // {
255
+  //   key: 'patrolInspection',
256
+  //   title: '队室三级质控巡查记录',
257
+  //   desc: '队室层级巡查问题记录',
258
+  //   icon: 'DocumentChecked',
259
+  //   api: importPatrolInspection,
260
+  //   loading: false,
261
+  //   lastResult: null
262
+  // },
263 263
   {
264 264
     key: 'realtimeInterception',
265 265
     title: '实时质控拦截记录',
@@ -350,51 +350,51 @@ const importItems = reactive([
350 350
     loading: false,
351 351
     lastResult: null
352 352
   },
353
-  {
354
-    key: 'dailyTraining',
355
-    title: '日常培训记录',
356
-    desc: '月度培训任务及完成情况记录',
357
-    icon: 'Reading',
358
-    api: importDailyTraining,
359
-    loading: false,
360
-    lastResult: null
361
-  },
362
-  {
363
-    key: 'leaderDuty',
364
-    title: '组长履职情况记录',
365
-    desc: '队室组长本班点评及问题处置',
366
-    icon: 'Management',
367
-    api: importLeaderDuty,
368
-    loading: false,
369
-    lastResult: null
370
-  },
371
-  {
372
-    key: 'healthSoldier',
373
-    title: '健康锐兵',
374
-    desc: '员工身心健康状况台账记录',
375
-    icon: 'FirstAidKit',
376
-    api: importHealthSoldier,
377
-    loading: false,
378
-    lastResult: null
379
-  },
380
-  {
381
-    key: 'dormFireSafety',
382
-    title: '宿舍消防安全专项自查',
383
-    desc: '宿舍消防隐患自查情况记录',
384
-    icon: 'House',
385
-    api: importDormFireSafety,
386
-    loading: false,
387
-    lastResult: null
388
-  },
389
-  {
390
-    key: 'trainingIssue',
391
-    title: '培训台账问题通报',
392
-    desc: '培训台账发现问题及整改通报',
393
-    icon: 'Bell',
394
-    api: importTrainingIssue,
395
-    loading: false,
396
-    lastResult: null
397
-  }
353
+  // {
354
+  //   key: 'dailyTraining',
355
+  //   title: '日常培训记录',
356
+  //   desc: '月度培训任务及完成情况记录',
357
+  //   icon: 'Reading',
358
+  //   api: importDailyTraining,
359
+  //   loading: false,
360
+  //   lastResult: null
361
+  // },
362
+  // {
363
+  //   key: 'leaderDuty',
364
+  //   title: '组长履职情况记录',
365
+  //   desc: '队室组长本班点评及问题处置',
366
+  //   icon: 'Management',
367
+  //   api: importLeaderDuty,
368
+  //   loading: false,
369
+  //   lastResult: null
370
+  // },
371
+  // {
372
+  //   key: 'healthSoldier',
373
+  //   title: '健康锐兵',
374
+  //   desc: '员工身心健康状况台账记录',
375
+  //   icon: 'FirstAidKit',
376
+  //   api: importHealthSoldier,
377
+  //   loading: false,
378
+  //   lastResult: null
379
+  // },
380
+  // {
381
+  //   key: 'dormFireSafety',
382
+  //   title: '宿舍消防安全专项自查',
383
+  //   desc: '宿舍消防隐患自查情况记录',
384
+  //   icon: 'House',
385
+  //   api: importDormFireSafety,
386
+  //   loading: false,
387
+  //   lastResult: null
388
+  // },
389
+  // {
390
+  //   key: 'trainingIssue',
391
+  //   title: '培训台账问题通报',
392
+  //   desc: '培训台账发现问题及整改通报',
393
+  //   icon: 'Bell',
394
+  //   api: importTrainingIssue,
395
+  //   loading: false,
396
+  //   lastResult: null
397
+  // }
398 398
 ])
399 399
 
400 400
 function beforeUpload(file) {

+ 1 - 1
src/views/portraitManagement/employeeProfile/index.vue

@@ -75,7 +75,7 @@
75 75
                   <div class="info-item-content">
76 76
                     <div class="info-item-label">标签:</div>
77 77
                     <div class="info-item-value">
78
-                      <span class="info-item-tag" v-if="portrait.roleNames">{{ portrait.roleNames }}</span>
78
+                      <span class="info-item-tag" v-if="portrait.userTags">{{ portrait.userTags }}</span>
79 79
                     </div>
80 80
                   </div>
81 81
                 </div>

+ 80 - 48
src/views/score/event/index.vue

@@ -188,7 +188,7 @@
188 188
           <el-col :span="12">
189 189
             <el-form-item label="部门名称" prop="deptId" :rules="rules.deptId">
190 190
               <el-select v-model="form.deptId" placeholder="请选择部门" style="width:100%" clearable filterable
191
-                @change="handleDeptChange">
191
+                :disabled="form.org !== '1'" @change="handleBrigadeChange">
192 192
                 <el-option v-for="d in deptOptions" :key="d.deptId" :label="d.deptName" :value="d.deptId" />
193 193
               </el-select>
194 194
             </el-form-item>
@@ -196,7 +196,7 @@
196 196
           <el-col :span="12">
197 197
             <el-form-item label="队室/班组" prop="teamId" :rules="rules.teamId">
198 198
               <el-select v-model="form.teamId" placeholder="请选择队室/班组" style="width:100%" clearable filterable
199
-                :disabled="form.org < 2" @change="handleTeamChange">
199
+                :disabled="form.org !== '2'" @change="handleDepartmentChange">
200 200
                 <el-option v-for="t in teamOptions" :key="t.id" :label="t.label" :value="t.id" />
201 201
               </el-select>
202 202
             </el-form-item>
@@ -204,7 +204,7 @@
204 204
           <el-col :span="12">
205 205
             <el-form-item label="通道/小组" prop="groupId" :rules="rules.groupId">
206 206
               <el-select v-model="form.groupId" placeholder="请选择通道/小组" style="width:100%" clearable filterable
207
-                :disabled="form.org < 3" @change="handleGroupChange">
207
+                :disabled="form.org !== '3'" @change="handleGroupChange">
208 208
                 <el-option v-for="g in groupOptions" :key="g.id" :label="g.label" :value="g.id" />
209 209
               </el-select>
210 210
             </el-form-item>
@@ -212,7 +212,7 @@
212 212
           <el-col :span="12">
213 213
             <el-form-item label="责任人" prop="personId" :rules="rules.personId">
214 214
               <el-select v-model="form.personId" placeholder="请选择责任人" style="width:100%" clearable filterable
215
-                :disabled="form.org < 4">
215
+                :disabled="form.org !== '4'" @change="handlePersonChange">
216 216
                 <el-option v-for="p in personOptions" :key="p.userId" :label="p.nickName" :value="p.userId" />
217 217
               </el-select>
218 218
             </el-form-item>
@@ -250,7 +250,7 @@
250 250
 <script setup>
251 251
 import { ref, reactive, computed, onMounted, getCurrentInstance } from 'vue'
252 252
 import { ElMessage, ElMessageBox } from 'element-plus'
253
-import { listUser } from '@/api/system/user'
253
+import { listUser, getDeptOrgInfo, getUserOrgInfo } from '@/api/system/user'
254 254
 import {
255 255
   listScoreEvent, addScoreEvent, updateScoreEvent, delScoreEvent,
256 256
   exportScoreEvent, importScoreEvent
@@ -289,13 +289,12 @@ const rules = computed(() => {
289 289
   return {
290 290
     org: [{ required: true, message: '请选择配分层级', trigger: 'submit' }],
291 291
     dimensionId: [{ required: true, message: '请选择维度', trigger: 'submit' }],
292
-    personName: [{ required: true, message: '请输入责任人', trigger: 'submit' }],
293 292
     eventTime: [{ required: true, message: '请选择事件时间', trigger: 'submit' }],
294 293
     scoreValue: [{ required: true, message: '请输入分值', trigger: 'submit' }],
295
-    deptId: ['1', '2', '3', '4'].includes(form.org) ? [{ required: true, message: '请选择部门', trigger: 'submit' }] : [],
296
-    teamId: ['2', '3', '4'].includes(form.org) ? [{ required: true, message: '请选择队室/班组', trigger: 'submit' }] : [],
297
-    groupId: ['3', '4'].includes(form.org) ? [{ required: true, message: '请选择通道/小组', trigger: 'submit' }] : [],
298
-    personId: ['4'].includes(form.org) ? [{ required: true, message: '请选择责任人', trigger: 'submit' }] : [],
294
+    deptId: form.org === '1' ? [{ required: true, message: '请选择部门', trigger: 'submit' }] : [],
295
+    teamId: form.org === '2' ? [{ required: true, message: '请选择队室/班组', trigger: 'submit' }] : [],
296
+    groupId: form.org === '3' ? [{ required: true, message: '请选择通道/小组', trigger: 'submit' }] : [],
297
+    personId: form.org === '4' ? [{ required: true, message: '请选择责任人', trigger: 'submit' }] : [],
299 298
   }
300 299
 })
301 300
 
@@ -321,56 +320,73 @@ async function handleFormLevelChange() {
321 320
   indicatorTree.value = []
322 321
   level2Options.value = []; level3Options.value = []; level4Options.value = []
323 322
   teamOptions.value = []; groupOptions.value = []; personOptions.value = []
324
-  const r = await getDimensionAll({ pageNum: 1, pageSize: 100, org: form.org })
323
+
324
+  const org = form.org
325
+  // if (org === '2') {
326
+  await loadAllTeams()
327
+  // } else if (org === '3') {
328
+  await loadAllGroups()
329
+  // } else if (org === '4') {
330
+  await loadAllPersons()
331
+  // }
332
+
333
+  const r = await getDimensionAll({ pageNum: 1, pageSize: 100, org })
325 334
   dimensionOptions.value = r.data || []
326 335
 }
327 336
 
337
+async function loadAllTeams() {
338
+  const r = await listDept({ deptType: 'MANAGER' })
339
+  teamOptions.value = (r.data || []).map(d => ({ id: d.deptId, label: d.deptName }))
340
+}
341
+
328 342
 async function loadDepts() {
329 343
   const r = await listDept()
330 344
   deptOptions.value = (r.data || []).filter(d => d.deptType === 'BRIGADE')
331 345
 }
332 346
 
333
-async function handleDeptChange(deptId, preserve) {
334
-  if (!preserve) {
335
-    form.teamId = null; form.groupId = null; form.personId = null
336
-    groupOptions.value = []; personOptions.value = []
337
-  }
338
-  if (deptId) {
339
-    const r = await deptTreeSelect({ parentId: deptId })
340
-    teamOptions.value = r.data || []
341
-    if (preserve && form.teamId) {
342
-      await handleTeamChange(form.teamId, true)
347
+async function loadAllGroups() {
348
+  const r = await listDept({ deptType: 'TEAMS' })
349
+  groupOptions.value = (r.data || []).map(d => ({ id: d.deptId, label: d.deptName }))
350
+}
351
+
352
+async function loadAllPersons() {
353
+  const r = await listUser({ pageSize: 9999 })
354
+  personOptions.value = r.rows || []
355
+}
356
+
357
+function handleBrigadeChange() {
358
+}
359
+
360
+async function handleDepartmentChange(val) {
361
+  form.deptId = null
362
+  if (val) {
363
+    const r = await getDeptOrgInfo({ deptId: val })
364
+    if (r.data) {
365
+      form.deptId = r.data.brigadeId
343 366
     }
344
-  } else {
345
-    teamOptions.value = []
346 367
   }
347 368
 }
348 369
 
349
-async function handleTeamChange(val, preserve) {
350
-  if (!preserve) {
351
-    form.groupId = null; form.personId = null
352
-    personOptions.value = []
353
-  }
354
-  const team = teamOptions.value.find(t => t.id === val)
355
-  if (team) {
356
-    const r = await deptTreeSelect({ parentId: team.id })
357
-    groupOptions.value = r.data || []
358
-    if (preserve && form.groupId) {
359
-      await handleGroupChange(form.groupId, true)
370
+async function handleGroupChange(val) {
371
+  form.deptId = null; form.teamId = null
372
+  if (val) {
373
+    const r = await getDeptOrgInfo({ deptId: val })
374
+    if (r.data) {
375
+      form.deptId = r.data.brigadeId
376
+      form.teamId = r.data.departmentId
360 377
     }
361
-  } else {
362
-    groupOptions.value = []
363 378
   }
364 379
 }
365 380
 
366
-async function handleGroupChange(val, preserve) {
367
-  if (!preserve) form.personId = null
368
-  const group = groupOptions.value.find(g => g.id === val)
369
-  if (group) {
370
-    const r = await listUser({ deptId: group.id })
371
-    personOptions.value = r.rows || []
372
-  } else {
373
-    personOptions.value = []
381
+async function handlePersonChange(val) {
382
+  form.deptId = null; form.teamId = null; form.groupId = null
383
+  if (val) {
384
+    const r = await getUserOrgInfo({ userId: val })
385
+    if (r.data) {
386
+      form.deptId = r.data.deptInfo.brigadeId
387
+      form.teamId = r.data.deptInfo.departmentId
388
+      form.groupId = r.data.deptInfo.teamId
389
+    }
374 390
   }
375 391
 }
376 392
 
@@ -440,14 +456,30 @@ function handleUpdate(row) {
440 456
   const record = row?.id ? row : list.value.find(r => r.id === ids.value[0])
441 457
   if (record) {
442 458
     Object.assign(form, record)
459
+    const org = String(record.org)
460
+    form.org = org
461
+    if (org === '1') {
462
+      form.deptId = record.deptId || null
463
+    } else if (org === '2') {
464
+      loadAllTeams().then(() => {
465
+        form.teamId = record.teamId || null
466
+        if (form.teamId) handleDepartmentChange(form.teamId)
467
+      })
468
+    } else if (org === '3') {
469
+      loadAllGroups().then(() => {
470
+        form.groupId = record.groupId || null
471
+        if (form.groupId) handleGroupChange(form.groupId)
472
+      })
473
+    } else if (org === '4') {
474
+      loadAllPersons().then(() => {
475
+        form.personId = record.personId || null
476
+        if (form.personId) handlePersonChange(form.personId)
477
+      })
478
+    }
443 479
     if (record.dimensionId) onDimensionChange(record.dimensionId, true)
444 480
     if (record.level2Id) onLevel2Change(record.level2Id, true)
445 481
     if (record.level3Id) onLevel3Change(record.level3Id, true)
446 482
     if (record.level4Id) onLevel4Change(record.level4Id, true)
447
-    if (record.deptId) handleDeptChange(record.deptId, true)
448
-    if (record.teamId) handleTeamChange(record.teamId, true)
449
-    if (record.groupId) handleGroupChange(record.groupId, true)
450
-
451 483
   }
452 484
   dialogTitle.value = '修改配分事项'; dialogVisible.value = true
453 485
 }

+ 7 - 0
src/views/system/dept/index.vue

@@ -311,4 +311,11 @@ function handleDelete(row) {
311 311
 }
312 312
 
313 313
 getList()
314
+onMounted(() => {
315
+    listDept().then(response => {
316
+    const data = { deptId: 0, deptName: '顶级节点', children: [] }
317
+    data.children = proxy.handleTree(response.data, "deptId")
318
+    deptOptions.value.push(data)
319
+  })
320
+})
314 321
 </script>

+ 52 - 1
src/views/system/user/components/UserInfoEdit.vue

@@ -92,7 +92,14 @@
92 92
           </el-col>
93 93
           <el-col :span="12">
94 94
             <el-form-item label="标签" prop="tags">
95
-              <el-input v-model="form.tags" placeholder="请输入标签" maxlength="50" />
95
+              <div class="tag-input-wrap">
96
+                <el-tag v-for="tag in tagsArray" :key="tag" closable :disable-transitions="false" @close="handleClose(tag)">
97
+                  {{ tag }}
98
+                </el-tag>
99
+                <el-input v-if="inputVisible" ref="tagInputRef" v-model="inputValue" size="small" style="width: 100px"
100
+                  @keyup.enter="handleInputConfirm" @blur="handleInputConfirm" />
101
+                <el-button v-else size="small" @click="showInput">+ 新增标签</el-button>
102
+              </div>
96 103
             </el-form-item>
97 104
           </el-col>
98 105
         </el-row>
@@ -431,6 +438,42 @@ defineProps({
431 438
 const userRef = ref(null)
432 439
 const form = defineModel('form', ref({}))
433 440
 
441
+const tagsArray = ref([])
442
+const inputVisible = ref(false)
443
+const inputValue = ref('')
444
+const tagInputRef = ref(null)
445
+
446
+watch(() => form.value.tags, (val) => {
447
+  if (val) {
448
+    tagsArray.value = val.split(',').filter(t => t.trim())
449
+  } else {
450
+    tagsArray.value = []
451
+  }
452
+}, { immediate: true })
453
+
454
+watch(tagsArray, (arr) => {
455
+  form.value.tags = arr.join(',')
456
+}, { deep: true })
457
+
458
+const handleClose = (tag) => {
459
+  tagsArray.value = tagsArray.value.filter(t => t !== tag)
460
+}
461
+
462
+const showInput = () => {
463
+  inputVisible.value = true
464
+  nextTick(() => {
465
+    tagInputRef.value?.focus()
466
+  })
467
+}
468
+
469
+const handleInputConfirm = () => {
470
+  if (inputValue.value) {
471
+    tagsArray.value = [...tagsArray.value, inputValue.value]
472
+  }
473
+  inputVisible.value = false
474
+  inputValue.value = ''
475
+}
476
+
434 477
 // 政治面貌、资质等级、紧急联系人关系、生肖、星座、血型、是否通过政审、学历、性格特征、工作风格、团队配合、关键词、能力表现、人际互动、成长潜力
435 478
 const {
436 479
   sys_user_political_status,
@@ -546,5 +589,13 @@ defineExpose({
546 589
       color: #000;
547 590
     }
548 591
   }
592
+
593
+  .tag-input-wrap {
594
+    display: flex;
595
+    flex-wrap: wrap;
596
+    gap: 6px;
597
+    align-items: center;
598
+    width: 100%;
599
+  }
549 600
 }
550 601
 </style>