소스 검색

feat(performance): 新增干部月度考核功能并重构相关代码

重构月度考核功能,新增干部考核模块,包括:
1. 添加干部考核API接口
2. 实现干部考核数据生成功能
3. 优化考核列表展示
4. 调整非干部考核代码结构
5. 完善考核结果展示和操作按钮样式
huoyi 1 개월 전
부모
커밋
85293c554b

+ 28 - 0
src/api/examManage/monthlyAssessPerformance.js

@@ -0,0 +1,28 @@
1
+import request from '@/utils/request'
2
+
3
+// 查询月考成绩列表
4
+export function listMonthlyScore(query) {
5
+  return request({
6
+    url: '/exam/monthlyScore/list',
7
+    method: 'get',
8
+    params: query
9
+  })
10
+}
11
+
12
+// 下载导入模板
13
+export function downloadTemplate() {
14
+  return request({
15
+    url: '/exam/monthlyScore/importTemplate',
16
+    method: 'post',
17
+    responseType: 'blob'
18
+  })
19
+}
20
+
21
+// 导入月考成绩数据
22
+export function importData(data) {
23
+  return request({
24
+    url: '/exam/monthlyScore/importData',
25
+    method: 'post',
26
+    data: data
27
+  })
28
+}

+ 19 - 0
src/api/performance/monthlyAssess.js

@@ -0,0 +1,19 @@
1
+import request from '@/utils/request'
2
+
3
+// 查询干部月度考核列表
4
+export function listCadreAssessment(query) {
5
+  return request({
6
+    url: '/personnel/cadre-assessment/list',
7
+    method: 'get',
8
+    params: query
9
+  })
10
+}
11
+
12
+// 生成本月考核数据
13
+export function generateCadreAssessment(data) {
14
+  return request({
15
+    url: '/personnel/cadre-assessment/generate',
16
+    method: 'post',
17
+    data: data
18
+  })
19
+}

src/api/performance/nonCadreMonthlyAssessSummary.js → src/api/performance/monthlyAssessSum.js


+ 0 - 70
src/api/performance/nonCadreMonthlyAssess.js

@@ -1,70 +0,0 @@
1
-import request from '@/utils/request'
2
-
3
-// 获取非干部月度考核列表
4
-export function getNonCadreMonthlyAssessList(query) {
5
-  return request({
6
-    url: '/performance/non-cadre-monthly-assess/list',
7
-    method: 'get',
8
-    params: query
9
-  })
10
-}
11
-
12
-// 新增非干部月度考核
13
-export function addNonCadreMonthlyAssess(data) {
14
-  return request({
15
-    url: '/performance/non-cadre-monthly-assess',
16
-    method: 'post',
17
-    data: data
18
-  })
19
-}
20
-
21
-// 更新非干部月度考核
22
-export function updateNonCadreMonthlyAssess(data) {
23
-  return request({
24
-    url: '/performance/non-cadre-monthly-assess',
25
-    method: 'put',
26
-    data: data
27
-  })
28
-}
29
-
30
-// 删除非干部月度考核
31
-export function deleteNonCadreMonthlyAssess(id) {
32
-  return request({
33
-    url: `/performance/non-cadre-monthly-assess/${id}`,
34
-    method: 'delete'
35
-  })
36
-}
37
-
38
-// 导出非干部月度考核数据
39
-export function exportNonCadreMonthlyAssess(query) {
40
-  return request({
41
-    url: '/performance/non-cadre-monthly-assess/export',
42
-    method: 'get',
43
-    params: query,
44
-    responseType: 'blob'
45
-  })
46
-}
47
-
48
-// 获取用工形式选项
49
-export function getEmploymentTypeOptions() {
50
-  return request({
51
-    url: '/performance/non-cadre-monthly-assess/employment-type-options',
52
-    method: 'get'
53
-  })
54
-}
55
-
56
-// 获取考核结果选项
57
-export function getAssessmentResultOptions() {
58
-  return request({
59
-    url: '/performance/non-cadre-monthly-assess/assessment-result-options',
60
-    method: 'get'
61
-  })
62
-}
63
-
64
-// 获取应用方式选项
65
-export function getApplicationMethodOptions() {
66
-  return request({
67
-    url: '/performance/non-cadre-monthly-assess/application-method-options',
68
-    method: 'get'
69
-  })
70
-}

+ 0 - 83
src/api/performance/nonCadreMonthlyScoreSum.js

@@ -1,83 +0,0 @@
1
-import request from '@/utils/request'
2
-
3
-// 获取非干部月度考核分数汇总数据
4
-export function getNonCadreMonthlyScoreSum(query) {
5
-  return request({
6
-    url: '/performance/non-cadre-monthly-score-sum',
7
-    method: 'get',
8
-    params: query
9
-  })
10
-}
11
-
12
-// 导出非干部月度考核分数汇总文档
13
-export function exportNonCadreMonthlyScoreSum(query) {
14
-  return request({
15
-    url: '/performance/non-cadre-monthly-score-sum/export',
16
-    method: 'get',
17
-    params: query,
18
-    responseType: 'blob'
19
-  })
20
-}
21
-
22
-// 获取整体分支分布数据
23
-export function getOverallScoreDistribution(query) {
24
-  return request({
25
-    url: '/performance/non-cadre-monthly-score-sum/overall-distribution',
26
-    method: 'get',
27
-    params: query
28
-  })
29
-}
30
-
31
-// 获取参与人数占比数据
32
-export function getParticipantRatio(query) {
33
-  return request({
34
-    url: '/performance/non-cadre-monthly-score-sum/participant-ratio',
35
-    method: 'get',
36
-    params: query
37
-  })
38
-}
39
-
40
-// 获取各部门分支分布对比数据
41
-export function getDepartmentComparison(query) {
42
-  return request({
43
-    url: '/performance/non-cadre-monthly-score-sum/department-comparison',
44
-    method: 'get',
45
-    params: query
46
-  })
47
-}
48
-
49
-// 获取汇总表数据
50
-export function getSummaryTableData(query) {
51
-  return request({
52
-    url: '/performance/non-cadre-monthly-score-sum/summary-table',
53
-    method: 'get',
54
-    params: query
55
-  })
56
-}
57
-
58
-// 获取分类结果汇总数据
59
-export function getClassificationSummary(query) {
60
-  return request({
61
-    url: '/performance/non-cadre-monthly-score-sum/classification-summary',
62
-    method: 'get',
63
-    params: query
64
-  })
65
-}
66
-
67
-// 获取大队分布统计数据
68
-export function getBrigadeDistribution(query) {
69
-  return request({
70
-    url: '/performance/non-cadre-monthly-score-sum/brigade-distribution',
71
-    method: 'get',
72
-    params: query
73
-  })
74
-}
75
-
76
-// 获取岗位分布统计数据
77
-export function getPositionDistribution(query) {
78
-  return request({
79
-    url: '/performance/non-cadre-monthly-score-sum/position-distribution',
80
-    method: 'get',
81
-    params: query
82
-  })
83
-}

+ 191 - 0
src/views/examManage/monthlyAssessPerformance/index.vue

@@ -0,0 +1,191 @@
1
+<template>
2
+  <div class="app-container">
3
+    <el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch">
4
+      <el-form-item label="年月" prop="yearMonth">
5
+        <el-date-picker v-model="queryParams.yearMonth" type="month" placeholder="请选择年月" value-format="YYYY-MM" style="width: 200px" />
6
+      </el-form-item>
7
+      <el-form-item label="姓名" prop="studentName">
8
+        <el-input v-model="queryParams.studentName" placeholder="请输入姓名" clearable style="width: 200px" />
9
+      </el-form-item>
10
+      <el-form-item label="科队" prop="team">
11
+        <el-select v-model="queryParams.team" placeholder="请选择科队" clearable style="width: 200px">
12
+          <el-option v-for="dict in exam_team" :key="dict.value" :label="dict.label" :value="dict.value" />
13
+        </el-select>
14
+      </el-form-item>
15
+      <el-form-item label="岗位" prop="jobPosition">
16
+        <el-input v-model="queryParams.jobPosition" placeholder="请输入岗位" clearable style="width: 200px" />
17
+      </el-form-item>
18
+      <el-form-item>
19
+        <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
20
+        <el-button icon="Refresh" @click="resetQuery">重置</el-button>
21
+      </el-form-item>
22
+    </el-form>
23
+
24
+    <el-row :gutter="10" class="mb8">
25
+      <el-col :span="1.5">
26
+        <el-button type="info" plain icon="Upload" @click="handleImport">导入</el-button>
27
+      </el-col>
28
+      <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
29
+    </el-row>
30
+
31
+    <el-table v-loading="loading" :data="trainingPerformanceList" >
32
+      <el-table-column label="年月" align="center" prop="yearMonth" />
33
+      <el-table-column label="学生" align="center" prop="studentName" />
34
+      <el-table-column label="科队" align="center" prop="team">
35
+        <template #default="scope">
36
+          <dict-tag :options="exam_team" :value="scope.row.team" />
37
+        </template>
38
+      </el-table-column>
39
+      <el-table-column label="岗位" align="center" prop="jobPosition">
40
+       
41
+      </el-table-column>
42
+      <el-table-column label="综合成绩" align="center" prop="comprehensiveScore" />
43
+      <el-table-column label="综合用时" align="center" prop="comprehensiveTime" />
44
+      <el-table-column label="专项成绩" align="center" prop="specialScore" />
45
+      <el-table-column label="专项用时" align="center" prop="specialTime" />
46
+    </el-table>
47
+
48
+    <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum"
49
+      v-model:limit="queryParams.pageSize" @pagination="getList" />
50
+
51
+    <!-- 导入对话框 -->
52
+    <el-dialog :title="upload.title" v-model="upload.open" width="400px" append-to-body>
53
+      <el-upload ref="uploadRef" :limit="1" accept=".xlsx, .xls" :headers="upload.headers"
54
+        :action="upload.url + '?updateSupport=' + upload.updateSupport" :disabled="upload.isUploading"
55
+        :on-progress="handleFileUploadProgress" :on-success="handleFileSuccess" :auto-upload="false" drag>
56
+        <el-icon class="el-icon--upload"><upload-filled /></el-icon>
57
+        <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
58
+        <template #tip>
59
+          <div class="el-upload__tip text-center">
60
+              <span>仅允许导入xls、xlsx格式文件。</span>
61
+              <el-link type="primary" :underline="false" style="font-size:16px;vertical-align: baseline;" @click="handleDownloadTemplate">下载模板</el-link>
62
+            </div>
63
+        </template>
64
+      </el-upload>
65
+      <template #footer>
66
+        <div class="dialog-footer">
67
+          <el-button type="primary" @click="submitFileForm">确 定</el-button>
68
+          <el-button @click="upload.open = false">取 消</el-button>
69
+        </div>
70
+      </template>
71
+    </el-dialog>
72
+  </div>
73
+</template>
74
+
75
+<script setup name="TrainingPerformance">
76
+import { listMonthlyScore, downloadTemplate, importData } from "@/api/examManage/monthlyAssessPerformance"
77
+import request from '@/utils/request'
78
+import { getToken } from "@/utils/auth"
79
+import { addDateRange, parseTime } from "@/utils/ruoyi"
80
+import { UploadFilled } from '@element-plus/icons-vue'
81
+
82
+const { proxy } = getCurrentInstance()
83
+const { exam_team, post } = proxy.useDict('exam_team', 'post')
84
+
85
+const trainingPerformanceList = ref([])
86
+const loading = ref(true)
87
+const showSearch = ref(true)
88
+const ids = ref([])
89
+const single = ref(true)
90
+const multiple = ref(true)
91
+const total = ref(0)
92
+const dateRange = ref([])
93
+
94
+// 导入参数
95
+const upload = reactive({
96
+  // 是否显示弹出层
97
+  open: false,
98
+  // 弹出层标题
99
+  title: "",
100
+  // 是否禁用上传
101
+  isUploading: false,
102
+  // 是否更新已经存在的用户数据
103
+  updateSupport: 0,
104
+  // 设置上传的请求头部
105
+  headers: { Authorization: "Bearer " + getToken() },
106
+  // 上传的地址
107
+  url: import.meta.env.VITE_APP_BASE_API + "/exam/monthlyScore/importData"
108
+})
109
+
110
+const data = reactive({
111
+  queryParams: {
112
+    pageNum: 1,
113
+    pageSize: 10,
114
+    yearMonth: undefined,
115
+    studentName: undefined,
116
+    team: undefined,
117
+    position: undefined
118
+  }
119
+})
120
+
121
+const { queryParams } = toRefs(data)
122
+
123
+/** 查询月考成绩列表 */
124
+function getList() {
125
+  loading.value = true;
126
+  let params = {
127
+    ...queryParams.value,
128
+  }
129
+  listMonthlyScore(params).then(response => {
130
+    trainingPerformanceList.value = response.rows
131
+    total.value = response.total
132
+    loading.value = false
133
+  })
134
+}
135
+
136
+/** 搜索按钮操作 */
137
+function handleQuery() {
138
+  queryParams.value.pageNum = 1
139
+  getList()
140
+}
141
+
142
+/** 重置按钮操作 */
143
+function resetQuery() {
144
+  dateRange.value = []
145
+  proxy.resetForm("queryRef")
146
+  handleQuery()
147
+}
148
+
149
+/** 多选框选中数据 */
150
+function handleSelectionChange(selection) {
151
+  ids.value = selection.map(item => item.id)
152
+  single.value = selection.length != 1
153
+  multiple.value = !selection.length
154
+}
155
+
156
+/** 导入按钮操作 */
157
+function handleImport() {
158
+  upload.title = "导入"
159
+  upload.open = true
160
+}
161
+
162
+/** 下载模板操作 */
163
+function handleDownloadTemplate() {
164
+  proxy.download("/exam/monthlyScore/importTemplate", {}, `monthly_score_template_${new Date().getTime()}.xlsx`, 'post')
165
+}
166
+
167
+/**文件上传中处理 */
168
+const handleFileUploadProgress = (event, file, fileList) => {
169
+  upload.isUploading = true
170
+}
171
+
172
+/** 文件上传成功处理 */
173
+const handleFileSuccess = (response, file, fileList) => {
174
+  upload.open = false
175
+  upload.isUploading = false
176
+  proxy.$refs["uploadRef"].handleRemove(file)
177
+  if (response.code === 200) {
178
+    proxy.$alert("<div style='overflow: auto;overflow-x: hidden;max-height: 70vh;padding: 10px 20px 0;'>" + response.msg + "</div>", "导入结果", { dangerouslyUseHTMLString: true })
179
+    getList()
180
+  } else {
181
+    proxy.$modal.msgError(response.msg)
182
+  }
183
+}
184
+
185
+/** 提交上传文件 */
186
+function submitFileForm() {
187
+  proxy.$refs["uploadRef"].submit()
188
+}
189
+
190
+getList()
191
+</script>

+ 50 - 26
src/views/performanceManage/monthlyAssess/index.vue

@@ -94,10 +94,10 @@
94 94
           <el-table-column label="是否豁免备注" prop="exemptionRemark" align="center" min-width="140" show-overflow-tooltip />
95 95
           <el-table-column label="考核月份" prop="assessmentMonth" align="center" min-width="120" />
96 96
 
97
-          <el-table-column label="操作" align="center" width="150" fixed="right">
97
+          <el-table-column label="操作" align="center" width="120" fixed="right">
98 98
             <template #default="scope">
99
-              <el-button size="small" type="primary" link @click="handleEdit(scope.row, 'non-cadre')">修改</el-button>
100
-              <el-button size="small" type="danger" link @click="handleDelete(scope.row)">删除</el-button>
99
+              <el-button link type="primary" icon="Edit" @click="handleEdit(scope.row, 'non-cadre')">修改</el-button>
100
+              <el-button link type="danger" icon="Delete" @click="handleDelete(scope.row)">删除</el-button>
101 101
             </template>
102 102
           </el-table-column>
103 103
         </el-table>
@@ -106,28 +106,32 @@
106 106
       <!-- 干部数据表格 -->
107 107
       <div v-else>
108 108
         <el-table v-loading="loading" :data="cadreList" border fit highlight-current-row style="width: 100%; margin-top: 20px;">
109
-          <el-table-column label="员工姓名" prop="employeeName" align="center" min-width="120" />
110
-          <el-table-column label="岗位" prop="position" align="center" min-width="120" />
111
-          <el-table-column label="区域" prop="area" align="center" min-width="100" />
109
+          <el-table-column label="姓名" prop="name" align="center" min-width="120" />
110
+          <el-table-column label="部门" prop="deptName" align="center" min-width="120" />
111
+          <el-table-column label="岗位" prop="post" align="center" min-width="120">
112
+            <template #default="scope">
113
+              <dict-tag :options="post" :value="scope.row.post" />
114
+            </template>
115
+          </el-table-column>
116
+          <el-table-column label="区域" prop="area" align="center" min-width="100">
117
+            <template #default="scope">
118
+              <dict-tag :options="work_area" :value="scope.row.area" />
119
+            </template>
120
+          </el-table-column>
112 121
           <el-table-column label="红线扣分" prop="redLineDeduction" align="center" min-width="100" />
113
-          <el-table-column label="红线扣分豁免情况" prop="redLineExemption" align="center" min-width="140" show-overflow-tooltip />
114 122
           <el-table-column label="违规排名扣分" prop="violationRankingDeduction" align="center" min-width="140" />
115
-          <el-table-column label="违规排名扣分豁免情况" prop="violationRankingExemption" align="center" min-width="180" show-overflow-tooltip />
116 123
           <el-table-column label="技能排名扣分" prop="skillRankingDeduction" align="center" min-width="140" />
117
-          <el-table-column label="技能排名扣分豁免情况" prop="skillRankingExemption" align="center" min-width="180" show-overflow-tooltip />
124
+          <el-table-column label="技能排名扣分豁免情况" prop="skillExemptionStatus" align="center" min-width="180" show-overflow-tooltip />
118 125
           <el-table-column label="总分" prop="totalScore" align="center" min-width="100" sortable />
119 126
           <el-table-column label="考核结果" prop="assessmentResult" align="center" min-width="120" />
120
-          <el-table-column label="考核结果备注" prop="assessmentResultRemark" align="center" min-width="140" show-overflow-tooltip />
121
-          <el-table-column label="考核月份" prop="assessmentMonth" align="center" min-width="120" />
122
-          <el-table-column label="应用方式" prop="applicationMethod" align="center" min-width="120" />
123
-          <el-table-column label="应用方式备注" prop="applicationMethodRemark" align="center" min-width="160" show-overflow-tooltip />
124
-
125
-          <el-table-column label="操作" align="center" width="150" fixed="right">
127
+          <el-table-column label="考核结果备注" prop="assessmentRemark" align="center" min-width="140" show-overflow-tooltip />
128
+          <el-table-column label="考核月份" align="center" min-width="120">
126 129
             <template #default="scope">
127
-              <el-button size="small" type="primary" link @click="handleEdit(scope.row, 'cadre')">修改</el-button>
128
-              <el-button size="small" type="danger" link @click="handleDelete(scope.row)">删除</el-button>
130
+              {{ scope.row.year }}-{{ String(scope.row.month).padStart(2, '0') }}
129 131
             </template>
130 132
           </el-table-column>
133
+          <el-table-column label="应用方式" prop="applicationMethod" align="center" min-width="120" />
134
+          <el-table-column label="应用方式备注" prop="applicationRemark" align="center" min-width="160" show-overflow-tooltip />
131 135
         </el-table>
132 136
       </div>
133 137
 
@@ -572,13 +576,14 @@
572 576
 </template>
573 577
 
574 578
 <script setup>
575
-import { ref, reactive, onMounted, getCurrentInstance } from 'vue'
579
+import { ref, reactive, onMounted, getCurrentInstance, watch } from 'vue'
576 580
 import { ElMessage, ElMessageBox } from 'element-plus'
577 581
 
578 582
 // API导入(需要根据实际API路径调整)
579
-import { getNonCadreMonthlyAssessList, addNonCadreMonthlyAssess, updateNonCadreMonthlyAssess, deleteNonCadreMonthlyAssess } from '@/api/performance/nonCadreMonthlyAssess.js'
583
+import { listCadreAssessment, generateCadreAssessment } from '@/api/performance/monthlyAssess.js'
580 584
 
581 585
 const { proxy } = getCurrentInstance()
586
+const { post, work_area } = proxy.useDict('post', 'work_area')
582 587
 
583 588
 // 响应式数据
584 589
 const loading = ref(false)
@@ -587,6 +592,11 @@ const queryFormRef = ref()
587 592
 const formRef = ref()
588 593
 const currentTab = ref('non-cadre')
589 594
 
595
+// 监听tab切换
596
+watch(() => currentTab.value, () => {
597
+  getList()
598
+})
599
+
590 600
 // 查询参数
591 601
 const queryParams = reactive({
592 602
   pageNum: 1,
@@ -754,13 +764,15 @@ const getList = async () => {
754 764
   loading.value = true
755 765
   try {
756 766
     if (currentTab.value === 'non-cadre') {
757
-      const res = await getNonCadreMonthlyAssessList(queryParams)
758
-      nonCadreList.value = res.rows || []
759
-      total.value = res.total || 0
767
+      // const res = await getNonCadreMonthlyAssessList(queryParams)
768
+      // nonCadreList.value = res.rows || []
769
+      // total.value = res.total || 0
760 770
     } else {
761
-      // 干部数据API(待实现)
762
-      cadreList.value = []
763
-      total.value = 0
771
+      // 干部数据API
772
+      const res = await listCadreAssessment(queryParams)
773
+      
774
+      cadreList.value = res.rows || []
775
+      total.value = res.total || 0
764 776
     }
765 777
   } catch (error) {
766 778
     console.error('获取数据失败:', error)
@@ -892,9 +904,21 @@ const handleExport = async () => {
892 904
 // 生成本月考核表
893 905
 const generateMonthlyAssessment = async () => {
894 906
   try {
895
-    ElMessage.success('生成本月考核表功能开发中')
907
+    ElMessageBox.confirm('是否生成本月干部考核数据?', '提示', {
908
+      confirmButtonText: '确定',
909
+      cancelButtonText: '取消',
910
+      type: 'warning'
911
+    }).then(async () => {
912
+      loading.value = true
913
+      const res = await generateCadreAssessment({ assessmentMonth: queryParams.assessmentMonth })
914
+      ElMessage.success('生成成功')
915
+      getList()
916
+    }).catch(() => {})
896 917
   } catch (error) {
918
+    console.error('生成失败:', error)
897 919
     ElMessage.error('生成失败')
920
+  } finally {
921
+    loading.value = false
898 922
   }
899 923
 }
900 924