瀏覽代碼

Merge branch 'personnelPerformance' into dev

huoyi 1 月之前
父節點
當前提交
7b5d626f75

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

@@ -0,0 +1,70 @@
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
+}

+ 20 - 0
src/api/performance/nonCadreMonthlyAssessSummary.js

@@ -0,0 +1,20 @@
1
+import request from '@/utils/request'
2
+
3
+// 获取非干部月度考核汇总数据
4
+export function getNonCadreMonthlyAssessSummary(query) {
5
+  return request({
6
+    url: '/performance/non-cadre-monthly-assess-summary',
7
+    method: 'get',
8
+    params: query
9
+  })
10
+}
11
+
12
+// 导出非干部月度考核汇总数据
13
+export function exportNonCadreMonthlyAssessSummary(query) {
14
+  return request({
15
+    url: '/performance/non-cadre-monthly-assess-summary/export',
16
+    method: 'get',
17
+    params: query,
18
+    responseType: 'blob'
19
+  })
20
+}

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

@@ -0,0 +1,83 @@
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
+}

+ 88 - 0
src/api/system/classificationAssess.js

@@ -0,0 +1,88 @@
1
+import request from '@/utils/request'
2
+
3
+// 查询考核指标列表
4
+// @param query 查询参数
5
+// @returns {*}
6
+export function listIndicator(query) {
7
+  return request({
8
+    url: '/system/indicator/list',
9
+    method: 'get',
10
+    params: query
11
+  })
12
+}
13
+
14
+// 导出考核指标列表
15
+// @param query 查询参数
16
+// @returns {*}
17
+export function exportIndicator(query) {
18
+  return request({
19
+    url: '/system/indicator/export',
20
+    method: 'post',
21
+    // data: query,
22
+    responseType: 'blob'
23
+  })
24
+}
25
+
26
+// 获取考核指标详细信息
27
+// @param id 考核指标ID
28
+// @returns {*}
29
+export function getIndicator(id) {
30
+  return request({
31
+    url: `/system/indicator/${id}`,
32
+    method: 'get'
33
+  })
34
+}
35
+
36
+// 新增考核指标
37
+// @param data 考核指标数据
38
+// @returns {*}
39
+export function addIndicator(data) {
40
+  return request({
41
+    url: '/system/indicator',
42
+    method: 'post',
43
+    data: data
44
+  })
45
+}
46
+
47
+// 修改考核指标
48
+// @param data 考核指标数据
49
+// @returns {*}
50
+export function updateIndicator(data) {
51
+  return request({
52
+    url: '/system/indicator',
53
+    method: 'put',
54
+    data: data
55
+  })
56
+}
57
+
58
+// 删除考核指标
59
+// @param ids 考核指标ID,多个用逗号分隔
60
+// @returns {*}
61
+export function delIndicator(ids) {
62
+  return request({
63
+    url: `/system/indicator/${ids}`,
64
+    method: 'delete'
65
+  })
66
+}
67
+
68
+// 导入考核指标数据
69
+// @param data 导入数据
70
+// @returns {*}
71
+export function importIndicator(data) {
72
+  return request({
73
+    url: '/system/indicator/importData',
74
+    method: 'post',
75
+    data: data,
76
+    
77
+  })
78
+}
79
+
80
+// 获取导入模板
81
+// @returns {*}
82
+export function getImportTemplate() {
83
+  return request({
84
+    url: '/system/indicator/importTemplate',
85
+    method: 'get',
86
+    responseType: 'blob'
87
+  })
88
+}

+ 48 - 0
src/api/system/classificationAssessIndicator.js

@@ -0,0 +1,48 @@
1
+import request from '@/utils/request'
2
+//查询考核指标分类列表
3
+export function queryAssessCategoryList(query) {
4
+    return request({
5
+        url: '/system/performanceIndicatorCategory/list',
6
+        method: 'get',
7
+        params: query
8
+    })
9
+}
10
+//获取考核指标分类详细信息
11
+export function queryAssessCategoryDetail(categoryId) {
12
+    return request({
13
+        url: `/system/performanceIndicatorCategory/${categoryId}`,
14
+        method: 'get',
15
+
16
+    })
17
+}
18
+//新增考核指标分类
19
+export function addAssessCategory(data) {
20
+    return request({
21
+        url: '/system/performanceIndicatorCategory',
22
+        method: 'post',
23
+        data
24
+    })
25
+}
26
+//修改考核指标分类
27
+export function updateAssessCategory(data) {
28
+    return request({
29
+        url: '/system/performanceIndicatorCategory',
30
+        method: 'put',
31
+        data
32
+    })
33
+}
34
+//删除考核指标分类
35
+export function deleteAssessCategory(ids) {
36
+    return request({
37
+        url: `/system/performanceIndicatorCategory/${ids}`,
38
+        method: 'delete',
39
+    })
40
+}
41
+//查询考核指标分类列表树形结构
42
+export function queryAssessCategoryTree(query) {
43
+    return request({
44
+        url: '/system/performanceIndicatorCategory/listTree',
45
+        method: 'get',
46
+        params: query
47
+    })
48
+}

File diff suppressed because it is too large
+ 1159 - 0
src/views/performanceManage/monthlyAssess/index.vue


+ 0 - 0
src/views/performanceManage/monthlyAssess/月度考核


+ 730 - 0
src/views/performanceManage/monthlyAssessSum/index.vue

@@ -0,0 +1,730 @@
1
+<template>
2
+  <div class="app-container">
3
+    <!-- 查询条件 -->
4
+    <div class="filter-section">
5
+      <el-card>
6
+        <div class="filter-container">
7
+          <el-form :model="queryParams" ref="queryFormRef" :inline="true" class="search-form">
8
+            <el-form-item label="考核月份" prop="assessmentMonth">
9
+              <el-date-picker v-model="queryParams.assessmentMonth" type="month" placeholder="请选择考核月份" 
10
+                value-format="YYYY-MM" style="width: 200px" />
11
+            </el-form-item>
12
+            
13
+            <el-form-item>
14
+              <el-button type="primary" icon="Search" @click="handleQuery">查询</el-button>
15
+              <el-button icon="Refresh" @click="resetQuery">重置</el-button>
16
+            </el-form-item>
17
+          </el-form>
18
+          
19
+          <div class="export-button">
20
+            <el-button type="warning" icon="Document" @click="handleExport">导出文档</el-button>
21
+          </div>
22
+        </div>
23
+      </el-card>
24
+    </div>
25
+
26
+    <!-- 非干部月度考核分数汇总 -->
27
+    <div class="main-section">
28
+      <h2 class="section-title">非干部月度考核分数汇总</h2>
29
+      
30
+      <!-- 第一行:两个区块 -->
31
+      <div class="chart-row">
32
+        <!-- 整体分支分布柱状图 -->
33
+        <el-card class="chart-card">
34
+          <div class="chart-header">整体分支分布柱状图</div>
35
+          <div ref="overallBarChart" class="chart-container"></div>
36
+        </el-card>
37
+        
38
+        <!-- 参与人数占比饼图 -->
39
+        <el-card class="chart-card">
40
+          <div class="chart-header">参与人数占比饼图</div>
41
+          <div ref="participantPieChart" class="chart-container"></div>
42
+        </el-card>
43
+      </div>
44
+
45
+      <!-- 第二行:两个区块 -->
46
+      <div class="chart-row">
47
+        <!-- 各部门分支分布对比图 -->
48
+        <el-card class="chart-card">
49
+          <div class="chart-header">各部门分支分布对比图</div>
50
+          <div ref="departmentComparisonChart" class="chart-container"></div>
51
+        </el-card>
52
+        
53
+        <!-- 汇总表 -->
54
+        <el-card class="chart-card">
55
+          <div class="chart-header">汇总表</div>
56
+          <el-table :data="summaryTableData" border style="width: 100%; margin-top: 10px;">
57
+            <el-table-column prop="range" label="区间" align="center" min-width="100" />
58
+            <el-table-column prop="simulationScore" label="2026年1月模拟分数汇总" align="center" min-width="150" />
59
+            <el-table-column prop="team1" label="一队" align="center" min-width="100" />
60
+            <el-table-column prop="team2" label="二队" align="center" min-width="100" />
61
+            <el-table-column prop="team3" label="三队" align="center" min-width="100" />
62
+          </el-table>
63
+        </el-card>
64
+      </div>
65
+    </div>
66
+
67
+    <!-- 非干部月度考核分类结果汇总 -->
68
+    <div class="main-section">
69
+      <h2 class="section-title">非干部月度考核分类结果汇总</h2>
70
+      
71
+      <!-- 汇总统计表格 -->
72
+      <el-card class="summary-table-card">
73
+        <div class="chart-header">汇总统计</div>
74
+        <el-table :data="classificationTableData" border style="width: 100%; margin-top: 10px;">
75
+          <el-table-column prop="assessmentGroup" label="考核组人数" align="center" min-width="120" />
76
+          <el-table-column prop="calculatedImprovement" label="测算待改进人数" align="center" min-width="140" />
77
+          <el-table-column prop="totalImprovement" label="待改进总人数" align="center" min-width="120" />
78
+          <el-table-column prop="exemption1" label="豁免" align="center" min-width="80" />
79
+          <el-table-column prop="actualImprovement" label="实际待改进总人数" align="center" min-width="140" />
80
+          <el-table-column prop="totalUnqualified" label="不称职总人数" align="center" min-width="120" />
81
+          <el-table-column prop="exemption2" label="豁免" align="center" min-width="80" />
82
+          <el-table-column prop="actualUnqualified" label="实际不称职人数" align="center" min-width="140" />
83
+        </el-table>
84
+      </el-card>
85
+
86
+      <!-- 第四行:两个区块 -->
87
+      <div class="chart-row">
88
+        <!-- 大队分布统计图 -->
89
+        <el-card class="chart-card">
90
+          <div class="chart-header">大队分布统计图</div>
91
+          <div class="pie-charts-container">
92
+            <div ref="brigadePieChart1" class="pie-chart"></div>
93
+            <div ref="brigadePieChart2" class="pie-chart"></div>
94
+          </div>
95
+        </el-card>
96
+        
97
+        <!-- 岗位分布统计图 -->
98
+        <el-card class="chart-card">
99
+          <div class="chart-header">岗位分布统计图</div>
100
+          <div class="pie-charts-container">
101
+            <div ref="positionPieChart1" class="pie-chart"></div>
102
+            <div ref="positionPieChart2" class="pie-chart"></div>
103
+          </div>
104
+        </el-card>
105
+      </div>
106
+    </div>
107
+
108
+    <!-- 第一个遍历:表格和两个饼状图 -->
109
+    <div class="traversal-section">
110
+      <div v-for="(item, index) in traversalData1" :key="index" class="traversal-container">
111
+        <div class="traversal-header">{{ item.title }}</div>
112
+        <div class="traversal-content">
113
+          <!-- 左边表格 -->
114
+          <div class="table-section">
115
+            <el-table :data="item.tableData" border style="width: 100%;">
116
+              <el-table-column prop="brigade" label="大队" align="center" min-width="100" />
117
+              <el-table-column prop="assessmentGroup" label="考核组" align="center" min-width="100" />
118
+              <el-table-column prop="groupCount" label="考核组人数" align="center" min-width="120" />
119
+              <el-table-column prop="calculatedImprovement" label="测算待改进人数" align="center" min-width="140" />
120
+              <el-table-column prop="improvementCount" label="待改进人数" align="center" min-width="120" />
121
+              <el-table-column prop="exemption1" label="豁免" align="center" min-width="80" />
122
+              <el-table-column prop="actualImprovement" label="实际待改进人数" align="center" min-width="140" />
123
+              <el-table-column prop="unqualifiedCount" label="不称职人数" align="center" min-width="120" />
124
+              <el-table-column prop="exemption2" label="豁免" align="center" min-width="80" />
125
+              <el-table-column prop="actualUnqualified" label="实际不称职人数" align="center" min-width="140" />
126
+            </el-table>
127
+          </div>
128
+          
129
+          <!-- 右边两个饼状图 -->
130
+          <div class="chart-section">
131
+            <div class="pie-chart-container">
132
+              <div class="pie-chart-title">考核结果分布</div>
133
+              <div :ref="el => setTraversalChartRef(el, `pieChart1_${index}`)" class="pie-chart"></div>
134
+            </div>
135
+            <div class="pie-chart-container">
136
+              <div class="pie-chart-title">改进情况分布</div>
137
+              <div :ref="el => setTraversalChartRef(el, `pieChart2_${index}`)" class="pie-chart"></div>
138
+            </div>
139
+          </div>
140
+        </div>
141
+      </div>
142
+    </div>
143
+
144
+    <!-- 第二个遍历:表格、柱状图和饼状图 -->
145
+    <div class="traversal-section">
146
+      <div v-for="(item, index) in traversalData2" :key="index" class="traversal-container">
147
+        <div class="traversal-header">{{ item.title }}</div>
148
+        <div class="traversal-content">
149
+          <!-- 左边表格 -->
150
+          <div class="table-section">
151
+            <el-table :data="item.tableData" border style="width: 100%;">
152
+              <el-table-column prop="brigade" label="大队" align="center" min-width="100" />
153
+              <el-table-column prop="assessmentGroup" label="考核组" align="center" min-width="100" />
154
+              <el-table-column prop="groupCount" label="考核组人数" align="center" min-width="120" />
155
+              <el-table-column prop="calculatedImprovement" label="测算待改进人数" align="center" min-width="140" />
156
+              <el-table-column prop="improvementCount" label="待改进人数" align="center" min-width="120" />
157
+              <el-table-column prop="exemption1" label="豁免" align="center" min-width="80" />
158
+              <el-table-column prop="actualImprovement" label="实际待改进人数" align="center" min-width="140" />
159
+              <el-table-column prop="unqualifiedCount" label="不称职人数" align="center" min-width="120" />
160
+              <el-table-column prop="exemption2" label="豁免" align="center" min-width="80" />
161
+              <el-table-column prop="actualUnqualified" label="实际不称职人数" align="center" min-width="140" />
162
+            </el-table>
163
+          </div>
164
+          
165
+          <!-- 右边柱状图和饼状图 -->
166
+          <div class="chart-section">
167
+            <div class="bar-chart-container">
168
+              <div class="chart-title">考核分数分布</div>
169
+              <div :ref="el => setTraversalChartRef(el, `barChart_${index}`)" class="bar-chart"></div>
170
+            </div>
171
+            <div class="pie-chart-container">
172
+              <div class="pie-chart-title">岗位分布</div>
173
+              <div :ref="el => setTraversalChartRef(el, `pieChart3_${index}`)" class="pie-chart"></div>
174
+            </div>
175
+          </div>
176
+        </div>
177
+      </div>
178
+    </div>
179
+  </div>
180
+</template>
181
+
182
+<script setup>
183
+import { ref, reactive, onMounted, nextTick } from 'vue'
184
+import { ElMessage } from 'element-plus'
185
+import * as echarts from 'echarts'
186
+
187
+// API导入
188
+import { getNonCadreMonthlyScoreSum } from '@/api/performance/nonCadreMonthlyScoreSum.js'
189
+
190
+// 响应式数据
191
+const loading = ref(false)
192
+const queryFormRef = ref()
193
+
194
+// 查询参数
195
+const queryParams = reactive({
196
+  assessmentMonth: ''
197
+})
198
+
199
+// 图表引用
200
+const overallBarChart = ref(null)
201
+const participantPieChart = ref(null)
202
+const departmentComparisonChart = ref(null)
203
+const brigadePieChart1 = ref(null)
204
+const brigadePieChart2 = ref(null)
205
+const positionPieChart1 = ref(null)
206
+const positionPieChart2 = ref(null)
207
+
208
+// 遍历图表引用
209
+const traversalChartsRefs = ref({})
210
+
211
+// 表格数据
212
+const summaryTableData = ref([
213
+  { range: '90-100分', simulationScore: '85', team1: '15', team2: '20', team3: '25' },
214
+  { range: '80-89分', simulationScore: '120', team1: '30', team2: '35', team3: '40' },
215
+  { range: '70-79分', simulationScore: '95', team1: '25', team2: '30', team3: '35' },
216
+  { range: '60-69分', simulationScore: '60', team1: '15', team2: '20', team3: '25' },
217
+  { range: '60分以下', simulationScore: '20', team1: '5', team2: '8', team3: '7' }
218
+])
219
+
220
+const classificationTableData = ref([
221
+  { 
222
+    assessmentGroup: '100', 
223
+    calculatedImprovement: '15', 
224
+    totalImprovement: '12', 
225
+    exemption1: '2', 
226
+    actualImprovement: '10', 
227
+    totalUnqualified: '5', 
228
+    exemption2: '1', 
229
+    actualUnqualified: '4'
230
+  }
231
+])
232
+
233
+// 遍历数据
234
+const traversalData1 = ref([
235
+  {
236
+    title: '大队考核统计',
237
+    tableData: [
238
+      { brigade: '一大队', assessmentGroup: '一组', groupCount: 50, calculatedImprovement: 8, improvementCount: 6, exemption1: 1, actualImprovement: 5, unqualifiedCount: 2, exemption2: 0, actualUnqualified: 2 },
239
+      { brigade: '一大队', assessmentGroup: '二组', groupCount: 45, calculatedImprovement: 7, improvementCount: 5, exemption1: 1, actualImprovement: 4, unqualifiedCount: 1, exemption2: 0, actualUnqualified: 1 },
240
+      { brigade: '二大队', assessmentGroup: '一组', groupCount: 55, calculatedImprovement: 9, improvementCount: 7, exemption1: 1, actualImprovement: 6, unqualifiedCount: 3, exemption2: 1, actualUnqualified: 2 },
241
+      { brigade: '二大队', assessmentGroup: '二组', groupCount: 48, calculatedImprovement: 6, improvementCount: 5, exemption1: 0, actualImprovement: 5, unqualifiedCount: 2, exemption2: 0, actualUnqualified: 2 }
242
+    ]
243
+  }
244
+])
245
+
246
+const traversalData2 = ref([
247
+  {
248
+    title: '岗位考核统计',
249
+    tableData: [
250
+      { brigade: '安检员', assessmentGroup: '一组', groupCount: 60, calculatedImprovement: 10, improvementCount: 8, exemption1: 1, actualImprovement: 7, unqualifiedCount: 3, exemption2: 0, actualUnqualified: 3 },
251
+      { brigade: '安检员', assessmentGroup: '二组', groupCount: 55, calculatedImprovement: 8, improvementCount: 6, exemption1: 1, actualImprovement: 5, unqualifiedCount: 2, exemption2: 0, actualUnqualified: 2 },
252
+      { brigade: '设备操作员', assessmentGroup: '一组', groupCount: 40, calculatedImprovement: 5, improvementCount: 4, exemption1: 0, actualImprovement: 4, unqualifiedCount: 1, exemption2: 0, actualUnqualified: 1 }
253
+    ]
254
+  }
255
+])
256
+
257
+// 图表实例
258
+let overallBarChartInstance = null
259
+let participantPieChartInstance = null
260
+let departmentComparisonChartInstance = null
261
+let brigadePieChart1Instance = null
262
+let brigadePieChart2Instance = null
263
+let positionPieChart1Instance = null
264
+let positionPieChart2Instance = null
265
+
266
+// 初始化图表
267
+const initCharts = () => {
268
+  nextTick(() => {
269
+    // 整体分支分布柱状图
270
+    if (overallBarChart.value) {
271
+      overallBarChartInstance = echarts.init(overallBarChart.value)
272
+      overallBarChartInstance.setOption({
273
+        tooltip: { trigger: 'axis' },
274
+        xAxis: { type: 'category', data: ['90-100分', '80-89分', '70-79分', '60-69分', '60分以下'] },
275
+        yAxis: { type: 'value' },
276
+        series: [{ type: 'bar', data: [85, 120, 95, 60, 20], itemStyle: { color: '#3b82f6' } }]
277
+      })
278
+    }
279
+
280
+    // 参与人数占比饼图
281
+    if (participantPieChart.value) {
282
+      participantPieChartInstance = echarts.init(participantPieChart.value)
283
+      participantPieChartInstance.setOption({
284
+        tooltip: { trigger: 'item' },
285
+        series: [{
286
+          type: 'pie',
287
+          radius: '70%',
288
+          data: [
289
+            { value: 380, name: '参与考核' },
290
+            { value: 20, name: '未参与考核' }
291
+          ]
292
+        }]
293
+      })
294
+    }
295
+
296
+    // 各部门分支分布对比图
297
+    if (departmentComparisonChart.value) {
298
+      departmentComparisonChartInstance = echarts.init(departmentComparisonChart.value)
299
+      departmentComparisonChartInstance.setOption({
300
+        tooltip: { trigger: 'axis' },
301
+        legend: { data: ['一队', '二队', '三队'] },
302
+        xAxis: { type: 'category', data: ['90-100分', '80-89分', '70-79分', '60-69分', '60分以下'] },
303
+        yAxis: { type: 'value' },
304
+        series: [
305
+          { name: '一队', type: 'bar', data: [15, 30, 25, 15, 5] },
306
+          { name: '二队', type: 'bar', data: [20, 35, 30, 20, 8] },
307
+          { name: '三队', type: 'bar', data: [25, 40, 35, 25, 7] }
308
+        ]
309
+      })
310
+    }
311
+
312
+    // 大队分布饼图1
313
+    if (brigadePieChart1.value) {
314
+      brigadePieChart1Instance = echarts.init(brigadePieChart1.value)
315
+      brigadePieChart1Instance.setOption({
316
+        tooltip: { trigger: 'item' },
317
+        series: [{
318
+          type: 'pie',
319
+          radius: '70%',
320
+          data: [
321
+            { value: 120, name: '一队' },
322
+            { value: 150, name: '二队' },
323
+            { value: 130, name: '三队' }
324
+          ]
325
+        }]
326
+      })
327
+    }
328
+
329
+    // 大队分布饼图2
330
+    if (brigadePieChart2.value) {
331
+      brigadePieChart2Instance = echarts.init(brigadePieChart2.value)
332
+      brigadePieChart2Instance.setOption({
333
+        tooltip: { trigger: 'item' },
334
+        series: [{
335
+          type: 'pie',
336
+          radius: '70%',
337
+          data: [
338
+            { value: 45, name: '优秀' },
339
+            { value: 280, name: '合格' },
340
+            { value: 75, name: '待改进' }
341
+          ]
342
+        }]
343
+      })
344
+    }
345
+
346
+    // 岗位分布饼图1
347
+    if (positionPieChart1.value) {
348
+      positionPieChart1Instance = echarts.init(positionPieChart1.value)
349
+      positionPieChart1Instance.setOption({
350
+        tooltip: { trigger: 'item' },
351
+        series: [{
352
+          type: 'pie',
353
+          radius: '70%',
354
+          data: [
355
+            { value: 150, name: '安检员' },
356
+            { value: 120, name: '设备操作员' },
357
+            { value: 80, name: '管理人员' },
358
+            { value: 50, name: '其他' }
359
+          ]
360
+        }]
361
+      })
362
+    }
363
+
364
+    // 岗位分布饼图2
365
+    if (positionPieChart2.value) {
366
+      positionPieChart2Instance = echarts.init(positionPieChart2.value)
367
+      positionPieChart2Instance.setOption({
368
+        tooltip: { trigger: 'item' },
369
+        series: [{
370
+          type: 'pie',
371
+          radius: '70%',
372
+          data: [
373
+            { value: 35, name: '优秀' },
374
+            { value: 320, name: '合格' },
375
+            { value: 45, name: '待改进' }
376
+          ]
377
+        }]
378
+      })
379
+    }
380
+  })
381
+}
382
+
383
+// 设置遍历图表引用
384
+const setTraversalChartRef = (el, key) => {
385
+  if (el) {
386
+    traversalChartsRefs.value[key] = el
387
+  }
388
+}
389
+
390
+// 初始化遍历图表
391
+const initTraversalCharts = () => {
392
+  nextTick(() => {
393
+    // 第一个遍历的饼状图
394
+    traversalData1.value.forEach((item, index) => {
395
+      // 饼状图1:考核结果分布
396
+      const pieChart1Key = `pieChart1_${index}`
397
+      if (traversalChartsRefs.value[pieChart1Key]) {
398
+        const pieChart1 = echarts.init(traversalChartsRefs.value[pieChart1Key])
399
+        pieChart1.setOption({
400
+          tooltip: { trigger: 'item' },
401
+          series: [{
402
+            type: 'pie',
403
+            radius: '70%',
404
+            data: [
405
+              { value: 120, name: '优秀' },
406
+              { value: 280, name: '合格' },
407
+              { value: 75, name: '待改进' }
408
+            ]
409
+          }]
410
+        })
411
+      }
412
+
413
+      // 饼状图2:改进情况分布
414
+      const pieChart2Key = `pieChart2_${index}`
415
+      if (traversalChartsRefs.value[pieChart2Key]) {
416
+        const pieChart2 = echarts.init(traversalChartsRefs.value[pieChart2Key])
417
+        pieChart2.setOption({
418
+          tooltip: { trigger: 'item' },
419
+          series: [{
420
+            type: 'pie',
421
+            radius: '70%',
422
+            data: [
423
+              { value: 15, name: '已改进' },
424
+              { value: 60, name: '待改进' },
425
+              { value: 5, name: '未改进' }
426
+            ]
427
+          }]
428
+        })
429
+      }
430
+    })
431
+
432
+    // 第二个遍历的图表
433
+    traversalData2.value.forEach((item, index) => {
434
+      // 柱状图:考核分数分布
435
+      const barChartKey = `barChart_${index}`
436
+      if (traversalChartsRefs.value[barChartKey]) {
437
+        const barChart = echarts.init(traversalChartsRefs.value[barChartKey])
438
+        barChart.setOption({
439
+          tooltip: { trigger: 'axis' },
440
+          xAxis: { type: 'category', data: ['90-100分', '80-89分', '70-79分', '60-69分', '60分以下'] },
441
+          yAxis: { type: 'value' },
442
+          series: [{ type: 'bar', data: [85, 120, 95, 60, 20], itemStyle: { color: '#3b82f6' } }]
443
+        })
444
+      }
445
+
446
+      // 饼状图:岗位分布
447
+      const pieChart3Key = `pieChart3_${index}`
448
+      if (traversalChartsRefs.value[pieChart3Key]) {
449
+        const pieChart3 = echarts.init(traversalChartsRefs.value[pieChart3Key])
450
+        pieChart3.setOption({
451
+          tooltip: { trigger: 'item' },
452
+          series: [{
453
+            type: 'pie',
454
+            radius: '70%',
455
+            data: [
456
+              { value: 150, name: '安检员' },
457
+              { value: 120, name: '设备操作员' },
458
+              { value: 80, name: '管理人员' },
459
+              { value: 50, name: '其他' }
460
+            ]
461
+          }]
462
+        })
463
+      }
464
+    })
465
+  })
466
+}
467
+
468
+// 窗口大小变化时重绘图表
469
+const handleResize = () => {
470
+  const charts = [
471
+    overallBarChartInstance,
472
+    participantPieChartInstance,
473
+    departmentComparisonChartInstance,
474
+    brigadePieChart1Instance,
475
+    brigadePieChart2Instance,
476
+    positionPieChart1Instance,
477
+    positionPieChart2Instance
478
+  ]
479
+  charts.forEach(chart => {
480
+    if (chart) chart.resize()
481
+  })
482
+}
483
+
484
+// 获取数据
485
+const getList = async () => {
486
+  loading.value = true
487
+  try {
488
+    const res = await getNonCadreMonthlyScoreSum(queryParams)
489
+    // 这里可以根据实际API返回的数据更新图表和表格数据
490
+    console.log('获取汇总数据:', res)
491
+  } catch (error) {
492
+    console.error('获取汇总数据失败:', error)
493
+    ElMessage.error('获取汇总数据失败')
494
+  } finally {
495
+    loading.value = false
496
+  }
497
+}
498
+
499
+// 查询
500
+const handleQuery = () => {
501
+  getList()
502
+}
503
+
504
+// 重置查询
505
+const resetQuery = () => {
506
+  queryFormRef.value?.resetFields()
507
+  getList()
508
+}
509
+
510
+// 导出
511
+const handleExport = async () => {
512
+  try {
513
+    ElMessage.success('导出功能开发中')
514
+  } catch (error) {
515
+    ElMessage.error('导出失败')
516
+  }
517
+}
518
+
519
+onMounted(() => {
520
+  initCharts()
521
+  initTraversalCharts()
522
+  window.addEventListener('resize', handleResize)
523
+  getList()
524
+})
525
+
526
+// 组件卸载时移除事件监听器
527
+onUnmounted(() => {
528
+  window.removeEventListener('resize', handleResize)
529
+  // 销毁图表实例
530
+  const charts = [
531
+    overallBarChartInstance,
532
+    participantPieChartInstance,
533
+    departmentComparisonChartInstance,
534
+    brigadePieChart1Instance,
535
+    brigadePieChart2Instance,
536
+    positionPieChart1Instance,
537
+    positionPieChart2Instance
538
+  ]
539
+  charts.forEach(chart => {
540
+    if (chart) chart.dispose()
541
+  })
542
+})
543
+</script>
544
+
545
+<style lang="less" scoped>
546
+.app-container {
547
+  padding: 20px;
548
+}
549
+
550
+.filter-section {
551
+  margin-bottom: 20px;
552
+}
553
+
554
+.filter-container {
555
+  display: flex;
556
+  justify-content: space-between;
557
+  align-items: center;
558
+}
559
+
560
+.search-form {
561
+  display: flex;
562
+  align-items: center;
563
+  gap: 10px;
564
+}
565
+
566
+.export-button {
567
+  margin-left: auto;
568
+}
569
+
570
+.main-section {
571
+  margin-bottom: 30px;
572
+}
573
+
574
+.section-title {
575
+  font-size: 20px;
576
+  font-weight: bold;
577
+  color: #333;
578
+  margin-bottom: 20px;
579
+  text-align: center;
580
+}
581
+
582
+.chart-row {
583
+  display: grid;
584
+  grid-template-columns: 1fr 1fr;
585
+  gap: 20px;
586
+  margin-bottom: 20px;
587
+}
588
+
589
+.chart-card {
590
+  height: 400px;
591
+}
592
+
593
+.summary-table-card {
594
+  margin-bottom: 20px;
595
+}
596
+
597
+.chart-header {
598
+  font-size: 16px;
599
+  font-weight: 600;
600
+  color: #333;
601
+  margin-bottom: 10px;
602
+  text-align: center;
603
+}
604
+
605
+.chart-container {
606
+  width: 100%;
607
+  height: 350px;
608
+}
609
+
610
+.pie-charts-container {
611
+  display: grid;
612
+  grid-template-columns: 1fr 1fr;
613
+  gap: 10px;
614
+  height: 350px;
615
+}
616
+
617
+.pie-chart {
618
+  width: 100%;
619
+  height: 100%;
620
+}
621
+
622
+:deep(.el-table) {
623
+  .el-table__header th {
624
+    background-color: #f5f7fa;
625
+    font-weight: 600;
626
+  }
627
+}
628
+
629
+/* 遍历样式 */
630
+.traversal-section {
631
+  margin-bottom: 30px;
632
+}
633
+
634
+.traversal-container {
635
+  border: 1px solid #dcdfe6;
636
+  border-radius: 8px;
637
+  overflow: hidden;
638
+  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
639
+  margin-bottom: 20px;
640
+}
641
+
642
+.traversal-header {
643
+  background-color: #f5f7fa;
644
+  padding: 15px 20px;
645
+  font-size: 18px;
646
+  font-weight: 600;
647
+  color: #303133;
648
+  border-bottom: 1px solid #dcdfe6;
649
+  text-align: left;
650
+}
651
+
652
+.traversal-content {
653
+  display: grid;
654
+  grid-template-columns: 1fr 1fr;
655
+  gap: 20px;
656
+  padding: 20px;
657
+}
658
+
659
+.table-section {
660
+  min-height: 400px;
661
+}
662
+
663
+.chart-section {
664
+  display: grid;
665
+  grid-template-columns: 1fr 1fr;
666
+  gap: 15px;
667
+  height: 400px;
668
+}
669
+
670
+.pie-chart-container, .bar-chart-container {
671
+  display: flex;
672
+  flex-direction: column;
673
+  border: 1px solid #e4e7ed;
674
+  border-radius: 6px;
675
+  padding: 10px;
676
+  background-color: #fff;
677
+}
678
+
679
+.pie-chart-title, .chart-title {
680
+  font-size: 14px;
681
+  font-weight: 600;
682
+  color: #606266;
683
+  margin-bottom: 10px;
684
+  text-align: center;
685
+}
686
+
687
+.pie-chart, .bar-chart {
688
+  flex: 1;
689
+  min-height: 300px;
690
+}
691
+
692
+/* 响应式布局 */
693
+@media (max-width: 1200px) {
694
+  .chart-row {
695
+    grid-template-columns: 1fr;
696
+  }
697
+  
698
+  .pie-charts-container {
699
+    grid-template-columns: 1fr;
700
+  }
701
+  
702
+  .traversal-content {
703
+    grid-template-columns: 1fr;
704
+    gap: 15px;
705
+  }
706
+  
707
+  .chart-section {
708
+    grid-template-columns: 1fr;
709
+    height: auto;
710
+  }
711
+  
712
+  .pie-chart, .bar-chart {
713
+    min-height: 250px;
714
+  }
715
+}
716
+
717
+@media (max-width: 768px) {
718
+  .traversal-content {
719
+    padding: 15px;
720
+  }
721
+  
722
+  .chart-section {
723
+    gap: 10px;
724
+  }
725
+  
726
+  .pie-chart-container, .bar-chart-container {
727
+    padding: 8px;
728
+  }
729
+}
730
+</style>

+ 0 - 0
src/views/performanceManage/monthlyAssessSum/月度汇总


+ 437 - 0
src/views/system/classificationAssess/index.vue

@@ -0,0 +1,437 @@
1
+<template>
2
+  <div class="app-container">
3
+    <el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="100px">
4
+      <el-form-item label="编码" prop="code">
5
+        <el-input v-model="queryParams.code" placeholder="请输入编码" clearable @keyup.enter="handleQuery" />
6
+      </el-form-item>
7
+      <el-form-item label="考核指标名称" prop="name">
8
+        <el-input v-model="queryParams.name" placeholder="请输入考核指标名称" clearable @keyup.enter="handleQuery" />
9
+      </el-form-item>
10
+
11
+      <!-- <el-form-item label="重要程度" prop="categoryName"> -->
12
+      <!-- <el-select v-model="queryParams.importance" placeholder="请选择重要程度" clearable style="width: 180px;">
13
+          <el-option v-for="dict in base_check_importance" :key="dict.value" :label="dict.label" :value="dict.value" />
14
+        </el-select> -->
15
+      <!-- <el-input v-model="queryParams.categoryName" placeholder="请输入所属分类名称" clearable @keyup.enter="handleQuery" />
16
+      </el-form-item> -->
17
+      <el-form-item>
18
+        <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
19
+        <el-button icon="Refresh" @click="resetQuery">重置</el-button>
20
+      </el-form-item>
21
+    </el-form>
22
+
23
+    <el-row :gutter="10" class="mb8">
24
+      <el-col :span="1.5">
25
+        <el-button type="primary" plain icon="Plus" @click="handleAdd"
26
+          v-hasPermi="['system:project:add']">新增</el-button>
27
+      </el-col>
28
+      <!-- <el-col :span="1.5">
29
+        <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate"
30
+          v-hasPermi="['system:project:edit']">修改</el-button>
31
+      </el-col> -->
32
+      <el-col :span="1.5">
33
+        <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete"
34
+          v-hasPermi="['system:project:remove']">删除</el-button>
35
+      </el-col>
36
+      <el-col :span="1.5">
37
+        <el-button type="warning" plain icon="Download" @click="handleExport"
38
+          v-hasPermi="['system:project:export']">导出</el-button>
39
+      </el-col>
40
+      <el-col :span="1.5">
41
+        <el-button type="info" plain icon="Upload" @click="handleImport"
42
+          v-hasPermi="['system:project:import']">导入</el-button>
43
+      </el-col>
44
+      <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
45
+    </el-row>
46
+
47
+    <el-table v-loading="loading" :data="indicatorList" @selection-change="handleSelectionChange">
48
+      <el-table-column type="selection" width="55" align="center" />
49
+      <el-table-column label="编码" align="center" prop="code" />
50
+      <el-table-column label="考核指标名称" align="center" prop="name" />
51
+      <el-table-column label="所属分类" align="center" prop="categoryName" />
52
+      <el-table-column label="分值" align="center" prop="score" />
53
+      <el-table-column label="单位" align="center" prop="unit" />
54
+      <el-table-column label="事病假" align="center" prop="leaveType" />
55
+      <!-- <el-table-column label="检查标准" align="center" prop="checkStandard" />
56
+      <el-table-column label="检查方法" align="center" prop="checkMethod" /> -->
57
+      <!-- <el-table-column label="重要程度" align="center" prop="importance">
58
+        <template #default="scope">
59
+          <dict-tag :options="base_check_importance" :value="scope.row.importance" />
60
+        </template>
61
+</el-table-column> -->
62
+      <!-- <el-table-column label="状态" align="center" prop="status" >
63
+        <template #default="scope">
64
+          <dict-tag :options="base_check_status" :value="scope.row.status"/>
65
+        </template>
66
+      </el-table-column> -->
67
+      <!-- <el-table-column label="备注" align="center" prop="remark" /> -->
68
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
69
+        <template #default="scope">
70
+          <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)"
71
+            v-hasPermi="['system:project:edit']">修改</el-button>
72
+          <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)"
73
+            v-hasPermi="['system:project:remove']">删除</el-button>
74
+        </template>
75
+      </el-table-column>
76
+    </el-table>
77
+
78
+    <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum"
79
+      v-model:limit="queryParams.pageSize" @pagination="getList" />
80
+
81
+    <!-- 添加或修改考核指标对话框 -->
82
+    <el-dialog :title="title" v-model="open" width="500px" append-to-body>
83
+      <el-form ref="projectRef" :model="form" :rules="rules" label-width="120px">
84
+        <!-- <el-form-item label="编码" prop="code">
85
+          <el-input v-model="form.code" placeholder="请输入编码"  />
86
+        </el-form-item> -->
87
+        <el-form-item label="考核指标名称" prop="name">
88
+          <el-input v-model="form.name" placeholder="请输入考核指标名称" />
89
+        </el-form-item>
90
+        <el-form-item label="所属分类" prop="categoryCode">
91
+          <el-tree-select v-model="form.categoryCode" :data="enableCategoryOptions"
92
+            :props="{ value: 'code', label: 'name', children: 'children' }" value-key="id" placeholder="请选择所属分类"
93
+            @node-click="handleNodeClick" />
94
+        </el-form-item>
95
+        <el-form-item label="分值" prop="score">
96
+          <el-input-number v-model="form.score" :min="0" :precision="2" placeholder="请输入分值" style="width: 100%" />
97
+        </el-form-item>
98
+
99
+
100
+
101
+
102
+        <el-form-item label="单位" prop="unit">
103
+          <el-input v-model="form.unit" placeholder="请输入单位" />
104
+        </el-form-item>
105
+
106
+        <el-form-item label="事病假" prop="leaveType">
107
+          <el-select v-model="form.leaveType" placeholder="请选择事病假" style="width: 100%">
108
+            <el-option label="事假" value="事假" />
109
+            <el-option label="病假" value="病假" />
110
+            <el-option label="无" value="无" />
111
+          </el-select>
112
+        </el-form-item>
113
+        <!-- <el-form-item label="重要程度" prop="importance">
114
+          <el-select v-model="form.importance" placeholder="请选择重要程度">
115
+            <el-option v-for="dict in base_check_importance" :key="dict.value" :label="dict.label"
116
+              :value="dict.value"></el-option>
117
+          </el-select>
118
+        </el-form-item> -->
119
+
120
+        <el-form-item label="备注" prop="remark">
121
+          <el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
122
+        </el-form-item>
123
+      </el-form>
124
+      <template #footer>
125
+        <div class="dialog-footer">
126
+          <el-button type="primary" @click="submitForm">确 定</el-button>
127
+          <el-button @click="cancel">取 消</el-button>
128
+        </div>
129
+      </template>
130
+    </el-dialog>
131
+
132
+    <!-- 导入对话框 -->
133
+    <el-dialog :title="upload.title" v-model="upload.open" width="400px" append-to-body>
134
+      <el-upload ref="uploadRef" :limit="1" accept=".xlsx, .xls" :headers="upload.headers"
135
+        :action="upload.url + '?updateSupport=' + upload.updateSupport" :disabled="upload.isUploading"
136
+        :on-progress="handleFileUploadProgress" :on-success="handleFileSuccess" :auto-upload="false" drag>
137
+        <el-icon class="el-icon--upload"><upload-filled /></el-icon>
138
+        <div class="el-upload__text">
139
+          将文件拖到此处,或<em>点击上传</em>
140
+        </div>
141
+        <template #tip>
142
+          <div class="el-upload__tip">
143
+            <!-- <el-checkbox v-model="upload.updateSupport" /> -->
144
+            <!-- 是否更新已经存在的考核指标数据 -->
145
+             <span>仅允许导入xls、xlsx格式文件。</span>
146
+            <el-link type="primary" :underline="false" style="font-size:12px;vertical-align: baseline;"
147
+              @click="importTemplate">下载模板</el-link>
148
+          </div>
149
+        </template>
150
+      </el-upload>
151
+      <template #footer>
152
+        <div class="dialog-footer">
153
+          <el-button type="primary" @click="submitFileForm">确 定</el-button>
154
+          <el-button @click="upload.open = false">取 消</el-button>
155
+        </div>
156
+      </template>
157
+    </el-dialog>
158
+  </div>
159
+</template>
160
+
161
+<script setup name="Project">
162
+import { listIndicator, getIndicator, delIndicator, addIndicator, updateIndicator, exportIndicator, importIndicator, getImportTemplate } from "@/api/system/classificationAssess"
163
+import { queryAssessCategoryTree } from "@/api/system/classificationAssessIndicator"
164
+import { getToken } from '@/utils/auth'
165
+const { proxy } = getCurrentInstance()
166
+const { base_check_importance, check_level, check_checked_level } = proxy.useDict('base_check_importance', 'check_level', 'check_checked_level')
167
+
168
+const indicatorList = ref([])
169
+const open = ref(false)
170
+const loading = ref(true)
171
+const showSearch = ref(true)
172
+const ids = ref([])
173
+const single = ref(true)
174
+const multiple = ref(true)
175
+const total = ref(0)
176
+const title = ref("")
177
+const base_check_status = ref([{ "value": "0", "label": "启用" }, { "value": "1", "label": "停用" }])
178
+const enableCategoryOptions = ref(undefined)
179
+
180
+// 导入参数
181
+const upload = reactive({
182
+  // 是否显示弹出层
183
+  open: false,
184
+  // 弹出层标题
185
+  title: "",
186
+  // 是否禁用上传
187
+  isUploading: false,
188
+  // 是否更新已经存在的考核指标数据
189
+  updateSupport: 0,
190
+  // 设置上传的请求头部
191
+  headers: { Authorization: "Bearer " + getToken() },
192
+  // 上传的地址
193
+  url: import.meta.env.VITE_APP_BASE_API + "/system/indicator/importData"
194
+})
195
+
196
+const uploadRef = ref()
197
+
198
+const data = reactive({
199
+  form: {},
200
+  queryParams: {
201
+    pageNum: 1,
202
+    pageSize: 10,
203
+    name: null,
204
+    code: null,
205
+  },
206
+  rules: {
207
+    name: [
208
+      { required: true, message: "考核指标名称不能为空", trigger: "blur" }
209
+    ],
210
+    categoryCode: [
211
+      { required: true, message: "分类编码不能为空", trigger: "blur" }
212
+    ],
213
+    // importance: [
214
+    //   { required: true, message: "重要程度不能为空", trigger: "change" }
215
+    // ],
216
+    status: [
217
+      { required: true, message: "状态不能为空", trigger: "change" }
218
+    ],
219
+    categoryName: [
220
+      { required: true, message: "分类名称不能为空", trigger: "blur" }
221
+    ],
222
+    code: [
223
+      { required: true, message: "编码不能为空", trigger: "blur" }
224
+    ],
225
+    // importanceDesc: [
226
+    //   { required: true, message: "重要程度名称不能为空", trigger: "blur" }
227
+    // ]
228
+  }
229
+})
230
+
231
+const { queryParams, form, rules } = toRefs(data)
232
+
233
+/** 查询考核指标列表 */
234
+function getList() {
235
+  loading.value = true
236
+  listIndicator(queryParams.value).then(response => {
237
+    indicatorList.value = response.rows
238
+    total.value = response.total
239
+    loading.value = false
240
+  })
241
+}
242
+
243
+// 取消按钮
244
+function cancel() {
245
+  open.value = false
246
+  reset()
247
+}
248
+
249
+// 表单重置
250
+function reset() {
251
+  form.value = {
252
+    tenantId: null,
253
+    revision: null,
254
+    createBy: null,
255
+    createTime: null,
256
+    updateBy: null,
257
+    updateTime: null,
258
+    id: null,
259
+    name: null,
260
+    categoryCode: null,
261
+    checkStandard: null,
262
+    checkMethod: null,
263
+    importance: null,
264
+    status: null,
265
+    categoryName: null,
266
+    remark: null,
267
+    code: null,
268
+    importanceDesc: null
269
+  }
270
+  proxy.resetForm("projectRef")
271
+}
272
+
273
+/** 搜索按钮操作 */
274
+function handleQuery() {
275
+  queryParams.value.pageNum = 1
276
+  getList()
277
+}
278
+
279
+/** 重置按钮操作 */
280
+function resetQuery() {
281
+  proxy.resetForm("queryRef")
282
+  handleQuery()
283
+}
284
+
285
+// 多选框选中数据
286
+function handleSelectionChange(selection) {
287
+  ids.value = selection.map(item => item.id)
288
+  single.value = selection.length != 1
289
+  multiple.value = !selection.length
290
+}
291
+
292
+/** 新增按钮操作 */
293
+function handleAdd() {
294
+  reset()
295
+  open.value = true
296
+  title.value = "添加考核指标"
297
+}
298
+
299
+/** 修改按钮操作 */
300
+function handleUpdate(row) {
301
+  reset()
302
+  const _id = row.id || ids.value
303
+  getIndicator(_id).then(response => {
304
+    form.value = {
305
+      ...response.data,
306
+      checkLevel: response.data?.checkLevel?.split(","),
307
+    }
308
+    open.value = true
309
+    title.value = "修改考核指标"
310
+  })
311
+}
312
+
313
+/** 提交按钮 */
314
+function submitForm() {
315
+  proxy.$refs["projectRef"].validate(valid => {
316
+    if (valid) {
317
+      // 根据categoryCode获取categoryName
318
+      if (form.value.categoryCode) {
319
+        form.value.categoryName = getCategoryNameByCode(form.value.categoryCode)
320
+      }
321
+      
322
+      // 名称转换
323
+      if (form.value.importance) {
324
+        form.value.importanceDesc = base_check_importance.value.find(item => item.value === form.value.importance).label;
325
+      }
326
+      // form.value.checkLevelDesc = check_level.value.find(item => item.value === form.value.checkLevel).label;
327
+      let res = {
328
+        ...form.value,
329
+        checkLevel: form.value.checkLevel && form.value.checkLevel.join(","),
330
+      }
331
+      if (form.value.id != null) {
332
+        updateIndicator(res).then(response => {
333
+          proxy.$modal.msgSuccess("修改成功")
334
+          open.value = false
335
+          getList()
336
+        })
337
+      } else {
338
+        addIndicator(res).then(response => {
339
+          proxy.$modal.msgSuccess("新增成功")
340
+          open.value = false
341
+          getList()
342
+        })
343
+      }
344
+    }
345
+  })
346
+}
347
+
348
+/** 删除按钮操作 */
349
+function handleDelete(row) {
350
+  const _ids = row.id || ids.value
351
+  proxy.$modal.confirm('是否确认删除数据项?').then(function () {
352
+    return delIndicator(_ids)
353
+  }).then(() => {
354
+    getList()
355
+    proxy.$modal.msgSuccess("删除成功")
356
+  }).catch(() => { })
357
+}
358
+
359
+/** 导出按钮操作 */
360
+function handleExport() {
361
+  // 过滤掉值为null的参数,但保留分页参数
362
+  const filteredParams = Object.fromEntries(
363
+    Object.entries(queryParams.value).filter(([key, value]) => {
364
+      // 保留分页参数
365
+      if (key === 'pageNum' || key === 'pageSize') return true
366
+      // 过滤掉其他为null的参数
367
+      return value !== null
368
+    })
369
+  )
370
+ 
371
+  proxy.download('/system/indicator/export', filteredParams, `indicator_${new Date().getTime()}.xlsx`)
372
+}
373
+/** 查询分类下拉树结构 */
374
+function getCategoryTree() {
375
+  queryAssessCategoryTree().then(response => {
376
+    enableCategoryOptions.value = response.data
377
+  })
378
+}
379
+
380
+function handleNodeClick(data) {
381
+  form.value.categoryName = data.name;
382
+}
383
+
384
+/** 根据categoryCode获取categoryName */
385
+function getCategoryNameByCode(categoryCode) {
386
+  if (!categoryCode || !enableCategoryOptions.value) return ''
387
+  
388
+  const findCategory = (categories) => {
389
+    for (const category of categories) {
390
+      if (category.code === categoryCode) {
391
+        return category.name
392
+      }
393
+      if (category.children && category.children.length > 0) {
394
+        const result = findCategory(category.children)
395
+        if (result) return result
396
+      }
397
+    }
398
+    return ''
399
+  }
400
+  
401
+  return findCategory(enableCategoryOptions.value)
402
+}
403
+
404
+/** 导入按钮操作 */
405
+function handleImport() {
406
+  upload.title = "考核指标导入"
407
+  upload.open = true
408
+}
409
+
410
+/** 下载模板操作 */
411
+function importTemplate() {
412
+  proxy.download('/system/indicator/importTemplate', {
413
+  }, `考核指标导入模板_${new Date().getTime()}.xlsx`)
414
+}
415
+
416
+/** 文件上传中处理 */
417
+const handleFileUploadProgress = (event, file, fileList) => {
418
+  upload.isUploading = true
419
+}
420
+
421
+/** 文件上传成功处理 */
422
+const handleFileSuccess = (response, file, fileList) => {
423
+  upload.open = false
424
+  upload.isUploading = false
425
+  uploadRef.value.handleRemove(file)
426
+  proxy.$alert("<div style='overflow: auto;overflow-x: hidden;max-height: 70vh;padding: 10px 20px 0;'>" + response.msg + "</div>", "导入结果", { dangerouslyUseHTMLString: true })
427
+  getList()
428
+}
429
+
430
+/** 提交上传文件 */
431
+function submitFileForm() {
432
+  uploadRef.value.submit()
433
+}
434
+
435
+getCategoryTree()
436
+getList()
437
+</script>

+ 0 - 0
src/views/system/classificationAssess/考核指标


+ 272 - 0
src/views/system/classificationAssessIndicator/index.vue

@@ -0,0 +1,272 @@
1
+<template>
2
+  <div class="app-container">
3
+    <el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px">
4
+      
5
+      <el-form-item label="指标名称" prop="name">
6
+        <el-input
7
+          v-model="queryParams.name"
8
+          placeholder="请输入指标名称"
9
+          clearable
10
+          @keyup.enter="handleQuery"
11
+        />
12
+      </el-form-item>
13
+      <el-form-item>
14
+        <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
15
+        <el-button icon="Refresh" @click="resetQuery">重置</el-button>
16
+      </el-form-item>
17
+    </el-form>
18
+
19
+    <el-row :gutter="10" class="mb8">
20
+      <el-col :span="1.5">
21
+        <el-button
22
+          type="primary"
23
+          plain
24
+          icon="Plus"
25
+          @click="handleAdd"
26
+          v-hasPermi="['system:checkCategory:add']"
27
+        >新增</el-button>
28
+      </el-col>
29
+      <el-col :span="1.5">
30
+        <el-button
31
+          type="info"
32
+          plain
33
+          icon="Sort"
34
+          @click="toggleExpandAll"
35
+        >展开/折叠</el-button>
36
+      </el-col>
37
+      <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
38
+    </el-row>
39
+
40
+    <el-table
41
+      v-if="refreshTable"
42
+      v-loading="loading"
43
+      :data="assessCategoryList"
44
+      row-key="id"
45
+      :default-expand-all="isExpandAll"
46
+      :tree-props="{children: 'children', hasChildren: 'hasChildren'}"
47
+    >
48
+      <el-table-column label="序号" align="center" prop="code" />
49
+      <el-table-column label="指标名称" align="center" prop="name" />
50
+      <el-table-column label="显示顺序" align="center" prop="orderNum" />
51
+      <!-- <el-table-column label="分值" align="center" prop="score" /> -->
52
+      <el-table-column label="备注" align="center" prop="remark" />
53
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
54
+        <template #default="scope">
55
+          <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:checkCategory:edit']">修改</el-button>
56
+          <el-button link type="primary" icon="Plus" @click="handleAdd(scope.row)" v-hasPermi="['system:checkCategory:add']">新增</el-button>
57
+          <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:checkCategory:remove']">删除</el-button>
58
+        </template>
59
+      </el-table-column>
60
+    </el-table>
61
+
62
+    <!-- 添加或修改指标对话框 -->
63
+    <el-dialog :title="title" v-model="open" width="500px" append-to-body>
64
+      <el-form ref="checkCategoryRef" :model="form" :rules="rules" label-width="80px">
65
+        <!-- <el-form-item label="序号" prop="code">
66
+      
67
+          <el-input v-model="form.code" placeholder="请输入序号" />
68
+        </el-form-item> -->
69
+        <el-form-item label="指标名称" prop="name">
70
+         
71
+          <el-input v-model="form.name" placeholder="请输入指标名称" />
72
+        </el-form-item>
73
+        <el-form-item label="上级位置" prop="parentId">
74
+        
75
+          <el-tree-select
76
+            v-model="form.parentId"
77
+            :data="assessCategoryOptions"
78
+            :props="{ value: 'id', label: 'name', children: 'children' }"
79
+            value-key="id"
80
+            placeholder="顶级节点"
81
+            check-strictly
82
+          />
83
+        </el-form-item>
84
+        <!-- <el-form-item label="分值/单位" prop="scoreUnit">
85
+          <div style="display: flex; align-items: center; gap: 8px; width: 100%;">
86
+            <el-input v-model="form.score" placeholder="" style="flex: 1;" />
87
+            <span>/</span>
88
+            <el-input v-model="form.unit" placeholder="请输入单位" style="flex: 1;" />
89
+          </div>
90
+        </el-form-item> -->
91
+        <el-form-item label="备注" prop="remark">
92
+          <el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
93
+        </el-form-item>
94
+      </el-form>
95
+      <template #footer>
96
+        <div class="dialog-footer">
97
+          <el-button type="primary" @click="submitForm">确 定</el-button>
98
+          <el-button @click="cancel">取 消</el-button>
99
+        </div>
100
+      </template>
101
+    </el-dialog>
102
+  </div>
103
+</template>
104
+
105
+<script setup name="CheckCategory">
106
+import { queryAssessCategoryList, queryAssessCategoryDetail, addAssessCategory, updateAssessCategory, deleteAssessCategory } from "@/api/system/classificationAssessIndicator"
107
+
108
+const { proxy } = getCurrentInstance()
109
+
110
+const assessCategoryList = ref([])
111
+const assessCategoryOptions = ref([])
112
+const open = ref(false)
113
+const loading = ref(true)
114
+const showSearch = ref(true)
115
+const title = ref("")
116
+const isExpandAll = ref(true)
117
+const refreshTable = ref(true)
118
+
119
+const data = reactive({
120
+  form: {},
121
+  queryParams: {
122
+    name: null,
123
+    parentId: null,
124
+    code: null,
125
+    code: null,
126
+    score: null,
127
+    unit: null,
128
+  },
129
+  rules: {
130
+    name: [
131
+      { required: true, message: "指标名称不能为空", trigger: "blur" }
132
+    ],
133
+    parentId: [
134
+      { required: true, message: "上级位置不能为空", trigger: "blur" }
135
+    ],
136
+    code: [
137
+      { required: true, message: "序号不能为空", trigger: "blur" }
138
+    ],
139
+  }
140
+})
141
+
142
+const { queryParams, form, rules } = toRefs(data)
143
+
144
+/** 查询考核指标分类列表 */
145
+function getList() {
146
+  loading.value = true
147
+  queryAssessCategoryList(queryParams.value).then(response => {
148
+    assessCategoryList.value = proxy.handleTree(response.data, "id", "parentId")
149
+    loading.value = false
150
+  })
151
+}
152
+
153
+/** 查询考核指标分类下拉树结构 */
154
+function getTreeselect() {
155
+  queryAssessCategoryList().then(response => {
156
+    assessCategoryOptions.value = []
157
+    const data = { id: 0, name: '顶级节点', children: [] }
158
+    data.children = proxy.handleTree(response.data, "id", "parentId")
159
+    assessCategoryOptions.value.push(data)
160
+  })
161
+}
162
+	
163
+// 取消按钮
164
+function cancel() {
165
+  open.value = false
166
+  reset()
167
+}
168
+
169
+// 表单重置
170
+function reset() {
171
+  form.value = {
172
+    tenantId: null,
173
+    revision: null,
174
+    createBy: null,
175
+    createTime: null,
176
+    updateBy: null,
177
+    updateTime: null,
178
+    id: null,
179
+    name: null,
180
+    parentId: null,
181
+    ancestors: null,
182
+    level: null,
183
+    code: null,
184
+    code: null,
185
+    score: null,
186
+    unit: null,
187
+    remark: null
188
+  }
189
+  proxy.resetForm("checkCategoryRef")
190
+}
191
+
192
+/** 搜索按钮操作 */
193
+function handleQuery() {
194
+  getList()
195
+}
196
+
197
+/** 重置按钮操作 */
198
+function resetQuery() {
199
+  proxy.resetForm("queryRef")
200
+  handleQuery()
201
+}
202
+
203
+/** 新增按钮操作 */
204
+function handleAdd(row) {
205
+  reset()
206
+  getTreeselect()
207
+  
208
+  if (row != null && row.id) {
209
+    form.value.parentId = row.id
210
+  } else {
211
+    form.value.parentId = 0
212
+  }
213
+  open.value = true
214
+  title.value = "添加指标"
215
+}
216
+
217
+/** 展开/折叠操作 */
218
+function toggleExpandAll() {
219
+  refreshTable.value = false
220
+  isExpandAll.value = !isExpandAll.value
221
+  nextTick(() => {
222
+    refreshTable.value = true
223
+  })
224
+}
225
+
226
+/** 修改按钮操作 */
227
+async function handleUpdate(row) {
228
+  reset()
229
+  await getTreeselect()
230
+  if (row != null) {
231
+    form.value.parentId = row.parentId
232
+  }
233
+  queryAssessCategoryDetail(row.id).then(response => {
234
+    form.value = response.data
235
+    open.value = true
236
+    title.value = "修改指标"
237
+  })
238
+}
239
+
240
+/** 提交按钮 */
241
+function submitForm() {
242
+  proxy.$refs["checkCategoryRef"].validate(valid => {
243
+    if (valid) {
244
+      if (form.value.id != null) {
245
+        updateAssessCategory(form.value).then(response => {
246
+          proxy.$modal.msgSuccess("修改成功")
247
+          open.value = false
248
+          getList()
249
+        })
250
+      } else {
251
+        addAssessCategory(form.value).then(response => {
252
+          proxy.$modal.msgSuccess("新增成功")
253
+          open.value = false
254
+          getList()
255
+        })
256
+      }
257
+    }
258
+  })
259
+}
260
+
261
+/** 删除按钮操作 */
262
+function handleDelete(row) {
263
+  proxy.$modal.confirm('是否确认删除数据项?').then(function() {
264
+    return deleteAssessCategory(row.id)
265
+  }).then(() => {
266
+    getList()
267
+    proxy.$modal.msgSuccess("删除成功")
268
+  }).catch(() => {})
269
+}
270
+
271
+getList()
272
+</script>

+ 0 - 0
src/views/system/classificationAssessIndicator/考核指标分类