declarationDialog.vue 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708
  1. <template>
  2. <ele-modal
  3. custom-class="ele-dialog-form long-dialog-form"
  4. :visible.sync="visibleDialog"
  5. :title="title"
  6. :close-on-click-modal="false"
  7. width="85%"
  8. append-to-body
  9. @close="handleClose"
  10. :maxable="true"
  11. >
  12. <el-form ref="form" :model="addForm" label-width="120px">
  13. <el-row>
  14. <el-col :span="8">
  15. <el-form-item label="工单编码">
  16. <el-input
  17. v-model="salesForm.code"
  18. size="small"
  19. placeholder="请输入"
  20. disabled
  21. ></el-input>
  22. </el-form-item>
  23. </el-col>
  24. <!-- 用计划名称 -->
  25. <el-col :span="8">
  26. <el-form-item label="名称">
  27. <el-input
  28. v-model="salesForm.name"
  29. size="small"
  30. placeholder="请输入"
  31. disabled
  32. ></el-input>
  33. </el-form-item>
  34. </el-col>
  35. <el-col :span="8">
  36. <el-form-item label="接收人">
  37. <el-input
  38. v-model="salesForm.receptionUserName"
  39. size="small"
  40. placeholder="请输入"
  41. disabled
  42. ></el-input>
  43. </el-form-item>
  44. </el-col>
  45. </el-row>
  46. <el-row>
  47. <el-col :span="8">
  48. <el-form-item label="接收时间">
  49. <el-input
  50. v-model="salesForm.receptionTime"
  51. size="small"
  52. placeholder="请输入"
  53. disabled
  54. ></el-input>
  55. </el-form-item>
  56. </el-col>
  57. <el-col :span="8">
  58. <el-form-item label="派单人">
  59. <el-input
  60. v-model="salesForm.dispatchUserName"
  61. size="small"
  62. placeholder="请输入"
  63. disabled
  64. ></el-input>
  65. </el-form-item>
  66. </el-col>
  67. <el-col :span="8">
  68. <el-form-item label="派单时间">
  69. <el-input
  70. v-model="salesForm.dispatchTime"
  71. size="small"
  72. placeholder="请输入"
  73. disabled
  74. ></el-input>
  75. </el-form-item>
  76. </el-col>
  77. </el-row>
  78. <el-row :gutter="24">
  79. <!-- <el-col :span="8">
  80. <el-form-item
  81. label="实际起始时间"
  82. prop="time"
  83. :rules="{
  84. required: true,
  85. message: '实际起始时间',
  86. trigger: 'change'
  87. }"
  88. >
  89. <el-date-picker
  90. style="width: 100%"
  91. v-model="addForm.time"
  92. type="datetimerange"
  93. value-format="yyyy-MM-dd HH:mm:ss"
  94. range-separator="至"
  95. start-placeholder="实际开始日期"
  96. end-placeholder="实际结束日期"
  97. :disabled="type == 'view'"
  98. @change="getTime"
  99. ></el-date-picker>
  100. </el-form-item>
  101. </el-col>
  102. <el-col :span="8">
  103. <el-form-item label="实际售后时长" prop="inFactDuration">
  104. <el-input v-model="addForm.inFactDuration" :disabled="true">
  105. <template slot="append">min</template>
  106. </el-input>
  107. </el-form-item>
  108. </el-col>
  109. <el-col :span="8">
  110. <el-form-item label="附件" prop="attachments">
  111. <fileMain v-model="addForm.attachments" :type="type == 'view' ? 'view' : 'add'"></fileMain>
  112. </el-form-item>
  113. </el-col>
  114. <el-col :span="8">
  115. <el-form-item label="故障现象" prop="faultPhenomenon">
  116. <el-input
  117. type="textarea"
  118. placeholder="请输入内容"
  119. v-model="addForm.faultPhenomenon"
  120. :disabled="type == 'view'"
  121. ></el-input>
  122. </el-form-item>
  123. </el-col>
  124. <el-col :span="8">
  125. <el-form-item label="故障原因" prop="faultReason">
  126. <el-input
  127. type="textarea"
  128. placeholder="请输入内容"
  129. v-model="addForm.faultReason"
  130. :disabled="type == 'view'"
  131. ></el-input>
  132. </el-form-item>
  133. </el-col>
  134. <el-col :span="8">
  135. <el-form-item label="维修过程" prop="maintenanceProcess">
  136. <el-input
  137. type="textarea"
  138. placeholder="请输入内容"
  139. v-model="addForm.maintenanceProcess"
  140. :disabled="type == 'view'"
  141. ></el-input>
  142. </el-form-item>
  143. </el-col>-->
  144. <!-- ***改 -->
  145. <div class="ele-body-custom">
  146. <el-tabs v-model="activeName" style="width: 100%" type="border-card">
  147. <el-tab-pane label="需求信息" name="需求信息">
  148. <el-col :span="24" class="ele-body-customA">
  149. <info
  150. ref="infoRef2"
  151. v-if="infoDisabled"
  152. type="view"
  153. :isPurchaseNeed="false"
  154. ></info>
  155. <info
  156. ref="infoRef2"
  157. v-else
  158. source="售后计划"
  159. state="可操作"
  160. type="view"
  161. :isPurchaseNeed="false"
  162. ></info>
  163. </el-col>
  164. </el-tab-pane>
  165. <el-tab-pane label="计划信息" name="计划信息">
  166. <planDialog ref="plan"></planDialog>
  167. </el-tab-pane>
  168. <el-tab-pane label="方案" name="方案">
  169. <el-col :span="24">
  170. <spareParts
  171. ref="sparePartsRef2"
  172. :state="type == 'edit' ? '可操作' : ''"
  173. :type="type == 'edit' ? 'edit' : 'view'"
  174. obtain="仓库"
  175. ></spareParts>
  176. <!-- source="报工信息" -->
  177. </el-col>
  178. </el-tab-pane>
  179. <!-- v-if="type == 'report'" 标记 -->
  180. <el-tab-pane
  181. v-if="infoShow"
  182. label="报工信息"
  183. name="报工信息"
  184. class="job_infor"
  185. >
  186. <el-col :span="12" class="timing">
  187. <el-form-item
  188. label="开始时间"
  189. prop="startTime"
  190. :rules="{
  191. required: true,
  192. message: '请选择开始时间',
  193. trigger: 'change'
  194. }"
  195. >
  196. <el-date-picker
  197. :disabled="type == 'view'"
  198. v-model="addForm.startTime"
  199. type="datetime"
  200. placeholder="选择开始时间"
  201. format="yyyy-MM-dd HH:mm:ss"
  202. value-format="yyyy-MM-dd HH:mm:ss"
  203. @change="handleTimeChange"
  204. ></el-date-picker>
  205. </el-form-item>
  206. <el-form-item
  207. label="结束时间"
  208. prop="endTime"
  209. :rules="{
  210. required: true,
  211. message: '请选择结束时间',
  212. trigger: 'change'
  213. }"
  214. >
  215. <el-date-picker
  216. :disabled="type == 'view'"
  217. v-model="addForm.endTime"
  218. type="datetime"
  219. placeholder="选择结束时间"
  220. format="yyyy-MM-dd HH:mm:ss"
  221. value-format="yyyy-MM-dd HH:mm:ss"
  222. @change="handleTimeChange"
  223. ></el-date-picker>
  224. </el-form-item>
  225. </el-col>
  226. <el-col :span="12">
  227. <el-form-item
  228. label="实际售后时长"
  229. prop="inFactDuration"
  230. class="after_sales"
  231. >
  232. <el-input v-model="days" :disabled="true">
  233. <template slot="append">天</template>
  234. </el-input>
  235. <el-input v-model="hours" :disabled="true">
  236. <template slot="append">小时</template>
  237. </el-input>
  238. <el-input v-model="minutes" :disabled="true">
  239. <template slot="append">分钟</template>
  240. </el-input>
  241. </el-form-item>
  242. </el-col>
  243. <el-col :span="24" class="ele-body-customA">
  244. <info
  245. ref="infoRef"
  246. source="报工信息"
  247. state="可操作"
  248. type="view"
  249. :isReportDetails="type == 'view' ? true : false"
  250. :isPurchaseNeed="false"
  251. ></info>
  252. </el-col>
  253. <el-col :span="24">
  254. <headerTitle
  255. title="配件申请清单"
  256. style="margin-top: 10px"
  257. ></headerTitle>
  258. <spareParts
  259. ref="sparePartsRef"
  260. :state="type == 'edit' ? '可操作' : ''"
  261. :type="type == 'edit' ? 'edit' : 'view'"
  262. ></spareParts>
  263. <!-- source="报工信息" -->
  264. </el-col>
  265. <el-col :span="24">
  266. <spareInfo
  267. :detailList="detailList"
  268. ref="spareCycleRef"
  269. :types="type"
  270. title="配件回收清单"
  271. v-if="visibleDialog"
  272. />
  273. </el-col>
  274. </el-tab-pane>
  275. </el-tabs>
  276. </div>
  277. </el-row>
  278. </el-form>
  279. <div slot="footer" class="footer">
  280. <el-button
  281. type="primary"
  282. :loading="loading"
  283. @click="submitAdd"
  284. v-if="type != 'view'"
  285. >{{ type == 'edit' ? '保存' : '报工' }}</el-button
  286. >
  287. <el-button
  288. type="primary"
  289. :loading="loading"
  290. @click="saveAdd"
  291. v-if="type == 'report'"
  292. >保存</el-button
  293. >
  294. <el-button @click="handleClose" :loading="loading">取消</el-button>
  295. </div>
  296. </ele-modal>
  297. </template>
  298. <script>
  299. import spareInfo from '@/views/salesServiceManagement/accessory/components/spareInfo.vue';
  300. // import fileMain from '@/components/addDoc/index.vue';
  301. import {
  302. reportWorkingSalesWorkOrder,
  303. updateScheme,
  304. getSalesWorkOrderById
  305. } from '@/api/salesServiceManagement/index';
  306. import spareParts from '@/views/salesServiceManagement/components/sparePartsList.vue';
  307. import info from '@/views/salesServiceManagement/components/info.vue';
  308. import planDialog from './planDialog.vue';
  309. export default {
  310. props: {},
  311. components: {
  312. // fileMain,
  313. spareParts,
  314. info,
  315. planDialog,
  316. spareInfo
  317. },
  318. watch: {},
  319. computed: {
  320. infoDisabled() {
  321. let flag = this.type == 'view' || this.type == 'report';
  322. return flag;
  323. },
  324. infoShow() {
  325. let flag =
  326. this.type == 'report' ||
  327. this.addForm.orderStatus == 3 ||
  328. this.addForm.orderStatus == 4 ||
  329. this.addForm.orderStatus == 5;
  330. return flag;
  331. }
  332. },
  333. data() {
  334. return {
  335. activeName: '需求信息',
  336. title: '',
  337. visibleDialog: false,
  338. addForm: {
  339. id: '',
  340. time: [],
  341. attachments: [],
  342. reason: ''
  343. },
  344. row: {},
  345. type: '',
  346. days: 0,
  347. hours: 0,
  348. minutes: 0,
  349. endTime: '', // 结束时间
  350. startTime: '', // 开始时间
  351. endTimePickerOptions: {
  352. disabledDate: (time) => {
  353. // 如果开始时间已选择,禁用开始时间之前的日期
  354. if (this.addForm.startTime) {
  355. return (
  356. time.getTime() < new Date(this.addForm.startTime).getTime()
  357. );
  358. }
  359. return false;
  360. }
  361. },
  362. salesForm: {
  363. code: '',
  364. name: '',
  365. receptionUserName: '',
  366. receptionTime: '',
  367. dispatchUserName: '',
  368. dispatchTime: ''
  369. },
  370. detailList: [],
  371. loading: false
  372. };
  373. },
  374. created() {},
  375. methods: {
  376. open(row, type) {
  377. this.visibleDialog = true;
  378. this.type = type;
  379. this.title = type == 'edit' ? '修改' : type == 'view' ? '详情' : '报工';
  380. if (type == 'report') {
  381. this.activeName = '报工信息';
  382. } else {
  383. this.activeName = '需求信息';
  384. }
  385. this.getDetail(row);
  386. },
  387. async getDetail(row) {
  388. const res = await getSalesWorkOrderById(row.id);
  389. this.addForm = res;
  390. this.salesForm = {
  391. code: res.code || '',
  392. receptionUserName: res.receptionUserName || '',
  393. receptionTime: res.receptionTime || '',
  394. dispatchUserName: res.afterSalesPlanVO.dispatchUserName || '',
  395. dispatchTime: res.afterSalesPlanVO.dispatchTime || '',
  396. name: res.afterSalesPlanVO.name || ''
  397. };
  398. // ***
  399. this.$nextTick(() => {
  400. // *** 报工信息的
  401. if (this.infoShow) {
  402. this.detailList = res.accessoryApply?.detailList;
  403. this.$refs.infoRef.init(res.afterSalesDemandVO);
  404. this.$refs.sparePartsRef.setTableValue(res?.costListVOS || []);
  405. this.$refs.infoRef2.init(res.afterSalesDemandVO);
  406. this.$refs.sparePartsRef2.setTableValue(res?.costListVOS || []);
  407. this.$set(this.addForm, 'startTime', this.addForm.acceptTime);
  408. this.$set(this.addForm, 'endTime', this.addForm.finishTime);
  409. this.calculateTimeConversion(res.inFactDuration);
  410. } else {
  411. this.$refs.infoRef2.init(res.afterSalesDemandVO);
  412. this.$refs.sparePartsRef2.setTableValue(res?.costListVOS || []);
  413. }
  414. this.$refs.plan.init(res.afterSalesPlanVO);
  415. });
  416. },
  417. // 时间选择
  418. handleTimeChange() {
  419. // 如果结束时间早于开始时间,清空结束时间
  420. if (this.addForm.startTime && this.addForm.endTime) {
  421. const startTime = new Date(this.addForm.startTime).getTime();
  422. const endTime = new Date(this.addForm.endTime).getTime();
  423. if (startTime > endTime) {
  424. this.addForm.endTime = '';
  425. this.$message.warning('结束时间不能小于开始时间');
  426. this.days = 0;
  427. this.hours = 0;
  428. this.minutes = 0;
  429. return;
  430. }
  431. if (this.addForm.startTime && this.addForm.endTime) {
  432. this.calculateTimeDifference();
  433. }
  434. }
  435. },
  436. // 时间转换 分钟
  437. calculateTimeConversion(minutes) {
  438. if (!minutes && minutes != 0) {
  439. this.timeAssignment(0, 0, 0);
  440. return;
  441. }
  442. // 确保输入是数字
  443. const totalMinutes = parseFloat(minutes);
  444. // 计算天、小时、分钟
  445. const days = (totalMinutes / (24 * 60)).toFixed(1);
  446. const hours = (totalMinutes / 60).toFixed(1);
  447. this.days = days;
  448. this.hours = hours;
  449. this.minutes = minutes;
  450. },
  451. // 时间赋值
  452. timeAssignment(days, hours, mins) {
  453. // 格式化结果(保留一位小数)
  454. let timeDifference = {
  455. days: days.toFixed(1),
  456. hours: hours.toFixed(1),
  457. minutes: mins.toFixed(0)
  458. };
  459. this.days = timeDifference.days;
  460. this.hours = timeDifference.hours;
  461. this.minutes = timeDifference.minutes;
  462. },
  463. // 时间转换 年月日 时分秒
  464. calculateTimeDifference() {
  465. // 计算时间差
  466. const startTime = new Date(this.addForm.startTime);
  467. const endTime = new Date(this.addForm.endTime);
  468. const timeDiff = endTime - startTime; // 毫秒数
  469. // 转换为天、小时、分钟
  470. const minutes = timeDiff / (1000 * 60);
  471. const hours = minutes / 60;
  472. const days = hours / 24;
  473. this.timeAssignment(days, hours, minutes);
  474. },
  475. // 提交
  476. async submitAdd() {
  477. // *** 更改
  478. let info = this.type == 'edit' ? 'infoRef2' : 'infoRef';
  479. let spare = this.type == 'edit' ? 'sparePartsRef2' : 'sparePartsRef';
  480. let validInfo = await this.$refs[info].getValidate();
  481. let validSpare = await this.$refs[spare].getValidate();
  482. let dataA = this.$refs[info].getValue();
  483. let obj = this.infoData(dataA);
  484. this.finalSubmit(spare, this.type, obj);
  485. },
  486. // *** 需求信息参数
  487. infoData(data) {
  488. let obj = JSON.parse(JSON.stringify(data));
  489. obj.productDetail = obj.tableList;
  490. delete obj.tableList;
  491. obj.id = this.addForm.afterSalesDemandVO.id;
  492. obj.productDetail.map((el) => delete el.produceTime);
  493. return obj;
  494. },
  495. listData(list) {
  496. let arr = [];
  497. if (list.length == 0) return list;
  498. list.map((item) => {
  499. this.addData(item, arr);
  500. });
  501. return arr;
  502. },
  503. addData(item, arr) {
  504. let totalCount = item.totalCount ? item.totalCount - 0 : '';
  505. if (!totalCount || totalCount == 1) {
  506. arr.push(item);
  507. return;
  508. }
  509. for (let i = 0; i < totalCount; i++) {
  510. item.totalPrice = item.singlePrice || 0;
  511. item.totalCount = 1;
  512. arr.push(item);
  513. }
  514. },
  515. // 最后提交 spare:具体的方案组件 obj:需求信息参数
  516. finalSubmit(spare, type, obj) {
  517. this.$refs.form.validate(async (valid) => {
  518. if (valid) {
  519. let data = {
  520. acceptTime: this.addForm.startTime,
  521. finishTime: this.addForm.endTime,
  522. attachments: this.addForm.attachments,
  523. maintenanceProcess: this.addForm.maintenanceProcess,
  524. faultPhenomenon: this.addForm.faultPhenomenon,
  525. faultReason: this.addForm.faultReason,
  526. inFactDuration: this.minutes,
  527. id: this.addForm.id,
  528. costListVOS: this.$refs[spare].getTableValue(),
  529. salesDemandUpdatePO: obj
  530. };
  531. // 报工 逻辑处理 配件申请清单数据
  532. if (type == 'report') {
  533. let list = this.$refs.spareCycleRef.getSpareData() || [];
  534. let detailList = this.listData(list);
  535. // 判断清单数据是否存在
  536. if (detailList.length > 0) {
  537. // 指定绑定第一条设备信息
  538. let item = data.salesDemandUpdatePO.productDetail[0];
  539. let accessoryApply = {
  540. demandDetailId: item.id,
  541. categoryCode: item.categoryCode,
  542. categoryName: item.categoryName,
  543. contactName: obj.contractInfo.name,
  544. contactCode: obj.contractInfo.code,
  545. detailList
  546. };
  547. data.accessoryApply = accessoryApply;
  548. }
  549. }
  550. // let api = this.type == 'edit' ? updateScheme : reportWorkingSalesWorkOrder;
  551. let api =
  552. type == 'edit' ? updateScheme : reportWorkingSalesWorkOrder;
  553. this.loading = true;
  554. await api(data)
  555. .then((res) => {
  556. this.loading = false;
  557. if (!res) return;
  558. this.$message.success('操作成功');
  559. this.visibleDialog = false;
  560. this.$emit('reload');
  561. })
  562. .catch((err) => {
  563. this.loading = false;
  564. });
  565. } else {
  566. return false;
  567. }
  568. });
  569. },
  570. // 保存
  571. saveAdd() {
  572. this.$refs.form.validate(async (valid) => {
  573. if (valid) {
  574. let dataA = this.$refs.infoRef2.getValue();
  575. let obj = this.infoData(dataA);
  576. let data = {
  577. acceptTime: this.addForm.startTime,
  578. finishTime: this.addForm.endTime,
  579. attachments: this.addForm.attachments,
  580. maintenanceProcess: this.addForm.maintenanceProcess,
  581. faultPhenomenon: this.addForm.faultPhenomenon,
  582. faultReason: this.addForm.faultReason,
  583. inFactDuration: this.minutes,
  584. id: this.addForm.id,
  585. costListVOS: this.$refs.sparePartsRef2.getTableValue(),
  586. salesDemandUpdatePO: obj
  587. };
  588. if (!data.acceptTime || !data.finishTime) {
  589. data.acceptTime = '';
  590. data.finishTime = '';
  591. data.inFactDuration = 0;
  592. }
  593. // 报工 逻辑处理 配件申请清单数据
  594. let list = this.$refs.spareCycleRef.getSpareData() || [];
  595. if (list.length > 0) {
  596. let detailList = this.listData(list);
  597. // 指定绑定第一条设备信息
  598. let item = data.salesDemandUpdatePO.productDetail[0];
  599. let accessoryApply = {
  600. demandDetailId: item.id,
  601. categoryCode: item.categoryCode,
  602. categoryName: item.categoryName,
  603. contactName: obj.contractInfo.name,
  604. contactCode: obj.contractInfo.code,
  605. detailList
  606. };
  607. data.accessoryApply = accessoryApply;
  608. }
  609. this.loading = true;
  610. await updateScheme(data)
  611. .then((res) => {
  612. this.loading = false;
  613. if (!res) return;
  614. this.$message.success('操作成功');
  615. this.visibleDialog = false;
  616. this.$emit('reload');
  617. })
  618. .catch((err) => {
  619. this.loading = false;
  620. });
  621. }
  622. });
  623. },
  624. handleClose() {
  625. this.visibleDialog = false;
  626. }
  627. }
  628. };
  629. </script>
  630. <style lang="scss" scoped>
  631. .dialog_top {
  632. margin-bottom: 10px;
  633. display: flex;
  634. align-items: center;
  635. span {
  636. margin-left: 50px;
  637. }
  638. .name {
  639. font-weight: 800;
  640. color: #40a9ff;
  641. }
  642. }
  643. ::v-deep .el-row {
  644. display: flex;
  645. flex-wrap: wrap;
  646. }
  647. .btns {
  648. text-align: right;
  649. // margin: 10px 0;
  650. }
  651. .main_container {
  652. width: 100%;
  653. display: flex;
  654. justify-content: space-between;
  655. }
  656. .ele-body-custom {
  657. width: 100%;
  658. margin-bottom: 24px;
  659. }
  660. .ele-body-customA {
  661. :deep(.divider) {
  662. display: none;
  663. }
  664. }
  665. .after_sales {
  666. :deep(.el-input--medium) {
  667. width: 30%;
  668. }
  669. :deep(.el-input--medium:nth-child(1)) {
  670. margin-right: 5%;
  671. }
  672. :deep(.el-input--medium:nth-child(2)) {
  673. margin-right: 5%;
  674. }
  675. }
  676. .job_infor {
  677. :deep(.ele-body) {
  678. padding: 15px 0;
  679. }
  680. }
  681. .timing {
  682. display: flex;
  683. :deep(.el-form-item) {
  684. width: 50%;
  685. .el-date-editor {
  686. width: 100%;
  687. }
  688. }
  689. }
  690. </style>