index.vue 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859
  1. <template>
  2. <div class="tenant">
  3. <!-- <Banner /> -->
  4. <div class="content">
  5. <byTable :source="sourceList.data" :pagination="sourceList.pagination" :config="config" :loading="loading" highlight-current-row
  6. :selectConfig="selectConfig" :table-events="{
  7. //element talbe事件都能传
  8. }" :action-list="[
  9. {
  10. text: '添加售后',
  11. disabled: false,
  12. action: () => clickAdd(),
  13. },
  14. ]" @get-list="getList">
  15. </byTable>
  16. </div>
  17. <el-dialog title="添加售后" v-model="dialogVisible" width="40%" destroy-on-close v-if="dialogVisible">
  18. <byForm :formConfig="formConfig" :formOption="formOption" v-model="formData.data" :rules="rules" ref="formDom" v-loading="submitLoading">
  19. <template #productSn>
  20. <div style="width: 100%; display: flex">
  21. <el-input v-model="formData.data.productSn" placeholder="请输入产品Sn" />
  22. <el-button @click="handleQuery" style="margin-left: 10px">查询</el-button>
  23. </div>
  24. </template>
  25. <template #file>
  26. <div style="width: 100%">
  27. <el-upload v-model:fileList="formData.data.fileList" action="https://winfaster.obs.cn-south-1.myhuaweicloud.com" :data="uploadData"
  28. multiple :before-upload="handleBeforeUpload" :on-success="handleSuccess" :on-preview="onPreviewFile">
  29. <el-button type="primary" plain>选择</el-button>
  30. </el-upload>
  31. </div>
  32. </template>
  33. </byForm>
  34. <template #footer>
  35. <el-button @click="dialogVisible = false" size="large">取 消</el-button>
  36. <el-button type="primary" @click="submitForm()" size="large" :loading="submitLoading">
  37. 确 定
  38. </el-button>
  39. </template>
  40. </el-dialog>
  41. <el-dialog title="售后跟进" v-model="openFollow" width="80%" destroy-on-close v-if="openFollow">
  42. <div style="width: 100%; display: flex">
  43. <div style="width: 48%; height: 70vh; overflow: auto; margin-right: 2%">
  44. <byForm :formConfig="formConfigDetail" :formOption="formOption" v-model="formData.detailData" ref="detailDom">
  45. <template #title1>
  46. <div style="width: 100%">
  47. <TitleInfo content="产品信息"></TitleInfo>
  48. </div>
  49. </template>
  50. <template #title2>
  51. <div style="width: 100%">
  52. <TitleInfo content="售后信息"></TitleInfo>
  53. </div>
  54. </template>
  55. <template #file>
  56. <div style="width: 100%">
  57. <el-upload v-model:fileList="formData.detailData.fileList" action="https://winfaster.obs.cn-south-1.myhuaweicloud.com"
  58. :data="uploadData" multiple :before-upload="handleBeforeUpload" :on-success="handleSuccess" :on-preview="onPreviewFile">
  59. <el-button type="primary" plain disabled>选择</el-button>
  60. </el-upload>
  61. </div>
  62. </template>
  63. </byForm>
  64. </div>
  65. <div style="width: 50%; height: 70vh; overflow: auto; padding-right: 20px">
  66. <el-form :model="formData.followData" label-width="120px" label-position="top" ref="followDom" :rules="followRules"
  67. v-loading="submitLoading">
  68. <div style="width: 100%">
  69. <TitleInfo content="配件问题" style="margin: 20px 0 20px 0"></TitleInfo>
  70. <el-collapse v-model="activeNames">
  71. <el-collapse-item v-for="(item, index) in formData.followData.bomDetailList" :key="item.id" :name="item.id">
  72. <template #title>
  73. <div style="width: 100%; display: flex">
  74. <div style="flex: 1">
  75. <el-icon color="red" v-if="
  76. submitData[item.id].quantity &&
  77. submitData[item.id].remark &&
  78. submitData[item.id].fileList.length > 0
  79. " style="margin-right: 10px">
  80. <WarnTriangleFilled />
  81. </el-icon>
  82. {{ item.productName }}
  83. </div>
  84. <div style="margin-right: 10px">
  85. [ {{ item.quantity }} ]
  86. </div>
  87. </div>
  88. </template>
  89. <div>
  90. <el-form-item label="售后数量">
  91. <el-input-number onmousewheel="return false;" v-model="submitData[item.id].quantity" placeholder="请输入" style="width: 100%"
  92. :precision="0" :controls="false" :min="0" :disabled="isDetail" />
  93. </el-form-item>
  94. <el-form-item label="售后说明">
  95. <el-input v-model="submitData[item.id].remark" type="textarea" :disabled="isDetail" />
  96. </el-form-item>
  97. <el-form-item label="现场照片" style="margin-top: 20px">
  98. <div>
  99. <el-upload v-model:fileList="submitData[item.id].fileList" action="https://winfaster.obs.cn-south-1.myhuaweicloud.com"
  100. :data="uploadData" multiple :before-upload="handleBeforeUpload" :on-success="handleSuccess"
  101. :on-preview="onPreviewFile">
  102. <el-button type="primary" plain :disabled="isDetail">选择</el-button>
  103. </el-upload>
  104. </div>
  105. </el-form-item>
  106. </div>
  107. </el-collapse-item>
  108. </el-collapse>
  109. </div>
  110. <div style="width: 100%; margin-top: 20px">
  111. <TitleInfo content="其他问题"></TitleInfo>
  112. </div>
  113. <el-form-item label=" " prop="afterSalesRemark">
  114. <el-input v-model="formData.followData.afterSalesRemark" type="textarea" placeholder="请输入" :disabled="isDetail" />
  115. </el-form-item>
  116. <div style="width: 100%">
  117. <TitleInfo content="售后金额" style="margin-top: 20px"></TitleInfo>
  118. </div>
  119. <el-form-item label=" " prop="amount">
  120. <el-input-number onmousewheel="return false;" v-model="formData.followData.amount" placeholder="请输入" style="width: 100%" :precision="2"
  121. :controls="false" :min="0" :disabled="isDetail" />
  122. </el-form-item>
  123. <div style="width: 100%">
  124. <TitleInfo content="程序文件" style="margin: 20px 0 20px 0"></TitleInfo>
  125. <el-upload v-model:fileList="formData.followData.fileListOne" action="https://winfaster.obs.cn-south-1.myhuaweicloud.com"
  126. :data="uploadData" multiple :before-upload="handleBeforeUpload" :on-success="handleSuccess" :on-preview="onPreviewFile">
  127. <el-button type="primary" plain disabled>选择</el-button>
  128. </el-upload>
  129. </div>
  130. <div style="width: 100%">
  131. <TitleInfo content="申请物料" style="margin: 20px 0 20px 0"></TitleInfo>
  132. <div style="width: 100%">
  133. <el-button type="primary" plain @click="openMaterial = true" v-if="!isDetail">
  134. 添加物料/半成品
  135. </el-button>
  136. <el-table :data="formData.followData.afterSalesMaterialsList" style="margin-top: 15px">
  137. <el-table-column prop="productName" label="产品名称" min-width="200" />
  138. <el-table-column prop="productSpec" label="规格型号" width="120" />
  139. <el-table-column prop="quantity" label="数量" width="150">
  140. <template #default="{ row, $index }">
  141. <el-form-item :prop="'afterSalesMaterialsList.' + $index + '.quantity'" :rules="rules.quantity" :inline-message="true">
  142. <el-input-number onmousewheel="return false;" v-model="row.quantity" :disabled="isDetail" :precision="0" :controls="false"
  143. :min="0" @change="changeAmount" style="width:80%" />
  144. </el-form-item>
  145. </template>
  146. </el-table-column>
  147. <!-- <el-table-column prop="productRemark" label="备注" min-width="150">
  148. <template #default="{ row, $index }">
  149. <el-form-item :prop="
  150. 'afterSalesMaterialsList.' + $index + '.productRemark'
  151. " :rules="rules.productRemark" :inline-message="true">
  152. <el-input v-model="row.productRemark" placeholder="请输入" type="textarea" :rows="3" />
  153. </el-form-item>
  154. </template>
  155. </el-table-column> -->
  156. <el-table-column prop="zip" label="操作" width="60" v-if="!isDetail">
  157. <template #default="{ $index }">
  158. <el-button type="primary" link @click="handleRemove($index)">删除</el-button>
  159. </template>
  160. </el-table-column>
  161. </el-table>
  162. </div>
  163. </div>
  164. </el-form>
  165. </div>
  166. </div>
  167. <template #footer>
  168. <el-button @click="openFollow = false" size="large">取 消</el-button>
  169. <el-button type="primary" @click="submitFollow()" size="large" :loading="submitLoading" v-if="!isDetail">确 定</el-button>
  170. </template>
  171. </el-dialog>
  172. <el-dialog v-model="openMaterial" title="选择物料/半成品" width="70%" append-to-body>
  173. <SelectMaterial @handleSelect="handleSelect"></SelectMaterial>
  174. <template #footer>
  175. <span class="dialog-footer">
  176. <el-button @click="openMaterial = false">取消</el-button>
  177. </span>
  178. </template>
  179. </el-dialog>
  180. </div>
  181. </template>
  182. <script setup>
  183. import { ElMessage, ElMessageBox } from "element-plus";
  184. import byTable from "@/components/byTable/index";
  185. import byForm from "@/components/byForm/index";
  186. import useUserStore from "@/store/modules/user";
  187. import TitleInfo from "@/components/TitleInfo/index.vue";
  188. import SelectMaterial from "@/components/product/SelectMaterial";
  189. const { proxy } = getCurrentInstance();
  190. const uploadData = ref({});
  191. const loading = ref(false);
  192. const submitLoading = ref(false);
  193. const sourceList = ref({
  194. data: [],
  195. pagination: {
  196. total: 3,
  197. pageNum: 1,
  198. pageSize: 10,
  199. keyword: "",
  200. },
  201. });
  202. const openMaterial = ref(false);
  203. const dialogVisible = ref(false);
  204. const openFollow = ref(false);
  205. const rules = ref({
  206. productSn: [{ required: true, message: "请输入产品Sn", trigger: "blur" }],
  207. type: [{ required: true, message: "请选择售后类型", trigger: "change" }],
  208. remark: [{ required: true, message: "请输入售后说明", trigger: "blur" }],
  209. contactName: [
  210. { required: true, message: "请输入客户联系人", trigger: "blur" },
  211. ],
  212. contactInfo: [
  213. { required: true, message: "请输入客户联系方式", trigger: "blur" },
  214. ],
  215. afterSalesPersonId: [
  216. { required: true, message: "请选择售后人员", trigger: "change" },
  217. ],
  218. quantity: [{ required: true, message: "请输入数量", trigger: "blur" }],
  219. });
  220. const userList = ref([]);
  221. const afterSalesType = ref([]);
  222. const selectConfig = computed(() => [
  223. // {
  224. // label: "售后类型",
  225. // prop: "type",
  226. // data: afterSalesType.value,
  227. // },
  228. // {
  229. // label: "售后状态",
  230. // prop: "status",
  231. // data: [
  232. // {
  233. // label: "进行中",
  234. // value: 0,
  235. // },
  236. // {
  237. // label: "完成",
  238. // value: 1,
  239. // },
  240. // ],
  241. // },
  242. ]);
  243. const config = computed(() => {
  244. return [
  245. {
  246. attrs: {
  247. label: "售后编码",
  248. prop: "code",
  249. },
  250. },
  251. {
  252. attrs: {
  253. label: "产品Sn",
  254. prop: "productSn",
  255. },
  256. },
  257. {
  258. attrs: {
  259. label: "产品名称",
  260. prop: "productName",
  261. },
  262. },
  263. {
  264. attrs: {
  265. label: "规格型号",
  266. prop: "productSpec",
  267. },
  268. },
  269. {
  270. attrs: {
  271. label: "售后金额",
  272. prop: "amount",
  273. },
  274. },
  275. {
  276. attrs: {
  277. label: "售后状态",
  278. prop: "status",
  279. },
  280. render(status) {
  281. return status == "0" ? "进行中" : "完成";
  282. },
  283. },
  284. {
  285. attrs: {
  286. label: "操作",
  287. width: "200",
  288. align: "center",
  289. fixed: "right",
  290. },
  291. renderHTML(row) {
  292. return [
  293. {
  294. attrs: {
  295. label: row.status == 0 ? "跟进" : "查看",
  296. type: "primary",
  297. text: true,
  298. disabled: false,
  299. },
  300. el: "button",
  301. click() {
  302. handleFollow(row);
  303. },
  304. },
  305. ];
  306. },
  307. },
  308. ];
  309. });
  310. const formData = reactive({
  311. data: {
  312. afterSalesDetailList: [],
  313. },
  314. followData: {},
  315. detailData: {},
  316. });
  317. const formOption = reactive({
  318. inline: true,
  319. labelWidth: 100,
  320. itemWidth: 100,
  321. rules: [],
  322. });
  323. const formConfig = computed(() => {
  324. return [
  325. {
  326. type: "slot",
  327. slotName: "productSn",
  328. prop: "productSn",
  329. label: "产品Sn",
  330. },
  331. {
  332. type: "input",
  333. itemType: "text",
  334. prop: "productName",
  335. label: "产品名称",
  336. disabled: true,
  337. },
  338. {
  339. type: "input",
  340. itemType: "text",
  341. prop: "productSpec",
  342. label: "规格型号",
  343. disabled: true,
  344. },
  345. {
  346. type: "input",
  347. itemType: "text",
  348. prop: "customerName",
  349. label: "客户名称",
  350. disabled: true,
  351. },
  352. {
  353. type: "input",
  354. itemType: "text",
  355. prop: "code",
  356. label: "合同编码",
  357. disabled: true,
  358. },
  359. {
  360. type: "select",
  361. prop: "type",
  362. label: "售后类型",
  363. required: true,
  364. itemWidth: 100,
  365. // multiple: true,
  366. data: afterSalesType.value,
  367. style: {
  368. width: "100%",
  369. },
  370. disabled: false,
  371. },
  372. {
  373. type: "input",
  374. itemType: "textarea",
  375. prop: "remark",
  376. label: "售后说明",
  377. required: true,
  378. },
  379. {
  380. type: "input",
  381. itemType: "text",
  382. prop: "contactName",
  383. label: "客户联系人",
  384. disabled: false,
  385. },
  386. {
  387. type: "input",
  388. itemType: "text",
  389. prop: "contactInfo",
  390. label: "客户联系方式",
  391. disabled: false,
  392. },
  393. {
  394. type: "select",
  395. prop: "afterSalesPersonId",
  396. label: "售后人员",
  397. itemWidth: 100,
  398. // multiple: true,
  399. filterable: true,
  400. data: userList.value,
  401. style: {
  402. width: "100%",
  403. },
  404. disabled: false,
  405. },
  406. {
  407. type: "slot",
  408. slotName: "file",
  409. label: "售后附件",
  410. },
  411. ];
  412. });
  413. const formConfigDetail = computed(() => {
  414. return [
  415. {
  416. type: "slot",
  417. slotName: "title1",
  418. },
  419. {
  420. type: "input",
  421. itemType: "text",
  422. label: "售后编码",
  423. prop: "code",
  424. itemWidth: 100,
  425. disabled: true,
  426. },
  427. {
  428. type: "input",
  429. itemType: "text",
  430. label: "产品Sn",
  431. prop: "productSn",
  432. itemWidth: 100,
  433. disabled: true,
  434. },
  435. {
  436. type: "input",
  437. itemType: "text",
  438. label: "产品名称",
  439. prop: "productName",
  440. itemWidth: 100,
  441. disabled: true,
  442. },
  443. {
  444. type: "input",
  445. itemType: "text",
  446. label: "规格型号",
  447. prop: "productSpec",
  448. itemWidth: 100,
  449. disabled: true,
  450. },
  451. {
  452. type: "slot",
  453. slotName: "title2",
  454. },
  455. {
  456. type: "select",
  457. prop: "type",
  458. label: "售后类型",
  459. required: true,
  460. itemWidth: 100,
  461. // multiple: true,
  462. data: afterSalesType.value,
  463. style: {
  464. width: "100%",
  465. },
  466. disabled: true,
  467. },
  468. {
  469. type: "input",
  470. itemType: "textarea",
  471. prop: "remark",
  472. label: "售后说明",
  473. disabled: true,
  474. },
  475. {
  476. type: "input",
  477. itemType: "text",
  478. prop: "contactName",
  479. label: "客户联系人",
  480. disabled: true,
  481. },
  482. {
  483. type: "input",
  484. itemType: "text",
  485. prop: "contactInfo",
  486. label: "客户联系方式",
  487. disabled: true,
  488. },
  489. {
  490. type: "select",
  491. prop: "afterSalesPersonId",
  492. label: "售后人员",
  493. itemWidth: 100,
  494. // multiple: true,
  495. filterable: true,
  496. data: userList.value,
  497. style: {
  498. width: "100%",
  499. },
  500. disabled: true,
  501. },
  502. {
  503. type: "slot",
  504. slotName: "file",
  505. label: "售后附件",
  506. },
  507. ];
  508. });
  509. const formConfigFollow = computed(() => {
  510. return [
  511. {
  512. type: "slot",
  513. slotName: "listSlot",
  514. },
  515. {
  516. type: "slot",
  517. slotName: "title1",
  518. },
  519. {
  520. type: "input",
  521. itemType: "textarea",
  522. prop: "remark",
  523. label: "",
  524. disabled: false,
  525. },
  526. {
  527. type: "slot",
  528. slotName: "fileSlot",
  529. },
  530. ];
  531. });
  532. const followRules = ref({
  533. afterSalesRemark: [
  534. { required: true, message: "请输入其他问题", trigger: "blur" },
  535. ],
  536. amount: [{ required: true, message: "请输入售后金额", trigger: "blur" }],
  537. });
  538. const formDom = ref(null);
  539. const followDom = ref(null);
  540. const getList = (req) => {
  541. sourceList.value.pagination = { ...sourceList.value.pagination, ...req };
  542. loading.value = true;
  543. proxy
  544. .post("/afterSalesRecord/page", sourceList.value.pagination)
  545. .then((res) => {
  546. sourceList.value.data = res.rows;
  547. sourceList.value.pagination.total = res.total;
  548. setTimeout(() => {
  549. loading.value = false;
  550. }, 200);
  551. });
  552. };
  553. const submitForm = () => {
  554. formDom.value.handleSubmit(() => {
  555. // if (formData.data.fileList && formData.data.fileList.length > 0) {
  556. // } else {
  557. // return ElMessage({
  558. // message: "请上传售后附件",
  559. // type: "info",
  560. // });
  561. // }
  562. formData.data.fileList = formData.data.fileList.map((x) => x.raw);
  563. submitLoading.value = true;
  564. proxy.post("/afterSalesRecord/add", formData.data).then(
  565. (res) => {
  566. ElMessage({
  567. message: "操作成功",
  568. type: "success",
  569. });
  570. dialogVisible.value = false;
  571. submitLoading.value = false;
  572. getList();
  573. },
  574. (err) => {
  575. submitLoading.value = false;
  576. }
  577. );
  578. });
  579. };
  580. const submitFollow = () => {
  581. followDom.value.validate((valid) => {
  582. if (valid) {
  583. let arr = Object.values(submitData.value);
  584. for (let i = 0; i < arr.length; i++) {
  585. const e = arr[i];
  586. if (e.quantity || e.remark.trim() || e.fileList.length > 0) {
  587. if (!e.quantity) {
  588. return ElMessage({
  589. message: `请填写${e.productName}配件的售后数量`,
  590. type: "info",
  591. });
  592. }
  593. if (!e.remark.trim()) {
  594. return ElMessage({
  595. message: `请填写${e.productName}配件的售后说明`,
  596. type: "info",
  597. });
  598. }
  599. if (e.fileList.length == 0) {
  600. return ElMessage({
  601. message: `请上传${e.productName}配件的现场照片`,
  602. type: "info",
  603. });
  604. }
  605. }
  606. }
  607. if (!(Number(formData.followData.amount) > 0)) {
  608. return ElMessage({
  609. message: `售后金额需大于0`,
  610. type: "info",
  611. });
  612. }
  613. for (let i = 0; i < arr.length; i++) {
  614. const e = arr[i];
  615. e.fileList = e.fileList.map((x) => x.raw);
  616. }
  617. submitLoading.value = true;
  618. proxy
  619. .post("/afterSalesRecord/afterSales", {
  620. id: formData.followData.id,
  621. afterSalesRemark: formData.followData.afterSalesRemark,
  622. amount: formData.followData.amount,
  623. afterSalesRecordDetailList: arr,
  624. afterSalesMaterialsList: formData.followData.afterSalesMaterialsList,
  625. })
  626. .then(
  627. (res) => {
  628. ElMessage({
  629. message: "操作成功",
  630. type: "success",
  631. });
  632. openFollow.value = false;
  633. submitLoading.value = false;
  634. getList();
  635. },
  636. (err) => {
  637. submitLoading.value = false;
  638. }
  639. );
  640. }
  641. });
  642. };
  643. const getDict = () => {
  644. proxy
  645. .get("/tenantUser/list", {
  646. pageNum: 1,
  647. pageSize: 10000,
  648. tenantId: useUserStore().user.tenantId,
  649. })
  650. .then((res) => {
  651. userList.value = res.rows.map((item) => {
  652. return {
  653. label: item.nickName,
  654. value: item.userId,
  655. };
  656. });
  657. });
  658. proxy.getDictOne(["after_sales_type"]).then((res) => {
  659. afterSalesType.value = res["after_sales_type"].map((x) => ({
  660. label: x.dictValue,
  661. value: x.dictKey,
  662. }));
  663. });
  664. };
  665. getDict();
  666. getList();
  667. const clickAdd = (type) => {
  668. formData.data = {
  669. afterSalesPersonId: useUserStore().user.userId,
  670. fileList: [],
  671. };
  672. dialogVisible.value = true;
  673. };
  674. const activeNames = ref([]);
  675. const submitData = ref({});
  676. const isDetail = ref(false);
  677. const handleFollow = (row) => {
  678. isDetail.value = row.status == 0 ? false : true;
  679. proxy.post("/afterSalesRecord/detail", { id: row.id }).then(async (res) => {
  680. // 左侧售后信息
  681. formData.detailData = res;
  682. proxy
  683. .post("/fileInfo/getList", {
  684. businessIdList: [row.id],
  685. })
  686. .then((fileObj) => {
  687. if (fileObj && fileObj[row.id]) {
  688. formData.detailData.fileList = fileObj[row.id].map((x) => ({
  689. raw: x,
  690. name: x.fileName,
  691. url: x.fileUrl,
  692. }));
  693. }
  694. });
  695. // 右侧跟进
  696. if (row.status == 0) {
  697. for (let i = 0; i < res.bomDetailList.length; i++) {
  698. const e = res.bomDetailList[i];
  699. submitData.value[e.id] = {
  700. bomDetailId: e.id,
  701. accessoriesId: e.productId,
  702. productName: e.productName,
  703. quantity: null,
  704. remark: "",
  705. fileList: [],
  706. };
  707. }
  708. formData.followData = res;
  709. formData.followData.id = row.id;
  710. formData.followData.afterSalesMaterialsList = [];
  711. openFollow.value = true;
  712. } else {
  713. let arr = res.bomDetailList.map((x) => x.afterSalesRecordDetail.id);
  714. for (let i = 0; i < res.bomDetailList.length; i++) {
  715. const e = res.bomDetailList[i];
  716. submitData.value[e.id] = {
  717. bomDetailId: e.id,
  718. accessoriesId: e.productId,
  719. productName: e.productName,
  720. quantity: e.afterSalesRecordDetail.quantity,
  721. remark: e.afterSalesRecordDetail.remark,
  722. fileList: [],
  723. };
  724. }
  725. formData.followData = res;
  726. formData.followData.id = row.id;
  727. // formData.followData.afterSalesMaterialsList = [];
  728. openFollow.value = true;
  729. const fileObj = await proxy.post("/fileInfo/getList", {
  730. businessIdList: arr,
  731. });
  732. for (let i = 0; i < res.bomDetailList.length; i++) {
  733. const e = res.bomDetailList[i];
  734. for (const key in fileObj) {
  735. if (e.afterSalesRecordDetail.id == key) {
  736. submitData.value[e.id].fileList = fileObj[key].map((item) => ({
  737. raw: item,
  738. name: item.fileName,
  739. url: item.fileUrl,
  740. }));
  741. }
  742. }
  743. }
  744. }
  745. if (res.bomInfoId) {
  746. proxy
  747. .post("/fileInfo/getList", { businessIdList: [res.bomInfoId] })
  748. .then((fileObj) => {
  749. formData.followData.fileListOne = fileObj[res.bomInfoId].map(
  750. (item) => ({
  751. raw: item,
  752. name: item.fileName,
  753. url: item.fileUrl,
  754. })
  755. );
  756. });
  757. }
  758. });
  759. };
  760. const handleQuery = () => {
  761. proxy
  762. .post("/productionTaskDetail/snInfo", {
  763. productSn: formData.data.productSn,
  764. })
  765. .then((res) => {
  766. if (res && res.productId) {
  767. formData.data.productId = res.productId;
  768. formData.data.code = res.contractCode;
  769. formData.data.productName = res.productName;
  770. formData.data.productSpec = res.productSpec;
  771. formData.data.customerName = res.customerName;
  772. }
  773. });
  774. };
  775. const handleBeforeUpload = async (file) => {
  776. const res = await proxy.post("/fileInfo/getSing", { fileName: file.name });
  777. uploadData.value = res.uploadBody;
  778. file.id = res.id;
  779. file.fileName = res.fileName;
  780. file.fileUrl = res.fileUrl;
  781. file.uploadState = true;
  782. return true;
  783. };
  784. const handleSuccess = (any, UploadFile) => {
  785. UploadFile.raw.uploadState = false;
  786. };
  787. const onPreviewFile = (file) => {
  788. window.open(file.raw.fileUrl, "_blank");
  789. };
  790. const handleSelect = (row) => {
  791. const flag = formData.followData.afterSalesMaterialsList.some(
  792. (x) => x.productId === row.id
  793. );
  794. if (flag) {
  795. return ElMessage({
  796. message: "该物料已选择",
  797. type: "info",
  798. });
  799. } else {
  800. formData.followData.afterSalesMaterialsList.push({
  801. productId: row.id,
  802. productCode: row.code,
  803. productName: row.name,
  804. productSpec: row.spec,
  805. quantity: null,
  806. });
  807. return ElMessage({
  808. message: "选择成功",
  809. type: "success",
  810. });
  811. }
  812. };
  813. const handleRemove = (index, type) => {
  814. formData.followData.afterSalesMaterialsList.splice(index, 1);
  815. return ElMessage({
  816. message: "删除成功",
  817. type: "success",
  818. });
  819. };
  820. </script>
  821. <style lang="scss" scoped>
  822. .tenant {
  823. padding: 20px;
  824. }
  825. ::v-deep {
  826. .el-form-item__content {
  827. display: block;
  828. }
  829. }
  830. ::v-deep(.el-input-number .el-input__inner) {
  831. text-align: left;
  832. }
  833. </style>