index.vue 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866
  1. <template>
  2. <div class="quicl-review" @scroll="handleScroll">
  3. <div class="card-container">
  4. <p>
  5. <el-button type="primary" @click="backPage" style="width: 80px">返回</el-button>
  6. </p>
  7. </div>
  8. <div class="card-container">
  9. <div class="search-content">
  10. <el-form :model="searchFrom" label-width="140px">
  11. <el-row>
  12. <el-col :span="6">
  13. <el-form-item label="执行包年度">
  14. <el-date-picker clearable class="w100" v-model="searchFrom.year" type="year" placeholder="请选择执行包年度" format="yyyy" value-format="yyyy"> </el-date-picker>
  15. </el-form-item>
  16. </el-col>
  17. <el-col :span="6">
  18. <el-form-item label="执行包季度">
  19. <el-select v-model="searchFrom.quarter" placeholder="请选择服务季度" class="w100" clearable>
  20. <el-option label="第一季度" :value="1"></el-option>
  21. <el-option label="第二季度" :value="2"></el-option>
  22. <el-option label="第三季度" :value="3"></el-option>
  23. <el-option label="第四季度" :value="4"></el-option>
  24. </el-select>
  25. </el-form-item>
  26. </el-col>
  27. <el-col :span="6">
  28. <el-form-item label="服务提交时间">
  29. <el-date-picker class="w100" clearable v-model="searchFrom.createTime" type="date" placeholder="选择日期" format="yyyy-MM-dd" value-format="yyyy-MM-dd">
  30. </el-date-picker>
  31. </el-form-item>
  32. </el-col>
  33. <el-col :span="6">
  34. <el-form-item label="服务类型">
  35. <el-select v-model="searchFrom.taskTypeId" placeholder="请选择服务类型" class="w100" clearable>
  36. <el-option :label="item.name" :value="item.id" v-for="item in taskTypeAvailArr" :key="item.id"></el-option>
  37. </el-select>
  38. </el-form-item>
  39. </el-col>
  40. </el-row>
  41. <el-row>
  42. <el-col :span="6">
  43. <el-form-item label="服务提供商">
  44. <el-select v-model="searchFrom.vendorId" placeholder="请选择服务提供商" class="w100" clearable filterable>
  45. <el-option v-for="item in deptListArr" :key="item.entId" :label="item.name" :value="item.entId" />
  46. </el-select>
  47. </el-form-item>
  48. </el-col>
  49. <el-col :span="6">
  50. <el-form-item label="推广员姓名">
  51. <el-select v-model="searchFrom.salesId" placeholder="请选择推广员姓名" class="w100" clearable filterable>
  52. <el-option v-for="item in userListArr" :key="item.userId" :label="item.realName" :value="item.userId" />
  53. </el-select>
  54. </el-form-item>
  55. </el-col>
  56. <el-col :span="6">
  57. <el-form-item label="产品所属生产企业">
  58. <el-select v-model="searchFrom.mahName" @change="mahNameChange" placeholder="请选择产品所属生产企业" class="w100" clearable>
  59. <el-option v-for="item in mahNameArr" :key="item.value" :label="item.label" :value="item.value" />
  60. </el-select>
  61. </el-form-item>
  62. </el-col>
  63. <el-col :span="6">
  64. <el-form-item label="关联产品名称">
  65. <el-select v-model="searchFrom.skuId" placeholder="请选择关联产品名称" class="w100" :disabled="drugDisabled" clearable filterable>
  66. <el-option v-for="item in currDrugList" :key="item.id" :label="item.drugName" :value="item.id" />
  67. </el-select>
  68. </el-form-item>
  69. </el-col>
  70. </el-row>
  71. <el-row>
  72. <el-col :span="6">
  73. <el-form-item label="执行包所属省份">
  74. <el-select v-model="searchFrom.provAbbr" placeholder="请选择省份" class="w100" clearable>
  75. <el-option v-for="province in abbreviationsProvincesList" :key="province" :label="province" :value="province" />
  76. </el-select>
  77. </el-form-item>
  78. </el-col>
  79. <el-col :span="2">
  80. <div class="search-btns">
  81. <el-button type="success" @click="clickBtn">搜索</el-button>
  82. <el-button @click="clearSearch">清空</el-button>
  83. </div>
  84. </el-col>
  85. </el-row>
  86. </el-form>
  87. </div>
  88. </div>
  89. <div class="card-container">
  90. <div class="card-all-review">
  91. <div class="btns">
  92. <el-button type="primary" @click="allClick">批量审核</el-button>
  93. </div>
  94. <div class="check-info">
  95. <el-checkbox v-model="allCheck" @change="allClick">全选</el-checkbox>
  96. <p>当前已选择{{ checkAllLength }}项,总积分:{{ checkAllTaskScore }}</p>
  97. </div>
  98. </div>
  99. </div>
  100. <div class="card-list card-container" v-loading="getPageLoading">
  101. <template v-if="list.length === 0">
  102. <div class="no-data">
  103. <el-empty description="暂无数据"></el-empty>
  104. </div>
  105. </template>
  106. <div class="cards" v-masonry :cols="2" :gutter="20" style="width: 100%">
  107. <template v-for="curr in list">
  108. <div class="card" v-masonry-tile :key="curr.info.taskId" v-if="curr.reviewInfo.show">
  109. <div class="task-info">
  110. <div class="task-type-info">
  111. <el-checkbox
  112. v-model="curr.reviewInfo.checked"
  113. @change="
  114. (val) => {
  115. itemChecked(val, curr);
  116. }
  117. "
  118. ></el-checkbox>
  119. 服务类型: {{ getName(curr?.info.taskTypeId) }}
  120. </div>
  121. <div class="info">
  122. <p>任务ID:{{ curr?.info.taskId }}</p>
  123. <p>任务编号:{{ curr?.info.taskNumber }}</p>
  124. </div>
  125. <div class="info">
  126. <p>服务积分:{{ curr?.info.taskScore }}</p>
  127. <p>代表姓名:{{ curr?.info.salesName }}</p>
  128. </div>
  129. <div class="info">
  130. <p>产品名称:{{ curr?.info.skuName }}</p>
  131. <p>生产企业:{{ curr?.info.mahName }}</p>
  132. </div>
  133. <div class="info">
  134. <p>执行包名称:{{ curr?.info.pkgName }}</p>
  135. <p>起止时间:{{ curr?.info.pkgStartTime }} ~ {{ curr?.info.pkgEndTime }}</p>
  136. </div>
  137. </div>
  138. <div class="detail">服务详情</div>
  139. <template v-if="curr?.info?.configs">
  140. <div v-for="(item, index) in curr?.info?.configs" :key="index" class="field-box">
  141. <template v-if="item.taskFiledType == 'domain' || item.taskFiledType == 'select'">
  142. <div class="title-value">{{ item.taskFiledValue }}:</div>
  143. <div class="desc-value" v-show="!(item.taskTypeId == '19' && item.taskFiledKey == 'temp3')">
  144. {{ getDesc(curr.info, item) }}
  145. </div>
  146. </template>
  147. <!-- * 文本类型 -->
  148. <template v-if="typeArr.includes(item.taskFiledType)">
  149. <div class="title-value">{{ item.taskFiledValue }}:</div>
  150. <div class="desc-value">
  151. {{ curr.info.taskContent[item.taskFiledKey] || '--' }}
  152. </div>
  153. </template>
  154. <!-- 图片上传 -->
  155. <div v-if="item.taskFiledType == 'img'" class="divline" style="width: 100%; height: 15px; background-color: #e9e9e9; margin-bottom: 5px"></div>
  156. <template v-if="item.taskFiledType == 'img'">
  157. <div class="upload-field">
  158. <div class="field-text" :class="{ required: item.isMustfill == '1' }">{{ item.taskFiledValue }}:</div>
  159. <!-- 上传组件 -->
  160. <div class="img-box" v-if="item.imgList">
  161. <div v-for="(iItem, index) in item.imgList" :key="index" class="img-box-content">
  162. <span class="type">{{ iItem.type }}</span>
  163. <el-image class="img-item" lazy :src="iItem.url" :preview-src-list="getPreviewList(item.previewList, index)" />
  164. </div>
  165. </div>
  166. </div>
  167. </template>
  168. <!-- 长文本 -->
  169. <template v-if="item.taskFiledType == 'longtext'">
  170. <div class="longtext-box">
  171. <div class="field-text" :class="{ required: item.isMustfill == '1' }">{{ item.taskFiledValue }}:</div>
  172. <textarea class="textarea-box" :disabled="true" :value="curr.info.taskContent[item.taskFiledKey] || '--'" :maxlength="item.taskFiledMaxsize" />
  173. </div>
  174. </template>
  175. </div>
  176. </template>
  177. <div class="divline" style="width: 100%; height: 15px; background-color: #e9e9e9; margin-bottom: 5px"></div>
  178. <div class="longtext-box review-textarea">
  179. <div class="field-text">意见说明</div>
  180. <el-input type="textarea" class="textarea-box" resize="none" v-model="curr.reviewInfo.checkMessage" />
  181. </div>
  182. <div class="btns">
  183. <el-button class="btn" type="danger" @click="passClick(curr, false)">不通过</el-button>
  184. <el-button class="btn" type="primary" @click="passClick(curr, true)">通过</el-button>
  185. </div>
  186. </div>
  187. </template>
  188. </div>
  189. </div>
  190. <!-- 审核弹窗 -->
  191. <el-dialog title="审核" :close-on-click-modal="false" :visible.sync="reviewDialog" top="12vh" width="50%" :before-close="handleClose" center>
  192. <div class="reviewContent" v-loading="loading">
  193. <div class="check-tips">审核令牌有效期为3分钟,请在【{{ expireTime }}】前完成审核操作,如果失效,请重新打开弹窗。</div>
  194. <div class="teskDetailsty">审批意见</div>
  195. <el-form :model="taskForm" :rules="rules" ref="taskForm" label-width="100px">
  196. <el-form-item label="审批意见:" prop="checkResult" class="formitem-box">
  197. <el-radio-group v-model="taskForm.checkResult">
  198. <el-radio :label="true">通过</el-radio>
  199. <el-radio :label="false">拒绝</el-radio>
  200. </el-radio-group>
  201. </el-form-item>
  202. <el-form-item
  203. label="意见说明:"
  204. prop="checkMessage"
  205. class="formitem-box"
  206. :rules="[
  207. {
  208. required: !taskForm.checkResult,
  209. message: '请输入审批说明',
  210. trigger: 'blur'
  211. }
  212. ]"
  213. >
  214. <el-input type="textarea" v-model="taskForm.checkMessage"></el-input>
  215. </el-form-item>
  216. <refuseReason @selectRefuseReason="selectRefuseReason" />
  217. </el-form>
  218. </div>
  219. <span slot="footer" class="dialog-footer">
  220. <el-button @click="handleClose">取 消</el-button>
  221. <el-button type="primary" @click="checkForm" v-loading="loading">确 定</el-button>
  222. </span>
  223. </el-dialog>
  224. </div>
  225. </template>
  226. <script>
  227. import {
  228. getTaskV2PageApi,
  229. getTaskTypeAvailApi,
  230. getDeptv2Avail,
  231. getDrug2Avail,
  232. getUserV2Avail,
  233. getTaskV2TokenApi,
  234. taskV2CheckBatchApi,
  235. checkSingleApi,
  236. getTaskV2PageTileApi
  237. } from '@/api/serviceManagement/servicesToBeReviewed/index.js';
  238. import refuseReason from '@/components/refuseReason';
  239. import { getDictType } from '@/api/common';
  240. import abbreviationsProvinces from '@/const/abbreviationsProvinces.js';
  241. import dayjs from 'dayjs';
  242. import { mapGetters } from 'vuex';
  243. export default {
  244. components: { refuseReason },
  245. data() {
  246. return {
  247. typeArr: ['area', 'text', 'inputautoselect', 'map', 'mapwithimg', 'datetime', 'datatimerange', 'money', 'number', ''],
  248. taskStatusArr: [],
  249. taskTypeAvailArr: [],
  250. mahNameArr: [],
  251. deptListArr: [],
  252. drugListArr: [],
  253. userListArr: [],
  254. currDrugList: [],
  255. drugDisabled: true,
  256. abbreviationsProvincesList: abbreviationsProvinces,
  257. nodeId: '',
  258. getPageLoading: false,
  259. searchFrom: {
  260. year: '',
  261. taskTypeId: '',
  262. quarter: '',
  263. createTime: '',
  264. provAbbr: '',
  265. mahName: '',
  266. vendorId: '',
  267. salesId: '',
  268. skuId: '',
  269. taskStatus: 3
  270. },
  271. page: {
  272. total: 0,
  273. currentPage: 1,
  274. pageSize: 10
  275. },
  276. nodeId: '',
  277. list: [],
  278. allCheck: false,
  279. checkAllLength: 0,
  280. checkAllTaskScore: 0,
  281. checkIds: [],
  282. reviewToken: '',
  283. expireTime: '',
  284. reviewDialog: false,
  285. taskForm: {
  286. checkResult: '',
  287. checkMessage: ''
  288. },
  289. rules: {
  290. checkResult: [{ required: true, message: '请选择审批意见', trigger: 'change' }]
  291. },
  292. loading: false
  293. };
  294. },
  295. async created() {
  296. await this.getDict();
  297. },
  298. computed: {
  299. ...mapGetters(['userInfo'])
  300. },
  301. mounted() {
  302. window.addEventListener('scroll', this.handleScroll);
  303. const roles = this.userInfo.roles;
  304. let nodeId = '';
  305. switch (true) {
  306. // 43 地市管理员
  307. case roles.includes(43):
  308. nodeId = 1;
  309. break;
  310. // 4 区域管理员
  311. case roles.includes(4):
  312. nodeId = 2;
  313. break;
  314. // 42 市场管理员: 获取审核节点为3和9 nodeid为12
  315. case roles.includes(42):
  316. nodeId = 12;
  317. break;
  318. // 40 商务管理员: 获取审核节点为3和8 nodeid为11
  319. case roles.includes(40):
  320. nodeId = 11;
  321. break;
  322. // 41 事业部分管领导
  323. case roles.includes(41):
  324. nodeId = 9;
  325. break;
  326. // 39 事业部总经理
  327. case roles.includes(39):
  328. nodeId = 15;
  329. break;
  330. default:
  331. nodeId = 1;
  332. }
  333. const currentYear = dayjs().format('YYYY');
  334. this.searchFrom.year = currentYear;
  335. this.nodeId = nodeId;
  336. this.searchFrom.nodeId = nodeId;
  337. this.getList();
  338. },
  339. beforeDestroy() {
  340. window.removeEventListener('scroll', this.handleScroll);
  341. },
  342. methods: {
  343. handleScroll(event) {
  344. const scrollHeight = event.target.scrollHeight; // 获取滚动元素的总高度
  345. const scrollTop = event.target.scrollTop; // 获取滚动元素的当前滚动高度
  346. const windowHeight = event.target.clientHeight; // 获取滚动元素的可视区域高度
  347. if (scrollTop + windowHeight >= scrollHeight - 10) {
  348. if (!this.getPageLoading && this.page.total > this.page.currentPage * this.page.pageSize) {
  349. this.page.currentPage += 1;
  350. this.getList();
  351. }
  352. }
  353. },
  354. getDict() {
  355. getDictType({ type: 'task_status' }).then((res) => {
  356. this.taskStatusArr = res.data.data;
  357. });
  358. getDictType({ type: 'mah_name' }).then((res) => {
  359. this.mahNameArr = res.data.data;
  360. });
  361. getTaskTypeAvailApi().then((res) => {
  362. this.taskTypeAvailArr = res.data.data;
  363. });
  364. getDeptv2Avail().then((res) => {
  365. this.deptListArr = res.data.data;
  366. });
  367. getUserV2Avail().then((res) => {
  368. this.userListArr = res.data.data;
  369. });
  370. getDrug2Avail().then((res) => {
  371. this.drugListArr = res.data.data;
  372. });
  373. },
  374. mahNameChange(e) {
  375. if (e) {
  376. const curr = this.drugListArr[e];
  377. this.currDrugList = curr;
  378. this.drugDisabled = false;
  379. } else {
  380. this.searchFrom.skuId = '';
  381. this.currDrugList = [];
  382. this.drugDisabled = true;
  383. }
  384. },
  385. async getList() {
  386. this.getPageLoading = true;
  387. const obj = Object.assign(
  388. {
  389. current: this.page.currentPage,
  390. size: this.page.pageSize
  391. },
  392. this.searchFrom
  393. );
  394. try {
  395. const res = await getTaskV2PageTileApi(obj);
  396. if (res.data.code === 0) {
  397. let list = res.data.data.records;
  398. // this.list.push(...res.data.data.records);
  399. this.page.total = res.data.data.total;
  400. list.forEach((item) => {
  401. let reviewInfo = {
  402. checked: false,
  403. checkMessage: '',
  404. show: true
  405. };
  406. item.reviewInfo = reviewInfo;
  407. });
  408. this.list.push(...list);
  409. this.$forceUpdate();
  410. this.getPageLoading = false;
  411. }
  412. } catch (err) {
  413. console.log('err', err);
  414. this.getPageLoading = false;
  415. }
  416. },
  417. allClick(val) {
  418. if (val) {
  419. this.list.forEach((item) => (item.reviewInfo.checked = true));
  420. this.$forceUpdate();
  421. this.calcInfo();
  422. }
  423. },
  424. calcInfo() {
  425. let checkAllLength = 0;
  426. let checkAllTaskScore = 0;
  427. let ids = [];
  428. this.list.forEach((item) => {
  429. if (item.reviewInfo.checked) {
  430. checkAllLength++;
  431. checkAllTaskScore += Number(item.info.taskScore);
  432. ids.push(item.info.taskId);
  433. }
  434. });
  435. this.checkAllLength = checkAllLength;
  436. this.checkAllTaskScore = checkAllTaskScore;
  437. this.checkIds = ids;
  438. },
  439. itemChecked(val, item) {
  440. this.$forceUpdate();
  441. if (val) {
  442. this.checkAllLength++;
  443. this.checkIds.push(item.info.taskId);
  444. this.checkAllTaskScore += Number(item.info.taskScore);
  445. } else {
  446. this.checkAllLength--;
  447. let index = this.checkIds.findIndex((curr) => curr === item.info.taskId);
  448. this.checkIds.splice(index, 1);
  449. this.checkAllTaskScore -= Number(item.info.taskScore);
  450. }
  451. },
  452. async allClick() {
  453. if (!this.checkIds.length) {
  454. return this.$message.error('请选择待审核数据');
  455. }
  456. await this.getToken(this.checkIds);
  457. this.reviewDialog = true;
  458. },
  459. async getToken(taskIds) {
  460. const tokenRes = await getTaskV2TokenApi({ taskIds: taskIds });
  461. if (tokenRes.data.code !== 0 || !tokenRes.data.data?.token) {
  462. return this.$message.error('获取token失败');
  463. }
  464. this.reviewToken = tokenRes.data.data.token;
  465. this.expireTime = tokenRes.data.data.expireTime;
  466. },
  467. handleClose() {
  468. this.reviewDialog = false;
  469. this.taskForm = {
  470. checkResult: '',
  471. checkMessage: ''
  472. };
  473. },
  474. clickBtn() {
  475. this.tableData = [];
  476. this.page.currentPage = 1;
  477. this.getList();
  478. },
  479. clearSearch() {
  480. this.searchFrom = {
  481. year: '',
  482. taskTypeId: '',
  483. quarter: '',
  484. createTime: '',
  485. provAbbr: '',
  486. mahName: '',
  487. vendorId: '',
  488. salesId: '',
  489. skuId: '',
  490. taskStatus: 3
  491. };
  492. this.searchFrom.nodeId = this.nodeId;
  493. },
  494. getName(taskType) {
  495. let curr = this.taskTypeAvailArr.find((item) => item.id == taskType);
  496. return curr.name;
  497. },
  498. getDesc(curr, item) {
  499. // 拜访类任务
  500. const arr = ['51', '52', '53'];
  501. if (arr.includes(item.taskTypeId) && item.taskFiledKey === 'temp24') {
  502. return curr.taskContent['temp24label'];
  503. }
  504. // 获取需要转换的字符串(例如 '1,2,3')
  505. const contentValue = curr.taskContent[item.taskFiledKey];
  506. if (!contentValue) return '--';
  507. // 获取字典表对应数组
  508. const itemList = curr.dict[item.dictGroupName] || [];
  509. // 按逗号拆分成数组
  510. const valueArray = contentValue.split(',');
  511. // 将每个拆分值找到对应的 label
  512. const result = valueArray.map((val) => {
  513. const foundItem = itemList.find((dictItem) => dictItem.value === val);
  514. return foundItem ? foundItem.label : null;
  515. });
  516. // 如果有任意一个值无法找到对应的 label,则直接返回 '--'
  517. if (result.some((label) => label === null)) {
  518. return '--';
  519. }
  520. // 否则,使用逗号拼接并返回
  521. return result.join(',');
  522. },
  523. async passClick(item, flag) {
  524. if (!flag && !item.reviewInfo.checkMessage) {
  525. return this.$message.error('请填写审核意见');
  526. }
  527. //
  528. let nodeId = '';
  529. const roles = this.userInfo.roles;
  530. switch (true) {
  531. // 43 地市管理员
  532. case roles.includes(43):
  533. nodeId = 2;
  534. break;
  535. // 4 区域管理员
  536. case roles.includes(4):
  537. nodeId = 3;
  538. break;
  539. // 42 市场管理员
  540. case roles.includes(42):
  541. nodeId = 8;
  542. break;
  543. // 40 商务管理员
  544. case roles.includes(40):
  545. nodeId = 9;
  546. break;
  547. // 39 事业部总经理
  548. case roles.includes(39):
  549. nodeId = 6;
  550. break;
  551. // 41 事业部分管领导
  552. case roles.includes(41):
  553. nodeId = 5;
  554. break;
  555. default:
  556. nodeId = 1;
  557. }
  558. let obj = {
  559. token: item.token.token,
  560. taskId: item.token.value,
  561. checkResult: flag,
  562. checkMessage: item.reviewInfo.checkMessage,
  563. nodeId: nodeId
  564. };
  565. try {
  566. const res = await checkSingleApi(obj);
  567. if (res.data.code === 0 && res.data.data) {
  568. item.reviewInfo.show = false;
  569. this.$forceUpdate();
  570. }
  571. } catch (err) {
  572. console.log('err', err);
  573. }
  574. },
  575. checkForm() {
  576. let nodeId = '';
  577. const roles = this.userInfo.roles;
  578. switch (true) {
  579. // 43 地市管理员
  580. case roles.includes(43):
  581. nodeId = 2;
  582. break;
  583. // 4 区域管理员
  584. case roles.includes(4):
  585. nodeId = 3;
  586. break;
  587. // 42 市场管理员
  588. case roles.includes(42):
  589. nodeId = 8;
  590. break;
  591. // 40 商务管理员
  592. case roles.includes(40):
  593. nodeId = 9;
  594. break;
  595. // 39 事业部总经理
  596. case roles.includes(39):
  597. nodeId = 6;
  598. break;
  599. // 41 事业部分管领导
  600. case roles.includes(41):
  601. nodeId = 5;
  602. break;
  603. default:
  604. nodeId = 1;
  605. }
  606. this.$refs.taskForm.validate(async (valid) => {
  607. if (valid) {
  608. let obj = {
  609. token: this.reviewToken,
  610. taskIds: this.checkIds,
  611. checkResult: this.taskForm.checkResult,
  612. checkMessage: this.taskForm.checkMessage,
  613. nodeId: nodeId
  614. };
  615. try {
  616. const res = await taskV2CheckBatchApi(obj);
  617. if (res.data.code === 0 && res.data.data) {
  618. this.$message.success('审核成功!');
  619. this.handleClose();
  620. this.list.forEach((item) => {
  621. if (item.reviewInfo.checked) {
  622. console.log('item', item);
  623. item.reviewInfo.show = false;
  624. }
  625. });
  626. }
  627. this.loading = false;
  628. } catch (err) {
  629. this.loading = false;
  630. console.log('err', err);
  631. }
  632. }
  633. });
  634. },
  635. selectRefuseReason(refuseReason) {
  636. let info;
  637. if (this.taskForm.checkMessage) {
  638. info = this.taskForm.checkMessage + refuseReason + ';';
  639. } else {
  640. info = refuseReason + ';';
  641. }
  642. this.$set(this.taskForm, 'checkMessage', info);
  643. },
  644. backPage() {
  645. this.$router.$avueRouter.closeTag();
  646. this.$router.back();
  647. }
  648. }
  649. };
  650. </script>
  651. <style lang="scss" scoped>
  652. .quicl-review {
  653. overflow: auto;
  654. height: 100%;
  655. padding-bottom: 30px;
  656. .card-container {
  657. margin: 0 10px;
  658. margin-bottom: 10px;
  659. padding: 20px;
  660. border-radius: 10px;
  661. background: #fff;
  662. box-sizing: border-box;
  663. }
  664. }
  665. .search-btns {
  666. margin-left: 50px;
  667. display: flex;
  668. justify-content: space-between;
  669. }
  670. .card-list {
  671. overflow: auto;
  672. min-height: 200px;
  673. box-sizing: border-box;
  674. .cards {
  675. box-sizing: border-box;
  676. width: 100%;
  677. padding: 10px;
  678. }
  679. .card {
  680. box-sizing: border-box;
  681. border-radius: 4px;
  682. box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.2);
  683. border: 1px solid #ebeef5;
  684. background-color: #fff;
  685. color: #303133;
  686. transition: 0.3s;
  687. min-height: 300px;
  688. width: 48%;
  689. // min-width: 500px;
  690. margin-bottom: 10px;
  691. padding: 10px;
  692. }
  693. .task-type-info {
  694. font-size: 16px;
  695. color: #333;
  696. font-weight: 600;
  697. margin-bottom: 5px;
  698. }
  699. .info {
  700. display: flex;
  701. font-size: 12px;
  702. color: #7f7f7f;
  703. margin-bottom: 5px;
  704. p {
  705. flex: 1;
  706. margin-right: 30px;
  707. }
  708. }
  709. .detail {
  710. font-size: 14px;
  711. font-weight: 500;
  712. color: #333333;
  713. border-bottom: 2px solid #d7d6d5;
  714. line-height: 30px;
  715. margin: 5px 0;
  716. }
  717. }
  718. .field-box {
  719. padding: 0 10px 5px;
  720. overflow: hidden;
  721. .title-value {
  722. //width: 50%;
  723. float: left;
  724. }
  725. .desc-value {
  726. float: left;
  727. }
  728. .upload-field {
  729. .img-box {
  730. padding-top: 5px;
  731. display: flex;
  732. }
  733. .file-box {
  734. .file-item {
  735. padding: 2px 8px;
  736. cursor: pointer;
  737. &:hover {
  738. background-color: #f5f7fa;
  739. color: #2d8cf0;
  740. }
  741. }
  742. }
  743. }
  744. .img-box-content {
  745. padding-top: 15px;
  746. position: relative;
  747. .type {
  748. font-size: 12px;
  749. position: absolute;
  750. top: 0;
  751. }
  752. }
  753. .img-item {
  754. width: 100px;
  755. height: 100px;
  756. margin-right: 5px;
  757. }
  758. .divline {
  759. width: 100%;
  760. height: 5px;
  761. background-color: #e9e9e9;
  762. margin-bottom: 5px;
  763. }
  764. .img-iten {
  765. height: 60px;
  766. margin-right: 5px;
  767. width: 50px;
  768. cursor: pointer;
  769. }
  770. }
  771. .longtext-box {
  772. .textarea-box {
  773. margin-top: 5px !important;
  774. width: 100%;
  775. padding: 3px;
  776. }
  777. }
  778. .no-data {
  779. margin: 0 auto;
  780. }
  781. .btns {
  782. padding: 0 20px;
  783. padding-top: 5px;
  784. display: flex;
  785. justify-content: space-between;
  786. .btn {
  787. width: 48%;
  788. }
  789. }
  790. .card-all-review {
  791. width: 350px;
  792. }
  793. .check-info {
  794. padding-left: 20px;
  795. margin-top: 10px;
  796. display: flex;
  797. height: 30px;
  798. align-items: center;
  799. p {
  800. color: #85ce61;
  801. border-radius: 3px;
  802. line-height: 14px;
  803. font-size: 14px;
  804. }
  805. }
  806. .teskDetailsty {
  807. width: 100%;
  808. height: 30px;
  809. line-height: 30px;
  810. font-size: 16px;
  811. font-weight: 600;
  812. color: #333333;
  813. border-bottom: 1px solid #d7d6d5;
  814. margin: 0 0 10px 0;
  815. }
  816. .check-btns {
  817. width: 150px;
  818. display: flex;
  819. justify-content: space-between;
  820. }
  821. .check-tips {
  822. margin-bottom: 5px;
  823. font-size: 16px;
  824. color: rgb(233 77 77);
  825. text-align: center;
  826. font-weight: 600;
  827. }
  828. </style>