walter il y a 7 mois
Parent
commit
2a46a57129

+ 3 - 1
.eslintrc.js

@@ -8,7 +8,9 @@ module.exports = {
   //   'eslint:recommended'
   // ],
   parserOptions: {
-    parser: 'babel-eslint'
+    parser: 'babel-eslint',
+    sourceType: "module",
+    ecmaVersion: 2020
   },
   rules: {
     'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',

Fichier diff supprimé car celui-ci est trop grand
+ 162 - 376
package-lock.json


+ 1 - 1
package.json

@@ -19,7 +19,7 @@
     "dingtalk-jsapi": "^2.13.51",
     "dingtalk-service-window-libs": "^0.3.0",
     "echarts": "^4.9.0",
-    "element-ui": "^2.13.2",
+    "element-ui": "^2.15.14",
     "file-saver": "^2.0.5",
     "imagemin-pngquant": "^9.0.2",
     "moment": "^2.29.0",

+ 5 - 0
src/assets/css/reset.css

@@ -416,4 +416,9 @@ a:hover {
 
   width: 100px !important;
   height: 100px !important;
+}
+
+
+.text-center {
+	text-align: center;
 }

+ 141 - 0
src/components/numberRangeSelector.vue

@@ -0,0 +1,141 @@
+<template>
+  <div>
+    <el-button-group>
+      <el-button size="small"  :disabled="disabled" @click.stop="openScope">
+        {{btRemark}}
+      </el-button>
+      <el-button size="small" icon="el-icon-delete" :disabled="disabled" @click.stop="clearScope"/>
+    </el-button-group>
+
+    <el-dialog
+        :visible.sync="showScope"
+        :show-close="false"
+        width="600px"
+        :title="title"
+        center
+        :before-close="onBeforeClose"
+    >
+      <el-form>
+        <el-form-item>
+          <el-input
+              v-model="minValue"
+              size="medium"
+              clearable
+              @input="onMinInput"
+              :disabled="disabled"
+              style="width: 200px;"
+          >
+            <template #prepend>最小值</template>
+          </el-input>
+        </el-form-item>
+        <el-form-item>
+          <el-input
+              v-model="maxValue"
+              size="medium"
+              clearable
+              @input="onMaxInput"
+              :disabled="disabled"
+              style="width: 200px;"
+          >
+            <template #append>最大值</template>
+          </el-input>
+        </el-form-item>
+        <el-form-item>
+          <el-button-group>
+            <el-button size="small" @click="onBeforeClose">取消</el-button>
+            <el-button type="primary" size="small" @click="submit">确定</el-button>
+          </el-button-group>
+        </el-form-item>
+      </el-form>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import {onlyNumberFilter} from "@/utils";
+export default {
+  name: "numberRangeSelector",
+  props:{
+    title:{
+      type: String,
+      default: ''
+    },
+    min:{
+      type: Number,
+      default: null
+    },
+    max:{
+      type: Number,
+      default: null
+    },
+    disabled:{
+      type: Boolean,
+      default: false
+    },
+  },
+  data() {
+    return {
+      showScope:false,
+      minValue:this.min,
+      maxValue:this.max,
+    }
+  },
+  computed: {
+    text(){
+      return this.min !== null && this.max !== null ? `分值区间 ${this.min} - ${this.max}` : ''
+    },
+    btRemark(){
+      return !!this.text ? this.text : '分值区间'
+    },
+
+  },
+  methods: {
+    onMaxInput(v){
+      this.maxValue = onlyNumberFilter(v)
+    },
+    onMinInput(v){
+      this.minValue = onlyNumberFilter(v)
+    },
+    submit(){
+      let min = null
+      let max = null
+      if(this.minValue !== null && this.maxValue !== null && this.minValue !== '' && this.maxValue !== ''){
+        min = Number(this.minValue)
+        max = Number(this.maxValue)
+        if(!Number.isInteger(min) || !Number.isInteger(max)) {
+          this.$message.error('只支持整数区间')
+          return
+        }
+      }else {
+        this.minValue = null
+        this.maxValue = null
+      }
+      this.$emit("update:min",min)
+      this.$emit("update:max",max)
+      this.$emit("scopeSubmit")
+      this.showScope = false
+    },
+    clearScope(){
+      this.minValue = null
+      this.maxValue = null
+      this.$emit("update:min",this.minValue)
+      this.$emit("update:max",this.maxValue)
+      this.$emit("scopeSubmit")
+    },
+    onBeforeClose(){
+      this.showScope = false
+      this.minValue = this.min
+      this.maxValue = this.max
+    },
+    openScope(){
+      this.showScope = true
+    },
+  }
+
+}
+</script>
+
+
+<style scoped lang="scss">
+
+</style>

+ 2 - 1
src/index.vue

@@ -493,7 +493,8 @@ export default {
 				{ title: '首页', children: this.returnRoutersArr('home'), icon: 'icon-shouye' },
 				{ title: 'A/B分', children: this.returnRoutersArr('abPoint'), icon: 'icon-PC_gongzuotai_ABfen' },
 				{ title: '任务', children: this.returnRoutersArr('task'), icon: 'icon-kaoqin_kaoqinyuebaobiao' },
-				{ title: '复核', children: this.returnRoutersArr('review'), icon: 'icon-jiedianyanshou-1' },
+				// { title: '复核', children: this.returnRoutersArr('review'), icon: 'icon-jiedianyanshou-1' },
+				{ title: '复核', children: this.returnRoutersArr('integral_review'), icon: 'icon-jiedianyanshou-1' },
 				{ title: '统计', children: this.returnRoutersArr('ranking'), icon: 'icon-dingdingPC_tongji1' },
 				{ title: '奖票', children: this.returnRoutersArr('award'), icon: 'icon-piao' },
 			];

+ 13 - 2
src/router/index.js

@@ -451,14 +451,25 @@ const routes = [{
 					jurisdiction: ['dept_manager', 'employee']
 				}
 			},
+			// {
+			// 	path: '/review',
+			// 	name: 'review',
+			// 	title: '复核',
+			// 	component: () => import( /* webpackChunkName: "review" */ '@/views/workbench/review.vue'),
+			// 	meta: {
+			// 		icon: 'icon-shezhi_gongdaolbiao',
+			// 		groupCode: 'review',
+			// 		// jurisdiction: ['dept_manager', 'employee']
+			// 	}
+			// },
 			{
 				path: '/review',
 				name: 'review',
 				title: '复核',
-				component: () => import( /* webpackChunkName: "review" */ '@/views/workbench/review.vue'),
+				component: () => import( /* webpackChunkName: "review" */ '@/views/workbench/integral_review.vue'),
 				meta: {
 					icon: 'icon-shezhi_gongdaolbiao',
-					groupCode: 'review',
+					groupCode: 'integral_review',
 					// jurisdiction: ['dept_manager', 'employee']
 				}
 			},

+ 1 - 1
src/screenSan.vue

@@ -8,7 +8,7 @@
 					<div style="height: 3rem;padding: 0  2rem;font-size: 20px;" class="zhuColor flex-box-ce">
 						<div class="flex-1 flex-box-ce">
 							<img :src="result.company.logo" class="logo" />
-							<div>{{ result.company.name }}</div>
+							<div style="max-width: 90%; height: 30px; line-height: 30px; overflow: hidden;">{{ result.company.name }}</div>
 						</div>
 						<div style="width: 400px;"></div>
 						<div class="flex-1 flex-box-end flex-box-ce">

+ 4 - 0
src/utils/index.js

@@ -0,0 +1,4 @@
+export function onlyNumberFilter(inputStr){
+    // return inputStr.replace(/[^(\d)]/g,"")
+    return inputStr.replace(/[^(-?\d)]/g,"")
+}

+ 1 - 1
src/views/ranking/integral_event.vue

@@ -29,7 +29,7 @@
 				<div class="form-item">
 					<div class="form-label">积分类型</div>
 					<div class="form-search">
-						<el-select  size="medium" v-model="formData.pt_id" clearable placeholder="请选择积分类型">
+						<el-select  size="medium" v-model="formData.pt_id" clearable placeholder="A/B分">
 							<el-option v-for="item in getTypes()" :key="item.name" :label="item.name" :value="item.id"></el-option>
 						</el-select>
 					</div>

+ 1 - 0
src/views/set/check.vue

@@ -42,6 +42,7 @@ export default {
 		  },
         {
           initialName: "正常打卡,每次加分",
+          message:'只包含打上班卡',
           initia_mark: false,
           initia_input: {
             age: "0",

+ 2 - 0
src/views/set/initialPoint.vue

@@ -18,6 +18,7 @@ export default {
 			initia_arr: [
 				{
 					initialName: '基础分',
+          message:'设置分值后,系统将为全部员工自动加上此项基础分;此项基础分仅加一次,计入每个员工的累计总分。',
 					initia_mark: true,
 					initia_input: {
 						age: ''
@@ -27,6 +28,7 @@ export default {
 				},
 				{
 					initialName: '工龄分',
+          message:'首次加分=员工已在职的月份数*工龄分,未满一个月的不加分;后续加分按已设置的工龄分值每月自动累加',
 					initia_mark: true,
 					initia_input: {
 						age: ''

+ 2 - 2
src/views/set/log.vue

@@ -12,7 +12,7 @@
 				</div>
 				<div class="flex-box-end" style="margin-top: 20px;">
 					<el-button  v-if="$authoritys() != 'dept_manager' && $authoritys() != 'employee'" plain @click="isShowLog = true">刷新汇报记录</el-button>
-					<el-button  type="primary" plain  @click="add()">添加日志模板</el-button>
+					<el-button  type="primary" plain  @click="add()">新增模板</el-button>
 					<el-button  type="primary" @click="isPz = true">设置<i class="el-icon-setting el-icon--right"></i></el-button>
 				</div>
 			</div>
@@ -48,7 +48,7 @@
 				</template>
 			</el-table>
 		</div>
-		<el-dialog title="日志配置" :visible.sync="isPz" top="25vh" width="520px" class="dialog">
+		<el-dialog :visible.sync="isPz" top="25vh" width="520px" class="dialog">
 			<el-alert class="el-dialog__body" title="日志配置适用所有日志" type="warning" :closable="false" show-icon></el-alert>
 			<el-form label-width="170px" ref="setForm" class="form">
 				<el-form-item label="是否允许查看日志内容"><el-switch v-model="see_log" :active-value="1" :inactive-value="0"></el-switch></el-form-item>

+ 3 - 3
src/views/set/screenSet.vue

@@ -113,7 +113,7 @@
 			</div>
 		</el-dialog>
 
-		<el-dialog :title="'设置('+selectItem.name+')'" :visible.sync="dialogVisible" width="1000px" class="dialog">
+		<el-dialog :title="'设置('+selectItem.name+')'" :visible.sync="dialogVisible" width="70%" class="dialog">
 			<div class="flex-box">
 				<div class="flex-4" style="padding-top: 50px;">
 					<div  style="color: #222;font-weight: 700;font-size: 16px;padding-left: 8px;">点击下面模块,快速定位到设置项
@@ -152,7 +152,7 @@
 							<div class="formTitle">组织名称和logo设置</div>
 							<div class="formBox">
 								<el-form-item label="组织名称">
-									<el-input class="width250" maxlength="10" show-word-limit v-model.trim="config.company.name" placeholder="请输入名称"></el-input>
+									<el-input style="width: 350px;" maxlength="20" show-word-limit v-model.trim="config.company.name" placeholder="请输入名称"/>
 								</el-form-item>
 								<el-form-item label="logo">
 									<upload
@@ -615,7 +615,7 @@ export default {
 				//配置格式 不是删除则必填
 				ranking_type:'ranking',
 				company: {
-					name: this.$getUserData().company_info.name.slice(0, 10), //不超过十个字 公司名截断
+					name: this.$getUserData().company_info.name.slice(0, 20), //不超过十个字 公司名截断
 					logo: 'https://integralsys.oss-cn-shenzhen.aliyuncs.com/intesys/dd/17/2022/07/01/CaBis82ryBYbncxc3nehiSXkiwDbhbwi.png' //公司logo
 				},
 				title: '积分数据大屏', //不超过十个字

+ 3 - 3
src/views/set/voluntarilyPoint.vue

@@ -121,11 +121,11 @@
 
 			<!-- 可写公共组建: -->
 			<!-- 新增加分组弹出框 -->
-			<el-dialog :close-on-click-modal="false" :title="grouping_type ? '编辑加分组' : '新增加分组'" :visible.sync="dialogVisible" width="40%">
+			<el-dialog :close-on-click-modal="false" :title="grouping_type ? '编辑加分组' : '新增加分组'" :visible.sync="dialogVisible">
 				<el-form :model="numberValidateForm" ref="numberValidateForm" label-width="100px" class="demo-ruleForm">
 					<el-form-item label="加分组名称" prop="name" :rules="[{ required: true, message: '请输入加分组名称' }]">
-						<el-input type="age" v-model="numberValidateForm.name" placeholder="请输入加分组名称"></el-input>
-					</el-form-item>
+            <el-input v-model="numberValidateForm.name" placeholder="请输入加分组名称" maxlength="30" show-word-limit />
+          </el-form-item>
 				</el-form>
 				<span slot="footer" class="dialog-footer" style=" overflow: hidden;">
 					<el-button

+ 812 - 0
src/views/workbench/integral_review.vue

@@ -0,0 +1,812 @@
+<template>
+  <div class="all padding-20">
+    <el-card style="margin-bottom: 20px;">
+      <el-form inline>
+        <el-form-item>
+          <el-select class="date-picker-width" size="medium" v-model="formData.dc_status"  placeholder="复核状态" :disabled="loading">
+            <el-option v-for="item in dc_status_options" :key="item.id" :label="item.name" :value="item.id"/>
+          </el-select>
+        </el-form-item>
+        <el-form-item>
+          <el-select size="medium" v-model="formData.source_type" placeholder="全部来源" :disabled="loading">
+            <el-option v-for="item in source_types" :key="item.id" :label="item.name" :value="item.id"/>
+          </el-select>
+        </el-form-item>
+        <el-form-item>
+          <el-select size="medium" v-model="formData.is_enable" style="margin-right: 5px" :disabled="loading">
+            <el-option  label="已启用用户" :value="1"></el-option>
+            <el-option  label="未授权&未启用用户" :value="0"></el-option>
+          </el-select>
+          <el-tooltip effect="dark" placement="top">
+            <template slot="content">
+              人员状态过滤。默认仅显示组织架构中“已启用”人员的积分事件,未启用、已离职等人员的积分事件可以通过“未启用&未授权”筛选查看
+            </template>
+            <span><i class="el-icon-warning"></i></span>
+          </el-tooltip>
+        </el-form-item>
+        <el-form-item>
+          <el-select size="medium" v-model="formData.employee_ids" filterable clearable placeholder="请输入或选择人员" :disabled="loading">
+            <el-option v-for="item in employee_list" :key="item.id" :label="item.name" :value="item.id"></el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item>
+          <el-select  size="medium" v-model="formData.pt_id" clearable placeholder="A/B分" :disabled="loading">
+            <el-option v-for="item in pts" :key="item.name" :label="item.name" :value="item.id"/>
+          </el-select>
+        </el-form-item>
+
+        <el-form-item>
+          <el-cascader
+              v-model="formData.rules"
+              :options="rule_trees"
+              :props="{ checkStrictly: true, value: 'id', label: 'name', children: 'child' }"
+              @change="onRuleChange"
+              size="medium"
+              ref="rule"
+              clearable
+              placeholder="规则分类"
+              :disabled="loading"
+          />
+        </el-form-item>
+        <el-form-item>
+          <el-date-picker
+              v-model="formData.time_scope"
+              type="daterange"
+              size="medium"
+              value-format="yyyy-MM-dd"
+              range-separator="至"
+              start-placeholder="开始日期"
+              end-placeholder="结束日期"
+              :disabled="loading"
+          />
+        </el-form-item>
+
+        <el-form-item>
+          <el-input
+              size="medium"
+              clearable
+              max="20"
+              v-model="formData.keyword"
+              placeholder="搜索内容"
+              :disabled="loading"
+          />
+        </el-form-item>
+<!--        <el-form-item>-->
+<!--          <el-input-->
+<!--              size="medium"-->
+<!--              clearable-->
+<!--              v-model="formData.point"-->
+<!--              placeholder="分值"-->
+<!--              @input="onPointInput"-->
+<!--              :disabled="loading"-->
+<!--          />-->
+<!--        </el-form-item>-->
+
+        <el-form-item>
+          <el-cascader
+              size="medium"
+              v-model="dept_names"
+              :options="dept_tree"
+              :props="{ checkStrictly: true, multiple: true, value: 'id', label: 'name', children: '_child' }"
+              ref="dept"
+              filterable
+              collapse-tags
+              clearable
+              placeholder="全公司"
+              style="min-width: 300px"
+              :disabled="loading"
+          />
+        </el-form-item>
+        <el-form-item>
+          <NumberRangeSelector
+              :min.sync="formData.minPoint"
+              :max.sync="formData.maxPoint"
+              :disabled="loading"
+              title="分值区间"
+              @scopeSubmit="handlePointScopeSubmit"
+          />
+        </el-form-item>
+      </el-form>
+      <el-row :gutter="5" justify="center" align="center">
+        <el-col :span="4">
+          <el-button-group>
+            <el-button type="primary" size="medium" :disabled="!canSubmitBatch" @click="openBatch">批处理</el-button>
+          </el-button-group>
+          <span style="padding-left: 20px;" :class="websocketAuth ? 'green' : 'orange'">
+            <i :class="websocketAuth ? 'el-icon-connection' : 'el-icon-warning-outline'">
+              {{websocketAuth ? '服务已启动' : '服务启动中.....'}}
+            </i>
+          </span>
+        </el-col>
+      </el-row>
+    </el-card>
+    <div>
+      <el-table
+          :data="integralList"
+          style="width: 100%;"
+          v-loading="loading"
+          @row-click="openDetail"
+          @selection-change="onSelectionChange"
+      >
+        <el-table-column
+            v-if="formData.dc_status === 0"
+            type="selection"
+            width="55"
+            :key="1"
+        />
+        <el-table-column prop="employee_name" label="姓名" align="center" width="200px" :key="2" >
+          <template slot-scope="scope">
+            <div class="flex-box">
+              <userImage :user_name="scope.row.employee_name" :img_url="scope.row.employee_img_url" width="50px" height="50px"></userImage>
+              <span style="line-height: 50px; padding-left: 10px;">{{ scope.row.employee_name }}</span>
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column
+            prop="dept"
+            show-overflow-tooltip
+            label="部门"
+            align="center"
+            :key="3"
+        />
+        <el-table-column prop="point" label="积分" align="center" :key="4">
+          <template slot-scope="scope">
+            <span :class="scope.row.point < 0 ? 'green' : 'red'">{{ scope.row.point }} {{ $getTypsName(scope.row.pt_id) }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column prop="remark" label="事件内容" align="center" show-overflow-tooltip :key="5" />
+        <el-table-column prop="event_time" label="时间" align="center" :key="6"/>
+        <el-table-column prop="source_type" label="事件来源" align="center" :key="7">
+          <template slot-scope="scope">
+            <span v-show="scope.row.source_type == 1">
+              积分奖扣
+              <span v-if="scope.row.recorder_name">({{ scope.row.recorder_name }})</span>
+            </span>
+            <span v-show="scope.row.source_type == 2">任务</span>
+            <span v-show="scope.row.source_type == 3">积分系统分配</span>
+            <span v-show="scope.row.source_type == 4">考勤系统分配</span>
+            <span v-show="scope.row.source_type == 5">
+								积分申请
+								<span v-if="scope.row.applyor_name">({{ scope.row.applyor_name }})</span>
+							</span>
+            <span v-show="scope.row.source_type == 6">绩效任务包</span>
+            <span v-show="scope.row.source_type == 8">积分导入</span>
+            <span v-show="scope.row.source_type == 9">A分转B分</span>
+            <span v-show="scope.row.source_type == 10">钉钉汇报(日志)奖扣分</span>
+            <span v-show="scope.row.source_type > 10">其他</span>
+          </template>
+        </el-table-column>
+<!--        <el-table-column prop="create_time" label="操作" v-if="formData.dc_status === 0" :key="8">-->
+<!--          <template slot-scope="scope">-->
+<!--            <el-link :underline="false" type="primary" :disabled="loading" @click.stop="openPass(scope.row)">通过</el-link>-->
+<!--            <el-link :underline="false" type="primary" :disabled="loading" style="padding: 0 10px;" @click.stop="setGrade(scope.row)">调整分数</el-link>-->
+<!--            <el-link :underline="false" type="danger" :disabled="loading" style="padding: 0 10px;" @click.stop="reject(scope.row)">驳回</el-link>-->
+<!--          </template>-->
+<!--        </el-table-column>-->
+        <template slot="empty">
+          <noData></noData>
+        </template>
+      </el-table>
+      <center class="pagination">
+        <el-pagination
+            background
+            @size-change="v => formData.page_size = v"
+            @current-change="v => formData.page = v"
+            :current-page="formData.page"
+            :page-sizes="[10, 20, 50,100]"
+            layout="total, sizes, prev, pager, next"
+            :page-size="formData.page_size"
+            :total="formData.total"
+        />
+      </center>
+    </div>
+    <el-dialog
+        :visible.sync="showDetail"
+        custom-class="text-center"
+        title="积分信息"
+        :close-on-click-modal="!loading || !currentItem"
+        :close-on-press-escape="!loading || !currentItem"
+        :show-close="false"
+        :before-close="closeDetail"
+    >
+      <div v-if="currentItem">
+        <el-row :gutter="5" v-if="this.currentItem.dc_status === 0" style="margin-bottom: 10px;">
+          <el-col :span="6" v-if="event_review_point">
+            <el-input size="small" v-model="currentItem.point" type="number">
+              <template #prepend>积分</template>
+            </el-input>
+          </el-col>
+          <el-col :span="event_review_point > 0 ? 14 : 19" >
+            <el-input :size=" event_review_point > 0 ? 'small' : 'medium'" v-model="currentItem.comment" maxlength="50" show-word-limit  clearable >
+              <template #prepend>备注</template>
+            </el-input>
+          </el-col>
+          <el-col :span="event_review_point > 0 ? 4 : 5">
+            <el-button-group>
+              <el-button :size=" event_review_point > 0 ? 'small' : 'medium'" type="warning" @click="disagree" :disabled="loading">驳回</el-button>
+              <el-button :size=" event_review_point > 0 ? 'small' : 'medium'" type="primary" :disabled="!websocketAuth" :loading="loading" @click="agree">通过</el-button>
+            </el-button-group>
+          </el-col>
+        </el-row>
+        <el-descriptions
+            :column="1"
+            border
+            :label-style="{textAlign:'center'}"
+            :content-style="{textAlign: 'center'}"
+        >
+          <el-descriptions-item label="姓名">{{currentItem.employee_name}}&nbsp;{{currentItem.dept}}</el-descriptions-item>
+          <el-descriptions-item label="积分">{{currentItem.point_mark}}&nbsp;{{$getTypsName(currentItem.pt_id)}}</el-descriptions-item>
+          <el-descriptions-item label="内容">{{currentItem.remark}}</el-descriptions-item>
+          <el-descriptions-item label="事件时间">{{currentItem.event_time}}</el-descriptions-item>
+          <el-descriptions-item label="创建时间">{{currentItem.create_time}}</el-descriptions-item>
+        </el-descriptions>
+<!--        <template v-if="currentItem?.dc_remark?.flow?.length > 0">-->
+        <template v-if="currentItem.dc_remark && currentItem.dc_remark.flow">
+          <h3 style="margin: 10px 0;">复核流程</h3>
+          <el-steps
+              :active="currentItem.dc_remark.flow.length"
+              align-center
+          >
+            <el-step
+                v-for="(item,index) in currentItem.dc_remark.flow"
+                :key="index"
+                :title="`${item.employee_name} ${item.action === 'agree' ? '复核通过' : (item.action === 'disagree' ? '复核驳回' : '')}`"
+            >
+              <template #description>
+                {{$moment(item.time * 1000).format('YYYY-MM-DD')}}&nbsp;{{item.comment || ''}}
+              </template>
+            </el-step>
+          </el-steps>
+        </template>
+      </div>
+      <el-empty v-else/>
+    </el-dialog>
+    <el-dialog
+        :visible.sync="showBatch"
+        custom-class="text-center"
+        title="批处理"
+        :close-on-click-modal="!loading || !selectedItems || selectedItems.length === 0"
+        :close-on-press-escape="!loading || !selectedItems || selectedItems.length === 0"
+        :show-close="false"
+        :before-close="closeBatch"
+    >
+      <el-row :gutter="5">
+        <el-col :span="18">
+          <el-input
+              v-model="batchComment"
+              maxlength="50"
+              show-word-limit
+              :disabled="loading"
+          >
+            <template #prepend>备注</template>
+          </el-input>
+        </el-col>
+        <el-col :span="6">
+          <el-button-group>
+            <el-button  type="warning" @click="disagreeBatch" :disabled="loading">驳回</el-button>
+            <el-button  type="primary" :disabled="!websocketAuth" :loading="loading" @click="agreeBatch">通过</el-button>
+          </el-button-group>
+        </el-col>
+      </el-row>
+      <el-progress text-inside :stroke-width="20" :percentage="batchProgress" style="margin: 10px 0;" v-show="loading" />
+      <el-table :data="selectedItems">
+        <el-table-column
+            prop="employee_name"
+            show-overflow-tooltip
+            label="姓名"
+            align="center"
+        />
+        <el-table-column
+            prop="point_mark"
+            show-overflow-tooltip
+            label="积分"
+            align="center"
+        />
+        <el-table-column
+            prop="remark"
+            show-overflow-tooltip
+            label="内容"
+            align="center"
+        />
+        <el-table-column align="center">
+          <template #header>
+            结果&nbsp;
+            <el-dropdown trigger="click" @command="copyResult" v-if="canClipboard">
+              <span><i class="el-icon-more"/></span>
+              <el-dropdown-menu slot="dropdown">
+                <el-dropdown-item command="normal">复制结果</el-dropdown-item>
+                <el-dropdown-item command="origin">复制结果源</el-dropdown-item>
+              </el-dropdown-menu>
+            </el-dropdown>
+          </template>
+          <template slot-scope="scope">
+            <el-link :type="scope.row.code === 1 ? 'primary' : (scope.row.code === 1 ? 'primary' : 'warning')">
+              <template v-if="loading && scope.row.code === -1">
+                <i class="el-icon-loading"></i>
+              </template>
+              <template v-else>
+                {{ batchResultMark(scope.row) }}
+              </template>
+            </el-link>
+          </template>
+        </el-table-column>
+      </el-table>
+    </el-dialog>
+  </div>
+</template>
+
+
+<script>
+import {onlyNumberFilter} from "@/utils";
+import {isNumeric} from "echarts/lib/util/number";
+import {_debounce, getTypsName} from "@/api/auth";
+import {wsClient} from "@/api/wsService";
+import NumberRangeSelector from '@/components/numberRangeSelector'
+
+export default {
+  name: "integral_review",
+  components:{NumberRangeSelector},
+  data(){
+    let pts = this.$getTyps().filter(item => item.code !== 'JX');
+    return {
+      pts,
+      rule_trees:[],
+      employee_list:[],
+      event_review_point:0,
+      source_types:[
+        { id: 0, name: '全部来源' },
+        { id: 1, name: '积分奖扣' },
+        { id: 2, name: '任务' },
+        { id: 3, name: '积分系统分配' },
+        { id: 4, name: '考勤系统分配' },
+        { id: 5, name: '积分申请' },
+        // {id: 6,name: '绩效任务包'},
+        { id: 8, name: '积分导入' },
+        { id: 9, name: 'A分转B分' },
+        { id: 10, name: '钉钉汇报(日志)分' }
+      ],
+      dc_status_options:[
+        { id: 0, name: '待复核' },
+        { id: 1, name: '通过' },
+        { id: 2, name: '驳回' },
+      ],
+      loading: false,
+      dept_names:[],
+      dept_tree: [],
+      formData: {
+        page: 1,
+        page_size: 10,
+        employee_ids:'',
+        pt_id:'',
+        source_type:0,
+        rules:[],
+        rule_id:0,
+        time_scope:[],
+        start_day:'',
+        end_day:'',
+        dc_status:0,
+        keyword:'',
+        point:'',
+        is_enable:1,
+        dept_ids:'',
+        minPoint:null,
+        maxPoint:null,
+      },
+      integralList:[],
+      selectedItems:[],
+      wsClient:wsClient,
+      showDetail:false,
+      showBatch:false,
+      currentItem:null,
+      batchComment:'',
+      batchPoint:0,
+      batchResult:[]
+    }
+  },
+  methods:{
+    getTypsName,
+    getRuleTrees(){
+      this.$axios('get', '/api/integral/rule/trees').then(res => {
+        this.rule_trees = this.getRuleTreeData(res.data.data.rule_tree);
+      });
+    },
+    // 规则递归 children
+    getRuleTreeData(data) {
+      for (var i = 0; i < data.length; i++) {
+        if (data[i].child.length < 1) {
+          // children若为空数组,则将children设为undefined
+          data[i].child = undefined;
+        } else {
+          // children若不为空数组,则继续 递归调用 本方法
+          this.getRuleTreeData(data[i].child);
+        }
+      }
+      return data;
+    },
+    getEmployee(){
+      this.$axios('get', '/api/employee/index', { page: 0, page_size: 3000, is_official: 1 }).then(res => {
+        this.employee_list = res.data.data.list;
+      });
+    },
+    onRuleChange(val){
+      this.formData.rule_id = val.length === 0 ? 0 : this.formData.rules[this.formData.rules.length - 1]
+    },
+    onPointInput(v){
+      this.formData.point = onlyNumberFilter(v)
+    },
+    getDepartment(){
+      this.$axios('get', '/api/department/tree').then(res => {
+        this.dept_tree = this.getTreeData(res.data.data.list);
+      });
+    },
+    // 递归判断列表,把最后的children设为undefined
+    getTreeData(data) {
+      for (var i = 0; i < data.length; i++) {
+        if (data[i]._child.length < 1) {
+          // children若为空数组,则将children设为undefined
+          data[i]._child = undefined;
+        } else {
+          // children若不为空数组,则继续 递归调用 本方法
+          this.getTreeData(data[i]._child);
+        }
+      }
+      return data;
+    },
+    handlePointScopeSubmit(){
+      this.formData.page = 1
+      this.getIntegralList()
+    },
+    getIntegralList(){
+      let self = this
+      if (self.loading) return;
+      self.loading = true;
+      let data = {
+        page:self.formData.page,
+        page_size:self.formData.page_size,
+        is_enable:self.formData.is_enable,
+        dc_status:[self.formData.dc_status],
+      }
+      if ([1,2].includes(self.formData.dc_status)) data.order_key = 'dc_time'
+
+      if (self.formData.source_type) data.source_type = self.formData.source_type;
+      if (self.formData.employee_ids) data.employee_ids = self.formData.employee_ids;
+      if (self.formData.pt_id) data.pt_id = self.formData.pt_id;
+      if (self.formData.rule_id) data.rule_id = self.formData.rule_id;
+      if (self.formData.start_day && self.formData.end_day) {
+        data.start_day = self.formData.start_day
+        data.end_day = self.formData.end_day
+      }
+      if (self.formData.keyword) data.keyword = self.formData.keyword
+      if (isNumeric(self.formData.point)) data.point = self.formData.point;
+      if (self.formData.dept_ids) data.dept_ids = self.formData.dept_ids;
+      if (self.formData.minPoint !== null && self.formData.maxPoint !== null) {
+        data.min_point = self.formData.minPoint
+        data.max_point = self.formData.maxPoint
+      }
+
+      self.$axios('get', '/api/integral/statistics/integral', data).then(res => {
+        self.integralList = res.data.data.list;
+        if(data.page === 1){
+          self.formData.total = res.data.data.total;
+        }
+      }).finally(() => {
+        self.loading = false;
+      });
+    },
+    onSelectionChange(selection){
+      this.selectedItems = selection.map(item => {
+        return {
+          event_id:item.id,
+          employee_name:item.employee_name,
+          point:item.point,
+          point_mark:item.point_mark + " " + this.$getTypsName(item.pt_id),
+          remark:item.remark,
+          hasFinish:false,
+          code:-1,
+          msg:'',
+        }
+      })
+    },
+    openDetail(item){
+      this.currentItem = item
+
+      let data = {
+        event_id: item.id
+      }
+      this.loading = true
+      this.$axios('get', '/api/integral/statistics/integral/info', data)
+          .then(res => {
+            if (res.data.code !== 1) return
+            this.currentItem.dc_remark = res.data.data.dc_remark
+          })
+          .finally(() => {
+            this.loading = false
+            this.showDetail = true
+          })
+    },
+    closeDetail(){
+      this.showDetail = false
+      this.currentItem = null
+      this.getIntegralList()
+    },
+    agree(){
+      if (!this.currentItem || this.loading) return
+      let data = {
+        type:'event_check',
+        action:'agree',
+        event_id:this.currentItem.id,
+        point:this.currentItem.point,
+        comment:this.currentItem?.comment || ''
+      }
+      this.showDetail = false
+      this.currentItem = null
+      this.loading = true
+      if (!this.wsClient.getAuthStatus()){
+        this.wsClient.initWebSocket(() => {
+          this.wsClient.send(data)
+        },(msg) => {
+          if (msg.type !== 'event_check') return
+          this.loading = false
+          this.getIntegralList()
+        })
+      }else {
+        this.wsClient.send(data,(msg) => {
+          if (msg.type !== 'event_check') return
+          this.loading = false
+          this.getIntegralList()
+        })
+      }
+    },
+    disagree(){
+      if (!this.currentItem || this.loading) return
+      let data = {
+        type:'event_check',
+        action:'disagree',
+        event_id:this.currentItem.id,
+        comment:this.currentItem?.comment || ''
+      }
+      this.showDetail = false
+      this.currentItem = null
+      this.loading = true
+      if (!this.wsClient.getAuthStatus()){
+        this.wsClient.initWebSocket(() => {
+          this.wsClient.send(data)
+        },(msg) => {
+          if (msg.type !== 'event_check') return
+          this.loading = false
+          this.getIntegralList()
+        })
+      }else {
+        this.wsClient.send(data,(msg) => {
+          if (msg.type !== 'event_check') return
+          this.loading = false
+          this.getIntegralList()
+        })
+      }
+
+    },
+    openBatch(){
+      console.log(this.selectedItems.map(item => item.event_id).toString())
+      this.showBatch = true
+      this.batchComment = ''
+    },
+    closeBatch(){
+      this.showBatch = false
+      this.batchComment = ''
+      this.batchResult = []
+      this.getIntegralList()
+    },
+    agreeBatch(){
+      this.loading = true
+      this.batchResult = []
+      this.wsClient.setBusinessFun((res) => {
+        if (res.type !== 'ping') this.batchResult.push(res)
+        if (res.type !== 'event_check') return
+        this.selectedItems.filter(item => item.event_id === res?.result?.source_msg?.event_id).forEach(item => {
+          item.hasFinish = true
+          item.code = res.code
+          item.msg = res.code === 1 ? '已处理' : (res?.msg ? res.msg : '处理失败')
+        })
+        if (this.selectedItems.filter(item => item.hasFinish).length >= this.selectedItems.length) this.loading = false
+      })
+      this.selectedItems.map(item => {
+        return {
+          type:'event_check',
+          action:'agree',
+          event_id:item.event_id,
+          point:item.point,
+          comment:this.batchComment || ''
+        }
+      }).forEach(data => {
+        this.wsClient.send(data)
+      })
+    },
+    disagreeBatch(){
+      this.loading = true
+      this.batchResult = []
+      this.wsClient.setBusinessFun(res => {
+        if (res.type !== 'ping') this.batchResult.push(res)
+        if (res.type !== 'event_check') return
+        this.selectedItems.filter(item => item.event_id === res?.result?.source_msg?.event_id).forEach(item => {
+          item.hasFinish = true
+          item.code = res.code
+          item.msg = res.code === 1 ? '已处理' : (res?.msg ? res.msg : '处理失败')
+        })
+        if (this.selectedItems.filter(item => item.hasFinish).length >= this.selectedItems.length) this.loading = false
+      })
+      this.selectedItems.map(item => {
+        return {
+          type:'event_check',
+          action:'disagree',
+          event_id:item.event_id,
+          comment:this.batchComment || ''
+        }
+      }).forEach(data => {
+        this.wsClient.send(data)
+      })
+    },
+    copyResult(origin){
+      switch (origin){
+        case 'normal':
+          let result = this.batchResult.filter(res => res.type === 'event_check').map(res => {
+            return {
+              type:res?.result?.source_msg?.type === 'event_check' ? '复核' : res.type,
+              action: res?.result?.source_msg?.action === 'agree' ? '同意' : (res?.result?.source_msg?.action === 'disagree' ? '驳回' : '未知'),
+              msg: res?.msg,
+              code: res?.code,
+              origin: {
+                action:res?.result?.source_msg?.action,
+                comment:res?.result?.source_msg?.comment,
+                no:res?.result?.source_msg?.event_id,
+                p:res?.result?.source_msg?.point,
+                t:res?.result?.source_msg?.type,
+              }
+            }
+          })
+          navigator.clipboard.writeText(JSON.stringify(result)).then(() => {
+            this.$message.success("已复制")
+          },(reason) => {
+            console.error('integral review clipboard',reason)
+            this.$message.info("没有任何结果")
+          })
+          break;
+        case 'origin':
+          navigator.clipboard.writeText(JSON.stringify(this.batchResult)).then(() => {
+            this.$message.success("已复制")
+          },(reason) => {
+            console.error('integral review clipboard',reason)
+            this.$message.info("没有任何结果")
+          })
+          break;
+      }
+    },
+    batchResultMark(item){
+      return !!item.msg ? item.msg : '待处理'
+    },
+
+  },
+  watch:{
+    'formData.time_scope'(v){
+      if (v){
+        this.formData.start_day = v[0]
+        this.formData.end_day = v[1]
+      }else {
+        this.formData.start_day = ''
+        this.formData.end_day = ''
+      }
+      this.formData.page = 1
+      this.getIntegralList()
+    },
+    'formData.employee_ids'(v){
+      this.formData.page = 1
+      this.getIntegralList()
+    },
+    'formData.pt_id'(v){
+      this.formData.page = 1
+      this.getIntegralList()
+    },
+    'formData.source_type'(v){
+      this.formData.page = 1
+      this.getIntegralList()
+    },
+    'formData.rule_id'(v){
+      this.formData.page = 1
+      this.getIntegralList()
+    },
+    'formData.dc_status'(v){
+      this.formData.page = 1
+      if (v !== 0) this.selectedItems = []
+      this.getIntegralList()
+    },
+    'formData.dept_ids'(v){
+      this.formData.page = 1
+      this.getIntegralList()
+    },
+    'formData.keyword' : {
+      deep: true,
+      handler: _debounce(function (v){
+        this.formData.page = 1
+        this.getIntegralList()
+      })
+    },
+    'formData.point': {
+      deep: true,
+      handler: _debounce(function (v,o){
+        if (v === o) return
+        this.formData.page = 1
+        this.getIntegralList()
+      })
+    },
+    'formData.is_enable'(v){
+      this.formData.page = 1
+      this.getIntegralList()
+    },
+    'formData.page'(v){
+      this.getIntegralList()
+    },
+    'formData.page_size'(v){
+      this.formData.page = 1
+      this.getIntegralList()
+    },
+    dept_names(v){
+      if (v.length !== 0){
+        let dept_ids = v.map(item => item[item.length - 1])
+        let set = new Set(dept_ids)
+        this.formData.dept_ids = [...set].toString()
+      } else {
+        this.formData.dept_ids = []
+      }
+      this.formData.page = 1
+      this.getIntegralList()
+    }
+  },
+  computed:{
+    websocketAuth(){
+      return this.wsClient.getAuthStatus()
+    },
+    canSubmitBatch(){
+      return !this.loading && this.websocketAuth && this.selectedItems && this.selectedItems.length > 0
+    },
+    batchProgress(){
+      return this.selectedItems && this.selectedItems.length > 0 ? (this.selectedItems.filter(item => item.hasFinish).length / this.selectedItems.length) * 100 : 0
+    },
+    canClipboard(){
+      return !!navigator?.clipboard && this.batchResult && this.batchResult.length > 0
+    }
+  },
+  mounted(){
+    this.getEmployee();
+    this.getDepartment();
+    this.getRuleTrees();
+    this.getIntegralList();
+    let siteConfig = this.$getCache('siteConfig');
+    this.event_review_point = siteConfig.event_review_point;
+
+    //初始化长连接
+    this.wsClient.initWebSocket()
+
+
+
+
+
+
+
+  },
+  beforeDestroy() {
+    if (this.wsClient) this.wsClient.close()
+  },
+  destroyed() {
+  }
+
+
+}
+</script>
+
+<style scoped lang="scss">
+
+.el-table tr{
+  cursor: pointer !important;
+}
+
+
+</style>

Certains fichiers n'ont pas été affichés car il y a eu trop de fichiers modifiés dans ce diff