Просмотр исходного кода

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

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

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

@@ -152,3 +152,20 @@ export function getDeptUserTree(params) {
152
     params: params
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
     meta: { title: '监控中心', icon: 'dashboard', affix: true },
91
     meta: { title: '监控中心', icon: 'dashboard', affix: true },
92
     children: [
92
     children: [
93
       {
93
       {
94
-        path: '/warningPage',
94
+        path: '/index',
95
         component: () => import('@/views/warningPage'),
95
         component: () => import('@/views/warningPage'),
96
         name: 'WarningPage',
96
         name: 'WarningPage',
97
         meta: { title: '预警页面', icon: 'dashboard' }
97
         meta: { title: '预警页面', icon: 'dashboard' }

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

@@ -251,15 +251,15 @@ const importItems = reactive([
251
     loading: false,
251
     loading: false,
252
     lastResult: null
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
     key: 'realtimeInterception',
264
     key: 'realtimeInterception',
265
     title: '实时质控拦截记录',
265
     title: '实时质控拦截记录',
@@ -350,51 +350,51 @@ const importItems = reactive([
350
     loading: false,
350
     loading: false,
351
     lastResult: null
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
 function beforeUpload(file) {
400
 function beforeUpload(file) {

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

@@ -75,7 +75,7 @@
75
                   <div class="info-item-content">
75
                   <div class="info-item-content">
76
                     <div class="info-item-label">标签:</div>
76
                     <div class="info-item-label">标签:</div>
77
                     <div class="info-item-value">
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
                     </div>
79
                     </div>
80
                   </div>
80
                   </div>
81
                 </div>
81
                 </div>

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

@@ -188,7 +188,7 @@
188
           <el-col :span="12">
188
           <el-col :span="12">
189
             <el-form-item label="部门名称" prop="deptId" :rules="rules.deptId">
189
             <el-form-item label="部门名称" prop="deptId" :rules="rules.deptId">
190
               <el-select v-model="form.deptId" placeholder="请选择部门" style="width:100%" clearable filterable
190
               <el-select v-model="form.deptId" placeholder="请选择部门" style="width:100%" clearable filterable
191
-                @change="handleDeptChange">
191
+                :disabled="form.org !== '1'" @change="handleBrigadeChange">
192
                 <el-option v-for="d in deptOptions" :key="d.deptId" :label="d.deptName" :value="d.deptId" />
192
                 <el-option v-for="d in deptOptions" :key="d.deptId" :label="d.deptName" :value="d.deptId" />
193
               </el-select>
193
               </el-select>
194
             </el-form-item>
194
             </el-form-item>
@@ -196,7 +196,7 @@
196
           <el-col :span="12">
196
           <el-col :span="12">
197
             <el-form-item label="队室/班组" prop="teamId" :rules="rules.teamId">
197
             <el-form-item label="队室/班组" prop="teamId" :rules="rules.teamId">
198
               <el-select v-model="form.teamId" placeholder="请选择队室/班组" style="width:100%" clearable filterable
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
                 <el-option v-for="t in teamOptions" :key="t.id" :label="t.label" :value="t.id" />
200
                 <el-option v-for="t in teamOptions" :key="t.id" :label="t.label" :value="t.id" />
201
               </el-select>
201
               </el-select>
202
             </el-form-item>
202
             </el-form-item>
@@ -204,7 +204,7 @@
204
           <el-col :span="12">
204
           <el-col :span="12">
205
             <el-form-item label="通道/小组" prop="groupId" :rules="rules.groupId">
205
             <el-form-item label="通道/小组" prop="groupId" :rules="rules.groupId">
206
               <el-select v-model="form.groupId" placeholder="请选择通道/小组" style="width:100%" clearable filterable
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
                 <el-option v-for="g in groupOptions" :key="g.id" :label="g.label" :value="g.id" />
208
                 <el-option v-for="g in groupOptions" :key="g.id" :label="g.label" :value="g.id" />
209
               </el-select>
209
               </el-select>
210
             </el-form-item>
210
             </el-form-item>
@@ -212,7 +212,7 @@
212
           <el-col :span="12">
212
           <el-col :span="12">
213
             <el-form-item label="责任人" prop="personId" :rules="rules.personId">
213
             <el-form-item label="责任人" prop="personId" :rules="rules.personId">
214
               <el-select v-model="form.personId" placeholder="请选择责任人" style="width:100%" clearable filterable
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
                 <el-option v-for="p in personOptions" :key="p.userId" :label="p.nickName" :value="p.userId" />
216
                 <el-option v-for="p in personOptions" :key="p.userId" :label="p.nickName" :value="p.userId" />
217
               </el-select>
217
               </el-select>
218
             </el-form-item>
218
             </el-form-item>
@@ -250,7 +250,7 @@
250
 <script setup>
250
 <script setup>
251
 import { ref, reactive, computed, onMounted, getCurrentInstance } from 'vue'
251
 import { ref, reactive, computed, onMounted, getCurrentInstance } from 'vue'
252
 import { ElMessage, ElMessageBox } from 'element-plus'
252
 import { ElMessage, ElMessageBox } from 'element-plus'
253
-import { listUser } from '@/api/system/user'
253
+import { listUser, getDeptOrgInfo, getUserOrgInfo } from '@/api/system/user'
254
 import {
254
 import {
255
   listScoreEvent, addScoreEvent, updateScoreEvent, delScoreEvent,
255
   listScoreEvent, addScoreEvent, updateScoreEvent, delScoreEvent,
256
   exportScoreEvent, importScoreEvent
256
   exportScoreEvent, importScoreEvent
@@ -289,13 +289,12 @@ const rules = computed(() => {
289
   return {
289
   return {
290
     org: [{ required: true, message: '请选择配分层级', trigger: 'submit' }],
290
     org: [{ required: true, message: '请选择配分层级', trigger: 'submit' }],
291
     dimensionId: [{ required: true, message: '请选择维度', trigger: 'submit' }],
291
     dimensionId: [{ required: true, message: '请选择维度', trigger: 'submit' }],
292
-    personName: [{ required: true, message: '请输入责任人', trigger: 'submit' }],
293
     eventTime: [{ required: true, message: '请选择事件时间', trigger: 'submit' }],
292
     eventTime: [{ required: true, message: '请选择事件时间', trigger: 'submit' }],
294
     scoreValue: [{ required: true, message: '请输入分值', trigger: 'submit' }],
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
   indicatorTree.value = []
320
   indicatorTree.value = []
322
   level2Options.value = []; level3Options.value = []; level4Options.value = []
321
   level2Options.value = []; level3Options.value = []; level4Options.value = []
323
   teamOptions.value = []; groupOptions.value = []; personOptions.value = []
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
   dimensionOptions.value = r.data || []
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
 async function loadDepts() {
342
 async function loadDepts() {
329
   const r = await listDept()
343
   const r = await listDept()
330
   deptOptions.value = (r.data || []).filter(d => d.deptType === 'BRIGADE')
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
   const record = row?.id ? row : list.value.find(r => r.id === ids.value[0])
456
   const record = row?.id ? row : list.value.find(r => r.id === ids.value[0])
441
   if (record) {
457
   if (record) {
442
     Object.assign(form, record)
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
     if (record.dimensionId) onDimensionChange(record.dimensionId, true)
479
     if (record.dimensionId) onDimensionChange(record.dimensionId, true)
444
     if (record.level2Id) onLevel2Change(record.level2Id, true)
480
     if (record.level2Id) onLevel2Change(record.level2Id, true)
445
     if (record.level3Id) onLevel3Change(record.level3Id, true)
481
     if (record.level3Id) onLevel3Change(record.level3Id, true)
446
     if (record.level4Id) onLevel4Change(record.level4Id, true)
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
   dialogTitle.value = '修改配分事项'; dialogVisible.value = true
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
 getList()
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
 </script>
321
 </script>

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

@@ -92,7 +92,14 @@
92
           </el-col>
92
           </el-col>
93
           <el-col :span="12">
93
           <el-col :span="12">
94
             <el-form-item label="标签" prop="tags">
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
             </el-form-item>
103
             </el-form-item>
97
           </el-col>
104
           </el-col>
98
         </el-row>
105
         </el-row>
@@ -431,6 +438,42 @@ defineProps({
431
 const userRef = ref(null)
438
 const userRef = ref(null)
432
 const form = defineModel('form', ref({}))
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
 const {
478
 const {
436
   sys_user_political_status,
479
   sys_user_political_status,
@@ -546,5 +589,13 @@ defineExpose({
546
       color: #000;
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
 </style>
601
 </style>