edit.vue 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. <template>
  2. <div class="form">
  3. <van-nav-bar
  4. :title="$t('afterSales.name')"
  5. :left-text="$t('common.back')"
  6. left-arrow
  7. @click-left="onClickLeft"
  8. >
  9. </van-nav-bar>
  10. <testForm
  11. v-model="formData.data"
  12. :formOption="formOption"
  13. :formConfig="formConfig"
  14. :rules="rules"
  15. @onSubmit="onSubmit"
  16. ref="formDom"
  17. >
  18. <template #top>
  19. <div style="width: 100%">
  20. <ShowFormData :data="formData.data" :config="topConfig">
  21. </ShowFormData>
  22. </div>
  23. </template>
  24. <template #list>
  25. <div style="width: 100%">
  26. <van-collapse v-model="activeNames">
  27. <van-collapse-item
  28. v-for="(item, index) in formData.data.bomDetailList"
  29. :key="item.id"
  30. :name="item.id"
  31. :value="'[ ' + item.quantity + ' ]'"
  32. >
  33. <template #title>
  34. <div>
  35. <van-icon
  36. name="warning-o"
  37. v-if="
  38. submitData[item.productId].remark &&
  39. submitData[item.productId].fileList.length > 0
  40. "
  41. color="#ee0a24"
  42. style="margin-right: 5px"
  43. />
  44. {{ item.productName }}
  45. </div>
  46. </template>
  47. <div>
  48. <van-field
  49. v-model="submitData[item.productId].remark"
  50. label="售后说明"
  51. type="textarea"
  52. placeholder="请输入"
  53. label-align="top"
  54. :rules="[{ required: true, message: '请填写售后说明' }]"
  55. />
  56. <van-field name="uploader" label="现场照片">
  57. <template #input>
  58. <van-uploader
  59. v-model="submitData[item.productId].fileList"
  60. :after-read="afterRead"
  61. multiple
  62. :max-size="5 * 1024 * 1024"
  63. @oversize="onOversize"
  64. />
  65. </template>
  66. </van-field>
  67. </div>
  68. </van-collapse-item>
  69. </van-collapse>
  70. <!-- <div
  71. v-for="(item, index) in formData.data.bomDetailList"
  72. :key="index"
  73. >
  74. <ShowFormData
  75. :data="item"
  76. :config="listConfig"
  77. :showMore="
  78. item.afterSalesRecordDetail || route.query.status == 0
  79. ? true
  80. : false
  81. "
  82. @onClickItem="handleClickItem(item)"
  83. >
  84. </ShowFormData>
  85. </div> -->
  86. </div>
  87. </template>
  88. </testForm>
  89. </div>
  90. </template>
  91. <script setup>
  92. import { ref, reactive, getCurrentInstance, onMounted } from "vue";
  93. import { showSuccessToast, showFailToast } from "vant";
  94. import { useRoute } from "vue-router";
  95. import testForm from "@/components/testForm/index.vue";
  96. import ShowFormData from "@/components/ShowFormData.vue";
  97. const proxy = getCurrentInstance().proxy;
  98. const route = useRoute();
  99. const formDom = ref(null);
  100. const activeNames = ref([]);
  101. const formData = reactive({
  102. data: {},
  103. });
  104. const rules = {
  105. customerId: [
  106. {
  107. required: true,
  108. message: proxy.t("afterSales.pleaseSelectTheCustomerName"),
  109. },
  110. ],
  111. };
  112. const formOption = reactive({
  113. readonly: false, //用于控制整个表单是否只读
  114. disabled: false,
  115. labelAlign: "top",
  116. scroll: true,
  117. labelWidth: "62pk",
  118. hiddenSubmitBtn: false,
  119. });
  120. const formConfig = reactive([
  121. {
  122. type: "slot",
  123. slotName: "top",
  124. },
  125. {
  126. type: "title",
  127. title: proxy.t("afterSales.originalPartsList"),
  128. },
  129. {
  130. type: "slot",
  131. slotName: "list",
  132. },
  133. {
  134. type: "title",
  135. title: proxy.t("afterSales.programFile"),
  136. },
  137. {
  138. type: "upload",
  139. label: " ",
  140. readonly: true,
  141. prop: "fileList",
  142. },
  143. ]);
  144. const topConfig = ref([
  145. {
  146. label: proxy.t("afterSales.afterSalesCode"),
  147. prop: "code",
  148. },
  149. {
  150. label: proxy.t("afterSales.productName"),
  151. prop: "productName",
  152. },
  153. {
  154. label: proxy.t("afterSales.productSN"),
  155. prop: "productSn",
  156. },
  157. ]);
  158. const listConfig = ref([
  159. {
  160. label: proxy.t("afterSales.accessoriesName"),
  161. prop: "productName",
  162. },
  163. {
  164. label: proxy.t("afterSales.quantity"),
  165. prop: "quantity",
  166. },
  167. ]);
  168. const onClickLeft = () => history.back();
  169. const submitData = ref({});
  170. const getDetails = (id) => {
  171. proxy.post("/afterSalesRecord/detail", { id }).then((res) => {
  172. formData.data = res.data;
  173. const obj = JSON.parse(window.localStorage.getItem("jxstAfterSalesData"));
  174. for (let i = 0; i < formData.data.bomDetailList.length; i++) {
  175. const e = formData.data.bomDetailList[i];
  176. submitData.value[e.productId] = {
  177. accessoriesId: e.productId,
  178. remark: "",
  179. fileList: [],
  180. };
  181. // if (e.afterSalesRecordDetail) {
  182. // e.productName = e.productName + proxy.t("afterSales.afterSales");
  183. // }
  184. // for (const key in obj) {
  185. // if (e.productId === key) {
  186. // e.accessoriesId = key;
  187. // e.remark = obj[key].remark;
  188. // e.fileList = obj[key].fileList;
  189. // }
  190. // }
  191. }
  192. if (res.data.bomInfoId) {
  193. proxy
  194. .post("/fileInfo/getList", { businessIdList: [res.data.bomInfoId] })
  195. .then((file) => {
  196. formData.data.fileList = file.data[res.data.bomInfoId].map((x) => ({
  197. ...x,
  198. url: x.fileUrl,
  199. }));
  200. });
  201. }
  202. });
  203. };
  204. onMounted(() => {
  205. if (route.query.id) {
  206. getDetails(route.query.id);
  207. if (route.query.status == 1) {
  208. formOption.hiddenSubmitBtn = true; //隐藏提交按钮
  209. }
  210. }
  211. });
  212. const onSubmit = () => {
  213. let arr = Object.values(submitData.value);
  214. for (let i = 0; i < arr.length; i++) {
  215. const e = arr[i];
  216. if (e.fileList.length == 0) {
  217. return showFailToast(`第${i + 1}个配件没传现场照片`);
  218. }
  219. }
  220. proxy
  221. .post("/afterSalesRecord/afterSales", {
  222. id: formData.data.id,
  223. afterSalesRecordDetailList: arr,
  224. })
  225. .then(
  226. () => {
  227. showSuccessToast(proxy.t("afterSales.operationSuccessful"));
  228. setTimeout(() => {
  229. onClickLeft();
  230. }, 500);
  231. },
  232. (err) => {
  233. return showFailToast(err.message);
  234. }
  235. );
  236. };
  237. const handleClickItem = (item) => {
  238. if (item.afterSalesRecordDetail || route.query.status == 0) {
  239. proxy.$router.push({
  240. path: "jxskAfterSalesEditItem",
  241. query: {
  242. data: JSON.stringify({
  243. bomDetailList: [item],
  244. code: formData.data.code,
  245. productName: formData.data.productName,
  246. productSn: formData.data.productSn,
  247. remark: item.afterSalesRecordDetail
  248. ? item.afterSalesRecordDetail.remark
  249. : "",
  250. fileList: [],
  251. status: route.query.status,
  252. }),
  253. },
  254. });
  255. }
  256. };
  257. const afterRead = (file) => {
  258. if (file && file.length > 0) {
  259. for (let i = 0; i < file.length; i++) {
  260. file[i].status = "uploading";
  261. file[i].message = "上传中...";
  262. proxy.post("/fileInfo/getSing", { fileName: file[i].file.name }).then(
  263. (res) => {
  264. let forms = new FormData();
  265. forms.append("file", file[i].file);
  266. proxy
  267. .post("https://winfaster.obs.cn-south-1.myhuaweicloud.com", {
  268. ...res.data.uploadBody,
  269. file: forms.get("file"),
  270. })
  271. .then(
  272. () => {
  273. file[i].id = res.data.id;
  274. file[i].url = res.data.fileUrl;
  275. file[i].fileName = res.data.fileName;
  276. delete file[i].status;
  277. delete file[i].message;
  278. },
  279. () => {
  280. file[i].status = "failed";
  281. file[i].message = "上传失败";
  282. }
  283. );
  284. },
  285. () => {
  286. file[i].status = "failed";
  287. file[i].message = "上传失败";
  288. }
  289. );
  290. }
  291. } else {
  292. file.status = "uploading";
  293. file.message = "上传中...";
  294. proxy.post("/fileInfo/getSing", { fileName: file.file.name }).then(
  295. (res) => {
  296. let forms = new FormData();
  297. forms.append("file", file.file);
  298. proxy
  299. .post("https://winfaster.obs.cn-south-1.myhuaweicloud.com", {
  300. ...res.data.uploadBody,
  301. file: forms.get("file"),
  302. })
  303. .then(
  304. () => {
  305. file.id = res.data.id;
  306. file.url = res.data.fileUrl;
  307. file.fileName = res.data.fileName;
  308. delete file.status;
  309. delete file.message;
  310. },
  311. () => {
  312. file.status = "failed";
  313. file.message = "上传失败";
  314. }
  315. );
  316. },
  317. () => {
  318. file.status = "failed";
  319. file.message = "上传失败";
  320. }
  321. );
  322. }
  323. };
  324. // 文件上传
  325. const onOversize = () => {
  326. showToast("文件大小不能超过 5MB");
  327. };
  328. </script>
  329. <style lang="scss" scoped>
  330. .form {
  331. margin-bottom: 60px;
  332. }
  333. ::v-deep {
  334. .van-field--label-top .van-icon-arrow {
  335. right: -2px;
  336. top: -12px;
  337. }
  338. .van-cell__value {
  339. padding-right: 10px;
  340. }
  341. }
  342. </style>