Sfoglia il codice sorgente

Merge branch 'performanceConfig'

huoyi 3 settimane fa
parent
commit
ebca0a635d

+ 26 - 0
src/api/performance/performance.js

@@ -0,0 +1,26 @@
1
+import request from '@/utils/request'
2
+//绩效查询
3
+export function getPerformanceList(query) {
4
+  return request({
5
+    url: '/item/indicators/query',
6
+    method: 'get',
7
+    params: query
8
+  })
9
+}
10
+//获取绩效矩阵参数配置
11
+export function getMatrixConfig(query) {
12
+  return request({
13
+    url: '/item/indicators/matrix/config',
14
+    method: 'get',
15
+    params: query
16
+  })
17
+}
18
+//保存绩效矩阵
19
+export function saveMatrixConfig(query) {
20
+  return request({
21
+    url: '/item/indicators/matrix/add',
22
+    method: 'get',
23
+    params: query
24
+  })
25
+}
26
+

+ 35 - 0
src/utils/request.js

@@ -150,4 +150,39 @@ export function download(url, params, filename, config) {
150 150
   })
151 151
 }
152 152
 
153
+// GET方法下载方法
154
+export function getDownload(url, params, filename, config) {
155
+  downloadLoadingInstance = ElLoading.service({ text: "正在下载数据,请稍候", background: "rgba(0, 0, 0, 0.7)", })
156
+  
157
+  // 处理GET请求参数
158
+  let requestUrl = url
159
+  if (params) {
160
+    const queryString = tansParams(params)
161
+    if (queryString) {
162
+      requestUrl += '?' + queryString
163
+    }
164
+  }
165
+  
166
+  return service.get(requestUrl, {
167
+    responseType: 'blob',
168
+    ...config
169
+  }).then(async (data) => {
170
+    const isBlob = blobValidate(data)
171
+    if (isBlob) {
172
+      const blob = new Blob([data])
173
+      saveAs(blob, filename)
174
+    } else {
175
+      const resText = await data.text()
176
+      const rspObj = JSON.parse(resText)
177
+      const errMsg = errorCode[rspObj.code] || rspObj.msg || errorCode['default']
178
+      ElMessage.error(errMsg)
179
+    }
180
+    downloadLoadingInstance.close()
181
+  }).catch((r) => {
182
+    console.error(r)
183
+    ElMessage.error('下载文件出现错误,请联系管理员!')
184
+    downloadLoadingInstance.close()
185
+  })
186
+}
187
+
153 188
 export default service

+ 1 - 0
src/utils/ruoyi.js

@@ -226,3 +226,4 @@ export function getNormalPath(p) {
226 226
 export function blobValidate(data) {
227 227
   return data.type !== 'application/json'
228 228
 }
229
+

+ 272 - 0
src/views/performanceManage/performanceConfig/index.vue

@@ -0,0 +1,272 @@
1
+<template>
2
+  <div class="app-container">
3
+    <el-card>
4
+      <!-- 第一行:标题 -->
5
+      <div class="header-section">
6
+        <h2 class="section-title">绩效指标</h2>
7
+      </div>
8
+
9
+      <!-- 第二行:多选按钮组 -->
10
+      <div class="button-group-section">
11
+        <el-checkbox-group v-model="selectedIndicators" class="indicator-checkbox-group" :min="3">
12
+          <el-checkbox-button v-for="indicator in indicatorOptions" :key="indicator.value" :label="indicator.value" disabled>
13
+            {{ indicator.label }}
14
+          </el-checkbox-button>
15
+        </el-checkbox-group>
16
+      </div>
17
+
18
+      <!-- 第三行:绩效矩阵标题 -->
19
+      <div class="header-section" style="margin-top: 30px;">
20
+        <h2 class="section-title">绩效矩阵</h2>
21
+      </div>
22
+
23
+      <!-- 第四行:默认值说明 -->
24
+      <!-- <div class="default-value-section">
25
+        <p class="default-value-text">
26
+          默认值a=3,b=5,c=2;abc可编辑,编辑后,计算逻辑按照下图取倒数
27
+        </p>
28
+      </div> -->
29
+
30
+      <!-- 第五行:绩效矩阵表格 -->
31
+      <div class="matrix-section">
32
+
33
+        <el-table :data="matrixData" border style="width:600px; margin-top: 20px;" class="performance-matrix">
34
+
35
+          <!-- 表头 -->
36
+          <el-table-column label="" prop="rowName" align="center" width="120" fixed />
37
+
38
+          <el-table-column v-for="header in matrixHeaders" :key="header" :label="header" align="center" min-width="120">
39
+            <template #default="scope">
40
+              <div v-if="scope.row.rowName === '查获效率' && header === '查获效率'" class="fixed-cell">
41
+                1
42
+              </div>
43
+              <div v-else-if="scope.row.rowName === '查获效率' && header === '巡检合格率'" class="editable-cell">
44
+                <el-input-number v-model="aValue" :min="1" :step="1" controls-position="right" size="small"
45
+                  style="width: 100%;" />
46
+              </div>
47
+              <div v-else-if="scope.row.rowName === '查获效率' && header === '抽问抽答正确率'" class="editable-cell">
48
+                <el-input-number v-model="bValue" :min="1" :step="1" controls-position="right" size="small"
49
+                  style="width: 100%;" />
50
+              </div>
51
+              <div v-else-if="scope.row.rowName === '巡检合格率' && header === '查获效率'" class="calculated-cell">
52
+                {{ reciprocalA }}
53
+              </div>
54
+              <div v-else-if="scope.row.rowName === '巡检合格率' && header === '巡检合格率'" class="fixed-cell">
55
+                1
56
+              </div>
57
+              <div v-else-if="scope.row.rowName === '巡检合格率' && header === '抽问抽答正确率'" class="editable-cell">
58
+                <el-input-number v-model="cValue" :min="1" :step="1" controls-position="right" size="small"
59
+                  style="width: 100%;" />
60
+              </div>
61
+              <div v-else-if="scope.row.rowName === '抽问抽答正确率' && header === '查获效率'" class="calculated-cell">
62
+                {{ reciprocalB }}
63
+              </div>
64
+              <div v-else-if="scope.row.rowName === '抽问抽答正确率' && header === '巡检合格率'" class="calculated-cell">
65
+                {{ reciprocalC }}
66
+              </div>
67
+              <div v-else-if="scope.row.rowName === '抽问抽答正确率' && header === '抽问抽答正确率'" class="fixed-cell">
68
+                1
69
+              </div>
70
+              <div v-else>
71
+                -
72
+              </div>
73
+            </template>
74
+          </el-table-column>
75
+        </el-table>
76
+
77
+        <div class="matrix-actions" style="margin-bottom: 20px;">
78
+          <el-button type="primary" @click="handleSaveMatrixConfig">保存配置</el-button>
79
+        </div>
80
+      </div>
81
+    </el-card>
82
+  </div>
83
+</template>
84
+
85
+<script setup>
86
+import { ref, reactive, onMounted, computed } from 'vue'
87
+import { ElMessage } from 'element-plus'
88
+import { getMatrixConfig, saveMatrixConfig } from '@/api/performance/performance.js'
89
+
90
+// 绩效指标选项
91
+const indicatorOptions = [
92
+  { label: '查获效率', value: 'detectionEfficiency' },
93
+  { label: '巡检合格率', value: 'inspectionPassRate' },
94
+  { label: '抽问抽答正确率', value: 'trainingScore' }
95
+]
96
+
97
+// 选中的指标(默认全选)
98
+const selectedIndicators = ref(['detectionEfficiency', 'inspectionPassRate', 'trainingScore'])
99
+
100
+// 矩阵表头
101
+const matrixHeaders = ['查获效率', '巡检合格率', '抽问抽答正确率']
102
+
103
+// 矩阵数据(简化版,主要用于显示行名)
104
+const matrixData = reactive([
105
+  { rowName: '查获效率' },
106
+  { rowName: '巡检合格率' },
107
+  { rowName: '抽问抽答正确率' }
108
+])
109
+
110
+// 可编辑的a、b、c值
111
+const aValue = ref(0)
112
+const bValue = ref(0)
113
+const cValue = ref(0)
114
+
115
+// 计算值(使用computed实现自动更新)
116
+const reciprocalA = computed(() => `1/${aValue.value}`)
117
+const reciprocalB = computed(() => `1/${bValue.value}`)
118
+const reciprocalC = computed(() => `1/${cValue.value}`)
119
+
120
+// 保存绩效矩阵配置
121
+const handleSaveMatrixConfig = async () => {
122
+  try {
123
+    const params = {
124
+      a: aValue.value,
125
+      b: bValue.value,
126
+      c: cValue.value
127
+    }
128
+
129
+    const response = await saveMatrixConfig(params)
130
+
131
+    if (response.code === 200) {
132
+      ElMessage.success('保存成功')
133
+    } else {
134
+      ElMessage.error('保存失败:' + response.msg)
135
+    }
136
+  } catch (error) {
137
+    console.error('保存配置异常:', error)
138
+    ElMessage.error('保存失败,请重试')
139
+  }
140
+}
141
+
142
+// 获取绩效矩阵配置
143
+const fetchMatrixConfig = async () => {
144
+  try {
145
+    const response = await getMatrixConfig({})
146
+
147
+    if (response.code === 200 && response.data) {
148
+      const { paramA, paramB, paramC } = response.data
149
+      // 设置从接口返回的a、b、c值
150
+      aValue.value = paramA || 0
151
+      bValue.value = paramB || 0
152
+      cValue.value = paramC || 0
153
+    }
154
+  } catch (error) {
155
+    console.error('获取配置异常:', error)
156
+    // 使用默认值
157
+    aValue.value = 3
158
+    bValue.value = 5
159
+    cValue.value = 2
160
+  }
161
+}
162
+
163
+onMounted(() => {
164
+  // 页面加载时获取配置
165
+  fetchMatrixConfig()
166
+})
167
+</script>
168
+
169
+<style lang="less" scoped>
170
+.app-container {
171
+  padding: 20px;
172
+}
173
+
174
+.header-section {
175
+  margin-bottom: 20px;
176
+
177
+  .section-title {
178
+    margin: 0;
179
+    color: #303133;
180
+    font-size: 18px;
181
+    font-weight: 600;
182
+  }
183
+}
184
+
185
+.button-group-section {
186
+  margin-bottom: 30px;
187
+
188
+  .indicator-checkbox-group {
189
+    display: flex;
190
+    gap: 10px;
191
+
192
+    :deep(.el-checkbox-button) {
193
+      .el-checkbox-button__inner {
194
+        padding: 12px 20px;
195
+        font-size: 14px;
196
+        border-radius: 4px;
197
+
198
+        &:hover {
199
+          color: #409EFF;
200
+          border-color: #409EFF;
201
+        }
202
+      }
203
+
204
+      &.is-checked {
205
+        .el-checkbox-button__inner {
206
+          background-color: #409EFF;
207
+          border-color: #409EFF;
208
+          color: #fff;
209
+
210
+          &:hover {
211
+            background-color: #66b1ff;
212
+            border-color: #66b1ff;
213
+          }
214
+        }
215
+      }
216
+    }
217
+  }
218
+}
219
+
220
+.default-value-section {
221
+  margin: 20px 0;
222
+  padding: 15px;
223
+  background-color: #f5f7fa;
224
+  border-radius: 4px;
225
+  border-left: 4px solid #409EFF;
226
+
227
+  .default-value-text {
228
+    margin: 0;
229
+    color: #606266;
230
+    font-size: 14px;
231
+    line-height: 1.5;
232
+  }
233
+}
234
+
235
+.matrix-section {
236
+  .matrix-actions {
237
+    margin-top: 20px;
238
+  }
239
+
240
+  .performance-matrix {
241
+    :deep(.el-table__header-wrapper) {
242
+      th {
243
+        background-color: #f5f7fa;
244
+        font-weight: 600;
245
+        color: #303133;
246
+      }
247
+    }
248
+
249
+    :deep(.el-table__body-wrapper) {
250
+      td {
251
+        .fixed-cell {
252
+          color: #303133;
253
+          font-weight: 600;
254
+        }
255
+
256
+        .editable-cell {
257
+          padding: 4px;
258
+        }
259
+
260
+        .calculated-cell {
261
+          color: #409EFF;
262
+          font-weight: 500;
263
+        }
264
+
265
+        &:not(:first-child) {
266
+          font-weight: 500;
267
+        }
268
+      }
269
+    }
270
+  }
271
+}
272
+</style>

+ 491 - 0
src/views/performanceManage/performanceSearch/index.vue

@@ -0,0 +1,491 @@
1
+<template>
2
+  <div class="app-container">
3
+    <el-card>
4
+      <!-- 第一行:科室班组个人按钮组 -->
5
+      <div class="filter-container">
6
+        <div class="button-group">
7
+          <span class="button-group-label">查询范围:</span>
8
+          <el-button v-for="item in queryTypeOptions" :key="item.value"
9
+            :type="queryType === item.value ? 'primary' : 'default'"
10
+            :class="queryType === item.value ? 'active' : 'inactive'" @click="handleQueryTypeChange(item.value)">
11
+            {{ item.label }}
12
+          </el-button>
13
+        </div>
14
+
15
+        <div class="button-group" style="margin-left: 20px;">
16
+          <span class="button-group-label">时间范围:</span>
17
+          <el-button v-for="item in timeRangeOptions" :key="item.value"
18
+            :type="timeRange === item.value ? 'primary' : 'default'"
19
+            :class="timeRange === item.value ? 'active' : 'inactive'" @click="handleTimeRangeChange(item.value)">
20
+            {{ item.label }}
21
+          </el-button>
22
+
23
+          <!-- 自定义时间范围选择器 -->
24
+          <el-date-picker v-if="timeRange === 'custom'" v-model="customDateRange" type="daterange" range-separator="至"
25
+            start-placeholder="开始日期" end-placeholder="结束日期" value-format="YYYY-MM-DD"
26
+            style="margin-left: 10px; width: 240px;" @change="handleCustomDateChange" />
27
+        </div>
28
+      </div>
29
+
30
+      <!-- 第二行:查询条件 -->
31
+      <el-form :model="queryParams" ref="queryFormRef" :inline="true" class="search-form">
32
+        <!-- 大队下拉框 -->
33
+        <el-form-item label="大队" prop="brigadeId" v-if="queryType === '3' || queryType === '2' || queryType === '1'">
34
+          <el-select v-model="queryParams.brigadeId" placeholder="请选择大队" clearable style="width: 200px"
35
+            @change="handleBrigadeChange">
36
+            <el-option v-for="item in brigadeOptions" :key="item.value" :label="item.text" :value="item.value" />
37
+          </el-select>
38
+        </el-form-item>
39
+        
40
+        <!-- 主管下拉框 -->
41
+        <el-form-item label="主管" prop="deptId" v-if="queryType === '3' || queryType === '2' || queryType === '1'">
42
+          <el-select v-model="queryParams.deptId" placeholder="请选择主管" clearable style="width: 200px"
43
+            @change="handleQuery">
44
+            <el-option v-for="item in departmentOptions" :key="item.value" :label="item.text" :value="item.value" />
45
+          </el-select>
46
+        </el-form-item>
47
+        
48
+        <!-- 班组下拉框 -->
49
+        <el-form-item label="班组" prop="teamId" v-if="queryType === '2' || queryType === '1'">
50
+          <el-select v-model="queryParams.teamId" placeholder="请选择班组" clearable style="width: 200px"
51
+            @change="handleQuery">
52
+            <el-option v-for="item in teamOptions" :key="item.value" :label="item.text" :value="item.value" />
53
+          </el-select>
54
+        </el-form-item>
55
+        
56
+        <!-- 姓名输入框 -->
57
+        <el-form-item label="姓名" prop="userName" v-if="queryType === '1'">
58
+          <el-input v-model="queryParams.userName" placeholder="请输入姓名" clearable style="width: 200px"
59
+            @input="handleQuery" />
60
+        </el-form-item>
61
+        <!-- <el-form-item>
62
+          <el-button type="primary" icon="Search" @click="handleQuery">查询</el-button>
63
+          <el-button icon="Refresh" @click="resetQuery">重置</el-button>
64
+        </el-form-item> -->
65
+      </el-form>
66
+
67
+      <!-- 导出按钮 -->
68
+      <div class="export-container">
69
+        <el-button type="warning" icon="Download" @click="handleExport">导出</el-button>
70
+      </div>
71
+
72
+      <!-- 表格 -->
73
+      <el-table v-loading="loading" :data="performanceList" border fit highlight-current-row
74
+        style="width: 100%; margin-top: 20px;">
75
+       <!-- 动态列 -->
76
+        <el-table-column v-if="queryType === '4'||queryType === '3'" label="大队"
77
+          :prop="queryType === '4'?'name':'brigadeName'" align="center" min-width="120" />
78
+        <!-- 动态列 -->
79
+        <el-table-column v-if="queryType === '3' || queryType === '2' || queryType === '1'" label="主管"
80
+          :prop="queryType === '3' ? 'name' : 'deptName'" align="center" min-width="120" />
81
+
82
+        <el-table-column v-if="queryType === '2' || queryType === '1'" label="班组"
83
+          :prop="queryType === '2' ? 'name' : 'className'" align="center" min-width="120" />
84
+
85
+        <el-table-column v-if="queryType === '1'" label="姓名" prop="name" align="center" min-width="100" />
86
+
87
+        <!-- 固定列 -->
88
+        <el-table-column label="总分" prop="totalScore" align="center" min-width="100" sortable
89
+          :sort-orders="['ascending', 'descending']" @sort-change="handleSortChange('totalScore', $event)" />
90
+
91
+        <el-table-column label="查获效率" prop="seizureEfficiency" align="center" min-width="120" sortable
92
+          :sort-orders="['ascending', 'descending']" @sort-change="handleSortChange('seizureEfficiency', $event)" />
93
+
94
+        <el-table-column label="抽问抽答正确率" prop="trainingScore" align="center" min-width="100" sortable
95
+          :sort-orders="['ascending', 'descending']" @sort-change="handleSortChange('trainingScore', $event)" />
96
+
97
+        <el-table-column label="巡检合格率" prop="inspectionPassRate" align="center" min-width="120" sortable
98
+          :sort-orders="['ascending', 'descending']" @sort-change="handleSortChange('inspectionPassRate', $event)" />
99
+      </el-table>
100
+
101
+      <!-- 分页 -->
102
+      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum"
103
+        v-model:limit="queryParams.pageSize" @pagination="getList" />
104
+    </el-card>
105
+  </div>
106
+</template>
107
+
108
+<script setup>
109
+import { ref, reactive, onMounted, getCurrentInstance, watch } from 'vue'
110
+import { getPerformanceList } from '@/api/performance/performance.js'
111
+import { listDept } from '@/api/system/dept.js'
112
+
113
+import { getDownload } from '@/utils/request.js'
114
+
115
+// 查询类型选项
116
+const queryTypeOptions = [
117
+  { label: '大队', value: '4' },
118
+  { label: '主管', value: '3' },
119
+  { label: '班组', value: '2' },
120
+  { label: '个人', value: '1' }
121
+]
122
+
123
+// 时间范围选项
124
+const timeRangeOptions = [
125
+  { label: '近三个月', value: 'threeMonths' },
126
+  { label: '近六个月', value: 'sixMonths' },
127
+  { label: '自定义', value: 'custom' }
128
+]
129
+
130
+// 响应式数据
131
+const queryType = ref('4') // 默认查询科室
132
+const timeRange = ref('threeMonths') // 默认近三个月
133
+const customDateRange = ref([])
134
+const loading = ref(false)
135
+const total = ref(0)
136
+const queryFormRef = ref()
137
+
138
+// 查询参数
139
+const queryParams = reactive({
140
+  pageNum: 1,
141
+  pageSize: 10,
142
+  brigadeId: '',
143
+  deptId: '',
144
+  teamId: '',
145
+  userName: '',
146
+  sortField: '',
147
+  sortOrder: ''
148
+})
149
+
150
+// 绩效数据列表
151
+const performanceList = ref([])
152
+
153
+// 部门数据
154
+const deptList = ref([])
155
+const brigadeOptions = ref([])
156
+const departmentOptions = ref([])
157
+const teamOptions = ref([])
158
+
159
+// 大队变化处理函数
160
+const handleBrigadeChange = (brigadeId) => {
161
+  // 清空主管和班组选项
162
+  queryParams.deptId = null
163
+  queryParams.teamId = null
164
+  teamOptions.value = []
165
+  
166
+  if (brigadeId) {
167
+    // 根据大队ID获取主管列表
168
+    departmentOptions.value = deptList.value.filter(item => 
169
+      item.deptType === 'MANAGER' && item.parentId === brigadeId
170
+    ).map(item => ({
171
+      value: item.deptId,
172
+      text: item.deptName
173
+    }))
174
+  } else {
175
+    // 如果没有选择大队,显示所有主管
176
+    departmentOptions.value = deptList.value.filter(item => item.deptType === 'MANAGER').map(item => ({
177
+      value: item.deptId,
178
+      text: item.deptName
179
+    }))
180
+  }
181
+  
182
+  handleQuery()
183
+}
184
+
185
+// 监听科室变化,获取对应班组
186
+watch(() => queryParams.deptId, async (newDeptId) => {
187
+  if (newDeptId) {
188
+    await fetchTeamByDept(newDeptId)
189
+  } else {
190
+    // 如果清空科室选择,重置班组选项为所有班组
191
+    teamOptions.value = deptList.value.filter(item => item.deptType === 'TEAMS').map(item => ({
192
+      value: item.deptId,
193
+      text: item.deptName
194
+    }))
195
+    queryParams.teamId = '' // 清空班组选择
196
+  }
197
+})
198
+
199
+// 获取部门数据
200
+const fetchDeptData = async () => {
201
+  try {
202
+    const response = await listDept({})
203
+    if (response.code === 200) {
204
+
205
+      deptList.value = response.data || []
206
+      // 生成大队选项
207
+      brigadeOptions.value = deptList.value.filter(item => item.deptType === 'BRIGADE').map(item => ({
208
+        value: item.deptId,
209
+        text: item.deptName
210
+      }))
211
+      // 生成主管选项
212
+      departmentOptions.value = deptList.value.filter(item => item.deptType === 'MANAGER').map(item => ({
213
+        value: item.deptId,
214
+        text: item.deptName
215
+      }))
216
+
217
+
218
+      // 生成班组选项
219
+      teamOptions.value = deptList.value.filter(item => item.deptType === 'TEAMS').map(item => ({
220
+        value: item.deptId,
221
+        text: item.deptName
222
+      }))
223
+    }
224
+  } catch (error) {
225
+    console.error('获取部门数据失败:', error)
226
+  }
227
+}
228
+
229
+// 根据科室ID获取班组列表
230
+const fetchTeamByDept = async (deptId) => {
231
+  try {
232
+    const response = await listDept({ parentId: deptId })
233
+    if (response.code === 200 && response.data) {
234
+      teamOptions.value = response.data.map(item => ({
235
+        value: item.deptId,
236
+        text: item.deptName
237
+      }))
238
+      // 清空班组选择,让用户重新选择
239
+      queryParams.teamId = ''
240
+    }
241
+  } catch (error) {
242
+    console.error('获取班组列表失败:', error)
243
+    // 如果获取失败,重置为所有班组
244
+    teamOptions.value = deptList.value.filter(item => item.deptType === 'TEAMS').map(item => ({
245
+      value: item.deptId,
246
+      text: item.deptName
247
+    }))
248
+  }
249
+}
250
+
251
+// 查询类型变化
252
+const handleQueryTypeChange = (type) => {
253
+  queryType.value = type
254
+  getList()
255
+}
256
+
257
+// 时间范围变化
258
+const handleTimeRangeChange = (range) => {
259
+  timeRange.value = range
260
+  if (range !== 'custom') {
261
+    getList()
262
+  }
263
+}
264
+
265
+// 格式化日期为 YYYY-MM-DD
266
+const formatDate = (date) => {
267
+  const year = date.getFullYear()
268
+  const month = String(date.getMonth() + 1).padStart(2, '0')
269
+  const day = String(date.getDate()).padStart(2, '0')
270
+  return `${year}-${month}-${day}`
271
+}
272
+
273
+// 计算时间范围
274
+const calculateTimeRange = (range) => {
275
+  const now = new Date()
276
+  const startTime = new Date()
277
+
278
+  switch (range) {
279
+    case 'threeMonths':
280
+      startTime.setMonth(now.getMonth() - 3)
281
+      break
282
+    case 'sixMonths':
283
+      startTime.setMonth(now.getMonth() - 6)
284
+      break
285
+    case 'custom':
286
+      if (customDateRange.value && customDateRange.value.length === 2) {
287
+        // 结束时间加一天
288
+        const endDate = new Date(customDateRange.value[1])
289
+        endDate.setDate(endDate.getDate() + 1)
290
+        return {
291
+          startTime: customDateRange.value[0],
292
+          endTime: formatDate(endDate)
293
+        }
294
+      }
295
+      return { startTime: '', endTime: '' }
296
+    default:
297
+      return { startTime: '', endTime: '' }
298
+  }
299
+
300
+  return {
301
+    startTime: formatDate(startTime),
302
+    endTime: formatDate(now)
303
+  }
304
+}
305
+
306
+// 自定义时间范围变化
307
+const handleCustomDateChange = () => {
308
+  if (customDateRange.value && customDateRange.value.length === 2) {
309
+    getList()
310
+  }
311
+}
312
+
313
+// 排序处理
314
+const handleSortChange = (field, { order }) => {
315
+  queryParams.sortField = field
316
+  queryParams.sortOrder = order === 'ascending' ? 'asc' : 'desc'
317
+  getList()
318
+}
319
+
320
+// 查询
321
+const handleQuery = () => {
322
+  queryParams.pageNum = 1
323
+  getList()
324
+}
325
+
326
+// 重置查询
327
+const resetQuery = () => {
328
+  queryFormRef.value.resetFields()
329
+  queryParams.pageNum = 1
330
+  queryParams.sortField = ''
331
+  queryParams.sortOrder = ''
332
+  getList()
333
+}
334
+
335
+// 获取绩效列表
336
+const getList = async () => {
337
+  loading.value = true
338
+
339
+  try {
340
+    // 计算时间范围
341
+    const timeRangeParams = calculateTimeRange(timeRange.value)
342
+
343
+    // 构建请求参数
344
+    const params = {
345
+      ...queryParams,
346
+      dimension: queryType.value,
347
+      ...timeRangeParams
348
+    }
349
+
350
+    // 根据查询类型清理不必要的参数
351
+    if (queryType.value === '3') {
352
+      // 主管查询:传递大队和主管参数
353
+      params.teamId = ''
354
+      params.userName = ''
355
+    } else if (queryType.value === '2') {
356
+      // 班组查询:传递大队、主管和班组参数
357
+      params.userName = ''
358
+    } else if (queryType.value === '1') {
359
+      // 个人查询:传递所有参数
360
+    } else if (queryType.value === '4') {
361
+      // 大队查询:不传递任何部门参数
362
+      params.brigadeId = ''
363
+      params.deptId = ''
364
+      params.teamId = ''
365
+      params.userName = ''
366
+    }
367
+
368
+    // 调用API
369
+    const response = await getPerformanceList(params)
370
+
371
+    if (response.code === 200) {
372
+
373
+      performanceList.value = response.data || []
374
+      total.value = response.total || 0
375
+    } else {
376
+      console.error('获取绩效列表失败:', response.msg)
377
+      performanceList.value = []
378
+      total.value = 0
379
+    }
380
+  } catch (error) {
381
+    console.error('获取绩效列表异常:', error)
382
+    performanceList.value = []
383
+    total.value = 0
384
+  } finally {
385
+    loading.value = false
386
+  }
387
+}
388
+
389
+// 获取当前实例
390
+const { proxy } = getCurrentInstance()
391
+
392
+// 导出
393
+const handleExport = () => {
394
+  try {
395
+    // 计算时间范围
396
+    const timeRangeParams = calculateTimeRange(timeRange.value)
397
+
398
+    // 构建请求参数
399
+    const params = {
400
+      ...queryParams,
401
+      dimension: queryType.value,
402
+      ...timeRangeParams
403
+    }
404
+
405
+    // 根据查询类型清理不必要的参数
406
+    if (queryType.value === '3') {
407
+      // 主管查询:传递大队和主管参数
408
+      params.teamId = ''
409
+      params.userName = ''
410
+    } else if (queryType.value === '2') {
411
+      // 班组查询:传递大队、主管和班组参数
412
+      params.userName = ''
413
+    } else if (queryType.value === '1') {
414
+      // 个人查询:传递所有参数
415
+    } else if (queryType.value === '4') {
416
+      // 大队查询:不传递任何部门参数
417
+      params.brigadeId = ''
418
+      params.deptId = ''
419
+      params.teamId = ''
420
+      params.userName = ''
421
+    }
422
+
423
+    // 使用proxy.getDownload下载文件(GET请求)
424
+    getDownload('/item/indicators/export', params, `绩效查询数据_${new Date().getTime()}.xlsx`)
425
+  } catch (error) {
426
+    console.error('导出异常:', error)
427
+    proxy.$modal.msgError('导出异常,请重试')
428
+  }
429
+}
430
+
431
+onMounted(() => {
432
+  fetchDeptData()
433
+  getList()
434
+})
435
+</script>
436
+
437
+<style lang="less" scoped>
438
+.app-container {
439
+  padding: 20px;
440
+}
441
+
442
+.filter-container {
443
+  display: flex;
444
+  align-items: center;
445
+  margin-bottom: 20px;
446
+}
447
+
448
+.button-group {
449
+  display: flex;
450
+  align-items: center;
451
+
452
+  .button-group-label {
453
+    margin-right: 10px;
454
+    font-weight: 600;
455
+    color: #606266;
456
+  }
457
+
458
+  .el-button {
459
+    margin-right: 10px;
460
+
461
+    &.active {
462
+      background-color: #409EFF;
463
+      border-color: #409EFF;
464
+      color: #fff;
465
+    }
466
+
467
+    &.inactive {
468
+      background-color: #fff;
469
+      border-color: #409EFF;
470
+      color: #409EFF;
471
+    }
472
+  }
473
+}
474
+
475
+.search-form {
476
+  margin-bottom: 20px;
477
+}
478
+
479
+.export-container {
480
+  margin-bottom: 20px;
481
+}
482
+
483
+:deep(.el-table) {
484
+  .el-table__header-wrapper {
485
+    th {
486
+      background-color: #f5f7fa;
487
+      font-weight: 600;
488
+    }
489
+  }
490
+}
491
+</style>