index.vue 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674
  1. <template>
  2. <div style="width: 100%; height: 100%; position: relative">
  3. <!-- 工单池 -->
  4. <template-page
  5. v-if="!(!!~['detail'].indexOf(pageType) && pageCode != '') && showTableBool"
  6. ref="pageRef"
  7. :getList="getList"
  8. :operation="operation()"
  9. :exportList="exportList"
  10. :optionsEvensGroup="optionsEvensGroup"
  11. :columnParsing="columnParsing"
  12. :tableAttributes="tableAttributes"
  13. :tableEvents="tableEvents"
  14. :moreParameters="moreParameters"
  15. :screeningAnalysis="screeningAnalysis"
  16. :filterMethod="filterMethod"
  17. :replaceOrNotMap="true"
  18. :defaultSearchData="defaultSearchData"
  19. >
  20. <div slot="moreSearch">
  21. <div style="margin-bottom: 10px">
  22. <span
  23. style="
  24. font-size: 12px;
  25. font-weight: 400;
  26. text-align: left;
  27. color: #666;
  28. line-height: 28px;
  29. margin-right: 10px;
  30. "
  31. >选择年份</span
  32. >
  33. <el-date-picker
  34. style="width: 130px"
  35. v-model="value1"
  36. format="yyyy"
  37. size="mini"
  38. type="year"
  39. placeholder="选择日期"
  40. >
  41. </el-date-picker>
  42. </div>
  43. </div>
  44. <!-- 创建工单 -->
  45. <div class="cartographer_big" v-if="!(!!~['detail'].indexOf(pageType) && pageCode != '')">
  46. <el-dialog
  47. title="创建工单"
  48. width="100%"
  49. :modal="false"
  50. :visible.sync="createFormBool"
  51. :before-close="handleClose"
  52. >
  53. <workOrderInfo :workOrderType="workOrderType" v-if="createFormBool" :cloneWorkOrder="cloneWorkOrder" />
  54. </el-dialog>
  55. </div>
  56. <!-- 批量预约/改约 -->
  57. <div class="cartographer_big" v-if="!(!!~['detail'].indexOf(pageType) && pageCode != '')">
  58. <el-dialog
  59. title="批量约单"
  60. width="100%"
  61. :modal="false"
  62. :visible.sync="rescheduleBool"
  63. :before-close="rescheduleClose"
  64. >
  65. <Reschedule v-if="rescheduleBool" :recordSelected="recordSelected" @close="rescheduleClose" />
  66. </el-dialog>
  67. </div>
  68. <!-- 批量派工/改派 -->
  69. <div class="cartographer_big" v-if="!(!!~['detail'].indexOf(pageType) && pageCode != '')">
  70. <el-dialog
  71. title="批量派单"
  72. width="100%"
  73. :modal="false"
  74. :visible.sync="reassignmentBool"
  75. :before-close="reassignmentClose"
  76. >
  77. <Reassignment v-if="reassignmentBool" :recordSelected="recordSelected" @close="reassignmentClose" />
  78. </el-dialog>
  79. </div>
  80. <div class="tubiao">
  81. <span style="margin-right: 4px; font-weight: bold; font-size: 12px">工单标识说明:</span>
  82. <img :src="v4" style="width: 20px; height: 20px; margin: 0 3px" />
  83. <span style="margin-right: 4px; font-size: 12px; display: inline-block; width: 76px">【4.0工单】</span>
  84. <img :src="gc" style="width: 20px; height: 20px; margin: 0 3px" />
  85. <span style="margin-right: 4px; font-size: 12px; display: inline-block; width: 76px">【工程】</span>
  86. <img :src="jj" style="width: 20px; height: 20px; margin: 0 3px" />
  87. <span style="margin-right: 4px; font-size: 12px; display: inline-block; width: 76px">【加急】</span>
  88. <img :src="ls" style="width: 20px; height: 20px; margin: 0 3px" />
  89. <span style="margin-right: 4px; font-size: 12px; display: inline-block; width: 76px">【零售】</span>
  90. <img :src="yjs" style="width: 20px; height: 20px; margin: 0 3px" />
  91. <span style="margin-right: 4px; font-size: 12px; display: inline-block; width: 76px">【已结算】</span>
  92. </div>
  93. <div class="tubiao2">
  94. <span style="margin-right: 4px; font-weight: bold; font-size: 12px; opacity: 0">工单标识说明:</span>
  95. <img :src="ywg" style="width: 20px; height: 20px; margin: 0 3px" />
  96. <span style="margin-right: 4px; font-size: 12px; display: inline-block; width: 76px">【已完工】</span>
  97. <img :src="yc" style="width: 20px; height: 20px; margin: 0 3px" />
  98. <span style="margin-right: 4px; font-size: 12px; display: inline-block; width: 76px">【异常】</span>
  99. <img :src="zj" style="width: 20px; height: 20px; margin: 0 3px" />
  100. <span style="margin-right: 4px; font-size: 12px; display: inline-block; width: 76px">【自建工单】</span>
  101. <img :src="pjsq" style="width: 20px; height: 20px; margin: 0 3px" />
  102. <span style="margin-right: 4px; font-size: 12px; display: inline-block; width: 76px">【配件申请】</span>
  103. <img :src="pjdh" style="width: 20px; height: 20px; margin: 0 3px" />
  104. <span style="margin-right: 4px; font-size: 12px; display: inline-block; width: 76px">【配件到货】</span>
  105. <img :src="pjqx" style="width: 20px; height: 20px; margin: 0 3px" />
  106. <span style="margin-right: 4px; font-size: 12px; display: inline-block; width: 76px">【配件取消】</span>
  107. </div>
  108. </template-page>
  109. <!-- 工单详情 -->
  110. <div class="cartographer_big haidhead__" v-if="!!~['detail'].indexOf(pageType) && pageCode != ''">
  111. <el-dialog
  112. class="noinonnlinin"
  113. :title="'工单详情-' + id"
  114. width="100%"
  115. :modal="false"
  116. :visible.sync="detailFormBool"
  117. :before-close="handleClose"
  118. >
  119. <Detail v-if="detailFormBool" :id="id" :workOrderType="workOrderType" />
  120. </el-dialog>
  121. </div>
  122. </div>
  123. </template>
  124. <script>
  125. import { EventBus } from '@/utils/eventBus'
  126. import TemplatePage from '@/components/template/template-page-1.vue'
  127. import import_mixin from '@/components/template/import_mixin.js'
  128. import operation_mixin from '@/components/template/operation_mixin.js'
  129. import { listPageV2 } from '@/api/workOrder/orderType'
  130. import {
  131. orderBaseList,
  132. orderBaseListExport,
  133. orderBaseStatusCount,
  134. orderBaseImport,
  135. orderBaseImport2,
  136. orderBaseImport3,
  137. orderBaseDetail
  138. } from '@/api/workOrderPool.js'
  139. import workOrderInfo from './detailModule/workOrderInfo/index.vue'
  140. import Detail from './detail'
  141. import Reassignment from './components/reassignment/index.vue'
  142. import Reschedule from './components/reschedule/index.vue'
  143. import { commonTemplateDownload } from '@/api/common.js'
  144. import orderListColumn from '@/mixin/orderListColumn'
  145. // -----------------------
  146. import v4 from '@/assets/order/4.0@2x.png'
  147. import gc from '@/assets/order/工程@2x.png'
  148. import jj from '@/assets/order/加急@2x.png'
  149. import ls from '@/assets/order/零售@2x.png'
  150. import yjs from '@/assets/order/已结算@2x.png'
  151. import ywg from '@/assets/order/已完工待结算@2x@2x.png'
  152. import yc from '@/assets/order/异常@2x.png'
  153. import zj from '@/assets/order/自建@2x.png'
  154. import pjsq from '@/assets/order/配件申请中@2x.png'
  155. import pjdh from '@/assets/order/配件已到货@2x.png'
  156. import pjqx from '@/assets/order/配件已取消@2x.png'
  157. export default {
  158. components: {
  159. TemplatePage,
  160. workOrderInfo,
  161. Detail,
  162. Reassignment,
  163. Reschedule
  164. },
  165. mixins: [import_mixin, operation_mixin, orderListColumn],
  166. data() {
  167. return {
  168. v4,
  169. gc,
  170. jj,
  171. ls,
  172. yjs,
  173. ywg,
  174. yc,
  175. zj,
  176. pjsq,
  177. pjdh,
  178. pjqx,
  179. id: this.$route.query.id || '',
  180. // 创建表单
  181. createFormBool: false,
  182. // 详情
  183. detailFormBool: true,
  184. // 批量改约
  185. rescheduleBool: false,
  186. // 批量派工/改派
  187. reassignmentBool: false,
  188. // 表格属性
  189. tableAttributes: {
  190. // 启用勾选列
  191. selectColumn: true,
  192. selectable: this.selectable
  193. },
  194. // 表格事件
  195. tableEvents: {
  196. 'selection-change': this.selectionChange
  197. },
  198. recordSelected: [],
  199. orderTypeList: [],
  200. orderStatusList: [],
  201. defaultSearchData: [],
  202. workOrderType: 1,
  203. cloneWorkOrder: null,
  204. value1: new Date(),
  205. showTableBool: true
  206. }
  207. },
  208. watch: {
  209. value1() {
  210. this.showTableBool = false
  211. this.$nextTick(() => {
  212. this.showTableBool = true
  213. })
  214. }
  215. },
  216. computed: {
  217. moreParameters() {
  218. return [
  219. {
  220. name: '工单类型',
  221. key: 'orderSmallTypeText',
  222. value: '',
  223. conditions: [
  224. {
  225. label: '全部',
  226. value: ''
  227. },
  228. ...this.orderTypeList
  229. ]
  230. },
  231. {
  232. name: '工单状态',
  233. key: 'orderStatus',
  234. value: this.pageType == 'orderStatus' && this.pageCode ? this.pageCode : '',
  235. conditions: [
  236. {
  237. label: '全部',
  238. value: ''
  239. },
  240. ...this.orderStatusList
  241. ]
  242. }
  243. ]
  244. },
  245. // 用户信息
  246. userInfo() {
  247. return JSON.parse(localStorage.getItem('greemall_user'))
  248. },
  249. // 事件组合
  250. optionsEvensGroup() {
  251. return [
  252. [
  253. [
  254. this.optionsEvensAuth(['createWorkOrder', 'createWbWorkOrder'], {
  255. name: '创建工单',
  256. click: () => {}
  257. }),
  258. this.optionsEvensAuth('createWorkOrder', {
  259. click: () => {
  260. this.workOrderType = 1
  261. this.createFormBool = true
  262. }
  263. }),
  264. this.optionsEvensAuth('createGCWorkOrder', {
  265. click: () => {
  266. this.workOrderType = 2
  267. this.createFormBool = true
  268. }
  269. }),
  270. this.optionsEvensAuth('createWbWorkOrder', {
  271. click: () => {
  272. this.workOrderType = 4
  273. this.createFormBool = true
  274. }
  275. })
  276. ],
  277. [
  278. this.optionsEvensAuth(
  279. ['import4', 'importTemplate', 'downloadImportTemplate', 'importTemplate2', 'downloadImportTemplate2'],
  280. {
  281. name: '导入工单',
  282. click: () => {}
  283. }
  284. ),
  285. this.optionsEvensAuth('import4', ({ moduleName }) => {
  286. return {
  287. name: moduleName,
  288. render: () => {
  289. return this.importButton(orderBaseImport3, moduleName)
  290. }
  291. }
  292. }),
  293. this.optionsEvensAuth('importTemplate', ({ moduleName }) => {
  294. return {
  295. name: moduleName,
  296. render: () => {
  297. return this.importButton(orderBaseImport, moduleName)
  298. }
  299. }
  300. }),
  301. this.optionsEvensAuth('downloadImportTemplate', {
  302. click: () => {
  303. commonTemplateDownload({ name: '工单导入模板.xlsx' }, `${this.$route.meta.title}`)
  304. .then(res => {
  305. this.$message({
  306. message: '下载成功',
  307. type: 'success'
  308. })
  309. })
  310. .catch(err => {
  311. this.$message.error('下载失败')
  312. })
  313. }
  314. }),
  315. this.optionsEvensAuth('importTemplate2', ({ moduleName }) => {
  316. return {
  317. name: moduleName,
  318. render: () => {
  319. return this.importButton(orderBaseImport2, moduleName)
  320. }
  321. }
  322. }),
  323. this.optionsEvensAuth('downloadImportTemplate2', {
  324. click: () => {
  325. commonTemplateDownload({ name: '工单导入模板2.xlsx' }, `${this.$route.meta.title}`)
  326. .then(res => {
  327. this.$message({
  328. message: '下载成功',
  329. type: 'success'
  330. })
  331. })
  332. .catch(err => {
  333. this.$message.error('下载失败')
  334. })
  335. }
  336. })
  337. ],
  338. [
  339. this.optionsEvensAuth(['bulkOrder', 'lotOrder'], {
  340. name: '批量操作',
  341. click: () => {}
  342. }),
  343. this.optionsEvensAuth('bulkOrder', {
  344. click: () => {
  345. if (this.recordSelected.length === 0) {
  346. this.$message.warning('请勾选工单')
  347. return
  348. }
  349. this.reassignmentBool = true
  350. }
  351. }),
  352. this.optionsEvensAuth('lotOrder', {
  353. click: () => {
  354. if (this.recordSelected.length === 0) {
  355. this.$message.warning('请勾选工单')
  356. return
  357. }
  358. this.rescheduleBool = true
  359. }
  360. })
  361. ]
  362. ]
  363. ]
  364. }
  365. },
  366. created() {
  367. this.initFun()
  368. EventBus.$on('handleOrderClone', () => {
  369. if (!(!!~['detail'].indexOf(this.pageType) && this.pageCode != '')) {
  370. this.handleClose()
  371. }
  372. })
  373. EventBus.$on('cloneWorkOrder', data => {
  374. if (!(!!~['detail'].indexOf(this.pageType) && this.pageCode != '')) {
  375. this.handleClose(() => {
  376. this.cloneWorkOrder = data
  377. this.workOrderType = data.saleType
  378. this.createFormBool = false
  379. this.$nextTick(() => {
  380. this.createFormBool = true
  381. })
  382. })
  383. }
  384. })
  385. if (!(!!~['detail'].indexOf(this.pageType) && this.pageCode != '')) {
  386. // 获取工单类型
  387. listPageV2({ pageNum: 1, pageSize: -1, params: [{ param: 'a.status', compare: '=', value: 'true' }] }).then(
  388. res => {
  389. var obj = {}
  390. res.data.records.map(item => {
  391. if (!obj[item.orderSmallTypeText]) {
  392. obj[item.orderSmallTypeText] = {
  393. value: item.orderSmallTypeText,
  394. label: item.orderSmallTypeText
  395. }
  396. }
  397. })
  398. this.orderTypeList = Object.values(obj)
  399. }
  400. )
  401. }
  402. },
  403. methods: {
  404. initFun() {
  405. if (this.pageType == 'detail') {
  406. this.id = this.pageCode
  407. orderBaseDetail({
  408. orderBaseId: this.id
  409. }).then(res => {
  410. this.workOrderType = Number(res?.data?.saleType)
  411. this.$nextTick(() => {
  412. this.detailFormBool = true
  413. })
  414. })
  415. }
  416. if (this.pageType == 'saleOrderId') {
  417. this.defaultSearchData = [{ param: 'a.sale_order_id', compare: '=', value: this.pageCode, label: '销售订单号' }]
  418. }
  419. if (this.pageType == 'pgIncreItemId') {
  420. this.defaultSearchData = [
  421. { param: 'a.pg_incre_order_id', compare: '=', value: this.pageCode, label: '增置服务订单ID' }
  422. ]
  423. }
  424. if (this.pageType == 'rpProjectRepairId') {
  425. this.defaultSearchData = [
  426. { param: 'a.rp_project_repair_id', compare: '=', value: this.pageCode, label: '维保配置ID' }
  427. ]
  428. }
  429. if (this.pageType == 'projectNo') {
  430. this.defaultSearchData = [{ param: 'a.project_no', compare: '=', value: this.pageCode, label: '工程编号' }]
  431. }
  432. },
  433. selectable(row, index) {
  434. var orderStatus = Object.entries(row.selectMapData.orderStatus).find(([key, val]) => val == row.orderStatus)?.[0]
  435. return (
  436. !row.isThreeOrder &&
  437. !['YWG', 'GCSZX', 'WDWG', 'YWGO'].includes(orderStatus) &&
  438. !['YJS', 'LRCD'].includes(orderStatus) &&
  439. !['YQX', 'FWZT', 'YCGB', 'FWQX'].includes(orderStatus) &&
  440. !row.rpProjectRepairId
  441. )
  442. },
  443. screeningAnalysis(jname, val) {
  444. if (jname == 'orderFlags') {
  445. return (val || []).map(item => item.tagName).join(',')
  446. } else {
  447. return val
  448. }
  449. },
  450. filterMethod(value, row, column) {
  451. if (column['property'] == 'orderFlags') {
  452. return (row[column['property']] || []).map(item => item.tagName).join(',') === value
  453. }
  454. return row[column['property']] === value
  455. },
  456. // 获取统计
  457. getOrderBaseStatusCount(...p) {
  458. orderBaseStatusCount(...p).then(res => {
  459. this.orderStatusList = [
  460. {
  461. label: '待预约',
  462. value: 'DYY'
  463. },
  464. {
  465. label: '待抢单',
  466. value: 'DQD'
  467. },
  468. {
  469. label: '待商户派工',
  470. value: 'DSHPG'
  471. },
  472. {
  473. label: '待网点派工',
  474. value: 'DWDPG'
  475. },
  476. {
  477. label: '待接单',
  478. value: 'DJD'
  479. },
  480. {
  481. label: '服务中',
  482. value: 'FWZ'
  483. },
  484. {
  485. label: '异常单',
  486. value: 'YCD'
  487. },
  488. {
  489. label: '已完工',
  490. value: 'YWGO'
  491. },
  492. {
  493. label: '已结算',
  494. value: 'YJS'
  495. },
  496. {
  497. label: '已取消',
  498. value: 'YQX'
  499. },
  500. {
  501. label: '配件申请中',
  502. value: 'PJSQZ'
  503. },
  504. {
  505. label: '配件已到货',
  506. value: 'PJYDH'
  507. },
  508. {
  509. label: '配件已取消',
  510. value: 'PJYQX'
  511. }
  512. ].map(item => {
  513. var data = res.data.find(val => val.orderStatus == item.value)
  514. if (data) {
  515. if (item.value == 'YWGO') {
  516. var data_ = res.data.find(val => val.orderStatus == 'YWG')
  517. var data_2 = res.data.find(val => val.orderStatus == 'GCSZX')
  518. var data_3 = res.data.find(val => val.orderStatus == 'YJS')
  519. item.label = `${item.label}(${data.total + data_.total + data_2.total + data_3.total})`
  520. } else {
  521. item.label = `${item.label}(${data.total})`
  522. }
  523. }
  524. return item
  525. })
  526. })
  527. },
  528. // 列表请求函数
  529. getList(p, cb) {
  530. var pam = JSON.parse(JSON.stringify(p))
  531. try {
  532. if (pam.orderStatus) {
  533. if (pam.orderStatus === 'YWGO') {
  534. pam.params.push({ param: 'a.order_status', compare: '=', value: ['YWG', 'YWGO', 'YJS', 'GCSZX'] })
  535. pam.orderStatus = ''
  536. } else {
  537. pam.params.push({ param: 'a.order_status', compare: '=', value: pam.orderStatus })
  538. }
  539. }
  540. if (pam.orderSmallTypeText) {
  541. pam.params.push({ param: 'a.order_small_type_text', compare: '=', value: pam.orderSmallTypeText })
  542. }
  543. if (this.value1) {
  544. pam.params.push(
  545. { param: 'a.create_time', compare: '>=', value: `${new Date(this.value1).getFullYear()}-1-1 00:00:00` },
  546. { param: 'a.create_time', compare: '<=', value: `${new Date(this.value1).getFullYear()}-12-31 23:59:59` }
  547. )
  548. }
  549. cb && cb(pam)
  550. return orderBaseList(pam)
  551. } catch (err) {
  552. } finally {
  553. this.$nextTick(() => {
  554. this.getOrderBaseStatusCount({
  555. orderSmallTypeText: pam.orderSmallTypeText || '',
  556. ...(() => {
  557. if (this.value1) {
  558. return {
  559. startTime: `${new Date(this.value1).getFullYear()}-1-1 00:00:00`,
  560. endTime: `${new Date(this.value1).getFullYear()}-12-31 23:59:59`
  561. }
  562. }
  563. return {}
  564. })()
  565. })
  566. })
  567. }
  568. },
  569. // 列表导出函数
  570. exportList: orderBaseListExport,
  571. // 监听勾选变化
  572. selectionChange(data) {
  573. this.recordSelected = data
  574. },
  575. operation() {
  576. return this.operationBtn({
  577. edit: {
  578. click: ({ row, index, column }) => {
  579. this.$router.push({
  580. name: 'workOrderPool',
  581. params: {
  582. pageName: row.id,
  583. pageType: 'detail',
  584. pageCode: row.id
  585. }
  586. })
  587. }
  588. }
  589. })
  590. },
  591. handleClose(cb) {
  592. this.$router.push({
  593. name: 'workOrderPool',
  594. params: {},
  595. query: {}
  596. })
  597. this.$nextTick(() => {
  598. this.cloneWorkOrder = null
  599. this.createFormBool = false
  600. this.detailFormBool = false
  601. this.recordSelected = []
  602. this.$refs?.pageRef?.refreshList()
  603. if (cb && typeof cb === 'function') {
  604. cb()
  605. }
  606. })
  607. },
  608. rescheduleClose() {
  609. this.rescheduleBool = false
  610. this.recordSelected = []
  611. this.$refs?.pageRef?.refreshList()
  612. },
  613. reassignmentClose() {
  614. this.reassignmentBool = false
  615. this.recordSelected = []
  616. this.$refs?.pageRef?.refreshList()
  617. }
  618. }
  619. }
  620. </script>
  621. <style lang="scss" scoped>
  622. .haidhead__ {
  623. ::v-deep .noinonnlinin {
  624. & > div > .el-dialog__header {
  625. display: none !important;
  626. }
  627. & > div > .el-dialog__body {
  628. width: 100%;
  629. height: 100% !important;
  630. position: relative;
  631. box-sizing: border-box;
  632. padding: 0px;
  633. overflow-y: auto;
  634. }
  635. }
  636. }
  637. .tubiao {
  638. position: absolute;
  639. bottom: 35px;
  640. left: 20px;
  641. z-index: 10;
  642. width: 60%;
  643. height: auto;
  644. display: flex;
  645. justify-content: flex-start;
  646. align-items: center;
  647. z-index: -1;
  648. }
  649. .tubiao2 {
  650. position: absolute;
  651. bottom: 5px;
  652. left: 20px;
  653. z-index: 10;
  654. width: 60%;
  655. height: auto;
  656. display: flex;
  657. justify-content: flex-start;
  658. align-items: center;
  659. z-index: -1;
  660. }
  661. </style>