1
0

9 Commity 368c930f3e ... 048f9acd2b

Autor SHA1 Správa Dátum
  walter 048f9acd2b 长连接 8 mesiacov pred
  walter b87a6b5288 积分规则取消编辑 8 mesiacov pred
  walter 3d938a7cb2 积分规则取消编辑 8 mesiacov pred
  walter f328bbaf40 部门对比 8 mesiacov pred
  walter 1d87cafd63 任务详情 8 mesiacov pred
  walter 4e6ef7ae51 取消规则编辑 8 mesiacov pred
  walter 8da90ea37b 部门对比优化websocket 8 mesiacov pred
  walter 723fd1ec4a 积分规则组件 8 mesiacov pred
  walter cdcc6a31c6 首页 9 mesiacov pred

+ 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>
+