index.vue 29 KB

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