applicationIntegrationPopup.vue 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833
  1. <template>
  2. <div>
  3. <!-- 奖扣ab分弹窗 -->
  4. <el-dialog :title="title" :visible.sync="visible" :close-on-click-modal="false" :before-close="closeDialog2" width="600px">
  5. <div>
  6. <el-form :model="dialogData" ref="dialogData" label-width="80px" v-loading="loading">
  7. <div v-for="(item, index) in dialogData.items" :key="index" @click="setIndex(index)">
  8. <div style="overflow: hidden;" class="flex-box flex-v-ce">
  9. <span style="line-height: 36px;" class="flex-1">申请明细({{ index + 1 }})</span>
  10. <el-button type="text" v-show="index > 0 || dialogData.items.length > 1" @click="delItem(index)">删除</el-button>
  11. </div>
  12. <el-form-item label="录入对象" :prop="'items.' + index + '.employeeName'" :rules="[{ required: true, message: '请选择录入对象', trigger: 'change' }]">
  13. <el-row>
  14. <el-col :span="18">
  15. <el-input auto-complete="off" v-model="item.employeeName" placeholder="请选择录入对象"></el-input>
  16. <div @click="item.show_employee_selector = true" style=" position: absolute; top: 0; right: 0; left: 0; bottom: 0; z-index: 9;"></div>
  17. </el-col>
  18. </el-row>
  19. <el-dialog title="选择人员" width="640px" :visible.sync="item.show_employee_selector" append-to-body :before-close="handleClose">
  20. <EmployeeSelector
  21. v-if="item.show_employee_selector"
  22. ref="employee"
  23. :multi="false"
  24. :user_no_select="false"
  25. :selected="item.employee_selected"
  26. @confirm="employee_confirm"
  27. />
  28. <span slot="footer" class="dialog-footer">
  29. <el-button @click="item.show_employee_selector = false">取 消</el-button>
  30. <el-button type="primary" @click="submitMembers('employee')">确 定</el-button>
  31. </span>
  32. </el-dialog>
  33. </el-form-item>
  34. <el-form-item label="指定规则"><el-switch v-model="item.rule_switch" @change="switchChange(index, item.rule_switch)" :disabled="ruleOnoff"></el-switch></el-form-item>
  35. <el-form-item
  36. label="选择规则"
  37. v-if="item.rule_switch"
  38. :prop="'items.' + index + '.rule_item_list_value'"
  39. :rules="[{ required: true, message: '请选择规则', trigger: 'change' }]"
  40. >
  41. <el-cascader
  42. v-model="item.rule_item_list_value"
  43. ref="ruleItem"
  44. :popper-class="'itemClass'"
  45. :options="rule_item_list"
  46. @change="ruleItemChange"
  47. :show-all-levels="false"
  48. filterable
  49. @expand-change="setIndex(index)"
  50. clearable
  51. :props="{ children: 'child', label: 'name', value: 'id' }"
  52. ></el-cascader>
  53. </el-form-item>
  54. <el-form-item v-if="item.rule_switch && item.rule_id">
  55. <div style="line-height: 24px;" v-show="item.rule_item_details.range_type == 1">
  56. {{ item.rule_item_details.min_point }}
  57. <span class="blue">{{ $getTypsName(item.rule_item_details.pt_id) }}</span>
  58. </div>
  59. <div style="line-height: 24px;" v-show="item.rule_item_details.range_type == 2">
  60. {{ item.rule_item_details.min_point }} ~ {{ item.rule_item_details.max_point }}
  61. <span class="blue">{{ $getTypsName(item.rule_item_details.pt_id) }}</span>
  62. </div>
  63. <div style="line-height: 24px;">{{ item.rule_item_details.name }}</div>
  64. </el-form-item>
  65. <el-form-item label="发生时间" :prop="'items.' + index + '.event_time'" :rules="[{ required: true, message: '请选择时间', trigger: 'blur' }]">
  66. <el-row>
  67. <el-col :span="18">
  68. <el-date-picker
  69. v-model="item.event_time"
  70. :picker-options="pickerBeginDateBefore"
  71. type="date"
  72. placeholder="请选择时间"
  73. value-format="yyyy-MM-dd"
  74. ></el-date-picker>
  75. </el-col>
  76. </el-row>
  77. </el-form-item>
  78. <el-form-item
  79. label="事件内容"
  80. :prop="'items.' + index + '.remark'"
  81. :rules="[{ required: true, message: '请输入事件内容', trigger: 'blur' }, { min: 3, max: 300, message: '长度在 3 到 300 个字符', trigger: 'blur' }]"
  82. >
  83. <el-row>
  84. <el-col :span="18"><el-input type="textarea" rows="5" placeholder="请输入事件内容" style="width: 100%;" v-model="item.remark"></el-input></el-col>
  85. </el-row>
  86. </el-form-item>
  87. <el-form-item label="图片" label-width="100px">
  88. <uploadOss
  89. :headers="Xtoken"
  90. class="avatar-uploader"
  91. :action="'https://' + 'integralsys.oss-cn-shenzhen.aliyuncs.com'"
  92. :show-file-list="true"
  93. :file-list="item.fileList"
  94. :on-success="handleFilesSuccess"
  95. :on-preview="onFilePreView"
  96. :before-upload="beforeUpload"
  97. :on-remove="onFileRemove"
  98. :limit="3"
  99. accept="image/jpeg,image/png"
  100. :multiple="true"
  101. ref="clearPicture"
  102. >
  103. <el-button size="small" type="primary">点击上传</el-button>
  104. (最多选择3张)
  105. </uploadOss>
  106. </el-form-item>
  107. <el-form-item
  108. v-loading.lock="fullscreenLoading"
  109. label="审批人"
  110. :prop="'items.' + index + '.approvalName'"
  111. :rules="[{ required: true, message: '请选择审批人', trigger: 'blur' }]"
  112. >
  113. <el-row>
  114. <el-col :span="18">
  115. <el-input auto-complete="off" v-model="item.approvalName" placeholder="请选择审批人"></el-input>
  116. <div @click="approval_selected_null(item)" style=" position: absolute; top: 0; right: 0; left: 0; bottom: 0; z-index: 9;"></div>
  117. </el-col>
  118. </el-row>
  119. <el-dialog title="选择人员" width="640px" :visible.sync="item.show_approval_selector" append-to-body :before-close="handleClose">
  120. <EmployeeSelector
  121. :can_select_employee="true"
  122. v-if="item.show_approval_selector"
  123. ref="approval"
  124. :multi="false"
  125. :employee_list="item.approval_employee_list"
  126. :user_no_select="false"
  127. :isCreatorSelect="true"
  128. :selected="item.approval_selected"
  129. @confirm="approval_confirm"
  130. />
  131. <span slot="footer" class="dialog-footer">
  132. <el-button @click="item.show_approval_selector = false">取 消</el-button>
  133. <el-button type="primary" @click="submitApproval('approval')">确 定</el-button>
  134. </span>
  135. </el-dialog>
  136. </el-form-item>
  137. </div>
  138. <el-form-item style="margin-bottom: 0;"><div>如需录入多条,请点击“增加一条”</div></el-form-item>
  139. <el-form-item style="margin-bottom: 0;"><el-button type="primary" plain @click="addItem">+ 增加一条</el-button></el-form-item>
  140. <el-form-item style="text-align: right; margin-bottom: 0;">
  141. <el-button @click="closeDialog2('dialogData')">取 消</el-button>
  142. <el-button :disabled="btn_loading" :loading="btn_loading" type="primary" @click="subData('dialogData')">确 认</el-button>
  143. </el-form-item>
  144. </el-form>
  145. </div>
  146. </el-dialog>
  147. <el-dialog :title="'提交结果'" :visible.sync="error_list_show" :before-close="closeDialog2" :append-to-body="true" width="700px">
  148. <el-table :data="error_list">
  149. <el-table-column prop="target" label="员工"></el-table-column>
  150. <el-table-column prop="status" label="处理状态">
  151. <template slot-scope="scope">
  152. <span :style="'color:' + (scope.row.status == 0 ? '#f70000' : '#47bf47')">{{ scope.row.status == 0 ? '申请失败' : '申请成功' }}</span>
  153. </template>
  154. </el-table-column>
  155. <el-table-column prop="remark" label="备注信息"></el-table-column>
  156. </el-table>
  157. </el-dialog>
  158. <el-dialog title="提交结果" :visible.sync="isResult" width="800" :close-on-click-modal="false" :close-on-press-escape="false" :show-close="false">
  159. <div class="" v-if="!isShowError">
  160. <div style="text-align: center;margin-bottom: 10px;" class="red" v-if="isShowError2">{{errorMsg}}</div>
  161. <el-progress :text-inside="true" :stroke-width="24" :percentage="percentage"></el-progress>
  162. <div class="orange" style="text-align: center;padding-top: 10px;" v-if="config.event_review_status&&config.event_apply_review">复核开启后,积分需管理员复核后才计入排名和统计</div>
  163. <div style="margin-top: 20px;border: 1px solid #f1f1f1;">
  164. <div class="flex-box-ce results" style="font-weight: 600;">
  165. <div style="border-right: 1px solid #f1f1f1;width: 50px;">序号</div>
  166. <div class="flex-1" style="border-right: 1px solid #f1f1f1;">奖扣对象</div>
  167. <div class="flex-2" style="border-right: 1px solid #f1f1f1;">申请内容</div>
  168. <!-- <div class="flex-1" style="border-right: 1px solid #f1f1f1;">积分</div> -->
  169. <div class="flex-2" >处理结果</div>
  170. </div>
  171. <div class="flex-box-ce results" v-for="(item, index) in results" :key="index">
  172. <div style="border-right: 1px solid #f1f1f1;width: 50px;">{{results.length-index}}</div>
  173. <div class="flex-1" style="border-right: 1px solid #f1f1f1;">{{ item.target }}</div>
  174. <div class="flex-2" style="border-right: 1px solid #f1f1f1;">{{ item.remark }}</div>
  175. <!-- <div class="flex-1" style="border-right: 1px solid #f1f1f1;">
  176. {{ item.point>0? '+'+item.point:item.point }}
  177. <span>{{ item.task.msg.pt_id==3? 'B分':'A分' }}</span>
  178. </div> -->
  179. <div class="flex-2 green" v-if="item.status == 1">{{ item.msg }}</div>
  180. <div class="flex-2 red" v-else>{{ item.msg }}</div>
  181. </div>
  182. </div>
  183. <span slot="footer">
  184. <div class="flex-box-end" style="margin-top: 20px;" v-show="isShowError2&&results.length!=resultList.length"><el-button type="primary" @click="isResult = false" size="small">确 定</el-button></div>
  185. <div class="flex-box-end" style="margin-top: 20px;" v-show="results.length==resultList.length">
  186. <el-button type="primary" @click="isResult = false" size="small">确 定</el-button>
  187. </div>
  188. </span>
  189. </div>
  190. <div v-else>
  191. <div style="text-align: center;" class="red">{{errorMsg}}</div>
  192. <span slot="footer">
  193. <div class="flex-box-end" style="margin-top: 20px;"><el-button type="primary" @click="isResult = false" size="small">确 定</el-button></div>
  194. </span>
  195. </div>
  196. </el-dialog>
  197. <!-- 缓存的奖扣 -->
  198. <el-dialog title="网络中断申请列表" :visible.sync="isShowBreak" width="800" :close-on-click-modal="false" :close-on-press-escape="false" :show-close="false">
  199. <div>
  200. <div style="margin-top: 20px;border: 1px solid #f1f1f1;max-height: 500px;overflow-y: auto;" class="scroll-bar">
  201. <div class="flex-box-ce results" style="font-weight: 600;">
  202. <div class="flex-1" style="border-right: 1px solid #f1f1f1;">奖扣对象</div>
  203. <div class="flex-1" style="border-right: 1px solid #f1f1f1;">分类</div>
  204. <div class="flex-1" style="border-right: 1px solid #f1f1f1;">规则</div>
  205. <div class="flex-2" style="border-right: 1px solid #f1f1f1;">事件内容</div>
  206. <!-- <div class="flex-1" style="border-right: 1px solid #f1f1f1;">积分</div> -->
  207. <div class="flex-1" style="border-right: 1px solid #f1f1f1;">递交人员</div>
  208. </div>
  209. <div class="flex-box-ce results" v-for="(item, index) in breakList" :key="index">
  210. <div class="flex-1" style="border-right: 1px solid #f1f1f1;">{{ item.name }}</div>
  211. <div class="flex-1" style="border-right: 1px solid #f1f1f1;">
  212. <span v-if="item.rule_name">{{ item.rule_name }}</span>
  213. <span v-else>--</span>
  214. </div>
  215. <div class="flex-1" style="border-right: 1px solid #f1f1f1;">
  216. <span v-if="item.item_name">{{ item.item_name }}</span>
  217. <span v-else>--</span>
  218. </div>
  219. <div class="flex-2" style="border-right: 1px solid #f1f1f1;">{{ item.remark }}</div>
  220. <!-- <div class="flex-1" style="border-right: 1px solid #f1f1f1;">{{ item.point }}
  221. <span>{{ item.pt_id==3? 'B分':'A分' }}</span>
  222. </div> -->
  223. <div class="flex-1" style="border-right: 1px solid #f1f1f1;">{{ item.reviewer_name }}</div>
  224. </div>
  225. </div>
  226. <span slot="footer">
  227. <div class="flex-box-end" style="margin-top: 20px;">
  228. <el-button type="primary" @click="colseBreak()" size="small">取 消</el-button>
  229. <el-button type="primary" @click="submitBreak()" size="small">再次提交</el-button>
  230. </div>
  231. </span>
  232. </div>
  233. </el-dialog>
  234. </div>
  235. </template>
  236. <script>
  237. import moment from 'moment';
  238. import EmployeeSelector from '@/components/EmployeeSelector';
  239. import uploadOss from '@/components/upload';
  240. export default {
  241. name: 'applicationIntegration',
  242. // 数据
  243. model: {
  244. prop: 'list',
  245. event: 'value'
  246. },
  247. props: {
  248. title: {
  249. type: String,
  250. default: ''
  251. },
  252. visible: {
  253. type: Boolean,
  254. default: false
  255. },
  256. isBreak: { //是否打开缓存的未完成奖扣
  257. type: Boolean,
  258. default: false
  259. },
  260. integralType: {
  261. type: Number,
  262. default: 0
  263. },
  264. ruleOnoff: {
  265. type: Boolean,
  266. default: false
  267. //true:选择规则; false:选择分类
  268. }
  269. },
  270. data() {
  271. var getUserData = this.$getUserData();
  272. return {
  273. pickerBeginDateBefore: {
  274. disabledDate(time) {
  275. return time.getTime() > Date.now();
  276. }
  277. },
  278. error_list: [], //错误信息数组
  279. error_list_show: false, //错误信息弹窗
  280. Xtoken: { 'X-Token': this.$getToken() },
  281. loading: false,
  282. dialogData: {
  283. items: [
  284. {
  285. rule_switch: true,
  286. rule_id: '',
  287. item_id: '',
  288. remark: '',
  289. event_time: moment().format('YYYY-MM-DD'),
  290. // 录入对象
  291. employee_id: getUserData.id,
  292. employeeName: getUserData.name,
  293. employee_selected: { dept: [], employee: [{ id: getUserData.id, name: getUserData.name }] },
  294. show_employee_selector: false,
  295. // 审批人信息
  296. reviewer_id: '',
  297. approvalName: '',
  298. approval_selected: { dept: [], employee: [] },
  299. approval_employee_list: [], //当前选中人的 上级
  300. show_approval_selector: false,
  301. // 附件
  302. fileList: [],
  303. files: [],
  304. // 规则分类 与 规则细则 名称
  305. rule_list_value: null,
  306. rule_item_list_value: null,
  307. rule_item_details: { range_type: '' }
  308. }
  309. ]
  310. },
  311. // 规则分类
  312. rule_list: [],
  313. // 规则细则
  314. rule_item_list: [],
  315. flatteningIntegralRules: null,
  316. user_info: null,
  317. btn_loading: false,
  318. itemIndex: 0,
  319. fullscreenLoading: false, //选择审批人时需要,获取录入对象的上级
  320. LocalValObj: { id: '', name: '' } ,//当前录入的审批人缓存
  321. // 长连接结果
  322. results: [], //提交的返回结果集合
  323. isResult: false,
  324. percentage: 0,
  325. resultList:[],//要发送数据的集合
  326. resultIndex:0,
  327. isShowError:false,
  328. isShowError2:false,
  329. errorMsg:'服务器繁忙,请稍后再试',
  330. breakList:[],
  331. isShowBreak:false,
  332. config:{},
  333. };
  334. },
  335. components: { EmployeeSelector, uploadOss },
  336. async mounted() {
  337. this.config=this.$store.state.config;
  338. this.user_info = this.$getUserData();
  339. var reviewerObj = await this.getLocalVal(this.user_info.id);
  340. var res = reviewerObj ? reviewerObj : { id: '', name: '' };
  341. this.LocalValObj = res;
  342. this.getRuleItemData();
  343. // 初始化审批人
  344. if (this.LocalValObj.id) {
  345. this.dialogData.items[0].approval_selected.employee = [this.LocalValObj];
  346. this.dialogData.items[0].reviewer_id = this.LocalValObj.id;
  347. this.dialogData.items[0].approvalName = this.LocalValObj.name;
  348. }
  349. if(this.isBreak){
  350. let data=this.$getCache('apply_list');
  351. data.forEach(item=>{
  352. item.name=this.$getCache('userList')[item.employee_id]?this.$getCache('userList')[item.employee_id].name:'--';
  353. item.reviewer_name=this.$getCache('userList')[item.reviewer_id]?this.$getCache('userList')[item.reviewer_id].name:'--';
  354. })
  355. this.breakList=data;
  356. this.isShowBreak=true;
  357. }
  358. },
  359. watch:{
  360. isResult(val){
  361. if(!val){
  362. this.isShowError=false;
  363. this.isShowBreak = false;
  364. this.errorMsg='服务器繁忙,请稍后再试';
  365. this.$refs['dialogData'].resetFields();
  366. this.closeDialog();
  367. this.closeDialog2();
  368. this.$socketApi.closewebsocket();
  369. }
  370. }
  371. },
  372. methods: {
  373. setIndex(index){
  374. if(index==this.itemIndex){
  375. return false
  376. }
  377. this.itemIndex = index;
  378. },
  379. // 关闭缓存弹窗
  380. colseBreak(){
  381. this.isShowBreak = false;
  382. this.breakList=[];
  383. this.$removeCache('apply_list');
  384. this.closeDialog();
  385. this.closeDialog2();
  386. },
  387. // 提交缓存申请
  388. submitBreak(){
  389. this.$removeCache('apply_list');
  390. this.resultList=JSON.parse(JSON.stringify(this.breakList));
  391. this.resultIndex=0;
  392. this.percentage=0;
  393. this.results=[];
  394. this.isResult=true;
  395. this.opneWebSocket()
  396. },
  397. //获取缓存起来的审批人
  398. getLocalVal(id) {
  399. return new Promise((resolve, reject) =>{
  400. let obj;
  401. this.$axios('get', '/api/employee/info', { id: id }).then(res =>{
  402. if(res.data.code == 1){
  403. let data = res.data.data;
  404. if(data.employee_detail.superior_list && data.employee_detail.superior_id != 0){
  405. obj = data.employee_detail.superior_list.filter(x => x.id == data.employee_detail.superior_id)[0];
  406. if(obj.id == this.user_info.id){
  407. obj = this.$getCache(id)
  408. }
  409. }else{
  410. obj = this.$getCache(id);
  411. }
  412. }
  413. }).finally(_ =>{
  414. resolve(obj)
  415. })
  416. })
  417. },
  418. submitMembers(name) {
  419. this.$refs[name][0].confirm(); //调用组件的confirm();
  420. },
  421. submitApproval(name) {
  422. this.$refs[name][0].confirm(); //调用组件的confirm();
  423. },
  424. //关闭
  425. handleClose(done) {
  426. done();
  427. },
  428. // 附件上传
  429. beforeUpload(file) {
  430. const isJPG = /^image\/(jpeg|png|jpg)$/.test(file.type);
  431. const isLt2M = file.size / 1024 / 1024 < 5;
  432. if (!isJPG) {
  433. this.$message.error('上传图片只能是 JPEG,PNG,JPG 格式!');
  434. }
  435. if (!isLt2M) {
  436. this.$message.error('上传图片大小不能超过 5MB!');
  437. }
  438. return isJPG && isLt2M;
  439. },
  440. onFilePreView(file) {
  441. window.open(file.response.url, '_blank');
  442. },
  443. onFileRemove(file, fileList) {
  444. this.dialogData.items[this.itemIndex].fileList = fileList;
  445. this.dialogData.items[this.itemIndex].files = [];
  446. fileList.forEach((element, index) => {
  447. this.dialogData.items[this.itemIndex].files.push(element.url);
  448. });
  449. },
  450. handleFilesSuccess(response, file, fileList) {
  451. let fileListData=fileList.filter(e=>{
  452. return e.url
  453. })
  454. this.dialogData.items[this.itemIndex].fileList = fileListData;
  455. this.dialogData.items[this.itemIndex].files = [];
  456. fileListData.forEach((element, index) => {
  457. this.dialogData.items[this.itemIndex].files.push(element.url);
  458. });
  459. },
  460. // 选择审批人前提
  461. approval_selected_null(item) {
  462. if (!item.employee_id) {
  463. this.$message.error('请先选择录入对象');
  464. } else {
  465. this.fullscreenLoading = true;
  466. this.getEmployeeList(item.employee_id, function(res) {
  467. if (res.length > 0) {
  468. item.approval_employee_list = res;
  469. item.show_approval_selector = true;
  470. } else {
  471. this.$message.error('您没有审批人,请联系管理员');
  472. }
  473. });
  474. }
  475. },
  476. //获取人员(上级人员)
  477. getEmployeeList(userIdArr, callBack) {
  478. this.$axios('get', 'api/employee/superior', { employee_id: userIdArr, filter_applyor: 1 })
  479. .then(res => {
  480. callBack(res.data.data.list);
  481. })
  482. .finally(() => {
  483. this.fullscreenLoading = false;
  484. });
  485. },
  486. // 获取规则信息
  487. getRuleData() {
  488. let data = {
  489. cycle_type: '1'
  490. };
  491. this.integralType === 1 ? (data.pt_id = '1') : this.integralType === 2 ? (data.pt_id = '2') : (data.pt_id = '3');
  492. this.$axios('get', '/api/integral/rule/trees', data).then(res => {
  493. if (res.data.code == 1) {
  494. const resultData = res.data.data;
  495. this.rule_list = resultData.rule_tree;
  496. }
  497. this.rule_list = this.getTreeData(this.rule_list);
  498. });
  499. },
  500. // 获取规则细则
  501. getRuleItemData() {
  502. let data = { cycle_type: '1' };
  503. this.loading = true;
  504. this.$axios('get', '/api/integral/rule/trees', data, 'v2').then(res => {
  505. if (res.data.code == 1) {
  506. const resultData = res.data.data;
  507. this.rule_item_list = resultData.tree;
  508. this.flatteningIntegralRules = this.getItemDetail(this.rule_item_list);
  509. this.loading = false;
  510. }
  511. });
  512. },
  513. // 规则细则变化关闭down
  514. ruleItemChange(value) {
  515. const item = this.dialogData.items[this.itemIndex];
  516. if(value.length>0){
  517. let ruleItemDetail = null;
  518. this.flatteningIntegralRules.forEach(element => {
  519. if (element.id == value[value.length - 1]) {
  520. ruleItemDetail = { ...element };
  521. }
  522. });
  523. item.rule_item_details = ruleItemDetail;
  524. item.remark = ruleItemDetail.name;
  525. item.rule_id = ruleItemDetail.pid;
  526. item.pt_id = ruleItemDetail.pt_id;
  527. item.item_id = value[value.length - 1];
  528. item.item_name = ruleItemDetail.name;
  529. this.$refs.ruleItem.dropDownVisible = false;
  530. }else{
  531. item.rule_id = '';
  532. item.pt_id="";
  533. item.item_id = '';
  534. item.remark = '';
  535. item.item_name = '';
  536. item.rule_item_list_value = '';
  537. item.rule_item_details = { range_type: '' };
  538. }
  539. },
  540. // 递归判断列表,把最后的child设为undefined
  541. getTreeData(data) {
  542. for (var i = 0; i < data.length; i++) {
  543. if (data[i].child.length < 1) {
  544. // child若为空数组,则将child设为undefined
  545. data[i].child = undefined;
  546. } else {
  547. // child若不为空数组,则继续 递归调用 本方法
  548. this.getTreeData(data[i].child);
  549. }
  550. }
  551. return data;
  552. },
  553. // 选择对象
  554. async employee_confirm(data) {
  555. const item = this.dialogData.items[this.itemIndex];
  556. item.employeeName = '';
  557. item.employee_selected = { dept: [], employee: [] };
  558. item.employee_id = '';
  559. if (data.employee !== null && data.employee.length != 0) {
  560. item.employeeName = data.employee[0].name;
  561. item.employee_selected.employee = [{ name: data.employee[0].name, id: data.employee[0].id, img_url: data.employee[0].img_url }];
  562. item.employee_id = data.employee[0].id;
  563. var reviewerObj = await this.getLocalVal(data.employee[0].id);
  564. var revieObj = reviewerObj ? reviewerObj : { id: '', name: '' };
  565. // 清空审批人数据
  566. if (revieObj.id) {
  567. item.approval_selected = { dept: [], employee: [revieObj] };
  568. } else {
  569. item.approval_selected = { dept: [], employee: [] };
  570. }
  571. item.reviewer_id = revieObj.id;
  572. item.approvalName = revieObj.name;
  573. item.approval_employee_list = []; //当前选中人的 上级
  574. }
  575. item.show_employee_selector = false;
  576. },
  577. getItemDetail(arr) {
  578. let result = [];
  579. for (const item of arr) {
  580. var res = JSON.parse(JSON.stringify(item)); // 先克隆一份数据作为第一层级的填充
  581. delete res['child'];
  582. result.push(res);
  583. if (item.child instanceof Array && item.child.length > 0) {
  584. // 如果当前child为数组并且长度大于0,才可进入getItemDetail()方法
  585. result = result.concat(this.getItemDetail(item.child));
  586. }
  587. }
  588. return result;
  589. },
  590. // 加一条
  591. addItem() {
  592. // if(this.dialogData.items.length==10){
  593. // this.$message({
  594. // type:"warning",
  595. // message: '一次只能添加10条申请'
  596. // });
  597. // return false
  598. // }
  599. this.dialogData.items.push({
  600. rule_switch: true,
  601. rule_id: '',
  602. item_id: '',
  603. remark: '',
  604. event_time: moment().format('YYYY-MM-DD'),
  605. // 录入对象
  606. employee_id: this.user_info.id,
  607. employeeName: this.user_info.name,
  608. employee_selected: { dept: [], employee: [{ id: this.user_info.id, img_url: this.user_info.img_url, name: this.user_info.name }] },
  609. show_employee_selector: false,
  610. // 审批人信息
  611. reviewer_id: this.LocalValObj.id,
  612. approvalName: this.LocalValObj.name,
  613. approval_selected: { dept: [], employee: this.LocalValObj.id ? [this.LocalValObj] : [] },
  614. approval_employee_list: [], //当前选中人的 上级
  615. show_approval_selector: false,
  616. // 附件
  617. fileList: [],
  618. files: [],
  619. // 规则分类 与 规则细则 名称
  620. rule_list_value: null,
  621. rule_item_list_value: null,
  622. rule_item_details: { range_type: '' }
  623. });
  624. },
  625. closeDialog(formName) {
  626. this.dialogData.items = [
  627. {
  628. rule_switch: true,
  629. rule_id: '',
  630. item_id: '',
  631. remark: '',
  632. event_time: moment().format('YYYY-MM-DD'),
  633. // 录入对象
  634. employee_id: this.user_info.id,
  635. employeeName: this.user_info.name,
  636. employee_selected: { dept: [], employee: [{ id: this.user_info.id, img_url: this.user_info.img_url, name: this.user_info.name }] },
  637. show_employee_selector: false,
  638. // 审批人信息
  639. reviewer_id: '',
  640. approvalName: '',
  641. approval_employee_list: [], //当前选中人的 上级
  642. approval_selected: { dept: [], employee: [] },
  643. show_approval_selector: false,
  644. // 附件
  645. fileList: [],
  646. files: [],
  647. // 规则分类 与 规则细则 名称
  648. rule_list_value: null,
  649. rule_item_list_value: null,
  650. rule_item_details: { range_type: '' }
  651. }
  652. ];
  653. },
  654. delItem(index) {
  655. this.$confirm('你确定要删除奖扣明细' + parseInt(index + 1) + '吗?', '提示', {
  656. confirmButtonText: '确定',
  657. cancelButtonText: '取消',
  658. type: 'warning'
  659. }).then(() => {
  660. this.dialogData.items.splice(index, 1);
  661. this.$message({
  662. type: 'success',
  663. message: '删除成功!'
  664. });
  665. });
  666. },
  667. subData(formName) {
  668. this.$refs[formName].validate(valid => {
  669. if (valid) {
  670. this.save();
  671. }
  672. });
  673. },
  674. closeDialog2(){
  675. this.$emit('update:visible', false);
  676. },
  677. // 提交数据
  678. save() {
  679. let data = { items: [] };
  680. this.dialogData.items.forEach(element => {
  681. data.items.push({
  682. rule_id: element.rule_id || 0,
  683. employee_id: element.employee_id,
  684. item_id: element.item_id || 0,
  685. item_name: element.item_name,
  686. remark: element.remark,
  687. event_time: element.event_time,
  688. pt_id: element.pt_id,
  689. reviewer_id: element.reviewer_id || 0,
  690. approvalName: element.approvalName,
  691. files: element.files
  692. });
  693. });
  694. this.webSocket(data);
  695. // 走长连接处理
  696. return false;
  697. this.btn_loading = true;
  698. this.$axios('post', '/api/integral/review/apply', data)
  699. .then(res => {
  700. if (res.data.code == 1) {
  701. this.closeDialog();
  702. this.error_list = res.data.data.list;
  703. this.error_list_show = true;
  704. }
  705. })
  706. .finally(() => {
  707. this.btn_loading = false;
  708. data.items.forEach(element => {
  709. this.$setCache(element.employee_id,{ id: element.reviewer_id, name: element.approvalName });
  710. });
  711. });
  712. },
  713. webSocket(data){
  714. data.items.forEach(item=>{
  715. item.type='point_apply';
  716. this.$setCache(item.employee_id,{ id: item.reviewer_id, name: item.approvalName });
  717. })
  718. this.resultList=data.items;
  719. this.resultIndex=0;
  720. this.percentage=0;
  721. this.results=[];
  722. this.isResult=true;
  723. this.opneWebSocket()
  724. },
  725. opneWebSocket() {
  726. let wsData=this.resultList;
  727. if(wsData[this.resultIndex]){
  728. this.$socketApi.sendData(wsData[this.resultIndex],this.onmessageWS)
  729. }else{
  730. console.log(this.results)
  731. }
  732. },
  733. onmessageWS(e){
  734. if(e.type=='point_apply'){
  735. this.results.push(e.result);
  736. this.resultIndex++;
  737. this.opneWebSocket();
  738. // 进度条
  739. let lng = this.resultList.length;
  740. this.percentage += Math.floor(100 / lng);
  741. if (lng == this.results.length) {
  742. this.percentage = 100;
  743. }
  744. }
  745. // 中途断开
  746. if(e.type=='break'){
  747. let wsData=this.resultList;
  748. this.errorMsg=e.msg
  749. this.$setCache('apply_list',wsData.slice(this.resultIndex,wsData.length));
  750. this.isShowError2 = true;
  751. }
  752. // 连接不上
  753. if(e.type=='error'){
  754. this.errorMsg=e.msg
  755. this.isShowError = true;
  756. }
  757. },
  758. // 当switch 改变了
  759. switchChange(index, value) {
  760. this.itemIndex = index;
  761. const item = this.dialogData.items[this.itemIndex];
  762. if (!value) {
  763. item.rule_id = '';
  764. item.item_id = '';
  765. item.rule_item_list_value = '';
  766. item.remark = '';
  767. item.rule_item_details = { range_type: '' };
  768. } else {
  769. item.rule_id = '';
  770. item.rule_list_value = '';
  771. }
  772. },
  773. // 选择审核人
  774. approval_confirm(data) {
  775. const item = this.dialogData.items[this.itemIndex];
  776. item.approvalName = '';
  777. item.approval_selected = { dept: [], employee: [] };
  778. item.reviewer_id = '';
  779. if (data.employee !== null && data.employee.length != 0) {
  780. item.approvalName = data.employee[0].name;
  781. item.approval_selected.employee = [{ name: data.employee[0].name, id: data.employee[0].id, img_url: data.employee[0].img_url }];
  782. item.reviewer_id = data.employee[0].id;
  783. }
  784. item.show_approval_selector = false;
  785. }
  786. }
  787. };
  788. </script>
  789. <style lang="scss">
  790. .itemClass .el-cascader-menu .el-cascader-menu__wrap li.el-cascader-node {
  791. height: auto;
  792. max-width: 500px;
  793. .el-cascader-node__label {
  794. white-space: initial;
  795. overflow: initial;
  796. text-overflow: initial;
  797. }
  798. }
  799. .results {
  800. border-bottom: 1px solid #f1f1f1;
  801. text-align: center;
  802. }
  803. .results div {
  804. padding: 10px;
  805. }
  806. </style>