1
0

13 Incheckningar cd070752f7 ... 7cc6be7858

Upphovsman SHA1 Meddelande Datum
  manywhy 7cc6be7858 Merge branch 'dev' 9 månader sedan
  manywhy 73f3cc2e7c 更新dev分支 9 månader sedan
  manywhy 71e6644c92 更新dev分支 9 månader sedan
  manywhy 08f74fc659 提交feature分支 9 månader sedan
  walter cda940b9ea 长连接粘贴板 10 månader sedan
  walter 048f9acd2b 长连接 10 månader sedan
  walter b87a6b5288 积分规则取消编辑 10 månader sedan
  walter 3d938a7cb2 积分规则取消编辑 10 månader sedan
  walter f328bbaf40 部门对比 10 månader sedan
  walter 1d87cafd63 任务详情 10 månader sedan
  walter 4e6ef7ae51 取消规则编辑 10 månader sedan
  walter 8da90ea37b 部门对比优化websocket 10 månader sedan
  walter 723fd1ec4a 积分规则组件 10 månader sedan

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

+ 2 - 1
src/attendance/view/AttendanceNew/ApplyRecord.vue

@@ -13,7 +13,7 @@
             <div class="content">
               <div class="title">
                 <div class="detail">{{ item.type_mark }}申请</div>
-                <div :class="{ wait: item.status == 0, refuse: item.status == -1 }" class="status">{{ filterStatus(item.status) }}</div>
+                <div :class="{ wait: item.status == 0, refuse: item.status == -1 }" class="status">{{ filtetatus(item.status) }}</div>
               </div>
               <div v-if="item.type == 4" class="desc">请假类型:{{ item.holiday_name }}</div>
               <div class="desc">申请时间:{{ item.application_time }}</div>
@@ -422,6 +422,7 @@ export default {
 }
 .leftkep {
   padding: 0.2rem 0.12rem 0.2rem 0.32rem;
+  box-sizing: border-box;
 }
 .headAll {
   height: calc(100% - 3rem) !important;

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 883 - 774
src/attendance/view/AttendanceNew/Index.vue


+ 3 - 1
src/components/DeptSelectorDropdown.vue

@@ -3,7 +3,7 @@
     <div class="dept_path" style="white-space:nowrap;" v-if="list.length==0">
       <div class="dept_paths">
         <a href="javascript:void(0);" @click="backToIndex(-1)">全公司</a>
-        <a v-for="(item, i) in selectedDeptStack" :key="i" href="javascript:void(0);" @click.stop="backToIndex(i)">
+        <a v-for="(item, i) in selectedDeptStack" style="display: flex; align-items: center;" :key="i" href="javascript:void(0);" @click.stop="backToIndex(i)">
           <van-icon name="arrow" />
           {{ item.name }}
         </a>
@@ -187,6 +187,8 @@ export default {
 }
 
 .employee_cell {
+  display: flex;
+  align-items: center;
   padding: 0.16rem 0.32rem;
   touch-action: none;
 }

+ 2 - 1
src/components/EmployeeSelectorCell.vue

@@ -27,8 +27,9 @@
           <em v-show="index > 0">,</em>
           {{ item.name }}
         </span>
-        等{{ selected_data.employee.length }}人
+        等
       </div>
+      <div>{{ selected_data.employee.length }}人</div>
     </template>
     <EmployeeSelector
       :title="bar_title"

+ 14 - 6
src/components/NumberInput.vue

@@ -8,6 +8,7 @@
     :required="required"
     :id="com_id"
     :class="{'v-input': show_dept_selector}"
+    style="display: flex; align-items: center;"
   >
     <template slot="right-icon">
       <div class="picker-box" @click="activeIsAdd" v-if="chosePoint&&!isForbidSet">
@@ -22,7 +23,7 @@
      <div class="flex-box-ce">
           <span v-if="isAdd" class="red">+</span>
           <span v-else class="green">-</span>
-          <van-field  style="padding: 0.1rem 0;" @input="onInput" type="digit" :readonly="onReadonly" @blur="onBlur"  v-model.number="numVal" placeholder="分值"/>
+          <van-field  style="padding: 0.1rem 0;" @input="onInput" type="digit" :readonly="onReadonly"  @focus="onFocus" @blur="onBlur"  v-model.number="numVal" placeholder="分值"/>
       </div>
 <!--     <div @click.stop="show_keyboard">
         <span v-if="input_value > 0" class="red">+</span>
@@ -126,11 +127,14 @@ export default {
   },
   computed:{
     onReadonly(){
-      if((this.min&&this.min == this.max)||this.isForbidSet){
-        return true
-      }else{
-       return false
-      }
+      // 防止传入的this.min, this.max为 '', undefined, null的情况
+      if((!!this.min && !!this.max && this.min == this.max) || this.isForbidSet) return true
+      else return false
+      // if((this.min&&this.min == this.max)||this.isForbidSet){
+      //   return true
+      // }else{
+      //  return false
+      // }
     }
   },
   watch: {
@@ -228,7 +232,11 @@ export default {
         // }
         this.$emit('value', value * 1)
     },
+    onFocus() {
+      this.$emit("inputing", "")
+    },
     onBlur() {
+       this.$emit("inputed", "")
       let value=this.numVal;
       if (!this.isAdd) {
         value = value * 1 * -1

+ 3 - 1
src/components/RuleCategorySelDropdown.vue

@@ -2,7 +2,7 @@
   <div class="dept-select-drodown__wrap">
       <div class="dept_path" style=" white-space:nowrap;">
         <div class="dept_paths">
-          <a href="javascript:void(0);" @click="backToIndex(-1)" >全部</a>
+          <a href="javascript:void(0);" style="display: flex; align-items: center;" @click="backToIndex(-1)" >全部</a>
           <a
             v-for="(item, i) in selectedDeptStack"
             :key="i"
@@ -182,6 +182,8 @@ export default {
   }
 
   .employee_cell {
+    display: flex;
+    align-items: center;
     padding: 0.16rem 0.32rem;
     touch-action: none;
   }

+ 147 - 32
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>
 
@@ -150,7 +171,7 @@
           >
             全部
           </el-button>
-          <el-tree
+           <!-- <el-tree
             ref="ruleTree"
             node-key="id"
             :data="ruleTree"
@@ -158,7 +179,9 @@
             highlight-current
             style="margin-top: 16px"
             @node-click="onRuleClick"
-          />
+          /> -->
+          <collapse :ruleTree="ruleTree" :current-rule-id="currentRuleId" @open="onRuleClick"/>
+          <!-- <collapse :current-rule-id="currentRuleId" :ruleTree="ruleTree"  /> -->
           <div style="height: 0.5rem;"></div>
         </div>
       </template>
@@ -167,8 +190,13 @@
 </template>
 
 <script>
+import {_debounce} from "../utils/auth";
+import collapse from "./collapse/index.vue";
 export default {
   name:'RuleScopeSelector',
+  components: {
+    collapse
+  },
   props:{
     visible:{
       type:Boolean,
@@ -196,11 +224,15 @@ export default {
       showSelector:false,
       itemObject:null,
       ruleTree:[],
+      activeNames: ['0'],
       items:[],
       itemSelected:[],
       currentRuleId:0,
       keyword:'',
-      showRule:false
+      showRule:false,
+      page:1,
+      pageSize:10,
+      pageList:[],
     }
   },
   watch:{
@@ -217,20 +249,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){
@@ -238,7 +278,7 @@ export default {
         item.forEach((record) => {
           let temp = {
             ...record,
-            selected:this.itemSelected.some(i => i.id === record.id)
+            selected: this.itemSelected.some(i => i.id === record.id)
           }
           this.items.push(temp)
         })
@@ -258,9 +298,9 @@ export default {
       this.$axiosUser('get','/api/pro/integral/rule/trees/scope',data)
         .then(res => {
           if (res.data.code === 1){
-            this.ruleTree = res.data.data.rule_tree
-            this.itemObject = res.data.data.item_list
-            this.initItems(this.itemObject)
+            this.ruleTree = res.data.data.rule_tree; // 分类列表,树结构
+            this.itemObject = res.data.data.item_list; // 细节列表
+             this.$refs.scroller.triggerPullToRefresh()
           }
         })
     },
@@ -282,14 +322,15 @@ export default {
       }
     },
     onRuleClick(rule){
-      this.currentRuleId = rule.id || 0
+      this.currentRuleId = rule.id || 0;
+      console.log(this.currentRuleId);
     },
     onRuleClear(){
-      this.$refs['ruleTree'].setCurrentKey(null)
+      this.$refs['ruleTree'] && this.$refs['ruleTree'].setCurrentKey(null)
       this.currentRuleId = 0
     },
     onConfirm(){
-      this.$emit("confirm",this.itemSelected.map(item => {
+      this.$emit("confirm", this.itemSelected.map(item => {
         return {...item}
       }))
       this.close()
@@ -301,9 +342,63 @@ export default {
       this.onConfirm()
     },
     clear(){
-      this.itemSelected = []
-      this.initItems(this.itemObject)
-    }
+      this.itemSelected = [];
+      this.onRefresh();
+    },
+    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() {}
 }
@@ -385,4 +480,24 @@ export default {
   padding: 0;
 }
 
+/deep/ .el-tree-node {
+  margin: 0 0.24rem;
+  border-bottom: 0.02rem solid #ebedf0;
+}
+/deep/ .el-tree-node__content {
+  height: 1rem;
+}
+
+/deep/ .el-tree-node__children .el-tree-node__content{
+  border-bottom: none;
+}
+
+/deep/ .el-tree-node__label {
+  font-size: 0.32rem;
+}
+
+/deep/ .el-tree-node__expand-icon {
+  font-size: 0.3rem;
+}
+
 </style>

+ 11 - 4
src/components/YearMonthPicker.vue

@@ -1,8 +1,15 @@
 <template>
   <div class="bg-fff">
     <van-row>
-      <van-col span="9"><div class="btn-left"><van-icon name="arrow-left" @click="prev" /></div></van-col>
-      <van-col span="6"><icon name="YMPicker_item_icon" class="YMPicker_item_icon"></icon><div class="date-text" @click="show = true">{{currentDate_show}}</div></van-col>
+      <van-col span="9">
+        <div class="btn-left">
+          <van-icon name="arrow-left" @click="prev" />
+        </div>
+      </van-col>
+      <van-col span="6" style="display: flex; align-items: center;">
+        <icon name="YMPicker_item_icon" class="YMPicker_item_icon"></icon>
+        <div class="date-text" @click="show = true">{{currentDate_show}}</div>
+      </van-col>
       <van-col span="9"><div class="btn-right"><van-icon name="arrow" @click="next" /></div></van-col>
     </van-row>
 
@@ -135,8 +142,8 @@
      background:#238dfa;
    }
   .YMPicker_item_icon{
-    width:0.23rem;
-    height:auto;
+    width: 0.25rem;
+    height: 0.25rem;
     padding-right: 0.15rem;
     color:#323233;
   }

+ 156 - 0
src/components/collapse/index.vue

@@ -0,0 +1,156 @@
+<template>
+  <div class="collspseBox">
+    <van-row class="collspse_item" v-for="(item, index) in  ruleTree" :key="item.id" >
+      <van-col class="icon" span="2"  @click.stop="open(item, index)">
+        <van-icon v-if="item.child && item.child.length > 0" size="16" :name="item.active ? 'arrow-down' : 'arrow'" />
+      </van-col>
+      <van-col span="22" class="title" :class="currentRuleId == item.id ? 'item-active' : 'item-gray'"  @click.stop="open(item, index)">
+        <label style="display: flex; align-items: center;">
+          <input class="radio_button" type="radio" :checked="currentRuleId == item.id" :value="item.id" name="treeGroup" @change="handleChange(item)">
+          {{ item.name }}
+        </label>
+      </van-col>
+
+      <van-col span="24" class="content" v-if="item.child && item.child.length > 0" :style="{ height: item.active ? 'auto' : '0' }">
+        <collapse :currentRuleId="currentRuleId" :ruleTree="item.child" @open="$emit('open', $event)" />
+      </van-col>
+    </van-row>
+  </div>
+</template>
+
+<!--  -->
+
+<script>
+  export default {
+    name: "collapse",
+    props: {
+      ruleTree: Array,
+      currentRuleId: {
+        type: [String, Number],
+        default: 0
+      },
+    },
+
+    data() {
+      return {
+        selectId: 0,
+      }
+    },
+
+    methods: {
+      handleChange(item) {
+        this.$emit("open", item);
+      },
+      open(item, index) {
+        this.$set(this.ruleTree[index], 'active', !this.ruleTree[index].active);
+      },
+
+
+    }
+  }
+</script>
+
+<style lang="scss" scoped>
+  .item-active {
+    color: #409EFF !important;
+  }
+  .item-gray {
+    color: #323233 !important;
+  }
+
+.collspseBox {
+  padding: 14px 10px;
+
+  .collspse_item {
+    background-color: #fff;
+    padding: 15px 12px;
+    border-radius: 8px;
+    overflow: hidden;
+    margin-bottom: 10px;
+    box-shadow: 0 0px 6px rgba(100, 101, 102, 0.1);
+
+    .icon {
+      text-align: center;
+      vertical-align: middle;
+      color: #d2d2d2;
+    }
+
+    .title {
+      font-size: 0.32rem;
+      color: #323233;
+      display: flex;
+      align-items: center;
+      white-space: nowrap;
+      text-wrap: nowrap;
+      word-break: keep-all;
+      overflow: hidden;
+      text-overflow: ellipsis;
+      /* 单选框样式 */
+      .radio_button {
+        -webkit-appearance: none; /* 移除默认样式 */
+        appearance: none; /* 移除默认样式 */
+        outline: none; /* 移除轮廓 */
+        display: inline-block;
+        width: 0.3rem; /* 设置宽度 */
+        height: 0.3rem; /* 设置高度 */
+        border-radius: 50%; /* 设置为圆形 */
+        background-color: white; /* 初始背景颜色为白色 */
+        position: relative; /* 设置相对定位 */
+        margin: 0 8px 0 0; /* 设置边距 */
+        border: 1px solid #d2d2d2;
+        cursor: pointer; /* 设置鼠标指针为手型 */
+      }
+
+      .radio_button:checked {
+        width: 0.3rem; /* 设置宽度 */
+        height: 0.3rem; /* 设置高度 */
+        background-color: #409EFF; /* 选中时中心白色 */
+        border: none; /* 选中时去掉边框 */
+        z-index: 2; /* 确保在最上面 */
+      }
+
+      .radio_button:checked::before {
+        content: "";
+        position: absolute;
+        top: 50%; /* 使伪元素垂直居中 */
+        left: 50%; /* 使伪元素水平居中 */
+        transform: translate(-50%, -50%); /* 使伪元素水平垂直居中 */
+        width: 0.12rem;
+        height: 0.12rem;
+        border-radius: 50%; /* 使伪元素变成圆形 */
+        background-color: #ffffff; /* 外部红色 */
+        z-index: 1; /* 确保伪元素在最前面 */
+      }
+    }
+
+    .content {
+      transition: all .5s;
+
+      .collspseBox {
+        padding: 0;
+
+        .collspse_item {
+          padding: 16px 0 0 12px;
+          margin-bottom: 0;
+          box-shadow: none;
+
+          .title {
+            display: flex;
+            align-items: center;
+            font-size: 0.3rem;
+            color: #2F3541;
+            font-family: "PingFang SC";
+            font-weight: 400;
+            position: relative;
+            padding-left: 5px;
+          }
+
+
+        }
+      }
+    }
+  }
+
+}
+
+</style>

+ 60 - 11
src/main.js

@@ -1,4 +1,3 @@
-
 import Vue from 'vue'
 import App from './App'
 import router from './router'
@@ -23,7 +22,39 @@ import axiosKc from '@/utils/axiosKc'
 import 'shepherd.js/dist/css/shepherd.css';
 
 // import 'vant/lib/index.css';
-import { Tabbar, Empty, TabbarItem, ShareSheet, Loading, Divider, Overlay,Grid, GridItem, Form, Field, NavBar, Row, Col, List, Picker, Cell, CellGroup, Toast, Popup, Dialog, RadioGroup, Radio, Notify, Button, Icon, Tab, Tabs } from 'vant'
+import {
+  Tabbar,
+  Empty,
+  TabbarItem,
+  ShareSheet,
+  Loading,
+  Divider,
+  Overlay,
+  Grid,
+  GridItem,
+  Form,
+  Field,
+  NavBar,
+  Row,
+  Col,
+  List,
+  Picker,
+  Cell,
+  CellGroup,
+  Toast,
+  Popup,
+  Dialog,
+  RadioGroup,
+  Radio,
+  Notify,
+  Button,
+  Icon,
+  Tab,
+  Tabs,
+  Collapse,
+  CollapseItem
+} from 'vant'
+
 
 /*element ui*/
 import {
@@ -34,7 +65,23 @@ import {
 import 'element-ui/lib/theme-chalk/index.css';
 
 
-import { getWxToken, setWxToken, getIsIdentity, supremeAuthority, getIsWx, getTypes, getTypesName, getUserData, getEmployeeMap, getCache, setCache, removeCache, returnDeptName, getEmployeeMapItem, returnFh } from '@/utils/auth'
+import {
+  getWxToken,
+  setWxToken,
+  getIsIdentity,
+  supremeAuthority,
+  getIsWx,
+  getTypes,
+  getTypesName,
+  getUserData,
+  getEmployeeMap,
+  getCache,
+  setCache,
+  removeCache,
+  returnDeptName,
+  getEmployeeMapItem,
+  returnFh
+} from '@/utils/auth'
 Vue.prototype.$echarts = echarts
 Vue.prototype.$moment = moment
 Vue.prototype.$getTypesName = getTypesName
@@ -52,8 +99,8 @@ Vue.prototype.$axiosKq = axiosKq
 Vue.prototype.$axiosKc = axiosKc
 Vue.prototype.$removeCache = removeCache
 Vue.prototype.$returnDeptName = returnDeptName
-Vue.prototype.$socketApi = socketApi   //长连接
-Vue.prototype.$socketApiTow = socketApiTow   //长连接
+Vue.prototype.$socketApi = socketApi //长连接
+Vue.prototype.$socketApiTow = socketApiTow //长连接
 Vue.prototype.$returnFh = returnFh
 Vue.prototype.$isWx = getIsWx()
 
@@ -70,10 +117,12 @@ Vue.component('userImage', userImage)
 /*element ui 按需引入*/
 Vue.use(ELTree).use(ELButton).use(ELDrawer)
 
-Vue.use(Button).use(Tabbar).use(TabbarItem).use(ShareSheet).use(Grid).use(Overlay).use(Loading).use(Divider).use(GridItem).use(Picker).use(Form).use(Field).use(List).use(Tabs).use(Tab).use(NavBar).use(Row).use(Col).use(Cell).use(CellGroup).use(Toast).use(Popup).use(Dialog).use(RadioGroup).use(Radio).use(Icon).use(Notify).use(Empty)
+Vue.use(Button).use(Tabbar).use(TabbarItem).use(ShareSheet).use(Grid).use(Overlay).use(Loading).use(Divider).use(
+  GridItem).use(Picker).use(Form).use(Field).use(List).use(Tabs).use(Tab).use(NavBar).use(Row).use(Col).use(Cell).use(
+  CellGroup).use(Toast).use(Popup).use(Dialog).use(RadioGroup).use(Radio).use(Icon).use(Notify).use(Empty).use(Collapse).use(CollapseItem)
 
-Vue.prototype.$route_back = function (setp) {
-  if (typeof (setp) == 'undefined') {
+Vue.prototype.$route_back = function(setp) {
+  if (typeof(setp) == 'undefined') {
     setp = -1
   }
   if (window.history.length <= 1 && window.plus) {
@@ -87,7 +136,7 @@ Vue.prototype.$route_back = function (setp) {
   }
 }
 
-Vue.directive('isKeyboard', function (el) {
+Vue.directive('isKeyboard', function(el) {
   let isAndroid = true;
   if (navigator.userAgent.indexOf('Android') > 0) {
     isAndroid = true;
@@ -97,7 +146,7 @@ Vue.directive('isKeyboard', function (el) {
   if (isAndroid) {
     //获取原窗口的高度
     var originalHeight = document.documentElement.clientHeight || document.body.clientHeight;
-    window.onresize = function () {
+    window.onresize = function() {
       //键盘弹起与隐藏都会引起窗口的高度发生变化
       var resizeHeight = document.documentElement.clientHeight || document.body.clientHeight;
       if (resizeHeight - 0 < originalHeight - 0) {
@@ -108,7 +157,7 @@ Vue.directive('isKeyboard', function (el) {
         el.style['display'] = 'block'
       }
     };
-  } else {  // ios:focusin和focusout支持冒泡,对应focus和blur, 使用focusin和focusout的原因是focusin和focusout可以冒泡,focus和blur不会冒泡,这样就可以使用事件代理,处理多个输入框存在的情况。
+  } else { // ios:focusin和focusout支持冒泡,对应focus和blur, 使用focusin和focusout的原因是focusin和focusout可以冒泡,focus和blur不会冒泡,这样就可以使用事件代理,处理多个输入框存在的情况。
     document.body.addEventListener("focusin", () => {
       //软键盘弹出的事件处理
       el.style['display'] = 'none'

+ 1 - 1
src/okr/view/okrHome.vue

@@ -169,7 +169,7 @@ export default {
   },
   computed:{
     barColor(){
-      return function (item) { 
+      return function (item) {
         return item.day<0 ? (item.composite_state == 4?'#2879ff':'#f56c6c'):'#2879ff'
        }
     },

+ 2 - 2
src/okr/view/okrHome/okrBack.vue

@@ -24,9 +24,9 @@
             <div v-else v-for="(item, index) in backlogList" :key="index">
               <div class="backlog_list_tit">{{ item.time }}</div>
               <div v-for="(arr, keys) in item.list" :key="keys" @click="openDetail(arr)" :style="'z-index:' + (item.list.length - keys)" class="performanceList backlog_list">
-                  <div class="flex-box">
+                  <div class="flex-box" style="align-items: center;">
                      <span class="flex-1" v-html="arr.content"></span>
-                     <van-icon name="arrow" />
+                     <van-icon name="arrow" color="#b1b1b1" />
                   </div>
               </div>
             </div>

+ 3 - 1
src/performance/components/statementcontent/statement_details.vue

@@ -3,7 +3,9 @@
     <van-nav-bar :title="barTItle" left-text="" left-arrow @click-left="$route_back"></van-nav-bar>
     <header class="performanceList" v-if="moduleshow">
       <van-row>
-        <van-col span="24"><van-search v-model="keyword" placeholder="请输入员工姓名搜索" @input="keyInput" style="padding: 0.2rem 0.12rem .2rem .32rem;" /></van-col>
+        <van-col span="24">
+          <van-search v-model="keyword" placeholder="请输入员工姓名搜索" @input="keyInput" style="padding: 0.2rem 0.32rem .2rem .32rem;" />
+        </van-col>
       </van-row>
     </header>
     <div class="headScreen flex-no-wrap" v-if="moduleshow">

+ 10 - 10
src/performance/components/workbenchcontent/messageInform.vue

@@ -25,15 +25,16 @@
               <div class="backlog_list_tit">{{ item.time }}</div>
               <div v-for="(arr, keys) in item.list" :key="keys" @click="unreadCli(arr)" :style="'z-index:' + (item.list.length - keys)" class="performanceList backlog_list">
                 <div class="flex-box">
-                <userImage
-                  class="about-me__avatar"
-                  :id="arr.userInfo.id"
-                  :img_url="arr.userInfo.img_url"
-                  :user_name="arr.userInfo.name"
-                  fontSize="0.24"
-                  width="0.65rem"
-                  height="0.65rem"
-                ></userImage>
+                  <userImage
+                    class="about-me__avatar"
+                    :id="arr.userInfo.id"
+                    :img_url="arr.userInfo.img_url"
+                    :user_name="arr.userInfo.name"
+                    fontSize="0.24"
+                    width="0.65rem"
+                    height="0.65rem"
+                  >
+                  </userImage>
                   <span v-html="arr.content"></span>
                 </div>
               </div>
@@ -67,7 +68,6 @@ export default {
         page: 1, // 当期页
         page_size: 10 // 一页多少数据
       },
-
       theBackupListcc: []
     }
   },

+ 20 - 3
src/point/view/integral/batchList.vue

@@ -66,6 +66,8 @@
                  name="积分"
                  required
                  v-if="item.pid==0"
+                 @inputing="inputing"
+                 @inputed="inputed"
                  v-validate="'required'">
                  </NumberInput>
                  <div class="flex-box flex-v-ce jf" v-else>
@@ -124,7 +126,9 @@
                   name="积分"
                   required
                   v-if="item.pid==0"
-                  v-validate="'required'">
+                  v-validate="'required'"
+                  @inputing="inputing"
+                  @inputed="inputed">
                   </NumberInput>
                   <div class="flex-box flex-v-ce jf" v-else>
                     <div>填写积分</div>
@@ -212,6 +216,8 @@
                      title="填写积分"
                      name="积分"
                      required
+                     @inputing="inputing"
+                     @inputed="inputed"
                      v-validate="'required'">
                      </NumberInput>
                  </div>
@@ -223,6 +229,8 @@
                      title="填写积分"
                      name="积分"
                      required
+                     @inputing="inputing"
+                     @inputed="inputed"
                      v-validate="'required'">
                      </NumberInput>
                  </div>
@@ -266,7 +274,7 @@
       </scroller>
       <div class="flex-box btns" v-show="rightText" :class="{ isIos: isIos }" >
         <van-button plain type="danger" class="flex-1" style="margin-right: 0.24rem" @click="reject()">拒绝</van-button>
-        <van-button plain type="info" class="flex-1" @click="pass()">通过</van-button>
+        <van-button plain type="info" class="flex-1" @click="pass()" :disabled="isDisabled">通过</van-button>
       </div>
       <van-dialog v-model="showReject" title="批量拒绝" class="reject_popup" show-cancel-button :beforeClose="save_btn">
         <van-cell-group>
@@ -319,7 +327,8 @@ export default {
       },
       isIos: this.$getCache('iPhone'),
       showReject: false, // 驳回弹窗
-      reject_text: ''// 驳回意见
+      reject_text: '',// 驳回意见
+      isDisabled: false
     }
   },
   created () {
@@ -360,6 +369,14 @@ export default {
 
       })
     },
+    // 用户输入中
+    inputing() {
+      this.isDisabled = true;
+    },
+    // 用户输入完
+    inputed() {
+      this.isDisabled = false;
+    },
     // 通过
     pass () {
       var obj, is = true, items = []

+ 125 - 26
src/point/view/integral/deptRank.vue

@@ -6,8 +6,12 @@
       <van-dropdown-item @open="calendarOpen">
         <van-icon name="calendar-o" slot="title" size="1.5em" />
       </van-dropdown-item>
-      <van-dropdown-item :title="searchForm.deptName" ref="deptDropdownItem"><DeptSelectorDropdown @onConfirm="onConfirmDept" /></van-dropdown-item>
-      <van-dropdown-item title="规则" ref="ruleDropdownItem"><RuleCategorySelDropdown @onConfirm="onConfirmRule" @onCancel="searchForm.ruleId = 0"/></van-dropdown-item>
+      <van-dropdown-item :title="searchForm.deptName" ref="deptDropdownItem">
+        <DeptSelectorDropdown @onConfirm="onConfirmDept" />
+      </van-dropdown-item>
+      <van-dropdown-item title="规则" ref="ruleDropdownItem">
+        <RuleCategorySelDropdown @onConfirm="onConfirmRule" @onCancel="searchForm.ruleId = 0"/>
+      </van-dropdown-item>
       <van-dropdown-item>
         <van-icon name="list-switch" slot="title" size="1.5em" />
         <template slot="default">
@@ -30,7 +34,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 +89,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 +137,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 +160,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 +232,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 +274,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>
@@ -269,4 +360,12 @@ export default {
   }
 
 }
+
+/deep/ .van-calendar__header-subtitle {
+  width: 100%;
+  font-size: 0.28rem;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
 </style>

+ 253 - 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 ref="copyResult" style="margin-left: 0.2rem;" @click.prevent.stop="rwsClipResult">{{rwsBusinessData.result.length}} / {{rwsBusinessData.dataList.length}}</van-tag>
+        </div>
+      </div>
     </van-popup>
   </div>
 </template>
@@ -136,6 +162,9 @@ 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";
+import Clipboard from "clipboard";
 
 Vue.use(Switch).use(Progress).use(Icon)
 
@@ -159,6 +188,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 +223,21 @@ export default {
       resultIndex:0,
       isShowError:false,
       errorMsg:'服务器繁忙,请稍后再试',
+      rws:null,
+      rwsHasAuth:false,
+      rwsBusinessData:{
+        showBusiness:false,
+        dataList:[],
+        msgQueue:[],
+        result:[],
+        intervalId:null,
+      },
+      rwsCopyResult: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 +272,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 +294,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 +312,14 @@ export default {
        }
     }
   },
+  activated() {
+    console.log('activated');
+    this.initRws();
+  },
+  beforeDestroy() {
+    console.log('before destroy');
+    this.clearRws();
+  },
   methods: {
     openText(){
        this.$dialog.alert({
@@ -439,7 +502,166 @@ 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 = [];
+      this.rwsBusinessData.copyResult = null;
+      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(event){
+      const clipboard = new Clipboard(event.target,{
+        text: () => JSON.stringify(this.rwsBusinessData.result)
+      });
+      clipboard.on('success',() => {
+        this.$notify({type: 'info', message: '复制成功'});
+        clipboard.destroy();
+      });
+      clipboard.on('error', () => {
+        this.$notify({type: 'info', message: '复制失败,请联系系统管理员'});
+        clipboard.destroy();
+      });
+      clipboard.onClick(event);
+
+      // 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>

+ 323 - 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.prevent.stop="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,9 @@ 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";
+import Clipboard from "clipboard";
 
 Vue.use(Switch).use(Progress)
 export default {
@@ -210,7 +245,16 @@ export default {
       resultIndex:0,
       isShowError:false,
       errorMsg:'服务器繁忙,请稍后再试',
-
+      rws:null,
+      rwsHasAuth:false,
+      rwsBusinessData:{
+        showBusiness:false,
+        dataList:[],
+        msgQueue:[],
+        result:[],
+        employees:[],
+        items:[],
+      }
     }
   },
   watch: {
@@ -272,14 +316,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 +344,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 +383,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 +468,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 +554,212 @@ 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(event){
+      const clipboard = new Clipboard(event.target,{
+        text: () => JSON.stringify(this.rwsBusinessData.result)
+      });
+      clipboard.on('success',() => {
+        this.$notify({type: 'info', message: '复制成功'});
+        clipboard.destroy();
+      });
+      clipboard.on('error', () => {
+        this.$notify({type: 'info', message: '复制失败,请联系系统管理员'});
+        clipboard.destroy();
+      });
+      clipboard.onClick(event);
+      // navigator.clipboard.writeText(JSON.stringify(this.rwsBusinessData.result));
+      // this.$notify({type: 'info', message: '结果已经复制到剪切板'})
   },
   created () {
     this.itemRule=[];
@@ -503,6 +778,10 @@ export default {
     this.$nextTick(()=>{
       this.rule_switch=true;
     })
+    this.initRws();
+  },
+  beforeDestroy() {
+    this.clearRws();
   }
 }
 </script>

+ 22 - 16
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>
@@ -23,23 +23,24 @@
     <van-search v-model="keyword" placeholder="请输入分类名称或规则内容" />
     <div class="dept_path" v-show="pid_list_arr.length > 0">
       <a href="javascript:void(0);" @click="back_by_index(0)">全部</a>
-      <a v-for="(item, index) in pid_list_arr" :key="index" href="javascript:void(0);" @click="back_by_index(index + 1)">
-        <van-icon name="arrow" />
+      <a v-for="(item, index) in pid_list_arr" :key="index" href="javascript:void(0);" @click="back_by_index(index + 1)" style="margin-left: 0.1rem;">
+        <van-icon name="arrow" size="12" />
         {{ item.name }}
       </a>
     </div>
     <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>
 
@@ -555,6 +557,8 @@ export default {
   margin-right: 0.1rem;
 }
 .dept_path a {
+  display: flex;
+  align-items: center;
   color: #238dfa;
   font-size: 0.28rem;
 }
@@ -565,13 +569,15 @@ export default {
   vertical-align: middle;
 }
 .dept_path {
+  display: flex;
+  align-items: center;
+  background-color: #fff;
   height: 0.6rem;
   position: relative;
   font-size: 0.32rem;
   line-height: 0.4rem;
   overflow-x: scroll;
   padding: 0 0.32rem;
-  background-color: #fff;
 }
 .dept_path:after {
   content: ' ';

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

+ 133 - 13
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;"/>
@@ -168,12 +169,14 @@
         </van-row>
       </div>
 
-<!--  团队PK    -->
-      <div class="rankingList" style="border-top: 0.2rem solid #f1f1f1;" v-if="pk.pkDocList.length > 0">
+      <!--  团队PK    -->
+      <div class="rankingList"  v-if="pk.pkDocList.length > 0">
         <van-cell title="团队PK" :value="pk.pkTimeScopeStr" is-link @click="openCalendar"></van-cell>
         <van-tabs
           v-model="pk.pkDocIndex"
           @click="clickPkDoc"
+          animated
+          swipeable
         >
           <van-tab v-for="(doc,index) in pk.pkDocList" :key="index" :title="doc.name">
             <van-cell-group v-if="pk.pkTeamList.length > 0">
@@ -236,6 +239,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 +252,7 @@ export default {
   name: 'pointHome',
   data() {
     return {
-      deptRank:false,
+      // deptRank:false,
       userMonth:{task:{reward:{},deduction:{},exec:{}},ratio:{}},
 
       // rankingList: [], // 我的排名列表
@@ -305,6 +310,8 @@ export default {
         left:0,
         top:0
       },
+      rws:null,
+      rwsHasAuth:false,
     };
   },
   created() {
@@ -339,6 +346,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 +618,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) {
@@ -718,7 +729,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(){
@@ -747,7 +759,7 @@ export default {
         this.pk.teamLoading = false;
 
         //ws数据初始化完成,部门排名才可以点击
-        this.deptRank = true;
+        // this.deptRank = true;
       })
       this.$nextTick(() => {
         setTimeout(() => {
@@ -756,11 +768,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: {
@@ -768,7 +879,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)
     }
   }
 };
@@ -1077,4 +1189,12 @@ export default {
   background-color: #F1F1F1;
 }
 
+/deep/ .van-calendar__header-subtitle {
+  width: 100%;
+  font-size: 0.28rem;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+
 </style>

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

+ 1 - 1
src/utils/auth.js

@@ -241,7 +241,7 @@ export function getTypesName(id) {
 //是否平台管理或者平台创始人
 export function getIsAdministrator() {
   var userInfo = getUserData();
-  if(userInfo.is_site_owner||userInfo.is_site_manager){
+  if(userInfo.is_site_owner || userInfo.is_site_manager){
     return true
   }else{
     return false

+ 4 - 2
src/view/body/initHome.vue

@@ -1,7 +1,9 @@
 <template>
     <div class="html-box">
       <van-nav-bar class="left-text-bold" left-text="首页">
-       <template slot="right"><van-icon v-if="is_app" class="icon-box"  name="scan" @click="$router.push({ name: 'scanqr' })"></van-icon></template>
+       <template slot="right">
+        <van-icon v-if="is_app" class="icon-box"  name="scan" @click="$router.push({ name: 'scanqr' })"></van-icon>
+        </template>
       </van-nav-bar>
       <div class="flex-box-ce" style="padding: 0.16rem 0.32rem;background-color: #FFFAE5;font-size: 0.28rem;" @click="openUrl" v-if="ggData.name">
         <van-icon name="bullhorn-o" />
@@ -155,7 +157,7 @@
         shepherd.start();
       },
       ActiveactiveName(val){
-        this.activeName=val;
+        this.activeName = val;
       },
       initTab(){
         this.tabs=[

+ 4 - 3
src/view/course/user.vue

@@ -148,7 +148,7 @@
       </van-overlay>
     </div>
   </template>
-  
+
   <script>
   import Clipboard from "clipboard";
   import QRCode from "qrcodejs2";
@@ -336,7 +336,7 @@
           e.clearSelection(); //清除选中的文字的选择状态
           that.$toast.success("ID复制成功~");
         });
-  
+
         that.clipboard.on("error", function(e) {
           console.error(e);
         });
@@ -347,6 +347,8 @@
           path: url
         });
       }
+
+
     }
   };
   </script>
@@ -543,4 +545,3 @@
     font-weight: 600;
   }
   </style>
-  

+ 53 - 19
src/view/index.vue

@@ -22,11 +22,11 @@
         </van-tabbar-item>
       </van-tabbar>
 
-      <van-popup v-model="updateVisible" :close-on-click-overlay="false" style="border-radius: 0.15rem; background: #fff0;">
+      <van-popup v-model="updateVisible" :close-on-click-overlay="false" style="border-radius: 0.15rem; background: #fff0; overflow: visible;">
         <div class="buyPopupBody" style="width: 85vw;">
           <div class="buyPopupContent">
-            <div class="buyPopupTitle"> {{announcement.type==1? '版本更新':'系统公告'}}</div>
-            <div style="max-height: 400px;overflow-y: auto;font-size: 0.3rem;" v-html="announcement.focus"></div>
+            <div class="buyPopupTitle"> {{announcement.type == 1? '版本更新':'系统公告'}}</div>
+            <div style="padding: 0.5rem 0.3rem 0.3rem 0.3rem; overflow-y: auto;font-size: 0.3rem; box-sizing: border-box;" v-html="announcement.focus"></div>
             <van-row gutter="20">
               <van-col span="12"><van-button block type="info" @click="updateVisible=false">我知道了</van-button></van-col>
               <van-col span="12"><van-button block type="default" @click="getItemBuyPopupPage">查看详情</van-button></van-col>
@@ -182,26 +182,60 @@
     margin-bottom: 0.08rem;
   }
 
+  // .buyPopupBody {
+  //   width: 85vw;
+  // }
+  // .buyPopupContent{
+  //   background: white;
+  //   padding:0.2rem 0.24rem;
+  //   border-radius: 0.15rem;
+  // }
+
+  // .buyPopupTitle{
+  //   background: #1a89fa;
+  //   text-align: center;
+  //   border-radius: 0.1rem;
+  //   font-weight: normal;
+  //   font-size: 0.32rem;
+  //   height: 0.8rem;
+  //   line-height: 0.8rem;
+  //   color: #fff;
+  //   margin-top: 0.24rem;
+  // }
+
   .buyPopupBody {
     width: 85vw;
+    .buyPopupContent {
+      position: relative;
+      background: white;
+      padding: 0 5vw 5vw 5vw;
+      border-radius: 0.15rem;
+      .buyPopupTitle {
+        background: #1a89fa;
+        position: absolute;
+        left: 0.6rem;
+        right: 0.6rem;
+        top: -0.3rem;
+        text-align: center;
+        border-radius: 0.1rem;
+        line-height: 2;
+        font-weight: normal;
+        font-size: 0.36rem;
+        color: #fff;
+      }
+      .buyPopupTxt {
+        font-size: 0.32rem;
+        line-height: 1.8;
+        padding-top: 0.8rem;
+      }
+      .buyPopupTel {
+        color: #1a89fa;
+        font-weight: bold;
+      }
+    }
   }
-  .buyPopupContent{
-    background: white;
-    padding:0.2rem 0.24rem;
-    border-radius: 0.15rem;
-  }
+
   .buyPopupContent /deep/ img,.buyPopupContent /deep/ ul,.buyPopupContent /deep/ li,.buyPopupContent /deep/ p{
     width: 100%;
   }
-  .buyPopupTitle{
-    background: #1a89fa;
-    text-align: center;
-    border-radius: 0.1rem;
-    font-weight: normal;
-    font-size: 0.32rem;
-    height: 0.8rem;
-    line-height: 0.8rem;
-    color: #fff;
-    margin-top: 0.24rem;
-  }
 </style>

+ 27 - 2
src/view/system/scan_qr.vue

@@ -30,7 +30,7 @@ export default {
   },
   watch:{
     $route(to, from) {
-      if(to.path=='/home'&&this.barcode){
+      if(to.path=='/home' && this.barcode){
         this.barcode.close();
       }
     }
@@ -39,7 +39,7 @@ export default {
     routeBack(is){
       this.barcode.close();
       this.$nextTick(()=>{
-          this.$route_back()
+        this.$route_back()
       })
     },
     backButtons(){
@@ -137,7 +137,32 @@ export default {
       });
     },
 
+    backChange() {
+      this.barcode.close();
+      this.$nextTick(()=>{
+        this.$route_back()
+      })
+    },
+    wulifanhui() {
+      console.log("监听到了");
+    }
+
+  },
+  mounted(){
+    // 如果支持 popstate 一般移动端都支持了
+    if (window.history && window.history.pushState) {
+      // 往历史记录里面添加一条新的当前页面的url
+      // history.pushState(null, null, document.URL);
+      // 给 popstate 绑定一个方法 监听页面刷新
+      window.addEventListener('popstate', this.backChange, false); //false阻止默认事件
+    }
   },
+
+  destroyed(){
+    window.removeEventListener('popstate', this.wulifanhui, false);//false阻止默认事件
+  },
+
+
   created () {
     setTimeout(() => {
       plus.navigator.setStatusBarStyle('light')

+ 4 - 3
src/view/user/account.vue

@@ -17,7 +17,7 @@
           <span class="per-info__tel">{{ user_info.name }}</span>
         </template>
       </van-cell> -->
-      
+
       <van-cell title="手机号" is-link to="user_mobile">
         <template slot="default">
           <span class="per-info__tel">{{ user_info.tel | mobile }}</span>
@@ -67,7 +67,7 @@ export default {
       auths: [],
       aweixin: null,
       wo_token:'',
-      isUploader:this.$getCache('isUploader'),
+      isUploader: this.$getCache('isUploader'),
     };
   },
   created() {
@@ -89,7 +89,7 @@ export default {
         message: '当您在我们的产品中使用拍照、拍摄、扫描二维码、图片上传等功能时,我们需要获取您设备的相机权限,以便您正常使用图片上传、图片下载、附件上传、头像设置等服务',
       }).then(() => {
         this.$setCache('isUploader',true)
-        this.isUploader=true
+        this.isUploader = true
       })
     },
     // 判断是否获取微信登录认证
@@ -294,6 +294,7 @@ export default {
     background-color: #fff;
     justify-content: center;
     touch-action: none;
+    color: #ff5f4e;
   }
 }
 </style>

+ 52 - 24
src/view/user/company_info.vue

@@ -1,20 +1,22 @@
 <template>
   <div>
     <van-nav-bar :title="title" left-text="返回" @click-left="$route_back" left-arrow></van-nav-bar>
-    <div class="body_com has_header">
-      <scroller>
-        <van-cell-group>
-          <van-cell title="公司LOGO" is-link class="company_info">
-            <template slot="default">
-              <img :src="site_info.logo_url?site_info.logo_url:'static/images/default_company_logo.png'" class="needsclick company_img" @click.stop="select_img" />
-            </template>
-          </van-cell>
-        </van-cell-group>
-        <van-cell-group class="company_name">
-          <van-cell title="公司名称" is-link :value="site_info.name" @click="showPopup" />
-        </van-cell-group>
-      </scroller>
-      <vue-img-cropper
+    <van-cell-group>
+      <van-cell title="公司LOGO" is-link class="company_info">
+        <template solt="default">
+          <vue-img-cropper v-if="isUploader" ref="cropper" :height="400" :width="400" :maxScale="6" :compressionRatio="0.5"  @cutImg="showCutImg" @showLoading="showLoading" @hideLoading="hideLoading">
+            <img :src="site_info.logo_url?site_info.logo_url : 'static/images/default_company_logo.png'" class="needsclick company_img" />
+          </vue-img-cropper>
+          <div v-else @click="openText()">
+            <img :src="site_info.logo_url?site_info.logo_url : 'static/images/default_company_logo.png'" class="needsclick company_img" />
+          </div>
+        </template>
+      </van-cell>
+    </van-cell-group>
+    <van-cell-group class="company_name">
+      <van-cell title="公司名称" is-link :value="site_info.name" @click="showPopup" />
+    </van-cell-group>
+      <!-- <vue-img-cropper
         ref="cropper"
         :height="400"
         :width="400"
@@ -24,7 +26,7 @@
         @showLoading="showLoading"
         @hideLoading="hideLoading"
         @showError="showError">
-      </vue-img-cropper>
+      </vue-img-cropper> -->
 
       <van-dialog v-model="show" title="修改公司名称" class="edit_com_popup" show-cancel-button @confirm="save_btn">
         <van-cell-group>
@@ -56,7 +58,8 @@ export default {
       user_info: this.$userInfo(),
       click_count: 0,
       edit_com_name: '',
-      company_info:{}
+      company_info:{},
+      isUploader: this.$getCache('isUploader'),
     }
   },
   // 组件
@@ -66,14 +69,39 @@ export default {
   },
   // 方法
   methods: {
-    select_img () {
-      let self = this
-      if (this.click_count == 0) {
-        self.$refs.cropper.getImg()
-        setTimeout(function () {
-          self.click_count = 0
-        }, 20)
-      }
+    // select_img () {
+    //   if (this.click_count == 0) {
+    //     // if(self.$getCache("isUploader")) {
+    //     //   self.$refs.cropper.getImg()
+    //     //   // setTimeout(() => {
+    //     //   //   self.click_count = 0
+    //     //   // }, 20)
+    //     // }else {
+
+    //     // }
+    //     this.$dialog.confirm({
+    //       title: '权限获取',
+    //       message: '当您在我们的产品中使用拍照、拍摄、扫描二维码、图片上传等功能时,我们需要获取您设备的相机权限,以便您正常使用图片上传、图片下载、附件上传、头像设置等服务',
+    //     }).then(() => {
+    //       this.$refs.cropper.getImg()
+
+    //       // setTimeout(() => {
+    //       //   this.click_count = 0
+    //       // }, 20)
+    //     })
+
+    //   }
+    // },
+
+    openText(){
+      // 功道云需要使用媒体、相册、文件等权限,以便您正常使用图片上传、图片分享、图片下载等服务。
+      this.$dialog.confirm({
+        title: '权限获取',
+        message: '当您在我们的产品中使用拍照、拍摄、扫描二维码、图片上传等功能时,我们需要获取您设备的相机权限,以便您正常使用图片上传、图片下载、附件上传、头像设置等服务',
+      }).then(() => {
+        this.$setCache('isUploader',true)
+        this.isUploader = true
+      })
     },
     showCutImg (d) {
       this.$toast.loading({

+ 20 - 10
src/view/user/department.vue

@@ -25,7 +25,9 @@
       <scroller ref="scroller_com"  :isInitRefresh="false" :on-refresh="refresh">
 
         <div style="padding: 0.2rem 0.32rem;background-color: #fff;" @click="parent_click">
-          <div style="background-color: #f7f8fa;border-radius:0.04rem;color:#c8c9cc;padding: 0.12rem 0.32rem;"><van-icon name="search" /> 请输入搜索姓名</div>
+          <div style="background-color: #f7f8fa;border-radius:0.04rem;color:#c8c9cc;padding: 0.12rem 0.32rem;">
+            <van-icon name="search" /> 请输入搜索姓名
+          </div>
         </div>
 <!--
         <van-search  placeholder="请输入搜索姓名" :disabled="true" @click="parent_click" /> -->
@@ -40,14 +42,18 @@
 
         <div>
           <van-cell-group :border="false" v-show="pid==0" >
-            <van-cell label-class="employee_count"
-            :title="company_info.name"
-            :border="false" clickable class="company_info"
-            @click="edit_site_info"
-            :is-link="getRole_noe"
-            :label="total +'人'">
+            <van-cell
+              label-class="employee_count"
+              :title="company_info.name"
+              :border="false"
+              clickable
+              class="company_info"
+              @click="edit_site_info"
+              :is-link="getRole_noe"
+              :label="total +'人'"
+            >
               <template slot="icon">
-                <img :src="company_info.logo_url?company_info.logo_url:'static/images/default_company_logo.png'" class="company_dept_img"/>
+                <img :src="company_info.logo_url ? company_info.logo_url : 'static/images/default_company_logo.png'" class="company_dept_img"/>
               </template>
             </van-cell>
           </van-cell-group>
@@ -60,7 +66,7 @@
             </van-cell>
           </van-cell-group>
           <div v-show="pid != 0">
-            <div class="fontColorC" style="padding: 0 0.32rem;font-size: 0.28rem;">管理员</div>
+            <div class="fontColorC" style="padding: 0.1rem 0.32rem;font-size: 0.28rem;">管理员</div>
             <div class="manager flex-box flex-v-ce">
                <div class="flex-box flex-v-ce flex-1 flex-d-wrap" style="padding-right: 0.2rem;" v-if="showDepart">
                   <van-tag closeable size="medium" type="primary" @close="closeManager(item)" v-for="(item,index) in dept_info.manager" :key="index" style="margin-right: 5px;margin-top: 5px;">{{item.name}}</van-tag>
@@ -68,7 +74,7 @@
                <div v-else style="color: #F56C6C;font-size: 14px" class="flex-1">管理员未设置</div>
                <van-button icon="plus" type="info" size="small" plain @click="show_dept_selector=true" />
             </div>
-            <div style="text-align: center;font-size: 12px;" class="fontColorC">只能选择直属部门的员工作为部门管理员</div>
+            <div style="text-align: center; padding: 0.2rem 0 0 0; font-size: 12px;" class="fontColorC">只能选择直属部门的员工作为部门管理员</div>
           </div>
           <van-cell-group>
             <van-cell  v-if="isApp && false" is-link title="邀请成员" @click="show_share" class="new_employee_cell employee_cell">
@@ -786,6 +792,8 @@ export default {
   }
   .pageIndexBtnText{font-size:0.24rem;}
 .dept_path a {
+  display: flex;
+  align-items: center;
   color: #238dfa;
   font-size: 0.28rem;
 }
@@ -800,6 +808,8 @@ export default {
   vertical-align: middle;
 }
 .dept_path {
+  display: flex;
+  align-items: center;
   position: relative;
   font-size: 0.32rem;
   line-height: 0.4rem;

+ 2 - 0
src/view/user/employee_info.vue

@@ -240,6 +240,8 @@ export default {
     padding-top: 0;
     font-size:0.32rem;
     color: #323233;
+    display: flex;
+    align-items: center;
     &.disabled{
       color: #959595;
     }

Vissa filer visades inte eftersom för många filer har ändrats