9 Commits 368c930f3e ... 048f9acd2b

Tác giả SHA1 Thông báo Ngày
  walter 048f9acd2b 长连接 10 tháng trước cách đây
  walter b87a6b5288 积分规则取消编辑 10 tháng trước cách đây
  walter 3d938a7cb2 积分规则取消编辑 10 tháng trước cách đây
  walter f328bbaf40 部门对比 10 tháng trước cách đây
  walter 1d87cafd63 任务详情 10 tháng trước cách đây
  walter 4e6ef7ae51 取消规则编辑 10 tháng trước cách đây
  walter 8da90ea37b 部门对比优化websocket 10 tháng trước cách đây
  walter 723fd1ec4a 积分规则组件 10 tháng trước cách đây
  walter cdcc6a31c6 首页 1 năm trước cách đây

+ 5 - 0
package-lock.json

@@ -11862,6 +11862,11 @@
         "resolve": "^1.1.6"
       }
     },
+    "reconnecting-websocket": {
+      "version": "4.4.0",
+      "resolved": "https://registry.npmmirror.com/reconnecting-websocket/-/reconnecting-websocket-4.4.0.tgz",
+      "integrity": "sha512-D2E33ceRPga0NvTDhJmphEgJ7FUYF0v4lr1ki0csq06OdlxKfugGzN0dSkxM/NfqCxYELK4KcaTOUOjTV6Dcng=="
+    },
     "redent": {
       "version": "1.0.0",
       "resolved": "https://registry.npmmirror.com/redent/-/redent-1.0.0.tgz",

+ 1 - 0
package.json

@@ -28,6 +28,7 @@
     "qrcode.vue": "^1.6.3",
     "qrcodejs2": "0.0.2",
     "qs": "^6.9.6",
+    "reconnecting-websocket": "^4.4.0",
     "sortablejs": "^1.14.0",
     "swiper": "^5.2.1",
     "vant": "^2.12.51",

+ 111 - 22
src/components/RuleScopeSelector.vue

@@ -92,28 +92,49 @@
       </div>
     </template>
     <div class="container">
-      <scroller>
+<!--      <scroller>-->
+<!--        <van-cell-group inset>-->
+<!--          <van-cell-->
+<!--            v-for="(item,index) in list"-->
+<!--            :key="index"-->
+<!--            @click="onSelected(item)"-->
+<!--          >-->
+<!--            <template slot="label">-->
+<!--              <span class="record green" v-if="item.min_point <= 0">{{(item.range_type == 1 ? item.min_point : item.min_point+'~'+item.max_point)}}</span>-->
+<!--              <span class="record red" v-if="item.min_point > 0">+ {{(item.range_type == 1 ? item.min_point : item.min_point+'~'+item.max_point)}}</span>-->
+<!--              <span class="type">{{$getTypesName(item.pt_id)}}</span>-->
+<!--            </template>-->
+<!--            <template slot="icon">-->
+<!--              <van-checkbox v-model="item.selected" shape="square" style="margin-right: 0.16rem;" />-->
+<!--            </template>-->
+<!--            <template slot="title">-->
+<!--              <div class="item-remark">{{item.remark}}</div>-->
+<!--            </template>-->
+<!--          </van-cell>-->
+
+<!--        </van-cell-group>-->
+<!--        <div style="height: 1rem;"></div>-->
+<!--      </scroller>-->
+      <scroller ref="scroller" :on-refresh="onRefresh" :on-infinite="onInfinite" no-data-text="没有了噢" :list="pageList">
         <van-cell-group inset>
           <van-cell
-            v-for="(item,index) in list"
+            v-for="(item,index) in pageList"
             :key="index"
             @click="onSelected(item)"
           >
-            <template slot="label">
+            <template #label>
               <span class="record green" v-if="item.min_point <= 0">{{(item.range_type == 1 ? item.min_point : item.min_point+'~'+item.max_point)}}</span>
               <span class="record red" v-if="item.min_point > 0">+ {{(item.range_type == 1 ? item.min_point : item.min_point+'~'+item.max_point)}}</span>
               <span class="type">{{$getTypesName(item.pt_id)}}</span>
             </template>
-            <template slot="icon">
+            <template #icon>
               <van-checkbox v-model="item.selected" shape="square" style="margin-right: 0.16rem;" />
             </template>
-            <template slot="title">
+            <template #title>
               <div class="item-remark">{{item.remark}}</div>
             </template>
           </van-cell>
-
         </van-cell-group>
-        <div style="height: 1rem;"></div>
       </scroller>
     </div>
 
@@ -167,6 +188,8 @@
 </template>
 
 <script>
+import {_debounce} from "../utils/auth";
+
 export default {
   name:'RuleScopeSelector',
   props:{
@@ -200,7 +223,10 @@ export default {
       itemSelected:[],
       currentRuleId:0,
       keyword:'',
-      showRule:false
+      showRule:false,
+      page:1,
+      pageSize:10,
+      pageList:[],
     }
   },
   watch:{
@@ -217,20 +243,28 @@ export default {
         this.getRuleScope()
       }
     },
+    currentRuleId(v){
+      this.$refs.scroller.triggerPullToRefresh()
+    },
+    keyword:_debounce(function (v){
+      this.$refs.scroller.triggerPullToRefresh()
+    }),
+
+
   },
   computed:{
-    list(){
-      if (this.currentRuleId > 0){
-        if (!this.itemObject[`rule_${this.currentRuleId}`]) return []
-        this.items = []
-        this.initItems({1:this.itemObject[`rule_${this.currentRuleId}`]})
-      } else {
-        if (!this.itemObject) return []
-        this.items = []
-        this.initItems(this.itemObject)
-      }
-      return this.items.filter(item => this.keyword ? item.remark.indexOf(this.keyword) > -1 : true)
-    },
+    // list(){
+    //   if (this.currentRuleId > 0){
+    //     if (!this.itemObject[`rule_${this.currentRuleId}`]) return []
+    //     this.items = []
+    //     this.initItems({1:this.itemObject[`rule_${this.currentRuleId}`]})
+    //   } else {
+    //     if (!this.itemObject) return []
+    //     this.items = []
+    //     this.initItems(this.itemObject)
+    //   }
+    //   return this.items.filter(item => this.keyword ? item.remark.indexOf(this.keyword) > -1 : true)
+    // },
   },
   methods:{
     initItems(itemObj){
@@ -260,7 +294,8 @@ export default {
           if (res.data.code === 1){
             this.ruleTree = res.data.data.rule_tree
             this.itemObject = res.data.data.item_list
-            this.initItems(this.itemObject)
+            // this.initItems(this.itemObject)
+            this.$refs.scroller.triggerPullToRefresh()
           }
         })
     },
@@ -303,7 +338,61 @@ export default {
     clear(){
       this.itemSelected = []
       this.initItems(this.itemObject)
-    }
+    },
+    calculateItem(){
+      this.items = []
+      let itemObjects = []
+      if (!this.itemObject) return
+      if (this.currentRuleId > 0){
+        if (!this.itemObject[`rule_${this.currentRuleId}`]) {
+          this.items = []
+          return
+        }
+        itemObjects = {1:this.itemObject[`rule_${this.currentRuleId}`]}
+      } else {
+        itemObjects = this.itemObject
+      }
+      Object.values(itemObjects)
+        .forEach((item) => {
+          item.filter(record => this.keyword ? record.remark.indexOf(this.keyword) > -1 : true)
+            .forEach((record) => {
+              let temp = {
+                ...record,
+                selected:this.itemSelected.some(i => i.id === record.id)
+              }
+              this.items.push(temp)
+            })
+        })
+    },
+    calculatePage(callback){
+      if (this.items.length <= 0) {
+        this.pageList = []
+        return
+      }
+      let start = (this.page - 1) * this.pageSize
+      let end = start + this.pageSize
+
+      let appends = this.items.slice(start,end)
+
+      if (this.page === 1){
+        this.pageList= appends
+      }else {
+        if (appends.length) this.pageList.splice(this.pageList.length,0,...appends)
+      }
+
+      if (typeof callback === 'function') callback(appends.length < this.pageSize)
+    },
+    onRefresh(done){
+      console.log('on refresh')
+      this.page = 1
+      this.calculateItem()      //计算需要展示的数据
+      this.calculatePage(done)
+    },
+    onInfinite(done){
+      console.log('on infinite')
+      this.page += 1
+      this.calculatePage(done)
+    },
   },
   mounted() {}
 }

+ 111 - 24
src/point/view/integral/deptRank.vue

@@ -30,7 +30,7 @@
     <div class="mrd-content">
       <scroller
         ref="scroller"
-        :on-refresh="onRefresh"
+        :on-refresh="getDataList"
       >
         <van-cell v-for="item in dataList" :key="item.id" :title="item.name" :value="item.point"/>
         <noData :list="dataList" />
@@ -85,6 +85,8 @@ import moment from "moment/moment";
 import { DropdownMenu, DropdownItem ,Calendar,Switch} from 'vant';
 import DeptSelectorDropdown from '@/components/DeptSelectorDropdown';
 import RuleCategorySelDropdown from '@/components/RuleCategorySelDropdown';
+import ReconnectingWebSocket from "reconnecting-websocket";
+import {generateUUID, getToken} from "../../../utils/auth";
 
 Vue.use(DropdownMenu).use(DropdownItem).use(Calendar).use(Switch);
 
@@ -131,7 +133,9 @@ export default {
       minDate:minDate,
       maxDate:maxDate,
       timeScope:[new Date(startDate),new Date(endDate)],
-      showSearchBar:!this.$supremeAuthority('employee')
+      showSearchBar:!this.$supremeAuthority('employee'),
+      rws:null,
+      rwsHasAuth:false,
     }
   },
   computed:{
@@ -152,29 +156,31 @@ export default {
       })
     },
     'searchForm.startDate'(val){
-      this.onRefresh()
+      this.getDataList()
     },
     'searchForm.endDate'(val){
-      this.onRefresh()
+      this.getDataList()
     },
     'searchForm.deptId'(val){
-      this.onRefresh()
+      this.getDataList()
     },
     'searchForm.deptIncludeSub'(val){
-      this.onRefresh()
+      this.getDataList()
     },
     'searchForm.ptId'(val){
-      this.onRefresh()
+      this.getDataList()
     },
     'searchForm.ruleId'(val){
-      this.onRefresh()
+      this.getDataList()
     },
     'searchForm.ruleIncludeSub'(val){
-      this.onRefresh()
+      this.getDataList()
+    },
+    rwsHasAuth(v){
+      // console.log('rws auth',v)
+      if (v) this.getDataList();
     },
-
   },
-  created() {},
   methods:{
     timeScopeThisWeek(){
       this.timeScope = [new Date(moment().startOf('week').format('YYYY-MM-DD')),new Date(moment().endOf('week').format('YYYY-MM-DD'))]
@@ -222,12 +228,38 @@ export default {
       this.searchForm.ruleId = ruleId || 0;
       this.$refs.ruleDropdownItem.toggle();
     },
-    onRefresh(done){
-      if (!this.searchForm.startDate || !this.searchForm.endDate || !this.searchForm.ptId){
+    // onRefresh(done){
+    //   if (!this.searchForm.startDate || !this.searchForm.endDate || !this.searchForm.ptId){
+    //     if (typeof done === 'function') done();
+    //     return;
+    //   }
+    //
+    //   let msg = {
+    //     type:'dr',
+    //     start_date:this.searchForm.startDate,
+    //     end_date:this.searchForm.endDate,
+    //     pt_id:this.searchForm.ptId,
+    //     dept_id:this.searchForm.deptId,
+    //     dept_include_sub:this.searchForm.deptIncludeSub ? 1 : 0,
+    //     item_id:0,
+    //     rule_id:this.searchForm.ruleId,
+    //     rule_include_sub:this.searchForm.ruleIncludeSub ? 1 : 0
+    //   }
+    //
+    //   this.$socketApiTow.sendData(msg,(res) => {
+    //     if (res.code !== 1 || res.type !== msg.type){
+    //       if (typeof done === 'function') done();
+    //       return;
+    //     }
+    //     this.dataList = res.result.list;
+    //     if (typeof done === 'function') done();
+    //   })
+    // },
+    getDataList(done){
+      if (!this.rws || !this.rwsHasAuth || !this.searchForm.startDate || !this.searchForm.endDate || !this.searchForm.ptId){
         if (typeof done === 'function') done();
         return;
       }
-
       let msg = {
         type:'dr',
         start_date:this.searchForm.startDate,
@@ -238,20 +270,75 @@ export default {
         item_id:0,
         rule_id:this.searchForm.ruleId,
         rule_include_sub:this.searchForm.ruleIncludeSub ? 1 : 0
-      }
+      };
 
-      this.$socketApiTow.sendData(msg,(res) => {
-        if (res.code !== 1 || res.type !== msg.type){
-          if (typeof done === 'function') done();
-          return;
-        }
-        this.dataList = res.result.list;
-        if (typeof done === 'function') done();
-      })
+      this.rws.send(JSON.stringify(msg));
 
+      if (typeof done === 'function') done();
+    },
 
+    onWsOpen(){
+      // console.log('on ws open');
+      let params = {
+        type:'auth',
+        token: getToken(),
+        machine: generateUUID(),
+      }
+      this.rws.send(JSON.stringify(params));
+    },
+    onWsMessage(event){
+      let msg = event.data ?  JSON.parse(event.data) : null;
+      if (!msg) return;
+      switch (msg.type){
+        case 'ping':
+          this.rws.send("dept rank keep connecting")
+          break;
+        case 'auth':
+          this.rwsHasAuth = msg.code === 1;
+          break;
+        case 'dr':
+          if (msg.code === 1) this.dataList = msg.result.list;
+          break;
+      }
+    },
+    onWsError(event){
+      this.rwsHasAuth = false;
+      // console.log('on ws error',event);
+    },
+    onWsClose(event){
+      this.rwsHasAuth = false;
+      // console.log('on ws close',event);
+    },
+    initRws(){
+      if (this.rws){
+        this.rws.close();
+        this.rws = null;
+        this.rwsHasAuth = false;
+      }
+      this.rws = new ReconnectingWebSocket(process.env.VUE_APP_WEBSCOKET_TOW);
+      this.rws.onopen = this.onWsOpen;
+      this.rws.onmessage = this.onWsMessage;
+      this.rws.onerror = this.onWsError;
+      this.rws.onclose = this.onWsClose;
+    },
+    clearRws(){
+      if (this.rws) this.rws.close();
+      this.rws = null;
+      this.rwsHasAuth = false;
     }
-  }
+  },
+  created() {},
+  mounted() {},
+  activated() {
+    this.initRws();
+  },
+  deactivated() {
+    this.clearRws();
+  },
+  beforeDestroy() {
+    this.clearRws();
+  },
+  destroyed() {},
 }
 
 </script>

+ 237 - 31
src/point/view/integral/integral_application.vue

@@ -89,40 +89,66 @@
     </div>
     <div style="padding:0.32rem;" class="flex-box-ce">
       <van-button size="large" plain type="info" style="margin-right: 0.2rem;width: 2rem;" @click="openSelect" v-if="rule_switch">已选{{items.length}}条</van-button>
-      <van-button size="large" @click="data_verify" :disabled="subloading" type="info">提交</van-button>
+<!--      <van-button size="large" @click="data_verify" :disabled="subloading" type="info">提交</van-button>-->
+      <van-button size="large" @click="rwsBusinessVerify" :disabled="subloading || !rwsHasAuth" type="info">提交</van-button>
     </div>
 
     <!-- 提交结果 -->
-    <van-popup v-model="isResult" style="width: 90%;border-radius: 5px;">
-    	<div v-if="!isShowError" style="padding: 0.24rem;">
-        <van-progress :percentage="percentage" />
-    		<div style="margin-top: 10px;border: 1px solid #f1f1f1;max-height: 7rem;overflow-y: auto;" class="scroll-bar">
-    			<div class="flex-box-ce results" style="font-weight: 600;">
-    				<div style="border-right: 1px solid #f1f1f1;width: 40px;">序号</div>
-    				<div class="flex-1" style="border-right: 1px solid #f1f1f1;">申请对象</div>
-    				<div class="flex-1" >处理结果</div>
-    			</div>
-    			<div class="flex-box-ce results" v-for="(item, index) in results" :key="index">
-    				<div style="border-right: 1px solid #f1f1f1;width: 40px;">{{results.length-index}}</div>
-    				<div class="flex-1" style="border-right: 1px solid #f1f1f1;">{{ item.target }}</div>
-    				<div class="flex-1 font-flex-word" v-if="item.status == 1">
-    					<span class="green">提交成功</span>
-    				</div>
-    				<div class="flex-1 red" v-else>{{ item.msg }}</div>
-    			</div>
-    		</div>
-        <div class="flex-box-end" style="margin-top: 20px;" v-show="results.length==resultList.length">
-          <van-button type="info" @click="isResult = false" size="small">确 定</van-button>
-        </div>
-    	</div>
-    	<div v-else>
-    		<div style="text-align: center;" class="red">{{errorMsg}}</div>
-    		<div>
-    			<div class="flex-box-end" style="margin-top: 10px;">
-            <van-button type="info" @click="isResult = false" size="small">确 定</van-button>
+<!--    <van-popup v-model="isResult" style="width: 90%;border-radius: 5px;">-->
+<!--    	<div v-if="!isShowError" style="padding: 0.24rem;">-->
+<!--        <van-progress :percentage="percentage" />-->
+<!--    		<div style="margin-top: 10px;border: 1px solid #f1f1f1;max-height: 7rem;overflow-y: auto;" class="scroll-bar">-->
+<!--    			<div class="flex-box-ce results" style="font-weight: 600;">-->
+<!--    				<div style="border-right: 1px solid #f1f1f1;width: 40px;">序号</div>-->
+<!--    				<div class="flex-1" style="border-right: 1px solid #f1f1f1;">申请对象</div>-->
+<!--    				<div class="flex-1" >处理结果</div>-->
+<!--    			</div>-->
+<!--    			<div class="flex-box-ce results" v-for="(item, index) in results" :key="index">-->
+<!--    				<div style="border-right: 1px solid #f1f1f1;width: 40px;">{{results.length-index}}</div>-->
+<!--    				<div class="flex-1" style="border-right: 1px solid #f1f1f1;">{{ item.target }}</div>-->
+<!--    				<div class="flex-1 font-flex-word" v-if="item.status == 1">-->
+<!--    					<span class="green">提交成功</span>-->
+<!--    				</div>-->
+<!--    				<div class="flex-1 red" v-else>{{ item.msg }}</div>-->
+<!--    			</div>-->
+<!--    		</div>-->
+<!--        <div class="flex-box-end" style="margin-top: 20px;" v-show="results.length==resultList.length">-->
+<!--          <van-button type="info" @click="isResult = false" size="small">确 定</van-button>-->
+<!--        </div>-->
+<!--    	</div>-->
+<!--    	<div v-else>-->
+<!--    		<div style="text-align: center;" class="red">{{errorMsg}}</div>-->
+<!--    		<div>-->
+<!--    			<div class="flex-box-end" style="margin-top: 10px;">-->
+<!--            <van-button type="info" @click="isResult = false" size="small">确 定</van-button>-->
+<!--          </div>-->
+<!--    		</div>-->
+<!--    	</div>-->
+<!--    </van-popup>-->
+
+<!--  rws提交结果  -->
+    <van-popup v-model="rwsBusinessData.showBusiness" :close-on-click-overlay="false" style="width: 90%;border-radius: 5px;">
+      <div style="padding: 0.24rem;">
+        <van-progress :percentage="rwsBusinessProgress" />
+        <div style="margin-top: 10px;border: 1px solid #f1f1f1;max-height: 7rem;overflow-y: auto;" class="scroll-bar">
+          <div class="flex-box-ce results" style="font-weight: 600;">
+            <div style="border-right: 1px solid #f1f1f1;width: 40px;">序号</div>
+            <div class="flex-1" style="border-right: 1px solid #f1f1f1;">申请对象</div>
+            <div class="flex-1" >处理结果</div>
+          </div>
+          <div class="flex-box-ce results" v-for="(item, index) in rwsBusinessData.dataList" :key="index">
+            <div style="border-right: 1px solid #f1f1f1;width: 40px;">{{`${index + 1}`}}</div>
+            <div class="flex-1" style="border-right: 1px solid #f1f1f1;">{{ item.employee_name }}</div>
+            <div class="flex-1">
+              <span :class="{'cyan':item.status === -2,'origin':item.status === -1,'green':item.status === 1,'red':item.status === 0}">{{item.msg}}</span>
+            </div>
           </div>
-    		</div>
-    	</div>
+        </div>
+        <div class="flex-box-end" style="margin-top: 20px;" >
+          <van-button type="info" :disabled="rwsBusinessProgress < 100" @click="rwsBusinessData.showBusiness = false" size="small">确 定</van-button>
+          <van-tag style="margin-left: 0.2rem;" @click="rwsClipResult">{{rwsBusinessData.result.length}} / {{rwsBusinessData.dataList.length}}</van-tag>
+        </div>
+      </div>
     </van-popup>
   </div>
 </template>
@@ -136,6 +162,8 @@ import moment from 'moment'
 import Vue from 'vue'
 import {Switch,Progress,Icon  } from 'vant'
 import RuleScopeSelector from "../../../components/RuleScopeSelector.vue";
+import ReconnectingWebSocket from "reconnecting-websocket";
+import {generateUUID, getToken} from "../../../utils/auth";
 
 Vue.use(Switch).use(Progress).use(Icon)
 
@@ -159,6 +187,7 @@ export default {
       superior_list:this.$userInfo().employee_detail.superior_list,
       employee_list: [this.$userInfo()],
       employeeid:this.$userInfo().id,
+      employeeName:this.$userInfo().name,
       ptId:3,
       change_reviewer:Number(this.$userInfo().site_config.change_reviewer),//是否允许员工修改审批人
       userName:'',
@@ -193,6 +222,20 @@ export default {
       resultIndex:0,
       isShowError:false,
       errorMsg:'服务器繁忙,请稍后再试',
+      rws:null,
+      rwsHasAuth:false,
+      rwsBusinessData:{
+        showBusiness:false,
+        dataList:[],
+        msgQueue:[],
+        result:[],
+        intervalId:null,
+      }
+    }
+  },
+  computed:{
+    rwsBusinessProgress(){
+      return this.rwsBusinessData.dataList.length === 0 ? 0 : Math.floor(this.rwsBusinessData.dataList.filter(item => item.status >= 0).length / this.rwsBusinessData.dataList.length * 100)
     }
   },
   watch: {
@@ -227,9 +270,11 @@ export default {
     employee_list(val) {
       if (val.length > 0) {
         this.employeeid=val[0].id;
+        this.employeeName=val[0].name;
         this.initializesReviewer(val[0].id);
       } else {
         this.employeeid = ''
+        this.employeeName = ''
         this.items.forEach(item=>{
           item.reviewer_id='';
           item.reviewer_list=[];
@@ -247,6 +292,14 @@ export default {
     		this.$socketApi.closewebsocket();
     	}
     },
+    'rwsBusinessData.showBusiness'(v){
+      if (!v) {
+        this.initRwsBusinessData();
+        this.items = [];
+        this.itemRule=[];//规则数组
+        this.rule_switch=true;
+      }
+    }
   },
   mounted() {
     this.initializesReviewer(this.employeeid);
@@ -257,6 +310,14 @@ export default {
        }
     }
   },
+  activated() {
+    console.log('activated');
+    this.initRws();
+  },
+  beforeDestroy() {
+    console.log('before destroy');
+    this.clearRws();
+  },
   methods: {
     openText(){
        this.$dialog.alert({
@@ -439,7 +500,152 @@ export default {
     		this.isShowError = true;
     	}
     },
-  }
+    initRws(){
+      if (this.rws){
+        this.rws.close();
+        this.rws = null;
+        this.rwsHasAuth = false;
+      }
+      this.rws = new ReconnectingWebSocket(process.env.VUE_APP_WEBSCOKET);
+      this.rws.onopen = this.onWsOpen;
+      this.rws.onmessage = this.onWsMessage;
+      this.rws.onerror = this.onWsError;
+      this.rws.onclose = this.onWsClose;
+    },
+    initRwsBusinessData(){
+      this.rwsBusinessData.dataList = [];
+      this.rwsBusinessData.msgQueue = [];
+      this.rwsBusinessData.result = [];
+      if (this.rwsBusinessData.intervalId) clearInterval(this.rwsBusinessData.intervalId);
+      this.rwsBusinessData.intervalId = null;
+    },
+    onWsOpen(){
+      let params = {
+        type:'auth',
+        token: getToken(),
+        machine: generateUUID(),
+      }
+      this.rws.send(JSON.stringify(params));
+    },
+    onWsMessage(event){
+      let msg = event.data ?  JSON.parse(event.data) : null;
+      if (!msg) return;
+      let type = msg.type || 'none';
+      switch (type){
+        case 'ping':
+          this.rws.send('integral application keep connecting');
+          break;
+        case 'auth':
+          this.rwsHasAuth = msg.code === 1;
+          break;
+        case 'point_apply':
+          this.rwsBusinessData.result.push(msg);
+          let businessId = msg.result.task.msg.businessId;
+          this.rwsBusinessData.dataList.forEach(item => {
+            if (item.businessId !== businessId) return;
+            item.status = msg.result.status;
+            item.msg = msg.result.msg;
+          })
+          this.rwsIntegralApplication();
+          break;
+      }
+    },
+    onWsError(event){
+      console.log('on ws error',event);
+      this.rwsHasAuth = false;
+    },
+    onWsClose(event){
+      console.log('on ws close',event)
+      this.rwsHasAuth = false;
+    },
+    clearRws(){
+      if (this.rws) this.rws.close();
+      this.rws = null;
+      this.rwsHasAuth = false;
+      this.initRwsBusinessData();
+    },
+    rwsBusinessVerify() {
+      if(!this.employeeid){
+        this.showMessage('请选择录入对象')
+        return false
+      }
+      if(this.items.length === 0){
+        this.showMessage('请选择规则')
+        return false
+      }
+
+      let now = moment();
+      let businessId = 1;
+      for (var i = 0; i < this.items.length; i++){
+        let item = this.items[i];
+        if (!item.remark){
+          this.showMessage(`第${i + 1}条申请,请输入时间内容及描述`);
+          return false;
+        }
+        if (item.reviewer_list.length <= 0){
+          this.showMessage(`第${i + 1}条申请,请选择审批人`);
+          return false;
+        }
+        if (moment(item.event_time).isAfter(now)){
+          this.showMessage(`第${i + 1}条申请,发生时间不能大于今天`);
+          return false;
+        }
+
+        this.rwsBusinessData.dataList.push({
+          rule_id: item.rule_id || 0,
+          employee_id: this.employeeid || 0,
+          item_id: item.item_id || 0,
+          remark: item.remark,
+          event_time: item.event_time,
+          files: item.files,
+          type:'point_apply',
+          reviewer_id:item.reviewer_list[0].id,
+          employee_name:this.employeeName,
+          status:-2,
+          msg:'待处理',
+          businessId:businessId,
+        });
+        /*队列数据*/
+        let msg = {
+          rule_id: item.rule_id || 0,
+          employee_id: this.employeeid || 0,
+          item_id: item.item_id || 0,
+          remark: item.remark,
+          event_time: item.event_time,
+          files: item.files,
+          type:'point_apply',
+          reviewer_id:item.reviewer_list[0].id,
+          businessId:businessId,
+        }
+        this.rwsBusinessData.msgQueue.push(msg);
+
+        businessId++;
+      }
+      if (this.rwsBusinessData.dataList.length <= 0){
+        this.showMessage("请重新指定规则");
+        return false;
+      }
+
+      this.rwsBusinessData.showBusiness = true;
+
+      /*开始提交*/
+      this.rwsIntegralApplication();
+    },
+    rwsClipResult(){
+      navigator.clipboard.writeText(JSON.stringify(this.rwsBusinessData.result));
+      this.$notify({type: 'info', message: '结果已经复制到剪切板'})
+    },
+    rwsIntegralApplication(){
+      let msg = this.rwsBusinessData.msgQueue.shift();
+      if (!msg) return;
+      this.rwsBusinessData.dataList.forEach(item => {
+        if (item.businessId !== msg.businessId) return;
+        item.status = -1;
+        item.msg = '处理中';
+      })
+      this.rws.send(JSON.stringify(msg));
+    }
+  },
 }
 </script>
 <style scoped>

+ 310 - 44
src/point/view/integral/integral_entry_n.vue

@@ -88,46 +88,78 @@
     <div v-isKeyboard>
       <div class="flex-box-ce footer">
         <van-button size="large" plain type="info" style="margin-right: 0.2rem;width: 2rem;" @click="openSelect">已选{{items.length}}条</van-button>
-        <van-button size="large" @click="data_verify" type="info">提交</van-button>
+<!--        <van-button size="large" @click="data_verify" type="info" :disabled="!rwsHasAuth" >提交</van-button>-->
+        <van-button size="large" @click="rwsBusinessVerify" type="info" :disabled="!rwsHasAuth" >提交</van-button>
       </div>
     </div>
 
     <!-- 提交结果 -->
-    <van-popup v-model="isResult" style="width: 90%;border-radius: 5px;">
-    	<div v-if="!isShowError" style="padding: 0.24rem;">
-        <van-progress :percentage="percentage" />
-    		<div style="margin-top: 10px;border: 1px solid #f1f1f1;max-height: 7rem;overflow-y: auto;" class="scroll-bar">
-    			<div class="flex-box-ce results" style="font-weight: 600;">
-    				<div style="border-right: 1px solid #f1f1f1;width: 40px;">序号</div>
-    				<div class="flex-1" style="border-right: 1px solid #f1f1f1;">奖扣对象</div>
-    				<div class="flex-1" style="border-right: 1px solid #f1f1f1;">积分</div>
-    				<div class="flex-1" >处理结果</div>
-    			</div>
-    			<div class="flex-box-ce results" v-for="(item, index) in results" :key="index">
-    				<div style="border-right: 1px solid #f1f1f1;width: 40px;">{{results.length-index}}</div>
-    				<div class="flex-1" style="border-right: 1px solid #f1f1f1;">{{ item.target }}</div>
-    				<div class="flex-1" style="border-right: 1px solid #f1f1f1;">{{ item.point>0? '+'+item.point:item.point }}<span> {{ $getTypesName(ptId) }}</span></div>
-    				<div class="flex-1" v-if="item.status == 1">
-    					<span v-if="item.msg=='奖扣成功'" class="green">{{ item.msg }}</span>
-    					<span class="blue" v-else>{{ item.msg }}</span>
-    				</div>
-    				<div class="flex-1 red" v-else>{{ item.msg }}</div>
-    			</div>
-    		</div>
-        <div class="flex-box-end" style="margin-top: 20px;" v-show="results.length==resultList.length">
-          <van-button type="info" @click="isResult = false" size="small">确 定</van-button>
-        </div>
-    	</div>
-    	<div v-else>
-    		<div style="text-align: center;" class="red">{{errorMsg}}</div>
-    		<div>
-    			<div class="flex-box-end" style="margin-top: 10px;">
-            <van-button type="info" @click="isResult = false" size="small">确 定</van-button>
+<!--    <van-popup v-model="isResult" style="width: 90%;border-radius: 5px;">-->
+<!--    	<div v-if="!isShowError" style="padding: 0.24rem;">-->
+<!--        <van-progress :percentage="percentage" />-->
+<!--    		<div style="margin-top: 10px;border: 1px solid #f1f1f1;max-height: 7rem;overflow-y: auto;" class="scroll-bar">-->
+<!--    			<div class="flex-box-ce results" style="font-weight: 600;">-->
+<!--    				<div style="border-right: 1px solid #f1f1f1;width: 40px;">序号</div>-->
+<!--    				<div class="flex-1" style="border-right: 1px solid #f1f1f1;">奖扣对象</div>-->
+<!--    				<div class="flex-1" style="border-right: 1px solid #f1f1f1;">积分</div>-->
+<!--    				<div class="flex-1" >处理结果</div>-->
+<!--    			</div>-->
+<!--    			<div class="flex-box-ce results" v-for="(item, index) in results" :key="index">-->
+<!--    				<div style="border-right: 1px solid #f1f1f1;width: 40px;">{{results.length-index}}</div>-->
+<!--    				<div class="flex-1" style="border-right: 1px solid #f1f1f1;">{{ item.target }}</div>-->
+<!--    				<div class="flex-1" style="border-right: 1px solid #f1f1f1;">{{ item.point>0? '+'+item.point:item.point }}<span> {{ $getTypesName(ptId) }}</span></div>-->
+<!--    				<div class="flex-1" v-if="item.status == 1">-->
+<!--    					<span v-if="item.msg=='奖扣成功'" class="green">{{ item.msg }}</span>-->
+<!--    					<span class="blue" v-else>{{ item.msg }}</span>-->
+<!--    				</div>-->
+<!--    				<div class="flex-1 red" v-else>{{ item.msg }}</div>-->
+<!--    			</div>-->
+<!--    		</div>-->
+<!--        <div class="flex-box-end" style="margin-top: 20px;" v-show="results.length==resultList.length">-->
+<!--          <van-button type="info" @click="isResult = false" size="small">确 定</van-button>-->
+<!--        </div>-->
+<!--    	</div>-->
+<!--    	<div v-else>-->
+<!--    		<div style="text-align: center;" class="red">{{errorMsg}}</div>-->
+<!--    		<div>-->
+<!--    			<div class="flex-box-end" style="margin-top: 10px;">-->
+<!--            <van-button type="info" @click="isResult = false" size="small">确 定</van-button>-->
+<!--          </div>-->
+<!--    		</div>-->
+<!--    	</div>-->
+<!--    </van-popup>-->
+    <RuleScopeSelector :visible.sync = showRuleSelector :selected="itemRule" multi @confirm="selected => itemRule = selected" :pt-id="ptId" />
+
+<!--  rws提交结果  -->
+    <van-popup v-model="rwsBusinessData.showBusiness" :close-on-click-overlay="false" style="width: 90%; border-radius: 5px;">
+      <div style="padding: 0.24rem;">
+        <van-progress :percentage="rwsBusinessProgress" />
+        <div style="margin-top: 10px;border: 1px solid #f1f1f1;max-height: 7rem;overflow-y: auto;" class="scroll-bar">
+          <div class="flex-box-ce results" style="font-weight: 600;">
+            <div style="border-right: 1px solid #f1f1f1;width: 40px;">序号</div>
+            <div class="flex-1" style="border-right: 1px solid #f1f1f1;">奖扣对象</div>
+            <div class="flex-1" style="border-right: 1px solid #f1f1f1;">积分</div>
+            <div class="flex-1" >处理结果</div>
+          </div>
+          <div class="flex-box-ce results" v-for="(item,index) in rwsBusinessData.dataList" :key="index">
+            <div style="border-right: 1px solid #f1f1f1;width: 40px;">{{`${index + 1}`}}</div>
+            <div class="flex-1" style="border-right: 1px solid #f1f1f1;">{{ item.employee_name }}</div>
+            <div class="flex-1" style="border-right: 1px solid #f1f1f1;">{{ item.point>0? '+'+item.point:item.point }}<span> {{ $getTypesName(ptId) }}</span></div>
+            <div class="flex-1">
+              <span :class="{'cyan':item.status === -2,'origin':item.status === -1,'green':item.status === 1,'red':item.status === 0}" >{{item.msg}}</span>
+            </div>
           </div>
-    		</div>
-    	</div>
+        </div>
+<!--        <div class="flex-box-end" style="margin-top: 20px;" v-show="rwsBusinessProgress >= 100">-->
+<!--          <van-button type="info" @click="rwsBusinessData.showBusiness = false" size="small">确 定</van-button>-->
+<!--        </div>-->
+        <div class="flex-box-end" style="margin-top: 20px;">
+          <van-button type="info" :disabled="rwsBusinessProgress < 100" @click="rwsBusinessData.showBusiness = false" size="small" >确 定</van-button>
+          <van-tag style="margin-left: 0.2rem;" @click="rwsClipResult">{{rwsBusinessData.result.length}} / {{rwsBusinessData.dataList.length}}</van-tag>
+        </div>
+      </div>
     </van-popup>
-    <RuleScopeSelector :visible.sync = showRuleSelector :selected="itemRule" multi @confirm="selected => itemRule = selected" :pt-id="ptId" />
+
   </div>
 </template>
 <script>
@@ -142,6 +174,8 @@ import Vue from 'vue'
 import ImageCamera from '@/attendance/components/image-camera';
 import {Switch,Progress} from 'vant'
 import RuleScopeSelector from "../../../components/RuleScopeSelector.vue";
+import ReconnectingWebSocket from "reconnecting-websocket";
+import {generateUUID, getToken} from "../../../utils/auth";
 
 Vue.use(Switch).use(Progress)
 export default {
@@ -210,7 +244,16 @@ export default {
       resultIndex:0,
       isShowError:false,
       errorMsg:'服务器繁忙,请稍后再试',
-
+      rws:null,
+      rwsHasAuth:false,
+      rwsBusinessData:{
+        showBusiness:false,
+        dataList:[],
+        msgQueue:[],
+        result:[],
+        employees:[],
+        items:[],
+      }
     }
   },
   watch: {
@@ -272,14 +315,17 @@ export default {
       }
     },
     employee_list(val) {
-      if (val.length > 0) {
-        this.dialogData.members = []
-        this.dialogData.members=val.map(element => {
-          return element.id
-        })
-      } else {
-        this.dialogData.members = []
-      }
+      // if (val.length > 0) {
+      //   this.dialogData.members = []
+      //   this.dialogData.members=val.map(element => {
+      //     return element.id
+      //   })
+      // } else {
+      //   this.dialogData.members = []
+      // }
+      //
+      // console.log(val);
+      this.rwsBusinessData.employees = val && val.length > 0 ? val : [];
     },
     isResult(val){
     	if(!val){
@@ -297,6 +343,25 @@ export default {
     		this.$socketApi.closewebsocket();
     	}
     },
+    'rwsBusinessData.showBusiness'(v){
+      if (!v){
+        this.initRwsBusinessData();
+        this.dialogData = {
+          members: [],
+          items: []
+        };
+        this.itemRule = [];
+        this.ruleCate = [];
+        this.rule_switch = true;
+        this.items = [];
+        this.employee_list = [];
+      }
+    }
+  },
+  computed:{
+    rwsBusinessProgress(){
+      return this.rwsBusinessData.dataList.length === 0 ? 0 : Math.floor(this.rwsBusinessData.dataList.filter(item => item.status >= 0).length / this.rwsBusinessData.dataList.length * 100);
+    }
   },
   methods: {
     openText(){
@@ -317,6 +382,7 @@ export default {
       this.$notify({type: 'danger', message: str})
     },
     data_verify () {
+      // console.log(this.dialogData,this.items);return ;
       let dialogData=this.dialogData
       dialogData.items=this.items.map(e=>{
         if(e.reviewer_list.length>0){
@@ -401,7 +467,9 @@ export default {
             files: element.files
           });
       });
-      this.webSocket(data);
+      // console.log(data,this.dialogData);this.isResult = true; return ;
+      this.rwsBusinessSubmit(data.members,data.items);
+      // this.webSocket(data);
     },
     webSocket(data){
     	let {members,items}=data;
@@ -485,6 +553,200 @@ export default {
 
       }).catch(() => {});
     },
+    initRws(){
+      if (this.rws){
+        this.rws.close();
+        this.rws = null;
+        this.rwsHasAuth = false;
+      }
+      this.rws = new ReconnectingWebSocket(process.env.VUE_APP_WEBSCOKET);
+      this.rws.onopen = this.onWsOpen;
+      this.rws.onmessage = this.onWsMessage;
+      this.rws.onerror = this.onWsError;
+      this.rws.onclose = this.onWsClose;
+    },
+    initRwsBusinessData(){
+      this.rwsBusinessData.dataList = [];
+      this.rwsBusinessData.msgQueue = [];
+      this.rwsBusinessData.result = [];
+      this.rwsBusinessData.items = [];
+    },
+    onWsOpen(){
+      let params = {
+        type:'auth',
+        token: getToken(),
+        machine: generateUUID(),
+      }
+      this.rws.send(JSON.stringify(params));
+    },
+    onWsMessage(event){
+      let msg = event.data ?  JSON.parse(event.data) : null;
+      if (!msg) return;
+      let type = msg.type || 'none';
+      switch (type){
+        case 'ping':
+          this.rws.send('point entry keep connecting');
+          break;
+        case 'auth':
+          this.rwsHasAuth = msg.code === 1;
+          break;
+        case 'pea':
+        case 'peb':
+          this.rwsBusinessData.result.push(msg);
+          let businessId = msg.result.task.msg.businessId;
+          this.rwsBusinessData.dataList.forEach(item => {
+            if (item.businessId !== businessId) return;
+            item.status = msg.result.status;
+            item.msg = msg.result.msg;
+          })
+          this.rwsPointEntry();
+          break;
+      }
+    },
+    onWsError(event){
+      console.log('on ws error',event);
+      this.rwsHasAuth = false;
+    },
+    onWsClose(event){
+      console.log('on ws close',event)
+      this.rwsHasAuth = false;
+    },
+    clearRws(){
+      if (this.rws) this.rws.close();
+      this.rws = null;
+      this.rwsHasAuth = false;
+      this.initRwsBusinessData();
+    },
+    rwsPointEntry(){
+      let msg = this.rwsBusinessData.msgQueue.shift();
+      if (!msg) return;
+      this.rwsBusinessData.dataList.forEach(item => {
+        if (item.businessId !== msg.businessId) return;
+        item.status = -1;
+        item.msg = '处理中';
+      })
+
+      this.rws.send(JSON.stringify(msg));
+    },
+    rwsBusinessSubmit(members,items){
+      if (!members || members.length <= 0 || !items || items.length <= 0) {
+        this.showMessage('规则/分类以及录入对象必须选择');
+        return;
+      }
+
+      let employeeMap = {}
+      this.rwsBusinessData.employees.forEach(employee => {
+        employeeMap[employee.id] = employee;
+      });
+      let businessId = 1;
+      this.initRwsBusinessData();   //清空提交业务数据
+      members.forEach(memberId => {
+        items.forEach(item => {
+          item.type = this.ptId === 2 ? 'pea' : 'peb';
+          item.employee_id = memberId;
+          item.employee_name = employeeMap[memberId] ? employeeMap[memberId].name : '';
+          item.status = -2;
+          item.msg = '待处理';
+          item.businessId = businessId;
+          this.rwsBusinessData.dataList.push(JSON.parse(JSON.stringify(item)))
+          businessId++;
+
+          /*队列数据*/
+          let msg = {
+            type:item.type,
+            employee_id:item.employee_id,
+            event_time:item.event_time,
+            files:item.files,
+            item_id:item.item_id,
+            point:item.point,
+            pt_id:item.pt_id,
+            remark:item.remark,
+            reviewer_id:item.reviewer_id,
+            rule_id:item.rule_id,
+            businessId:item.businessId,
+          }
+          this.rwsBusinessData.msgQueue.push(JSON.parse(JSON.stringify(msg)))
+        })
+      })
+      this.rwsBusinessData.showBusiness = true;
+
+
+      /*开始提交*/
+      this.rwsPointEntry();
+    },
+    rwsBusinessVerify(){
+      if (this.items.length === 0) {
+        this.showMessage("请选择规则或者分类");
+        return false;
+      }
+
+      if (this.rwsBusinessData.employees.length === 0) {
+        this.showMessage("请选择录入对象");
+        return false;
+      }
+
+      this.rwsBusinessData.items = this.items.map(item => {
+        item.reviewer_id = item.reviewer_list.length > 0 ? item.reviewer_list[0].id : '';
+        return item;
+      })
+
+
+      let userMaxPoint = null;
+      let userMinPoint = null;
+
+      this.$userInfo().point_config.point_limit.forEach(point => {
+        if (this.ptId !== point.pt_id) return;
+        userMaxPoint = Math.abs(point.point);
+        userMinPoint = userMaxPoint * -1;
+      });
+
+
+      let members = this.rwsBusinessData.employees.map(employee => employee.id);
+      let items = [];
+
+      // for ([item,index] of this.rwsBusinessData.items){
+      for (var i = 0; i < this.rwsBusinessData.items.length; i++){
+        let item = this.rwsBusinessData.items[i];
+        items.push({
+          rule_id: item.rule_id || 0,
+          item_id: item.item_id || 0,
+          point: item.point,
+          remark: item.remark,
+          event_time: item.event_time,
+          pt_id: this.ptId,
+          reviewer_id: item.reviewer_id || 0,
+          files: item.files
+        })
+
+        if (item.point === 0){
+          this.showMessage(`第${i + 1}条奖扣输入积分分值不能为0`);
+          return false;
+        }
+        if (!item.remark){
+          this.showMessage(`第${i + 1}条奖扣请输入事件内容及描述`);
+          return false;
+        }
+
+        /*非创始人并且奖扣A分/指定分类/企业配置规则内要验证权限分时,验证权限分*/
+        if (!this.isCreator && (this.ptId === 2 || !this.rule_switch || this.$userInfo().site_config.rule_limit_check > 0) && userMaxPoint !== null && userMinPoint !== null){
+          if (item.reviewer_id > 0) continue;
+
+          if (item.point > 0 && item.point > userMaxPoint){
+            this.showMessage(`第${i + 1}条奖扣输入积分分值超出权限分,请选择审批人递交`);
+            return false;
+          }else if (item.point <= 0 && item.point < userMinPoint){
+            this.showMessage(`第${i + 1}`);
+            return false;
+          }
+        }
+      }
+
+      this.rwsBusinessSubmit(members,items);
+    },
+    rwsClipResult(){
+      navigator.clipboard.writeText(JSON.stringify(this.rwsBusinessData.result));
+      this.$notify({type: 'info', message: '结果已经复制到剪切板'})
+    }
   },
   created () {
     this.itemRule=[];
@@ -503,6 +765,10 @@ export default {
     this.$nextTick(()=>{
       this.rule_switch=true;
     })
+    this.initRws();
+  },
+  beforeDestroy() {
+    this.clearRws();
   }
 }
 </script>

+ 15 - 13
src/point/view/integral/rule_category.vue

@@ -1,11 +1,11 @@
 <template>
   <div>
     <van-nav-bar title="积分规则" left-text="返回" left-arrow class="headerbar no-down-icon">
-      <template slot="right">
-        <van-dropdown-menu duration="0.3" text="text" class="department_right_nav" v-if="this.getRole_noe">
-          <van-dropdown-item title="+" @change="plus_menu" :options="options" />
-        </van-dropdown-menu>
-      </template>
+<!--      <template slot="right">-->
+<!--        <van-dropdown-menu duration="0.3" text="text" class="department_right_nav" v-if="this.getRole_noe">-->
+<!--          <van-dropdown-item title="+" @change="plus_menu" :options="options" />-->
+<!--        </van-dropdown-menu>-->
+<!--      </template>-->
 
       <template slot="left" v-if="pid > 0">
         <div @click="back">
@@ -13,7 +13,7 @@
           <span class="van-nav-bar__text">返回</span>
         </div>
       </template>
-      <template slot="left" v-if="pid == 0">
+      <template slot="left" v-else-if="pid === 0">
         <div @click="$route_back">
           <van-icon name="arrow-left" />
           <span class="van-nav-bar__text">返回</span>
@@ -31,15 +31,16 @@
     <div class="body_com" :class="{ show_dept_path: pid_list_arr.length > 0 }">
       <scroller :on-refresh="get_department_list" :isInitRefresh="false">
         <van-cell-group v-if="pid > 0 && keyword == ''">
-          <van-cell :title="pid_list_arr[pid_list_arr.length - 1].name" class="employee_cell" @click="edit_cate">
+<!--          <van-cell :title="pid_list_arr[pid_list_arr.length - 1].name" class="employee_cell" @click="edit_cate">-->
+          <van-cell :title="pid_list_arr[pid_list_arr.length - 1].name" class="employee_cell">
             <template slot="icon">
               <img src="static/images/e66f.jpg" class="employee_cell_head_img" />
             </template>
 
-            <van-icon v-if="!select_mode && this.getRole_noe" name="edit" slot="right-icon" />
-            <template v-else slot="right-icon">
-              <span></span>
-            </template>
+<!--            <van-icon v-if="!select_mode && this.getRole_noe" name="edit" slot="right-icon" />-->
+<!--            <template v-else slot="right-icon">-->
+<!--              <span></span>-->
+<!--            </template>-->
           </van-cell>
         </van-cell-group>
 
@@ -61,7 +62,8 @@
         </van-cell-group>
 
         <van-cell-group v-for="(item, index) in list" :key="index" v-show="item.remark.indexOf(keyword) >= 0">
-          <van-cell :title="item.remark" class="employee_cell rule_list_item" @click="employee_click(item)">
+<!--          <van-cell :title="item.remark" class="employee_cell rule_list_item" @click="employee_click(item)">-->
+          <van-cell :title="item.remark" class="employee_cell rule_list_item">
             <template slot="label">
               <div v-show="item.cycle_type == 2"><van-tag size="medium" plain>自动规则</van-tag></div>
               <span class="record green" v-if="item.min_point < 0">{{ item.range_type == 1 ? item.min_point : item.min_point + '~' + item.max_point }}</span>
@@ -72,7 +74,7 @@
           </van-cell>
         </van-cell-group>
 
-        <van-empty description="暂无内容" v-show="list != null && rule_category_list != null && list.length == 0 && rule_category_list.length == 0" />
+        <van-empty description="暂无规则,请在PC端设置" v-show="list != null && rule_category_list != null && list.length === 0 && rule_category_list.length === 0" />
       </scroller>
     </div>
 

+ 3 - 2
src/point/view/integral/rule_item_edit.vue

@@ -1,6 +1,7 @@
 <template>
   <div class="rule_item_edit_box">
-    <van-nav-bar title="修改规则" left-text="返回" @click-left="$route_back" left-arrow right-text="删除" @click-right="del"></van-nav-bar>
+<!--    <van-nav-bar title="修改规则" left-text="返回" @click-left="$route_back" left-arrow right-text="删除" @click-right="del"></van-nav-bar>-->
+    <van-nav-bar title="规则内容" left-text="返回" @click-left="$route_back" left-arrow ></van-nav-bar>
     <div class="body_com has_header">
       <scroller>
         <van-cell-group>
@@ -29,7 +30,7 @@
             </van-radio-group>
           </van-cell>
         </van-cell-group>
-        <div style="padding:0.32rem;"><van-button size="large" @click="data_verify" type="info">保存</van-button></div>
+        <div style="padding:0.32rem;"><van-button size="large" disabled @click="data_verify" type="info">保存</van-button></div>
       </scroller>
     </div>
   </div>

+ 121 - 12
src/point/view/pointHome.vue

@@ -53,8 +53,9 @@
           </van-grid-item>
           <van-grid-item @click="goDeptRank">
             <template #text>
-              <van-loading v-if="!deptRank" type="spinner" size="10px"/>
-              <span class="van-grid-item__text" v-else>部门对比</span>
+<!--              <van-loading v-if="!deptRank" type="spinner" size="10px"/>-->
+<!--              <span class="van-grid-item__text" v-else>部门对比</span>-->
+              <span class="van-grid-item__text">部门对比</span>
             </template>
             <template #icon>
               <img src="static/images/callback1.png" style="-webkit-touch-callout: none;"/>
@@ -236,6 +237,8 @@ import {getToken, setToken} from '@/utils/auth';
 import moment, {min} from 'moment';
 import Vue from 'vue';
 import { NoticeBar, Swipe, SwipeItem, Cell, Dialog,Popup,Loading  } from 'vant';
+import ReconnectingWebSocket from "reconnecting-websocket";
+import {generateUUID} from "../../utils/auth";
 Vue.use(NoticeBar)
   .use(Swipe)
   .use(SwipeItem)
@@ -247,7 +250,7 @@ export default {
   name: 'pointHome',
   data() {
     return {
-      deptRank:false,
+      // deptRank:false,
       userMonth:{task:{reward:{},deduction:{},exec:{}},ratio:{}},
 
       // rankingList: [], // 我的排名列表
@@ -305,6 +308,8 @@ export default {
         left:0,
         top:0
       },
+      rws:null,
+      rwsHasAuth:false,
     };
   },
   created() {
@@ -339,6 +344,9 @@ export default {
       this.getMenu(res);
     });
   },
+  beforeDestroy() {
+    this.clearRws();
+  },
   methods: {
     timeScopeThisWeek(){
       this.pkTimeScope = [new Date(moment().startOf('week').format('YYYY-MM-DD')),new Date(moment().endOf('week').format('YYYY-MM-DD'))]
@@ -608,10 +616,11 @@ export default {
       });
       var http1 = this.$axiosUser('get', '/api/pro/integral/statistics', { employee_id: this.userInfo.id, month: this.month }, 'v3'); // 获取个人统计
       this.rankingListname(); //排行榜
-      this.$socketApiTow.authWebSocket(() =>{
-        // this.getPkDocList();    //团队pk
-        this.opneWebSocket();   //本月B分奖扣
-      });
+      // this.$socketApiTow.authWebSocket(() =>{
+      //   // this.getPkDocList();    //团队pk
+      //   this.opneWebSocket();   //本月B分奖扣
+      // });
+      this.initRws();   //初始化websocket数据
 
       Promise.all([http1]).then(res => {
           if (res[0].data.code === 1) {
@@ -636,7 +645,6 @@ export default {
               target_ratio: target_ratio
             }
             this.userMonth=data;
-            console.log(this.userMonth)
 
             //ws数据初始化完成,部门排名才可以点击
             // this.deptRank = true;
@@ -719,7 +727,8 @@ export default {
       this.saveScrollerPosition();
       if (this.pk.currentDocIndex !== index && this.pk.pkDocList.length > index){
         this.pk.currentDocIndex = index;
-        this.getPkRankList(this.pk.pkDocList[index].id)
+        // this.getPkRankList(this.pk.pkDocList[index].id)
+        this.rwsPkRankList(this.pk.pkDocList[index].id)
       }
     },
     getPkDocList(){
@@ -748,7 +757,7 @@ export default {
         this.pk.teamLoading = false;
 
         //ws数据初始化完成,部门排名才可以点击
-        this.deptRank = true;
+        // this.deptRank = true;
       })
       this.$nextTick(() => {
         setTimeout(() => {
@@ -757,11 +766,110 @@ export default {
       })
     },
     goDeptRank(){
-      if (!this.deptRank) return;
+      // if (!this.deptRank) return;
       this.$router.push({ name: 'dept_rank' });
     },
     goAppeal(){
       this.$router.push({name:'appeal'})
+    },
+    initRws(){
+      if (this.rws){
+        this.rws.close();
+        this.rws = null;
+        this.rwsHasAuth = false;
+      }
+      this.rws = new ReconnectingWebSocket(process.env.VUE_APP_WEBSCOKET_TOW);
+      this.rws.onopen = this.onWsOpen;
+      this.rws.onmessage = this.onWsMessage;
+      this.rws.onerror = this.onWsError;
+      this.rws.onclose = this.onWsClose;
+    },
+    onWsOpen(){
+      let params = {
+        type:'auth',
+        token: getToken(),
+        machine: generateUUID(),
+      }
+      this.rws.send(JSON.stringify(params));
+    },
+    onWsMessage(event){
+      let msg = event.data ?  JSON.parse(event.data) : null;
+      if (!msg) return;
+      let type = msg.type || 'none';
+      switch (type){
+        case 'ping':
+          this.rws.send('point home keep connecting');
+          break;
+        case 'auth':
+          this.rwsHasAuth = msg.code === 1;
+          this.rwsEsInfo();
+          this.rwsPkDoc();
+          break;
+        case 'es_info':
+          if (msg.code !== 1) return;
+          let data = msg.result;
+          let task = data.task;
+          let ratio = task.ratio.enable === 0 ? '-' : `${task.ratio.reward_ratio}:1`;
+          let target_ratio = task.ratio.target <= 0 ? '0:1' : `${task.ratio.target}:1`;
+          data.ratio = {
+            ratio: ratio,
+            target_ratio: target_ratio
+          }
+          this.userMonth=data;
+          break;
+        case 'team_pk':
+          if (msg.code !== 1) return;
+          this.pk.pkTeamList = msg.result.teams;
+          this.pk.teamLoading = false;
+          this.$nextTick(() => {
+            setTimeout(() => {
+              this.restoreScrollerPosition()
+            },50)
+          })
+          break;
+      }
+    },
+    onWsError(event){
+      this.rwsHasAuth = false;
+    },
+    onWsClose(event){
+      this.rwsHasAuth = false;
+    },
+    clearRws(){
+      if (this.rws) this.rws.close();
+      this.rws = null;
+      this.rwsHasAuth = false;
+    },
+    rwsEsInfo(){
+      if (!this.rws || this.rws.readyState !== ReconnectingWebSocket.OPEN || !this.rwsHasAuth) return;
+      let params = {
+        type:'es_info',
+        recorder_id: this.userInfo.id,
+        month:this.month
+      };
+      this.rws.send(JSON.stringify(params))
+    },
+    rwsPkDoc(){
+      this.$axiosUser('get','/api/pro/pk/doc/list/visible')
+        .then(res => {
+          this.pk.pkDocList = res.data.data.list;
+          if(this.pk.pkDocList.length > 0) this.rwsPkRankList(this.pk.pkDocList[0].id)
+        })
+    },
+    rwsPkRankList(docId){
+      if (!this.rws || this.rws.readyState !== ReconnectingWebSocket.OPEN || !this.rwsHasAuth || this.pk.teamLoading) return;
+      if (!this.pk.pkTimeScope || this.pk.pkTimeScope.length !== 2) {
+        this.pk.pkTeamList = [];
+        return;
+      }
+      let type = "team_pk";
+      let params = {
+        type:type,
+        doc_id:docId,
+        start_date:this.$moment(this.pk.pkTimeScope[0]).format("YYYY-MM-DD"),
+        end_date:this.$moment(this.pk.pkTimeScope[1]).format("YYYY-MM-DD"),
+      };
+      this.rws.send(JSON.stringify(params));
     }
   },
   watch: {
@@ -769,7 +877,8 @@ export default {
       this.pk.pkTimeScope[0] = val[0]
       this.pk.pkTimeScope[1] = val[1]
       this.pk.pkTimeScopeStr = this.$moment(this.pk.pkTimeScope[0]).format("MM/DD") + "-" + this.$moment(this.pk.pkTimeScope[1]).format("MM/DD");
-      if (this.pk.pkDocList.length > this.pk.currentDocIndex) this.getPkRankList(this.pk.pkDocList[this.pk.currentDocIndex].id)
+      // if (this.pk.pkDocList.length > this.pk.currentDocIndex) this.getPkRankList(this.pk.pkDocList[this.pk.currentDocIndex].id)
+      if (this.pk.pkDocList.length > this.pk.currentDocIndex) this.rwsPkRankList(this.pk.pkDocList[this.pk.currentDocIndex].id)
     }
   }
 };

+ 16 - 0
src/point/view/task/taskFile.vue

@@ -149,6 +149,22 @@
             title="提前奖分"
             :value="`${info.point_config.ahead_award_point} B分/天`"
           />
+          <van-cell
+            title-class="align_self"
+            value-class="align_self"
+            :border="false"
+            v-if="info.task_file_list.length > 0"
+          >
+            <template #title>
+              <div class="time">
+                <span>任务图片</span>
+                <span>
+                  <van-image v-for="(items, index) in info.task_file_list" :key="index" @click="open_image(info.task_file_list)" width="45" height="45" radius="3" :src="items" />
+                </span>
+              </div>
+            </template>
+          </van-cell>
+