From df3902e7eae5dd38a2d47aa63e5f27131f701db9 Mon Sep 17 00:00:00 2001
From: zouyu <2723363702@qq.com>
Date: 星期一, 20 四月 2026 13:49:14 +0800
Subject: [PATCH] 绩效管理模块调整

---
 src/api/system/user.js                                                   |   18 ++
 src/views/performance/attendance/index.vue                               |   94 +++++++++
 src/views/business/inspectionTask/inspection.vue                         |  115 ++++++++++--
 src/views/performance/attendance/components/staffClockInRecord.vue       |    6 
 src/views/business/materialOrder/index.vue                               |    3 
 src/views/system/user/index.vue                                          |   63 ++++++
 src/views/business/productOrder/components/addOrder.vue                  |   28 ++-
 src/api/performance/class.js                                             |    1 
 src/views/business/productOrder/components/printDialog.vue               |   13 
 src/utils/date.js                                                        |   44 ++++
 src/views/business/materialOrderComponents/materialOrder/printDialog.vue |    9 
 src/views/performance/class/index.vue                                    |  131 ++++---------
 src/api/performance/attendance.js                                        |   10 +
 13 files changed, 385 insertions(+), 150 deletions(-)

diff --git a/src/api/performance/attendance.js b/src/api/performance/attendance.js
index 653f30b..abba4e9 100644
--- a/src/api/performance/attendance.js
+++ b/src/api/performance/attendance.js
@@ -64,3 +64,13 @@
     data: data
   });
 }
+
+// 缁╂晥绠$悊-浜哄憳鑰冨嫟-瀵煎嚭鑰冨嫟璁板綍
+export function exportStaffAttendanceRecords(query) {
+  return request({
+    url: "/staff/attendance/exportStaffAttendanceRecords",
+    method: "get",
+    params: query,
+    responseType:'blob'
+  });
+}
diff --git a/src/api/performance/class.js b/src/api/performance/class.js
index f3dcf6a..0104601 100644
--- a/src/api/performance/class.js
+++ b/src/api/performance/class.js
@@ -88,6 +88,7 @@
     url: "/performanceShift/export",
     method: "get",
     params: query,
+    responseType:'blob'
   });
 }
 
diff --git a/src/api/system/user.js b/src/api/system/user.js
index 850ab66..9dc4395 100644
--- a/src/api/system/user.js
+++ b/src/api/system/user.js
@@ -203,3 +203,21 @@
     method: "get",
   });
 }
+
+// 鑾峰彇鐢ㄦ埛鍒楄〃
+export function selectUserListByPerformance(query) {
+  return request({
+    url: "/system/newUser/selectUserListByPerformance",
+    method: "get",
+    params:query
+  });
+}
+
+// 鏇存柊鐢ㄦ埛鎺掑簭
+export function updateUserSort(data) {
+  return request({
+    url: "/system/user/updateUserSort",
+    method: "post",
+    data:data
+  });
+}
diff --git a/src/utils/date.js b/src/utils/date.js
index 1b14b70..70729fb 100644
--- a/src/utils/date.js
+++ b/src/utils/date.js
@@ -130,3 +130,47 @@
   }
   return workMonth
 }
+
+/**
+ * 鍒ゆ柇鏃堕棿鍖洪棿鏄惁瓒呰繃 1 涓嚜鐒舵湀
+ * @param {string} startTime - 寮�濮嬫椂闂� yyyy-MM-dd HH:mm:ss
+ * @param {string} endTime - 缁撴潫鏃堕棿 yyyy-MM-dd HH:mm:ss
+ * @returns {boolean} true=瓒呰繃涓�涓湀锛宖alse=鏈秴杩�
+ */
+export function isOverOneMonth(startTime, endTime) {
+  // 1. 瑙f瀽涓烘棩鏈熷璞�
+  const start = new Date(startTime);
+  const end = new Date(endTime);
+
+  // 2. 鏍¢獙鏃ユ湡鍚堟硶鎬�
+  if (isNaN(start.getTime()) || isNaN(end.getTime())) {
+    throw new Error("鏃堕棿鏍煎紡閿欒锛岃浣跨敤 yyyy-MM-dd HH:mm:ss 鏍煎紡");
+  }
+
+  // 3. 濡傛灉缁撴潫鏃堕棿鏃╀簬寮�濮嬫椂闂达紝鐩存帴杩斿洖false
+  if (end < start) return false;
+
+  // 4. 璁$畻骞翠唤宸�佹湀浠藉樊
+  const startYear = start.getFullYear();
+  const startMonth = start.getMonth();
+  const startDay = start.getDate();
+  const startRest = start.getTime() - new Date(startYear, startMonth, startDay).getTime(); // 鏃跺垎绉掓绉�
+
+  const endYear = end.getFullYear();
+  const endMonth = end.getMonth();
+  const endDay = end.getDate();
+  const endRest = end.getTime() - new Date(endYear, endMonth, endDay).getTime();
+
+  // 鎬绘湀浠藉樊鍊�
+  const monthDiff = (endYear - startYear) * 12 + (endMonth - startMonth);
+
+  // 5. 鍒ゆ柇閫昏緫
+  if (monthDiff > 1) {
+    return true; // 鏈堜唤宸�>1 鈫� 瓒呰繃
+  } else if (monthDiff === 1) {
+    // 鏈堜唤宸�=1 鈫� 姣旇緝 鏃�+鏃跺垎绉掞紝瓒呰繃鍒欏垽瀹氳秴鏃�
+    return endDay > startDay || (endDay === startDay && endRest > startRest);
+  } else {
+    return false; // 鏈堜唤宸�<1 鈫� 鏈秴杩�
+  }
+}
diff --git a/src/views/business/inspectionTask/inspection.vue b/src/views/business/inspectionTask/inspection.vue
index dd99387..977484e 100644
--- a/src/views/business/inspectionTask/inspection.vue
+++ b/src/views/business/inspectionTask/inspection.vue
@@ -422,6 +422,19 @@
       <lims-table :tableData="tableData0" :column="column0" :page="page0" :tableLoading="tableLoading0"
         :height="'calc(100vh - 90px)'" :currentChange="handleChangeTask"></lims-table>
     </el-drawer>
+    <el-dialog
+      title="鍝戦搩鐗囪澶囪瘯鏍风被鍨�"
+      :visible.sync="dialogVisible"
+      :before-close="handleDialogCancel"
+      width="30%">
+      <el-select v-model="deviceDbTableName" placeholder="璇烽�夋嫨璇曟牱绫诲瀷" style="width:100%" size="small">
+        <el-option label="鐗囩姸" value="TestData"></el-option>
+        <el-option label="绠$姸" value="TestData2"></el-option>
+      </el-select>
+      <span slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="handleDialogConfirm">纭� 瀹�</el-button>
+      </span>
+    </el-dialog>
     <el-dialog :visible.sync="reviewDia" title="妫�楠屽鏍�" width="500px">
       <div v-if="reviewDia" class="body" style="display: flex; padding: 10px">
         <div class="search_label" style="width: 150px">
@@ -664,6 +677,11 @@
   },
   data() {
     return {
+      // 瀛樺偍 Promise 鐨� resolve/reject锛岀敤浜庡脊妗嗙‘璁�/鍙栨秷鏃惰皟鐢�
+      dialogResolve: null,
+      dialogReject: null,
+      dialogVisible: false,
+      deviceDbTableName: '',
       outerColorList:[],
       insulationColorList:[],
       letteringInfoList: [],
@@ -1313,35 +1331,82 @@
       this.$refs.purchaseDialog.$refs["purchaseForm"].resetFields();
       this.purchaseDialog = false;
     },
+    openDialog() {
+      this.dialogVisible = true;
+      this.deviceDbTableName = ''; // 閲嶇疆琛ㄥ崟
+      // 杩斿洖 Promise锛岀瓑寰呯敤鎴锋搷浣�
+      return new Promise((resolve, reject) => {
+        this.dialogResolve = resolve;
+        this.dialogReject = reject;
+      });
+    },
+    // 寮规纭鎻愪氦
+    handleDialogConfirm() {
+      // 鍏抽棴寮规
+      this.dialogVisible = false;
+      // 璋冪敤 resolve锛屼紶閫掕〃鍗曟暟鎹紝鎭㈠鎵ц鍚庣画浠g爜
+      this.dialogResolve(this.deviceDbTableName);
+    },
 
+    // 寮规鍙栨秷/鍏抽棴
+    handleDialogCancel() {
+      console.log(111)
+      this.dialogVisible = false;
+      // 璋冪敤 reject锛岀粓姝㈠悗缁唬鐮�
+      this.dialogReject();
+    },
     // 鏁版嵁閲囬泦
-
-  getDataAcquisitionDevice() {
-    let itemIds = [];
-    this.currentSample.insProduct.forEach((item) => {
-      if (item.inspectionItemType === "1") {
-        itemIds.push(item.id);
+    async getDataAcquisitionDevice() {
+      //杩囨护閫変腑鐨勮澶囧垪琛�
+    let deviceList = []
+    for (let item in this.param){
+      let val1 = this.param[item]
+      for(let item2 in val1){
+        if(item2==='equipName'){
+          let equipName = val1[item2]
+          equipName.forEach(item=>{
+            if(item.v.v && Array.isArray(item.v.v)){
+              deviceList.push(...item.v.v)
+            }
+          })
+        }
       }
-    });
-    const params = {
-      entrustCode: this.insOrder.entrustCode,
-      lotBatchNo: this.insOrder.lotBatchNo,
-      sampleCode: this.currentSample.sampleCode,
-      id: this.currentSample.id,
-      itemIds: itemIds,
-    };
-    this.dataAcquisitionLoading = true;
-    dataCollection(params).then((res) => {
-      this.dataAcquisitionLoading = false;
-      if (res.code != 200) {
-        return;
+    }
+    //鏁扮粍鍘婚噸
+    let deviceSetList = [...new Set(deviceList)]
+    try{
+      if(deviceSetList.includes('NS-YL3141') && !this.deviceDbTableName){
+        await this.openDialog();
       }
-      this.dataAcquisitionInfoNew = this.HaveJson(res.data);
-      // 瀵规暟閲囧洖鏉ョ殑鍊艰繘琛屽鐞�
-      this.handleDataAcquisition(res.data);
-    }).catch(err => {
-      this.dataAcquisitionLoading = false;
-    });
+      let itemIds = [];
+      this.currentSample.insProduct.forEach((item) => {
+        if (item.inspectionItemType === "1") {
+          itemIds.push(item.id);
+        }
+      });
+      const params = {
+        entrustCode: this.insOrder.entrustCode,
+        lotBatchNo: this.insOrder.lotBatchNo,
+        sampleCode: this.currentSample.sampleCode,
+        id: this.currentSample.id,
+        itemIds: itemIds,
+        dbTable: this.deviceDbTableName,
+      };
+      this.dataAcquisitionLoading = true;
+      dataCollection(params).then((res) => {
+        this.dataAcquisitionLoading = false;
+        if (res.code != 200) {
+          return;
+        }
+        this.dataAcquisitionInfoNew = this.HaveJson(res.data);
+        // 瀵规暟閲囧洖鏉ョ殑鍊艰繘琛屽鐞�
+        this.handleDataAcquisition(res.data);
+      }).catch(err => {
+        this.dataAcquisitionLoading = false;
+      });
+    }catch (error){
+      console.error('鏁版嵁閲囬泦璁惧鍒楄〃澶勭悊澶辫触',error)
+    }
   },
     objectOrder(obj) {
       let newkey = Object.keys(obj).sort();
diff --git a/src/views/business/materialOrder/index.vue b/src/views/business/materialOrder/index.vue
index 39e4bdc..76591cd 100644
--- a/src/views/business/materialOrder/index.vue
+++ b/src/views/business/materialOrder/index.vue
@@ -1135,8 +1135,6 @@
         if (res.code === 200) {
           this.tableData = res.data.records
           this.page.total = res.data.total
-
-          console.log('data ======> ', this.tableData)
         }
       }).catch(err => {
         this.tableLoading = false
@@ -1597,7 +1595,6 @@
       this.multipleSelection = val
     },
     changeRowClass({ row, rowIndex }) {
-      console.log(row,row.isFirst==1)
       if (row.isFirst == 1) {
         return 'highlight-danger-row-border'
       }
diff --git a/src/views/business/materialOrderComponents/materialOrder/printDialog.vue b/src/views/business/materialOrderComponents/materialOrder/printDialog.vue
index 3dca547..58a72ce 100644
--- a/src/views/business/materialOrderComponents/materialOrder/printDialog.vue
+++ b/src/views/business/materialOrderComponents/materialOrder/printDialog.vue
@@ -77,7 +77,7 @@
           <div>
             <div class="titleH1" style="text-align: center;margin-bottom: 1px">妫�娴嬩腑蹇冩牱鍝佹爣璇嗗崱</div>
             <div style="text-align: center;">
-              <barcode :value="item.barcode" :height="22" :width="1.6" :displayValue="false"></barcode>
+              <barcode :margin="1" :value="item.barcode" :height="22" :width="1.6" :displayValue="false"></barcode>
             </div>
             <div style="margin-left: 12px;text-align: left">
               <div class="item">
@@ -225,7 +225,7 @@
         targetStyles: ["*"], // 浣跨敤dom鐨勬墍鏈夋牱寮忥紝寰堥噸瑕�
         printable: 'printOrder',//椤甸潰
         type: "html",//鏂囨。绫诲瀷
-        maxWidth:360,
+        maxWidth:440,
         header: '',
         style:
           `@page {
@@ -234,14 +234,13 @@
             margin-top: 0.4cm;
             margin-bottom: 0.4cm;
             padding-bottom: 0px;
-            size: 400px 75px collapse;
+            size: 440px 75px collapse;
           }
           html{
             zoom:100%;
-
           }
           @media print{
-            width: 400px;
+            width: 440px;
             height: 75px;
             margin:0;
           }`,
diff --git a/src/views/business/productOrder/components/addOrder.vue b/src/views/business/productOrder/components/addOrder.vue
index bef0cef..47d61ec 100644
--- a/src/views/business/productOrder/components/addOrder.vue
+++ b/src/views/business/productOrder/components/addOrder.vue
@@ -88,19 +88,25 @@
               </el-form-item>
             </el-col>
             <el-col :span="6">
+              <el-form-item label="闆朵欢鍙�" prop="partNo">
+                <el-input v-model="addObj.partNo" clearable placeholder="璇疯緭鍏ラ浂浠跺彿" size="small">
+                </el-input>
+              </el-form-item>
+            </el-col>
+            <el-col :span="6">
               <el-form-item label="闆朵欢鎻忚堪:" prop="partDesc">
                 <el-input v-model="addObj.partDesc" clearable placeholder="璇疯緭鍏ラ浂浠舵弿杩�" size="small">
                 </el-input>
               </el-form-item>
             </el-col>
+          </el-row>
+          <el-row>
             <el-col :span="6">
               <el-form-item label="渚涘簲鍟嗗悕绉�:" prop="supplierName">
                 <el-input v-model="addObj.supplierName" clearable placeholder="璇疯緭鍏ヤ緵搴斿晢鍚嶇О" size="small">
                 </el-input>
               </el-form-item>
             </el-col>
-          </el-row>
-          <el-row>
             <el-col :span="6">
               <el-form-item label="鑱旂郴鏂瑰紡:" prop="phone">
                 <el-input v-model="addObj.phone" :disabled="active>1&&tabIndex!=4" clearable placeholder="閫夋嫨濮旀墭瀹㈡埛" size="small"></el-input>
@@ -121,14 +127,15 @@
                 </el-input>
               </el-form-item>
             </el-col>
+
+          </el-row>
+          <el-row>
             <el-col :span="6">
               <el-form-item label="鏍峰搧鏁伴噺:" prop="sampleNum" style="margin-right: 0">
                 <el-input-number v-model="addObj.sampleNum" :disabled="active>1" :max="100" :min="1" :precision="0"
                                  size="small" @change="addStandardTree"></el-input-number>
               </el-form-item>
             </el-col>
-          </el-row>
-          <el-row>
             <el-col :span="6">
               <el-form-item label="鏍峰搧鐘舵��:" prop="sampleStatus">
                 <el-select v-model="addObj.sampleStatus" :disabled="active>1&&tabIndex!=4" size="small">
@@ -148,6 +155,8 @@
                 </el-select>
               </el-form-item>
             </el-col>
+          </el-row>
+          <el-row>
             <el-col :span="6">
               <el-form-item label="鎶ュ憡鍙戦�佹柟寮�:" prop="send">
                 <el-radio-group v-model="addObj.send" :disabled="active>1&&tabIndex!=4" size="mini">
@@ -156,8 +165,6 @@
                 </el-radio-group>
               </el-form-item>
             </el-col>
-          </el-row>
-          <el-row>
             <el-col :span="6">
               <el-form-item label="鏍峰搧澶勭悊鏂瑰紡:" prop="processing">
                 <el-radio-group v-model="addObj.processing" :disabled="active>1&&tabIndex!=4" size="mini" style="display: flex; flex-direction: column;">
@@ -178,6 +185,8 @@
                           size="small"></el-input>
               </el-form-item>
             </el-col>
+          </el-row>
+          <el-row>
             <el-col :span="6">
               <el-form-item label="鏄惁鐣欐牱:" prop="isLeave">
                 <el-radio-group v-model="addObj.isLeave" border :disabled="active>1&&tabIndex!=4" size="mini">
@@ -186,8 +195,6 @@
                 </el-radio-group>
               </el-form-item>
             </el-col>
-          </el-row>
-          <el-row>
             <el-col :span="6">
               <el-form-item label="濮旀墭浜�:" prop="prepareUser">
                 <el-input v-model="addObj.prepareUser" :disabled="active>1&&tabIndex!=4" :placeholder="active>1 ? '' : '璇疯緭鍏�'" clearable size="small"></el-input>
@@ -204,14 +211,14 @@
                           size="small" style="width: 100%" type="textarea"></el-input>
               </el-form-item>
             </el-col>
+          </el-row>
+          <el-row>
             <el-col :span="6">
               <el-form-item label="澶囨敞鑻辨枃:" prop="remarkEn">
                 <el-input v-model="addObj.remarkEn" :autosize="{ minRows: 2, maxRows: 2}" :disabled="active>1&&tabIndex!=4" :placeholder="active>1 ? '' : '璇疯緭鍏�'" clearable
                           size="small" type="textarea"></el-input>
               </el-form-item>
             </el-col>
-          </el-row>
-          <el-row>
             <el-col :span="6">
               <el-form-item label="鏍峰搧鍚嶇О:" prop="sampleView">
                 <el-input v-model="addObj.sampleView" :disabled="active>1&&tabIndex!=4" :placeholder="active>1 ? '' : '璇疯緭鍏�'" clearable
@@ -658,6 +665,7 @@
         contract:null,
         updateBatchNo: null,
         partDesc: null,
+        partNo: null,
         supplierName: null,
         custom: null,
         company: null,
diff --git a/src/views/business/productOrder/components/printDialog.vue b/src/views/business/productOrder/components/printDialog.vue
index 77a921f..832f394 100644
--- a/src/views/business/productOrder/components/printDialog.vue
+++ b/src/views/business/productOrder/components/printDialog.vue
@@ -1,6 +1,6 @@
 <template>
   <div>
-    <el-dialog :visible.sync="isShow" title="鏍囩鎵撳嵃" top="5vh" width="600px" @close="$emit('closePrintDialog')">
+    <el-dialog :visible.sync="isShow" title="鏍囩鎵撳嵃" top="5vh" width="800px" @close="$emit('closePrintDialog')">
       <div style="width:100%;height: 400px;overflow-y: auto;text-align: left">
         <div class="dia_body">
           <el-checkbox
@@ -75,7 +75,7 @@
           <div>
             <div class="titleH1" style="text-align: center;margin-bottom: 1px">妫�娴嬩腑蹇冩牱鍝佹爣璇嗗崱</div>
             <div style="text-align: center;">
-              <barcode :displayValue="false" :height="22" :value="item.barcode" :width="1.6"></barcode>
+              <barcode :displayValue="false" :height="30" :value="item.barcode" :width="1.5"></barcode>
             </div>
             <div style="margin-left: 12px;text-align: left">
               <div class="item">
@@ -124,6 +124,7 @@
 <script>
 import PrintJS from "print-js";
 import {labelOrderPrinting} from "@/api/business/productOrder";
+import {stringToBase64} from '@/utils/base64Util'
 
 export default {
   name: "printDialog",
@@ -165,7 +166,7 @@
             res.data.forEach(item => {
               item.sendTime = item.sendTime && item.sendTime.substring(0, 10)
               item.sampleNumber = item.qtyArrived + item.buyUnitMeas
-              this.$set(item, 'barcode', item.entrustCode)
+              this.$set(item, 'barcode', item.entrustCode+","+stringToBase64(item.partColor))
               this.$set(item, 'isLeave', item.insState === '2')
             })
             this.barcodeData = res.data
@@ -221,7 +222,7 @@
         targetStyles: ["*"], // 浣跨敤dom鐨勬墍鏈夋牱寮忥紝寰堥噸瑕�
         printable: 'printOrder',//椤甸潰
         type: "html",//鏂囨。绫诲瀷
-        maxWidth: 360,
+        maxWidth: 440,
         header: '',
         style:
           `@page {
@@ -230,14 +231,14 @@
             margin-top: 0.4cm;
             margin-bottom: 0.4cm;
             padding-bottom: 0px;
-            size: 400px 75px collapse;
+            size: 440px 75px collapse;
           }
           html{
             zoom:100%;
 
           }
           @media print{
-            width: 400px;
+            width: 440px;
             height: 75px;
             margin:0;
           }`,
diff --git a/src/views/performance/attendance/components/staffClockInRecord.vue b/src/views/performance/attendance/components/staffClockInRecord.vue
index e2fdaa2..54a5ded 100644
--- a/src/views/performance/attendance/components/staffClockInRecord.vue
+++ b/src/views/performance/attendance/components/staffClockInRecord.vue
@@ -20,19 +20,19 @@
       //杩涘嚭闂ㄧ被鍨嬪垪琛�
       enterOrExitList:[
         {
-          effect:'',
+          effect:'light',
           type:'success',
           label:'杩涢棬',
           value:1
         },
         {
-          effect:'',
+          effect:'light',
           type:'',
           label:'鍑洪棬',
           value:2
         },
         {
-          effect:'',
+          effect:'light',
           type:'info',
           label:'杩�/鍑洪棬',
           value:3
diff --git a/src/views/performance/attendance/index.vue b/src/views/performance/attendance/index.vue
index d8089c8..c8784c4 100644
--- a/src/views/performance/attendance/index.vue
+++ b/src/views/performance/attendance/index.vue
@@ -30,12 +30,12 @@
         </div>
       </div>
       <div class="search_thing">
-        <el-button size="mini" type="primary" @click="refreshTable()"
-          >鏌� 璇�</el-button
+        <el-button icon="el-icon-search" size="mini" type="primary" @click="refreshTable()">鏌� 璇�</el-button
         >
-        <el-button size="mini" @click="resetQuery">閲嶇疆</el-button>
-        <el-button size="mini" type="primary" @click="openAddAttendanceDialog()">鎵嬪姩鏂板</el-button>
-        <el-button size="mini" type="success" @click="openSyncAttendanceDialog()">鍚屾鑰冨嫟璁板綍</el-button>
+        <el-button icon="el-icon-refresh-left" size="mini" @click="resetQuery">閲嶇疆</el-button>
+        <el-button icon="el-icon-plus" size="mini" type="primary" @click="openAddAttendanceDialog()">鎵嬪姩鏂板</el-button>
+        <el-button icon="el-icon-refresh" size="mini" type="success" @click="openSyncAttendanceDialog()">鍚屾鑰冨嫟璁板綍</el-button>
+        <el-button plain icon="el-icon-download" size="mini" type="primary" @click="openAttendanceRecordDialog()">瀵煎嚭</el-button>
       </div>
     </div>
     <div class="container">
@@ -211,6 +211,45 @@
     <el-button type="primary" @click="confirmSyncAttendance">纭� 瀹�</el-button>
   </span>
     </el-dialog>
+    <el-dialog
+      title="瀵煎嚭鑰冨嫟璁板綍"
+      :visible.sync="attendanceRecordVisible"
+      width="40%">
+      <el-row>
+        <el-col :span="4">
+          <label>缁熻缁村害:</label>
+        </el-col>
+        <el-col :span="20">
+            <el-radio-group v-model="reportType" size="mini" disabled>
+              <el-radio label="YEAR">骞村害</el-radio>
+              <el-radio label="MONTH">鏈堝害</el-radio>
+            </el-radio-group>
+        </el-col>
+      </el-row>
+      <el-row style="margin-top:20px">
+        <el-col :span="4">
+          <label>缁熻鏃ユ湡:</label>
+        </el-col>
+        <el-col :span="20">
+          <el-date-picker
+            size="small"
+            v-model="reportDateRange"
+            style="width:100%"
+            @change="changeReportDateRange"
+            type="datetimerange"
+            value-format="yyyy-MM-dd HH:mm:ss"
+            :default-time="['00:00:00','23:59:59']"
+            range-separator="鑷�"
+            start-placeholder="寮�濮嬫棩鏈�"
+            end-placeholder="缁撴潫鏃ユ湡">
+          </el-date-picker>
+        </el-col>
+      </el-row>
+      <span slot="footer" class="dialog-footer">
+        <el-button @click="attendanceRecordVisible = false">鍙� 娑�</el-button>
+        <el-button :loading="exportLoading" type="primary" @click="exportStaffAttendanceRecords()">纭� 瀹�</el-button>
+      </span>
+    </el-dialog>
   </div>
 </template>
 
@@ -222,10 +261,12 @@
   checkDutyDate,
   saveOrUpdateStaffAttendanceTrackingRecord,
   removeStaffAttendanceTrackingRecord,
-  syncAttendanceRecord
+  syncAttendanceRecord,
+  exportStaffAttendanceRecords
 } from '@/api/performance/attendance'
 import {getDicts} from "@/api/system/dict/data";
-import {getTimeRange} from "@/utils/date";
+import {getTimeRange,isOverOneMonth} from "@/utils/date";
+import {transformExcel} from '@/utils/file'
 export default {
   name: "Attendance",
   components: {
@@ -233,8 +274,12 @@
   },
   data() {
     return {
+      reportDateRange:[],
+      reportType:"MONTH",
+      attendanceRecordVisible:false,
       syncDateRange:[],
       syncAttendanceVisible: false,
+      exportLoading: false,
       attendanceForm:{
         workDataId: null,
         offWorkDataId: null,
@@ -313,6 +358,41 @@
     window.removeEventListener("resize",this.resizeHandler)
   },
   methods: {
+    changeReportDateRange(val){
+      //鍒ゆ柇鏃堕棿鍖洪棿鏄惁瓒呰繃涓�涓湀
+      if(val && val.length===2){
+        const flag = isOverOneMonth(val[0],val[1]);
+        this.reportType = flag?'YEAR':'MONTH'
+      }
+    },
+    openAttendanceRecordDialog (){
+      this.reportDateRange = getTimeRange()
+      this.$nextTick(()=>{
+        this.attendanceRecordVisible = true
+      })
+    },
+    //瀵煎嚭鑰冨嫟璁板綍
+    exportStaffAttendanceRecords(){
+      this.exportLoading = true
+      let params = {
+        attendanceReportType:this.reportType,
+      }
+      if (this.reportDateRange && this.reportDateRange.length === 2) {
+        params.startDate = this.reportDateRange[0];
+        params.endDate = this.reportDateRange[1];
+      } else {
+        params.startDate = "";
+        params.endDate = "";
+      }
+      exportStaffAttendanceRecords({...params}).then(res=>{
+        transformExcel(res, "涓ぉ鑰愪笣璐ㄩ噺鑰冨嫟姹囨��.xlsx")
+        this.$message.success("瀵煎嚭鎴愬姛")
+      }).catch(error=>{
+        console.error(error)
+      }).finally(()=>{
+        this.exportLoading = false
+      })
+    },
     getShiftByDic(e) {
       let obj = this.dailyTypeList.find((m) => m.dictValue == e);
       if (obj) {
diff --git a/src/views/performance/class/index.vue b/src/views/performance/class/index.vue
index 0210486..c48d607 100644
--- a/src/views/performance/class/index.vue
+++ b/src/views/performance/class/index.vue
@@ -41,8 +41,7 @@
             浜哄憳鍚嶇О
             <span style="color:#ff4949">(浜哄憳鏁伴噺:{{list.length}})</span>
           </div>
-          <div class="content-user" :class="{ hoverType: currentUserIndex == index }" v-for="(item, index) in list"
-            :key="'e' + index" v-on:mouseenter="onMouseEnter(index)" v-on:mouseleave="currentUserIndex = null">
+          <div class="content-user" v-for="(item, index) in list">
             <div class="user-pic">
               {{ item.userName ? item.userName.charAt(0) : "" }}
             </div>
@@ -55,13 +54,7 @@
                 ">
                 {{ item.userName }}
               </p>
-              <p style="color: #999999;font-size: 12px;transform: scale(0.8) translateX(-20px);white-space: nowrap;width: 150px;margin: 0;">
-                <span>鏃�:{{ item.monthlyAttendance.morningShift}},</span>
-                <span>涓�:{{ item.monthlyAttendance.swingShift}},</span>
-                <span>澶�:{{ item.monthlyAttendance.nightShift}},</span>
-                <span>浼�:{{ item.monthlyAttendance.holidayShift}},</span>
-                <span>鍋�:{{ item.monthlyAttendance.leaveShift}},</span>
-                <span>宸�:0</span>
+              <p style="color: #999999;font-size: 12px;transform: scale(0.8) translateX(-20px);white-space: nowrap;width: 150px;margin: 0;" v-text="item.monthlyAttendanceStr">
               </p>
               <p style="margin-top: 4px; margin: 0">
                 <span style="
@@ -69,7 +62,7 @@
                     font-size: 12px;
                     display: inline-block;
                     transform: scale(0.8) translateX(-10px);
-                  ">鍚堣鍑哄嫟: </span><span style="font-size: 16px; color: #ff4902">{{item.monthlyAttendance.morningShift+item.monthlyAttendance.swingShift+item.monthlyAttendance.nightShift}}澶�</span>
+                  ">鍚堣鍑哄嫟: </span><span style="font-size: 16px; color: #ff4902">{{item.monthlyAttendance.totalCount}}澶�</span>
               </p>
             </div>
           </div>
@@ -86,8 +79,7 @@
                 </p>
               </div>
             </div>
-            <div class="content-body" v-for="(item, index) in list" :key="'c' + index"
-              v-on:mouseenter="onMouseEnter(index)" v-on:mouseleave="currentUserIndex = null">
+            <div class="content-body" v-for="(item, index) in list" :key="'c' + index">
               <div class="content-body-item" v-for="(m, i) in item.list" :key="'d' + i"
                 :class="{ hoverType: currentUserIndex == index }">
                 <el-dropdown trigger="click" placement="bottom" @command="(e) => handleCommand(e, m)"
@@ -115,8 +107,8 @@
             浜哄憳鍚嶇О
             <span style="color:#ff4949">(浜哄憳鏁伴噺:{{yearList.length}})</span>
           </div>
-          <div class="content-user" :class="{ hoverType: currentUserIndex == index }" v-for="(item, index) in yearList"
-            :key="'e' + index" v-on:mouseenter="onMouseEnter(index)" v-on:mouseleave="currentUserIndex = null">
+          <div class="content-user" v-for="(item, index) in yearList"
+            :key="'e' + index">
             <div class="user-pic">
               {{ item.userName ? item.userName.charAt(0) : "" }}
             </div>
@@ -129,21 +121,14 @@
                 ">
                 {{ item.userName }}
               </p>
-              <p style="color: #999999;font-size: 12px;transform: scale(0.8) translateX(-20px);white-space: nowrap;width: 150px;margin: 0;">
-                <span>鏃�:{{ item.sidebarAnnualAttendance.morningShift}},</span>
-                <span>涓�:{{ item.sidebarAnnualAttendance.swingShift}},</span>
-                <span>澶�:{{ item.sidebarAnnualAttendance.nightShift}},</span>
-                <span>浼�:{{ item.sidebarAnnualAttendance.holidayShift}},</span>
-                <span>鍋�:{{ item.sidebarAnnualAttendance.leaveShift}},</span>
-                <span>宸�:0</span>
-              </p>
+              <p style="color: #999999;font-size: 12px;transform: scale(0.8) translateX(-20px);white-space: nowrap;width: 150px;margin: 0;" v-text="item.sidebarAnnualAttendanceStr"></p>
               <p style="margin-top: 4px; margin: 0">
                 <span style="
                     color: #999999;
                     font-size: 12px;
                     display: inline-block;
                     transform: scale(0.8) translateX(-10px);
-                  ">鍚堣鍑哄嫟: </span><span style="font-size: 16px; color: #ff4902">{{item.sidebarAnnualAttendance.morningShift+item.sidebarAnnualAttendance.swingShift+item.sidebarAnnualAttendance.nightShift}}澶�</span>
+                  ">鍚堣鍑哄嫟: </span><span style="font-size: 16px; color: #ff4902">{{item.sidebarAnnualAttendance.totalCount}}澶�</span>
               </p>
             </div>
           </div>
@@ -158,21 +143,15 @@
                   <span class="month">{{ item }}鏈�</span>
                 </div>
               </div>
-              <div class="content-body" v-for="(item, index) in yearList" :key="'c' + index"
-                v-on:mouseenter="onMouseEnter(index)" v-on:mouseleave="currentUserIndex = null" :style="`display: grid;
+              <div class="content-body" v-for="(item, index) in yearList" :key="'c' + index" :style="`display: grid;
               grid-template-columns: repeat(${monthList.length}, 1fr);`">
-                <div class="content-body-item" v-for="(m, i) in item.monthlyAttendance" :key="'d' + i"
+                <div class="content-body-item" v-for="(m, i) in item.monthlyAttendances" :key="'d' + i"
                   :class="{ hoverType: currentUserIndex == index }">
                   <p style="color: rgb(153, 153, 153); font-size: 12px">
-                    鍚堣鍑哄嫟锛�<span style="font-size: 14px; color: #000">{{m.morningShift+m.swingShift+m.nightShift}}</span>
+                    鍚堣鍑哄嫟锛�<span style="font-size: 14px; color: #000">{{m.monthlyAttendance.totalCount}}</span>
                   </p>
                   <p style="color: rgb(153, 153, 153); font-size: 12px">
-                    <span>鏃�:{{ m.morningShift}},</span>
-                    <span>涓�:{{ m.swingShift}},</span>
-                    <span>澶�:{{ m.nightShift}},</span>
-                    <span>浼�:{{ m.holidayShift}},</span>
-                    <span>鍋�:{{ m.leaveShift}},</span>
-                    <span>宸�:0</span>
+                    <span>{{m.monthlyAttendanceStr}}</span>
                   </p>
                 </div>
               </div>
@@ -265,9 +244,7 @@
           <span style="color: red; margin-right: 4px">*</span>浜哄憳鍚嶇О锛�
         </div>
         <div class="search_input" style="width: calc(100% - 90px)">
-          <el-select v-model="schedulingQuery.userId" popper-class="select-with-all" placeholder="璇烽�夋嫨" style="width: 100%" multiple collapse-tags clearable>
-<!--            <el-option v-for="item in personList" :key="item.id" :label="item.name" :value="item.id">-->
-<!--            </el-option>-->
+          <el-select v-model="schedulingQuery.userIdList" popper-class="select-with-all" placeholder="璇烽�夋嫨" style="width: 100%" multiple collapse-tags clearable>
             <template slot="prefix">
               <el-button
                 type="text"
@@ -284,7 +261,10 @@
               :key="item.id"
               :label="item.name"
               :value="item.id"
-            />
+            >
+              <span style="float: left">{{ item.name }}</span>
+              <span style="float: right; color: #8492a6; font-size: 13px">{{ item.account }}</span>
+            </el-option>
           </el-select>
         </div>
       </div>
@@ -320,11 +300,12 @@
   exportFile,
   obtainItemParameterList,
   update,
-  selectUserCondition,
   editAnnotationText,
   delAnnotationText
 } from "@/api/performance/class";
+import {selectUserListByPerformance} from '@/api/system/user'
 import {getWorkMonth} from "@/utils/date";
+import {transformExcel} from '@/utils/file'
 export default {
   name: 'Class',
   data() {
@@ -394,7 +375,7 @@
       loading: false,
       schedulingQuery: {
         week: "",
-        userId: [],
+        userIdList: [],
         shift: "",
       },
       list: [],
@@ -418,7 +399,7 @@
   },
   computed:{
     isAllSelected() {
-      return this.schedulingQuery.userId.length === this.personList.length && this.personList.length > 0;
+      return this.schedulingQuery.userIdList.length === this.personList.length && this.personList.length > 0;
     },
   },
   watch: {
@@ -446,10 +427,10 @@
   methods: {
     handleSelectAll() {
       if (this.isAllSelected) {
-        this.schedulingQuery.userId = [];
+        this.schedulingQuery.userIdList = [];
       } else {
         // 鍙�変腑鍙敤閫夐」鐨剉alue
-        this.schedulingQuery.userId = this.personList.map(item => item.id);
+        this.schedulingQuery.userIdList = this.personList.map(item => item.id);
       }
     },
     handleContextMenu(target,e) {
@@ -595,9 +576,6 @@
         this.yearList = res.data
       });
     },
-    onMouseEnter(index) {
-      this.currentUserIndex = index;
-    },
     confirmScheduling() {
       if (!this.schedulingQuery.week) {
         this.$message.error("璇烽�夋嫨鍛ㄦ");
@@ -611,8 +589,8 @@
         getYearAndMonthAndDays(new Date(time + 24 * 60 * 60 * 1000 * 5)) +
         " 00:00:00";
       if (
-        !this.schedulingQuery.userId ||
-        this.schedulingQuery.userId.length == 0
+        !this.schedulingQuery.userIdList ||
+        this.schedulingQuery.userIdList.length == 0
       ) {
         this.$message.error("璇烽�夋嫨浜哄憳");
         return;
@@ -625,7 +603,7 @@
       add({
         startWeek,
         endWeek,
-        userId: this.schedulingQuery.userId.join(","),
+        userIdList: this.schedulingQuery.userIdList,
         shift: this.schedulingQuery.shift,
       })
         .then((res) => {
@@ -634,7 +612,7 @@
           this.schedulingVisible = false;
           this.schedulingQuery = {
             week: "",
-            userId: [],
+            userIdList: [],
             shift: "",
           };
           this.refresh();
@@ -746,21 +724,18 @@
         time,
         userName: this.query.userName,
         laboratory: this.query.laboratory,
-        isMonth: this.query.month ? true : false,
+        isMonth: !!this.query.month,
       })
         .then((res) => {
-          this.$message.success("涓嬭浇鎴愬姛");
           this.downLoading = false;
-          const blob = new Blob([res], {
-            type: "application/force-download",
-          });
-          let fileName = "";
+          let fileName = "涓ぉ鑰愪笣璐ㄩ噺閮�";
           if (this.query.month) {
-            fileName = year + "-" + this.query.month + " 鐝淇℃伅";
+            fileName += this.query.month + "鏈堢彮娆′俊鎭�";
           } else {
-            fileName = year + " 鐝姹囨��";
+            fileName += year + "骞寸彮娆℃眹鎬�";
           }
-          this.$download.saveAs(blob, fileName + ".xlsx");
+          transformExcel(res, fileName + ".xlsx");
+          this.$message.success("瀵煎嚭鎴愬姛");
         })
         .catch((err) => {
           this.downLoading = false;
@@ -772,29 +747,16 @@
       });
     },
     obtainItemParameterList() {
-      if (this.PROJECT == "妫�娴嬩腑蹇�") {
-        this.laboratory = [
-          {
-            label: "閫氫俊浜у搧瀹為獙瀹�",
-            value: "閫氫俊浜у搧瀹為獙瀹�",
-          },
-          {
-            label: "鐢靛姏浜у搧瀹為獙瀹�",
-            value: "鐢靛姏浜у搧瀹為獙瀹�",
-          },
-        ];
-      } else {
-        obtainItemParameterList().then((res) => {
-          let data = [];
-          res.data.forEach((a) => {
-            data.push({
-              label: a.laboratoryName,
-              value: a.id,
-            });
+      obtainItemParameterList().then((res) => {
+        let data = [];
+        res.data.forEach((a) => {
+          data.push({
+            label: a.laboratoryName,
+            value: a.id,
           });
-          this.laboratory = data;
         });
-      }
+        this.laboratory = data;
+      });
     },
     handleCommand(e, m) {
       if (e != m.shift) {
@@ -808,16 +770,9 @@
       }
     },
     getUsers() {
-      selectUserCondition({ type: 1 }).then((res) => {
-        let arr = res.data;
-        this.personList = arr;
+      selectUserListByPerformance().then((res) => {
+        this.personList = res.data;
       });
-    },
-    getDayByDic(e) {
-      let obj = this.classType.find((m) => m.dictLabel == e);
-      if (obj) {
-        return obj.dictValue;
-      }
     },
     getShiftByDic(e) {
       let obj = this.classType.find((m) => m.dictValue == e);
diff --git a/src/views/system/user/index.vue b/src/views/system/user/index.vue
index 3306ae7..f7f14d0 100644
--- a/src/views/system/user/index.vue
+++ b/src/views/system/user/index.vue
@@ -47,7 +47,7 @@
             </div>
           </div>
           <el-col>
-            <el-table v-loading="loading" :data="userList" :header-cell-style="{ background: '#f8f8f9', color: '#515a6e' }" border>
+            <el-table row-id="userId" ref="dragTable" v-loading="loading" :data="userList" :header-cell-style="{ background: '#f8f8f9', color: '#515a6e' }" border>
               <el-table-column label="搴忓彿" align="center" type="index" />
               <el-table-column label="濮撳悕" align="center" key="nickName" prop="nickName" :show-overflow-tooltip="true" />
               <el-table-column label="璐﹀彿" align="center" key="userName" prop="userName" :show-overflow-tooltip="true" />
@@ -75,6 +75,7 @@
               </el-table-column>
             </el-table>
             <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNum"
+                        :page-sizes="[20,50,100,200,500]"
               :limit.sync="queryParams.pageSize" @pagination="getList" />
           </el-col>
         </pane>
@@ -299,7 +300,8 @@
   uploadFile,
   selectRoleList,
   selectCustomEnum,
-  addDepartment
+  addDepartment,
+  updateUserSort
 } from "@/api/system/user";
 import {optionSelect} from '@/api/system/post'
 import { getToken } from "@/utils/auth";
@@ -307,6 +309,7 @@
 import "@riophae/vue-treeselect/dist/vue-treeselect.css";
 import { Splitpanes, Pane } from "splitpanes";
 import "splitpanes/dist/splitpanes.css";
+import Sortable from "sortablejs";
 
 export default {
   nickName: "User",
@@ -378,7 +381,7 @@
       // 鏌ヨ鍙傛暟
       queryParams: {
         pageNum: 1,
-        pageSize: 10,
+        pageSize: 20,
         nickName: undefined,
         phonenumber: undefined,
         status: undefined,
@@ -467,6 +470,7 @@
         fatherId: 10001,
         nickName: '',
       },
+      sortTable: null,
     };
   },
   watch: {
@@ -482,7 +486,52 @@
       this.initPassword = response.msg;
     });
   },
+  mounted(){
+    // 鎸傝浇鍚庡垵濮嬪寲鎷栨嫿
+    this.initDrag()
+  },
   methods: {
+    //琛ㄦ牸琛屾嫋鎷芥帓搴�
+    initDrag() {
+      // 鑾峰彇 el-table 鐨� tbody 鍏冪礌锛堟嫋鎷界殑鐩爣瀹瑰櫒锛�
+      const tbody = this.$refs.dragTable.$el.querySelector(
+        '.el-table__body-wrapper tbody'
+      )
+
+      // 鍒濆鍖� Sortable
+      this.sortable = Sortable.create(tbody, {
+        animation: 150, // 鎷栨嫿鍔ㄧ敾杩囨浮鏃堕暱
+        ghostClass: 'sortable-ghost', // 鎷栨嫿鍗犱綅绗︽牱寮�
+        chosenClass: 'sortable-chosen', // 閫変腑琛屾牱寮�
+        dragClass: 'sortable-drag', // 鎷栨嫿鍏冪礌鏍峰紡
+        // 鎷栨嫿缁撴潫瑙﹀彂锛堟牳蹇冮�昏緫锛�
+        onEnd: ({ oldIndex, newIndex }) => {
+          // oldIndex锛氬師绱㈠紩锛宯ewIndex锛氭柊绱㈠紩
+          const defNum = (this.queryParams.pageNum-1)*this.queryParams.pageSize
+          // const row = this.userList[oldIndex]
+          // let sort = newIndex+defNum;//鎺掑簭涓嬫爣
+          const row = this.userList.splice(oldIndex, 1)[0]
+          this.userList.splice(newIndex, 0, row)
+          const data = this.userList.map(item=>{return {userId:item.userId,userName:item.userName}})
+          console.log(data)
+          console.log(this.userList)
+          // 璋冪敤鎺ュ彛鏇存柊鎺掑簭
+          // let data = {
+          //   userId:row.userId,
+          //   sort: sort
+          // }
+          // updateUserSort(data).then(res=>{
+          //   if(res.code===200){
+          //     this.$message.success("鏇存柊鎴愬姛")
+          //     this.$nextTick(()=>{
+          //       this.getList()
+          //     })
+          //   }
+          // })
+
+        },
+      })
+    },
     /** 鏌ヨ鐢ㄦ埛鍒楄〃 */
     getList() {
       this.loading = true;
@@ -909,6 +958,14 @@
 </script>
 
 <style scoped lang="scss">
+:deep(.sortable-ghost) {
+  opacity: 0.8;
+  background: #f0f9eb;
+}
+:deep(.sortable-chosen) {
+  cursor: move;
+  background: #e1f3d8;
+}
 .search_form {
   display: flex;
   justify-content: space-between;

--
Gitblit v1.9.3