index.vue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593
  1. <template>
  2. <div class="ele-body">
  3. <el-card shadow="never" v-loading="loading">
  4. <work-search
  5. class="seep-search"
  6. ref="workSearch"
  7. :levelList="levelList"
  8. @search="reload"
  9. ></work-search>
  10. <el-tabs v-model="orderStatus" type="card" @tab-click="handleClick">
  11. <el-tab-pane label="全部" name="all"></el-tab-pane>
  12. <el-tab-pane label="待执行" name="0"></el-tab-pane>
  13. <el-tab-pane label="执行中" name="1"></el-tab-pane>
  14. <el-tab-pane label="待验收" name="3"></el-tab-pane>
  15. <el-tab-pane label="已完成" name="5"></el-tab-pane>
  16. </el-tabs>
  17. <!-- 数据表格 -->
  18. <ele-pro-table
  19. ref="table"
  20. :columns="columns"
  21. :datasource="datasource"
  22. cache-key="systemRoleTable"
  23. :pageSize="20"
  24. >
  25. <!-- 表头工具栏 -->
  26. <template v-slot:toolbar></template>
  27. <template v-slot:code="{ row }">
  28. <el-link
  29. type="primary"
  30. :underline="false"
  31. @click="declarationForm(row, 'view')"
  32. >{{ row.code }}</el-link
  33. >
  34. </template>
  35. <!-- 操作列 -->
  36. <template v-slot:action="{ row }">
  37. <el-link
  38. type="primary"
  39. :underline="false"
  40. @click="declarationForm(row, 'edit')"
  41. v-if="
  42. (row.orderStatus == 1 || row.orderStatus == 6) &&
  43. $hasPermission('eom:aftersalesworkorder:update')
  44. "
  45. >修改</el-link
  46. >
  47. <el-link
  48. type="primary"
  49. :underline="false"
  50. @click="declarationForm(row, 'report')"
  51. v-if="
  52. (row.orderStatus == 1 || row.orderStatus == 6) &&
  53. $hasPermission('eom:aftersalesworkorder:reportWorking')
  54. "
  55. >报工</el-link
  56. >
  57. <el-link
  58. type="primary"
  59. v-if="
  60. row.orderStatus == 0 &&
  61. $hasPermission('eom:aftersalesworkorder:receive')
  62. "
  63. :underline="false"
  64. @click="handleCommand('handleReceive', row)"
  65. >接收</el-link
  66. >
  67. <el-link
  68. type="primary"
  69. v-if="
  70. (row.orderStatus == 0 || row.orderStatus == 1) &&
  71. $hasPermission('eom:aftersalesworkorder:reassignment')
  72. "
  73. :underline="false"
  74. @click="handleCommand('toRedeploy', row)"
  75. >转派</el-link
  76. >
  77. <el-link
  78. type="primary"
  79. v-if="
  80. (row.orderStatus == 1 || row.orderStatus == 2) &&
  81. $hasPermission('eom:sparepartsapply:save')
  82. "
  83. :underline="false"
  84. @click="handleCommand('addSpareItems', row)"
  85. >申请配件</el-link
  86. >
  87. <el-link
  88. type="primary"
  89. v-if="
  90. acceptShow(row) &&
  91. $hasPermission('eom:aftersalesworkorder:checkAndAccept')
  92. "
  93. :underline="false"
  94. @click="handleCommand('checkAndAccept', row)"
  95. >验收</el-link
  96. >
  97. <!-- v-if="row.orderStatus == 4" -->
  98. <el-link
  99. type="primary"
  100. v-if="
  101. evaluateShow(row) &&
  102. $hasPermission('eom:aftersalesworkorder:comment')
  103. "
  104. :underline="false"
  105. @click="handleCommand('evaluate', row)"
  106. >评价</el-link
  107. >
  108. </template>
  109. </ele-pro-table>
  110. </el-card>
  111. <!-- 详情 -->
  112. <detailDialog ref="detailDialogRef"></detailDialog>
  113. <!-- 备品备件 -->
  114. <applyForSpare @reload="reload" ref="edit" />
  115. <!-- 报工 -->
  116. <declarationDialog
  117. ref="declarationDialogRef"
  118. @reload="reload"
  119. ></declarationDialog>
  120. <!-- 转派 -->
  121. <redeployOther ref="redeployOtherRef" @reload="reload" />
  122. <ele-modal
  123. custom-class="ele-dialog-form long-dialog-form"
  124. :visible.sync="visibleCheckAndAccept"
  125. title="验收"
  126. :close-on-click-modal="false"
  127. width="500px"
  128. append-to-body
  129. :maxable="true"
  130. >
  131. <div>
  132. <el-form
  133. ref="form"
  134. :model="form"
  135. label-width="100px"
  136. class="create-form"
  137. >
  138. <el-form-item label="验收人" prop="accepterUserId">
  139. <el-select
  140. v-model="form.accepterUserId"
  141. size="small"
  142. style="width: 100%"
  143. >
  144. <el-option
  145. :value="item.id"
  146. :label="item.contactName"
  147. v-for="(item, index) in contactInfoVOS"
  148. @click.native="accepterUserChange(item)"
  149. :key="index"
  150. ></el-option>
  151. </el-select>
  152. </el-form-item>
  153. <el-form-item label="验收意见" prop="accepterRemark">
  154. <el-input
  155. placeholder="请输入内容"
  156. v-model="form.accepterRemark"
  157. type="textarea"
  158. ></el-input>
  159. </el-form-item>
  160. <el-form-item label="附件" prop="accepterAttachments">
  161. <fileMain v-model="form.accepterAttachments"></fileMain>
  162. </el-form-item>
  163. </el-form>
  164. </div>
  165. <div slot="footer" class="footer">
  166. <el-button type="primary" @click="checkAndAccept(1)">通过</el-button>
  167. <el-button type="primary" @click="checkAndAccept(0)">不通过</el-button>
  168. <el-button @click="visibleCheckAndAccept = false">取消</el-button>
  169. </div>
  170. </ele-modal>
  171. <addDialog ref="addDialogRef" @success="reload"></addDialog>
  172. </div>
  173. </template>
  174. <script>
  175. // import fileMain from '@/components/addDoc/index.vue';
  176. import workSearch from './components/work-search.vue';
  177. import detailDialog from './components/detailDialog.vue';
  178. import applyForSpare from '../components/applyForSpare.vue';
  179. import declarationDialog from './components/declarationDialog.vue';
  180. import redeployOther from './components/redeployOther2.vue';
  181. import addDialog from '@/views/salesServiceManagement/evaluate/components/addDialog.vue';
  182. import {
  183. getSalesWorkOrder,
  184. deleteSalesWorkOrder,
  185. receiveSalesWorkOrder,
  186. checkAndAccept,
  187. getSalesWorkOrderById,
  188. checkByWorkId,
  189. afterSalesEvaluation
  190. } from '@/api/salesServiceManagement/index';
  191. import { getByCode } from '@/api/system/dictionary-data';
  192. import dictMixins from '@/mixins/dictMixins';
  193. export default {
  194. mixins: [dictMixins],
  195. components: {
  196. workSearch,
  197. detailDialog,
  198. applyForSpare,
  199. declarationDialog,
  200. redeployOther,
  201. addDialog,
  202. // fileMain
  203. },
  204. data() {
  205. return {
  206. visibleCheckAndAccept: false,
  207. form: {
  208. accepterUserId: '',
  209. accepterUserName: '',
  210. accepterRemark: ''
  211. },
  212. contactInfoVOS: [],
  213. workOrderStatus: [
  214. // { code: 0, label: '待接收' },
  215. { code: 0, label: '待执行' },
  216. { code: 1, label: '已接收' },
  217. { code: 2, label: '执行中' },
  218. { code: 3, label: '待验收' },
  219. { code: 4, label: '待评价' },
  220. { code: 5, label: '已完成' },
  221. { code: 6, label: '验收不通过' }
  222. ],
  223. resultStatus: [
  224. { code: 5, label: '未修复' },
  225. { code: 4, label: '已修复' }
  226. ],
  227. // 表格列配置
  228. columns: [
  229. {
  230. columnKey: 'index',
  231. label: '序号',
  232. type: 'index',
  233. width: 55,
  234. align: 'center',
  235. showOverflowTooltip: true,
  236. fixed: 'left'
  237. },
  238. {
  239. prop: 'code',
  240. slot: 'code',
  241. label: '工单编号',
  242. align: 'center',
  243. showOverflowTooltip: true,
  244. minWidth: 150
  245. },
  246. {
  247. prop: 'planCode',
  248. label: '计划单号',
  249. align: 'center',
  250. showOverflowTooltip: true,
  251. minWidth: 110
  252. },
  253. {
  254. prop: 'planName',
  255. label: '计划名称',
  256. align: 'center',
  257. showOverflowTooltip: true,
  258. minWidth: 110
  259. },
  260. {
  261. prop: 'executeUserName',
  262. label: '报工人',
  263. align: 'center',
  264. showOverflowTooltip: true,
  265. minWidth: 110
  266. },
  267. {
  268. prop: 'accepterUserName',
  269. label: '验收人',
  270. align: 'center',
  271. showOverflowTooltip: true,
  272. minWidth: 110
  273. },
  274. {
  275. slot: 'faultLevel',
  276. prop: 'faultLevel',
  277. label: '故障等级',
  278. align: 'center',
  279. showOverflowTooltip: true,
  280. formatter: (row) => {
  281. return this.levelData[row.faultLevel] || '';
  282. }
  283. },
  284. {
  285. prop: 'contactName',
  286. label: '客户名称',
  287. align: 'center',
  288. showOverflowTooltip: true,
  289. minWidth: 110
  290. },
  291. {
  292. prop: 'categoryName',
  293. label: '设备名称',
  294. align: 'center',
  295. minWidth: 110,
  296. showOverflowTooltip: true,
  297. formatter: (row) => {
  298. if (!row.deviceDetails) return '';
  299. let str = '';
  300. row.deviceDetails.map((el, idx) => {
  301. if (idx + 1 == row.deviceDetails.length) {
  302. str += el.categoryName;
  303. } else {
  304. str = str + '' + el.categoryName + ',';
  305. }
  306. });
  307. return str;
  308. }
  309. },
  310. {
  311. prop: 'accepterTime',
  312. label: '验收时间',
  313. align: 'center',
  314. showOverflowTooltip: true,
  315. minWidth: 110
  316. },
  317. {
  318. prop: 'acceptTime',
  319. label: '开始时间',
  320. align: 'center',
  321. showOverflowTooltip: true,
  322. minWidth: 110
  323. },
  324. {
  325. prop: 'finishTime',
  326. label: '结束时间',
  327. align: 'center',
  328. showOverflowTooltip: true,
  329. minWidth: 110
  330. },
  331. {
  332. prop: 'planFinishTime',
  333. label: '计划完成时间',
  334. align: 'center',
  335. showOverflowTooltip: true,
  336. minWidth: 110
  337. },
  338. {
  339. prop: 'totalCost',
  340. label: '费用( 元 )',
  341. align: 'center',
  342. showOverflowTooltip: true,
  343. minWidth: 110
  344. },
  345. {
  346. columnKey: 'inFactDuration',
  347. label: '工时',
  348. align: 'center',
  349. resizable: false,
  350. showOverflowTooltip: true,
  351. minWidth: 120,
  352. formatter: (row) => {
  353. if (row.inFactDuration || row.inFactDuration == 0) {
  354. let str = ((row.inFactDuration - 0) / 60).toFixed(1);
  355. return str + ' 小时';
  356. }
  357. }
  358. },
  359. {
  360. prop: 'orderStatus',
  361. label: '状态',
  362. align: 'center',
  363. showOverflowTooltip: true,
  364. formatter: (row) => {
  365. return this.workOrderStatus.find(
  366. (item) => item.code == row.orderStatus
  367. )?.label;
  368. }
  369. },
  370. {
  371. columnKey: 'action',
  372. label: '操作',
  373. width: 240,
  374. align: 'center',
  375. resizable: false,
  376. slot: 'action',
  377. showOverflowTooltip: true
  378. }
  379. ],
  380. // 加载状态
  381. loading: false,
  382. row: {},
  383. levelData: {},
  384. levelList: [],
  385. orderStatus: 'all'
  386. };
  387. },
  388. computed: {
  389. // 评价
  390. evaluateShow() {
  391. return (row) => {
  392. return row.orderStatus == 4;
  393. };
  394. },
  395. // 验收
  396. acceptShow() {
  397. return (row) => {
  398. return row.orderStatus == 3 || row.orderStatus == 6;
  399. };
  400. }
  401. },
  402. created() {
  403. this.getLevelCode('fault_level');
  404. },
  405. methods: {
  406. handleClick(e) {
  407. let where = this.$refs.workSearch.$refs.seekPage.defaultWhere || {};
  408. this.reload(where);
  409. },
  410. //查询问题等级字典
  411. async getLevelCode(code) {
  412. const res = await getByCode(code);
  413. if (res?.code === '0') {
  414. let obj = {};
  415. let arr = [];
  416. res.data.map((el) => {
  417. arr.push({
  418. label: Object.values(el)[0],
  419. value: Object.keys(el)[0]
  420. });
  421. obj = { ...obj, ...el };
  422. });
  423. this.levelList = arr;
  424. this.levelData = obj;
  425. }
  426. },
  427. /* 表格数据源 */
  428. datasource({ page, limit, where, order }) {
  429. return getSalesWorkOrder({ pageNum: page, size: limit, ...where });
  430. },
  431. /* 刷新表格 */
  432. reload(where) {
  433. // 判断如果是选择的全部 不用传参
  434. if (this.orderStatus == 'all') {
  435. // where = where ? delete where.orderStatus : '';
  436. if (where) {
  437. delete where.orderStatus;
  438. }
  439. return this.$refs.table.reload({ page: 1, where });
  440. }
  441. // 不是的话 赋值工单状态
  442. if (!where) {
  443. where = { orderStatus: this.orderStatus };
  444. } else {
  445. where.orderStatus = this.orderStatus;
  446. }
  447. this.$refs.table.reload({ page: 1, where });
  448. this.$emit('getToDoReminder')
  449. },
  450. async cancel(row) {
  451. const res = await deleteSalesWorkOrder([row.id]);
  452. if (res) {
  453. this.$message.success('删除成功');
  454. this.reload();
  455. }
  456. },
  457. async addSpareItems(row) {
  458. let data = await getSalesWorkOrderById(row.id);
  459. let dataP = {
  460. receivingDeptName: data.executeGroupName,
  461. receivingDeptId: data.executeGroupId,
  462. recipientName: data.executeUserName,
  463. recipientId: data.executeUserId,
  464. name: data.name,
  465. receptionUserId: data.receptionUserId,
  466. id: data.id,
  467. userId: data.executeUserId,
  468. userName: data.executeUserName,
  469. details: data.costListVOS.filter((item) => {
  470. if (item.typeId == 2 && item.isApply != 1) {
  471. item.totalPrice = item.settlementPrice;
  472. item.categoryCode = item.code;
  473. item.categoryName = item.name;
  474. return item;
  475. }
  476. })
  477. };
  478. this.$refs.edit.open(JSON.parse(JSON.stringify(dataP)), 'work');
  479. },
  480. //接收
  481. async handleReceive(row) {
  482. const res = await receiveSalesWorkOrder(row);
  483. if (!res) return;
  484. this.$message.success('操作成功');
  485. this.reload();
  486. },
  487. //验收
  488. async checkAndAccept(accepterStatus) {
  489. if (!this.form.accepterUserId) {
  490. this.$message.warning('请选择验收人!');
  491. return;
  492. }
  493. const res = await checkAndAccept({
  494. id: this.row.id,
  495. ...this.form,
  496. accepterStatus
  497. });
  498. if (!res) return;
  499. this.$message.success('操作成功');
  500. this.visibleCheckAndAccept = false;
  501. this.reload();
  502. },
  503. accepterUserChange(item) {
  504. this.form.accepterUserName = item.contactName;
  505. },
  506. // 转派
  507. async toRedeploy(row) {
  508. this.$refs.redeployOtherRef.open(row, 'transfer');
  509. },
  510. //报工
  511. async declarationForm(row, type) {
  512. if (type !== 'view') {
  513. let flag = await this.permission(row);
  514. if (!flag) return;
  515. }
  516. this.$refs.declarationDialogRef.open(row, type);
  517. },
  518. // 校验
  519. async permission(row, command) {
  520. // 点评论/验收的话不走这个方法
  521. if (command == 'evaluate' || command == 'checkAndAccept') {
  522. return true;
  523. }
  524. try {
  525. await checkByWorkId(row.id);
  526. return true;
  527. } catch {
  528. return false;
  529. }
  530. },
  531. goDetail(row) {
  532. this.$refs.declarationDialogRef.open(row, 'view');
  533. },
  534. async handleCommand(command, row) {
  535. let flag = await this.permission(row, command);
  536. if (!flag) return;
  537. if (command === 'addSpareItems') {
  538. this.addSpareItems(row);
  539. }
  540. if (command === 'handleReceive') {
  541. this.handleReceive(row);
  542. }
  543. if (command === 'toRedeploy') {
  544. this.toRedeploy(row);
  545. }
  546. if (command == 'evaluate') {
  547. try {
  548. await afterSalesEvaluation(row.id);
  549. this.$refs.addDialogRef.open(row, 'add');
  550. } catch (err) {}
  551. }
  552. if (command == 'checkAndAccept') {
  553. try {
  554. await afterSalesEvaluation(row.id);
  555. this.visibleCheckAndAccept = true;
  556. this.form = {
  557. accepterUserId: '',
  558. accepterUserName: '',
  559. accepterRemark: ''
  560. };
  561. const { afterSalesDemandVO } = await getSalesWorkOrderById(row.id);
  562. this.contactInfoVOS = afterSalesDemandVO.contactInfoVOS || [];
  563. this.row = row;
  564. } catch (err) {}
  565. }
  566. }
  567. }
  568. };
  569. </script>
  570. <style lang="scss" scoped>
  571. .el-dropdown-link {
  572. cursor: pointer;
  573. color: var(--color-primary-5);
  574. }
  575. .el-icon-arrow-down {
  576. font-size: 12px;
  577. }
  578. ::v-deep .seep-search {
  579. .el-input__inner {
  580. padding: 0 5px 0 10px;
  581. }
  582. }
  583. </style>