index.vue 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661
  1. <template>
  2. <view class="mainBox">
  3. <uni-nav-bar background-color="#157A2C" color="#fff" fixed="true" statusBar="true" left-icon="back" title="售后工单"
  4. @clickLeft="back">
  5. </uni-nav-bar>
  6. <view class="top-wrapper">
  7. <uni-section>
  8. <uni-easyinput @clear="clearSearch" prefixIcon="search" style="width: 460rpx" v-model="searchVal"
  9. placeholder="名称">
  10. </uni-easyinput>
  11. </uni-section>
  12. <button class="search_btn" @click="doSearch">搜索</button>
  13. <image class="menu_icon" src="~@/static/pda/menu.svg" @click="showSearch"></image>
  14. </view>
  15. <view class="">
  16. <view class="tab_box rx-sc">
  17. <view class="tab_item" v-for="(item,index) in tabList" :key="index"
  18. :class="{active: pickTabIndex == item.value}">
  19. <view @click="changeChartsTab(item.value)">
  20. {{item.label}}
  21. </view>
  22. </view>
  23. </view>
  24. </view>
  25. <view class="wrapper">
  26. <u-list @scrolltolower="scrolltolower" class="listContent" style="height: auto;">
  27. <view v-for="(item, index) in tableList" :key="index" style="position: relative;">
  28. <myCard @addSpareItems="addSpareItems(item.id)" @report="edit('report',item.id)"
  29. @handleDetail="handleDetail(item)" @edit="edit('edit',item.id)" @details="edit('view',item.id)"
  30. @handleAudit="handleAudit(item)" @checkAndAccept="checkAndAccept(item)"
  31. @evaluate="evaluate(item)" :item="item" :index="index+1" @receive="receive(item)"
  32. :columns="columns" :btnList="btnList">
  33. </myCard>
  34. <u-empty v-show="emptyShow && tableList.length==0" width="300" height="300" textSize="30"></u-empty>
  35. </view>
  36. </u-list>
  37. </view>
  38. <CheckAndAccept ref="acceptRef" @getList='doSearch' />
  39. <Evaluate ref="evaluateRef" @getList='doSearch' />
  40. <u-toast ref="uToast"></u-toast>
  41. <MySearch :show.sync="searchShow" :formItems="formItems" @search="confirmSearch"></MySearch>
  42. </view>
  43. </template>
  44. <script>
  45. import {
  46. getByCode
  47. } from '@/api/pda/common.js'
  48. import {
  49. initDict
  50. } from '@/utils/utils.js'
  51. import {
  52. getSalesWorkOrder,
  53. receiveSalesWorkOrder,
  54. checkByWorkId
  55. } from '@/api/salesServiceManagement/workOrder/index.js'
  56. import myCard from '@/pages/saleManage/components/myCard.vue'
  57. import CheckAndAccept from './components/forWork/checkAndAccept.vue'
  58. import Evaluate from './components/forWork/evaluate.vue'
  59. import {
  60. getBpmCustomFormList,
  61. } from '@/api/wt/index.js'
  62. export default {
  63. components: {
  64. myCard,
  65. CheckAndAccept,
  66. Evaluate,
  67. },
  68. watch: {
  69. fault_level_arr: {
  70. handler(val) {
  71. console.log(val);
  72. this.formItems.find(item => item.prop === 'faultLevel').props.localdata = val
  73. },
  74. deep: true
  75. }
  76. },
  77. data() {
  78. return {
  79. searchForm: {},
  80. emptyShow: false,
  81. searchShow: false,
  82. fault_level_obj: {},
  83. fault_level_arr: [],
  84. formItems: [{
  85. label: '工单编号:',
  86. prop: 'code',
  87. component: 'MyInput',
  88. props: {
  89. placeholder: '请输入内容',
  90. }
  91. },
  92. {
  93. label: '客户名称:',
  94. prop: 'contactName',
  95. component: 'MyInput',
  96. props: {
  97. placeholder: '请输入内容',
  98. }
  99. },
  100. {
  101. label: '设备名称:',
  102. prop: 'deviceName',
  103. component: 'MyInput',
  104. props: {
  105. placeholder: '请输入内容',
  106. }
  107. },
  108. {
  109. label: '故障等级:',
  110. prop: 'faultLevel',
  111. component: 'MySelect',
  112. props: {
  113. localdata: [],
  114. dataKey: 'label',
  115. dataValue: 'value'
  116. }
  117. },
  118. {
  119. label: '计划单号:',
  120. prop: 'planCode',
  121. component: 'MyInput',
  122. props: {
  123. placeholder: '请输入内容',
  124. }
  125. },
  126. {
  127. label: '计划名称:',
  128. prop: 'planName',
  129. component: 'MyInput',
  130. props: {
  131. placeholder: '请输入内容',
  132. }
  133. },
  134. {
  135. label: '报工人:',
  136. prop: 'executeUserName',
  137. component: 'MyInput',
  138. props: {
  139. placeholder: '请输入内容',
  140. }
  141. },
  142. {
  143. label: '验收人:',
  144. prop: 'accepterUserName',
  145. component: 'MyInput',
  146. props: {
  147. placeholder: '请输入内容',
  148. }
  149. },
  150. ],
  151. tabList: [{
  152. value: 'all',
  153. label: '全部',
  154. },
  155. {
  156. value: '0',
  157. label: '待执行',
  158. },
  159. {
  160. value: '1',
  161. label: '执行中',
  162. },
  163. {
  164. value: '3',
  165. label: '待验收',
  166. },
  167. {
  168. value: '5',
  169. label: '已完成',
  170. },
  171. ],
  172. workOrderStatus: [
  173. // { code: 0, label: '待接收' },
  174. {
  175. code: 0,
  176. label: '待执行'
  177. },
  178. {
  179. code: 1,
  180. label: '已接收'
  181. },
  182. {
  183. code: 2,
  184. label: '执行中'
  185. },
  186. {
  187. code: 3,
  188. label: '待验收'
  189. },
  190. {
  191. code: 4,
  192. label: '待评价'
  193. },
  194. {
  195. code: 5,
  196. label: '已完成'
  197. },
  198. {
  199. code: 6,
  200. label: '验收不通过'
  201. }
  202. ],
  203. pickTabIndex: 'all',
  204. searchVal: '',
  205. isEnd: false,
  206. page: 1,
  207. size: 10,
  208. tableList: [],
  209. columns: [
  210. [{
  211. label: '工单编号:',
  212. prop: 'code',
  213. type: 'title',
  214. className: 'perce100',
  215. }],
  216. [{
  217. label: '计划单号:',
  218. prop: 'planCode'
  219. }],
  220. [{
  221. label: '计划名称:',
  222. prop: 'planName',
  223. }],
  224. [{
  225. label: '报工人:',
  226. prop: 'executeUserName'
  227. }, {
  228. label: '验收人:',
  229. prop: 'accepterUserName',
  230. }],
  231. [{
  232. label: '故障等级:',
  233. prop: 'faultLevel',
  234. formatter: (row) => {
  235. console.log(this.fault_level_obj);
  236. return this.fault_level_obj[row.faultLevel]
  237. }
  238. }, {
  239. label: '客户名称:',
  240. prop: 'contactName',
  241. }],
  242. [{
  243. label: '设备名称:',
  244. prop: 'categoryName',
  245. formatter: (row) => {
  246. if (!row.deviceDetails) return '';
  247. let str = '';
  248. row.deviceDetails.map((el, idx) => {
  249. if (idx + 1 == row.deviceDetails.length) {
  250. str += el.categoryName;
  251. } else {
  252. str = str + '' + el.categoryName + ',';
  253. }
  254. });
  255. return str;
  256. }
  257. }],
  258. [{
  259. label: '验收时间:',
  260. prop: 'accepterTime'
  261. }, {
  262. label: '开始时间:',
  263. prop: 'acceptTime',
  264. }],
  265. [{
  266. label: '结束时间:',
  267. prop: 'finishTime'
  268. }, {
  269. label: '计划完成时间:',
  270. prop: 'planFinishTime',
  271. }],
  272. [{
  273. label: '实际售后时长:',
  274. prop: 'inFactDuration',
  275. formatter: (row) => {
  276. if (row.inFactDuration || row.inFactDuration == 0) {
  277. let str = ((row.inFactDuration - 0) / 60).toFixed(1);
  278. return str + ' 小时';
  279. }
  280. }
  281. }, {
  282. label: '状态:',
  283. prop: 'orderStatus',
  284. formatter: (row) => {
  285. return this.workOrderStatus.find(
  286. (item) => item.code == row.orderStatus
  287. )?.label;
  288. }
  289. }],
  290. [{
  291. label: '操作:',
  292. prop: 'action',
  293. type: 'action',
  294. className: 'perce100',
  295. }],
  296. ],
  297. btnList: [{
  298. name: '详情',
  299. apiName: 'details',
  300. btnType: 'primary',
  301. type: '2',
  302. pageUrl: '',
  303. }, {
  304. name: '修改',
  305. apiName: 'edit',
  306. btnType: 'primary',
  307. type: '2',
  308. pageUrl: '',
  309. judge: [{
  310. authorities: '',
  311. }, {
  312. key: 'orderStatus',
  313. value: [1, 6],
  314. }],
  315. },
  316. {
  317. name: '报工',
  318. apiName: 'report',
  319. btnType: 'error ',
  320. type: '2',
  321. pageUrl: '',
  322. judge: [{
  323. authorities: '',
  324. }, {
  325. key: 'orderStatus',
  326. value: [1, 6],
  327. }],
  328. }, {
  329. name: '接收',
  330. apiName: 'receive',
  331. btnType: 'error ',
  332. type: '2',
  333. pageUrl: '',
  334. judge: [{
  335. authorities: '',
  336. }, {
  337. key: 'orderStatus',
  338. value: [0],
  339. }],
  340. }, {
  341. name: '转派',
  342. apiName: 'handleAudit',
  343. btnType: 'primary',
  344. type: '2',
  345. pageUrl: '',
  346. judge: [{
  347. authorities: '',
  348. }, {
  349. key: 'orderStatus',
  350. value: [0, 1],
  351. }],
  352. },
  353. {
  354. name: '验收',
  355. apiName: 'checkAndAccept',
  356. btnType: 'primary',
  357. type: '2',
  358. pageUrl: '',
  359. judge: [{
  360. authorities: '',
  361. }, {
  362. key: 'orderStatus',
  363. value: [3, 6],
  364. }],
  365. },
  366. {
  367. name: '评价',
  368. apiName: 'evaluate',
  369. btnType: 'primary',
  370. type: '2',
  371. pageUrl: '',
  372. judge: [{
  373. authorities: '',
  374. }, {
  375. key: 'orderStatus',
  376. value: [4],
  377. }],
  378. },
  379. {
  380. name: '申请配件',
  381. apiName: 'addSpareItems',
  382. btnType: 'primary',
  383. type: '2',
  384. pageUrl: '',
  385. judge: [{
  386. authorities: '',
  387. }, {
  388. key: 'orderStatus',
  389. value: [1, 2],
  390. }],
  391. },
  392. {
  393. name: '用车申请',
  394. apiName: 'handleDetail',
  395. btnType: 'primary',
  396. type: '2',
  397. pageUrl: '',
  398. judge: [{
  399. authorities: '',
  400. }, {
  401. key: 'pieCarType',
  402. value: [1, 2],
  403. }],
  404. },
  405. ],
  406. }
  407. },
  408. onLoad() {
  409. this.getDict()
  410. },
  411. onShow() {
  412. this.doSearch();
  413. },
  414. created() {
  415. },
  416. onReachBottom() {
  417. this.getList()
  418. },
  419. methods: {
  420. async getDict() {
  421. let res = await getByCode('fault_level')
  422. let [arr, obj] = initDict(res)
  423. this.fault_level_obj = obj
  424. this.fault_level_arr = arr
  425. console.log(arr, obj);
  426. },
  427. async handleDetail(row) {
  428. const list = await getBpmCustomFormList({
  429. status: 1
  430. })
  431. const data = list.find(
  432. (item) => item?.code === 'carBy'
  433. );
  434. console.log(data, 'data')
  435. // return
  436. let params = JSON.stringify({
  437. id: data.id,
  438. processInstanceId: data.processInstance?.id || data.processDefinitionId || '',
  439. type: 'add',
  440. isEdit: true,
  441. manage_workorder: {
  442. id: row.id, // 列表工单ID
  443. code: row.code, // 列表工单编号(要显示的code)
  444. name: row.planName // 列表工单名称(可选,根据弹窗需求传递)
  445. }
  446. })
  447. let queryParams = `params=${params}`
  448. let url = '/pages/home/wt/components/formParser/routerView'
  449. uni.navigateTo({
  450. url: `${url}?${queryParams}`
  451. })
  452. },
  453. changeChartsTab(value) {
  454. this.pickTabIndex = value;
  455. this.doSearch();
  456. },
  457. doSearch() {
  458. this.isEnd = false;
  459. this.page = 1;
  460. this.getList();
  461. },
  462. //获取列表信息
  463. getList() {
  464. this.emptyShow = false
  465. if (this.isEnd) {
  466. this.$refs.uToast.show({
  467. message: "暂无更多数据",
  468. duration: 1000
  469. })
  470. return
  471. }
  472. uni.showLoading({
  473. title: '加载中'
  474. })
  475. let data = {
  476. pageNum: this.page,
  477. size: this.size,
  478. keyWord: this.searchVal,
  479. ...this.searchForm
  480. }
  481. if (this.pickTabIndex != 'all') {
  482. data.orderStatus = this.pickTabIndex;
  483. }
  484. getSalesWorkOrder(data).then(res => {
  485. if (this.page === 1) {
  486. this.tableList = res.list
  487. if (this.tableList.length === 0) {
  488. this.emptyShow = true
  489. }
  490. } else {
  491. this.tableList.push(...res.list)
  492. }
  493. this.page += 1
  494. this.isEnd = this.tableList.length >= res.count;
  495. uni.hideLoading();
  496. }).catch((e) => {
  497. uni.hideLoading();
  498. })
  499. },
  500. scrolltolower() {
  501. if (this.isEnd) {
  502. return
  503. }
  504. this.getList();
  505. },
  506. // 申请配件
  507. async addSpareItems(id) {
  508. const result = await this.checkId(id)
  509. if (result) {
  510. uni.navigateTo({
  511. url: `/pages/salesServiceManagement/workOrder/components/accessory?id=${id}`
  512. })
  513. }
  514. },
  515. // 验收
  516. checkAndAccept(item) {
  517. this.$refs.acceptRef.open(item.id);
  518. },
  519. // 评价
  520. evaluate(item) {
  521. this.$refs.evaluateRef.open(item.id);
  522. },
  523. // 转派
  524. handleAudit(item) {
  525. console.log(item, 'item ---')
  526. uni.navigateTo({
  527. url: `/pages/salesServiceManagement/workOrder/components/forWork/transfer?id=${item.id}`
  528. })
  529. },
  530. // 报工
  531. async edit(type, id) {
  532. // 判断报工是否可执行
  533. if (type == 'report') {
  534. const result = await this.checkId(id)
  535. if (!result) return
  536. }
  537. uni.navigateTo({
  538. url: `/pages/salesServiceManagement/workOrder/components/editPlan?type=${type}&id=${id}`
  539. })
  540. },
  541. // 接收
  542. async receive(item) {
  543. const data = await uni.showModal({
  544. title: '确认接收',
  545. content: '确定要接收这条数据吗?',
  546. confirmText: '接收',
  547. confirmColor: '#157a2c',
  548. });
  549. if (data[1].confirm) {
  550. const res = await receiveSalesWorkOrder(item);
  551. if (!res) return;
  552. this.$refs.uToast.show({
  553. type: "success",
  554. message: "操作成功",
  555. })
  556. this.doSearch();
  557. }
  558. },
  559. clearSearch() {
  560. this.searchVal = ''
  561. this.doSearch()
  562. },
  563. showSearch() {
  564. this.searchShow = true
  565. },
  566. confirmSearch(e) {
  567. console.log(e);
  568. let data = JSON.parse(JSON.stringify(e))
  569. this.searchForm = data
  570. this.doSearch()
  571. },
  572. async checkId(id) {
  573. try {
  574. await checkByWorkId(id)
  575. return true
  576. } catch (error) {
  577. console.log(error);
  578. return false
  579. }
  580. }
  581. }
  582. }
  583. </script>
  584. <style lang="scss" scoped>
  585. .top-wrapper {
  586. background-color: #fff;
  587. display: flex;
  588. width: 750rpx;
  589. height: 88rpx;
  590. padding: 16rpx 32rpx;
  591. align-items: center;
  592. gap: 16rpx;
  593. /deep/.uni-section {
  594. margin-top: 0px;
  595. }
  596. /deep/.uni-section-header {
  597. padding: 0px;
  598. }
  599. .search_btn {
  600. width: 120rpx;
  601. height: 70rpx;
  602. line-height: 70rpx;
  603. padding: 0 24rpx;
  604. background: $theme-color;
  605. font-size: 32rpx;
  606. color: #fff;
  607. margin: 0;
  608. margin-left: 26rpx;
  609. }
  610. .menu_icon {
  611. width: 44rpx;
  612. height: 44rpx;
  613. margin-left: 14rpx;
  614. }
  615. }
  616. .tab_box {
  617. width: 100%;
  618. height: 68rpx;
  619. border-bottom: 1rpx solid #E1E1E1;
  620. .tab_item {
  621. height: 68rpx;
  622. line-height: 68rpx;
  623. padding: 0 20rpx;
  624. font-size: 32rpx;
  625. color: #979C9E;
  626. }
  627. .active {
  628. box-sizing: border-box;
  629. border-bottom: 6rpx solid $theme-color;
  630. color: $theme-color;
  631. }
  632. }
  633. /deep/ .u-empty {
  634. margin-top: 200px !important;
  635. }
  636. </style>