add copy.vue 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  1. <template>
  2. <div class="form">
  3. <van-nav-bar title="物料库" left-text="返回" left-arrow @click-left="onClickLeft"> </van-nav-bar>
  4. <van-form @submit="onSubmit" label-align="top" style="margin-top: 20px; overflow-y: auto">
  5. <van-cell-group inset>
  6. <van-field
  7. v-model="formData.productClassifyName"
  8. is-link
  9. readonly
  10. label="物料分类"
  11. placeholder="请选择物料分类"
  12. @click="show = true"
  13. :rules="[{ required: true, message: '物料分类不能为空' }]"
  14. required />
  15. <van-popup v-model:show="show" round position="bottom">
  16. <van-cascader
  17. title="请选择物料分类"
  18. :options="classification"
  19. :field-names="fieldNames"
  20. @close="show = false"
  21. @change="onChange"
  22. @finish="onFinish" />
  23. </van-popup>
  24. <van-field
  25. v-model="formData.typeName"
  26. is-link
  27. readonly
  28. label="物料类型"
  29. placeholder="选择物料类型"
  30. @click="typeModal = true"
  31. :rules="[{ required: true, message: '物料类型不能为空' }]"
  32. required />
  33. <van-popup v-model:show="typeModal" round position="bottom">
  34. <van-picker :columns="typeList" @cancel="typeModal = false" @confirm="onConfirmType" />
  35. </van-popup>
  36. <van-field
  37. v-model="formData.name"
  38. name="物料名称"
  39. label="物料名称"
  40. placeholder="请填写物料名称"
  41. :rules="[{ required: true, message: '物料名称不能为空' }]"
  42. required />
  43. <van-field
  44. v-model="formData.spec"
  45. name="规格型号"
  46. label="规格型号"
  47. placeholder="请填写规格型号"
  48. :rules="[{ required: true, message: '规格型号不能为空' }]"
  49. required />
  50. <van-field
  51. v-model="formData.unitName"
  52. is-link
  53. readonly
  54. label="单位"
  55. placeholder="选择单位"
  56. @click="unitModal = true"
  57. :rules="[{ required: true, message: '单位不能为空' }]"
  58. required />
  59. <van-popup v-model:show="unitModal" round position="bottom">
  60. <van-picker :columns="unitList" @cancel="unitModal = false" @confirm="onConfirmUnit" />
  61. </van-popup>
  62. <van-field name="uploader" label="文件上传">
  63. <template #input>
  64. <van-uploader v-model="fileList" :after-read="afterRead" multiple :max-count="9" :max-size="5 * 1024 * 1024" @oversize="onOversize" />
  65. </template>
  66. </van-field>
  67. <van-field v-model="formData.remark" rows="3" type="textarea" name="备注" label="备注" placeholder="请填写备注" />
  68. </van-cell-group>
  69. <div style="margin: 16px">
  70. <van-button round block type="primary" native-type="submit"> 提交 </van-button>
  71. </div>
  72. </van-form>
  73. </div>
  74. </template>
  75. <script setup>
  76. import { ref, getCurrentInstance, onMounted } from "vue";
  77. import { showSuccessToast, showToast } from "vant";
  78. import { useRoute } from "vue-router";
  79. import { getUserInfo } from '@/utils/auth';
  80. const proxy = getCurrentInstance().proxy;
  81. const route = useRoute();
  82. const show = ref(false);
  83. const typeModal = ref(false);
  84. const unitModal = ref(false);
  85. const classification = ref([]);
  86. const fieldNames = {
  87. text: "label",
  88. value: "id",
  89. };
  90. const typeList = ref([
  91. {
  92. text: "原料",
  93. value: "1",
  94. },
  95. {
  96. text: "辅料",
  97. value: "2",
  98. },
  99. {
  100. text: "配件",
  101. value: "3",
  102. },
  103. {
  104. text: "包材",
  105. value: "4",
  106. },
  107. {
  108. text: "其他",
  109. value: "5",
  110. },
  111. ]);
  112. const unitList = ref([]);
  113. const getDict = () => {
  114. proxy
  115. .post("/dictTenantData/page", {
  116. pageNum: 1,
  117. pageSize: 999,
  118. tenantId: getUserInfo().tenantId,
  119. dictCode: "unit",
  120. })
  121. .then((res) => {
  122. unitList.value = res.data.rows.map((item, index) => {
  123. return {
  124. text: item.dictValue,
  125. value: item.dictKey,
  126. }
  127. })
  128. })
  129. }
  130. getDict()
  131. const formData = ref({
  132. id: null,
  133. definition: "2",
  134. productClassifyId: null,
  135. productClassifyName: null,
  136. code: null,
  137. customCode: null,
  138. type: null,
  139. typeName: null,
  140. name: null,
  141. spec: null,
  142. unit: null,
  143. remark: null,
  144. fileList: [],
  145. });
  146. const onConfirmType = ({ selectedOptions }) => {
  147. formData.value.type = selectedOptions[0].value;
  148. formData.value.typeName = selectedOptions[0].text;
  149. typeModal.value = false;
  150. };
  151. const onConfirmUnit = ({ selectedOptions }) => {
  152. formData.value.unit = selectedOptions[0].value;
  153. formData.value.unitName = selectedOptions[0].text;
  154. unitModal.value = false;
  155. };
  156. const onChange = ({ selectedOptions }) => {
  157. if (selectedOptions && selectedOptions.length > 0) {
  158. formData.value.productClassifyId = selectedOptions[selectedOptions.length - 1].id;
  159. formData.value.productClassifyName = selectedOptions[selectedOptions.length - 1].label;
  160. }
  161. };
  162. const onFinish = ({ selectedOptions }) => {
  163. show.value = false;
  164. if (selectedOptions && selectedOptions.length > 0) {
  165. formData.value.productClassifyId = selectedOptions[selectedOptions.length - 1].id;
  166. formData.value.productClassifyName = selectedOptions[selectedOptions.length - 1].label;
  167. }
  168. };
  169. const fileList = ref([]);
  170. const afterRead = (file) => {
  171. if (file && file.length > 0) {
  172. for (let i = 0; i < file.length; i++) {
  173. file[i].status = "uploading";
  174. file[i].message = "上传中...";
  175. proxy.post("/fileInfo/getSing", { fileName: file[i].file.name }).then(
  176. (res) => {
  177. let forms = new FormData();
  178. forms.append("file", file[i].file);
  179. proxy.post("https://winfaster.obs.cn-south-1.myhuaweicloud.com", { ...res.data.uploadBody, file: forms.get("file") }).then(
  180. () => {
  181. file[i].id = res.data.id;
  182. file[i].url = res.data.fileUrl;
  183. file[i].fileName = res.data.fileName;
  184. delete file[i].status;
  185. delete file[i].message;
  186. },
  187. () => {
  188. file[i].status = "failed";
  189. file[i].message = "上传失败";
  190. }
  191. );
  192. },
  193. () => {
  194. file[i].status = "failed";
  195. file[i].message = "上传失败";
  196. }
  197. );
  198. }
  199. } else {
  200. file.status = "uploading";
  201. file.message = "上传中...";
  202. proxy.post("/fileInfo/getSing", { fileName: file.file.name }).then(
  203. (res) => {
  204. let forms = new FormData();
  205. forms.append("file", file.file);
  206. proxy.post("https://winfaster.obs.cn-south-1.myhuaweicloud.com", { ...res.data.uploadBody, file: forms.get("file") }).then(
  207. () => {
  208. file.id = res.data.id;
  209. file.url = res.data.fileUrl;
  210. file.fileName = res.data.fileName;
  211. delete file.status;
  212. delete file.message;
  213. },
  214. () => {
  215. file.status = "failed";
  216. file.message = "上传失败";
  217. }
  218. );
  219. },
  220. () => {
  221. file.status = "failed";
  222. file.message = "上传失败";
  223. }
  224. );
  225. }
  226. };
  227. const onOversize = () => {
  228. showToast("文件大小不能超过 5MB");
  229. };
  230. const onClickLeft = () => history.back();
  231. const onSubmit = () => {
  232. if (fileList.value && fileList.value.length > 0) {
  233. formData.value.fileList = fileList.value.map((item) => {
  234. return {
  235. id: item.id,
  236. fileName: item.fileName,
  237. };
  238. });
  239. } else {
  240. formData.value.fileList = [];
  241. }
  242. proxy.post("/productInfo/" + route.query.type, formData.value).then(() => {
  243. showSuccessToast("添加成功");
  244. setTimeout(() => {
  245. history.back();
  246. }, 500);
  247. });
  248. };
  249. const treeToList = (arr) => {
  250. let res = []; // 用于存储递归结果(扁平数据)
  251. // 递归函数
  252. let fn = (source) => {
  253. source.forEach((el) => {
  254. res.push(el);
  255. el.children && el.children.length > 0 ? fn(el.children) : ""; // 子级递归
  256. });
  257. };
  258. fn(arr);
  259. return res;
  260. };
  261. onMounted(() => {
  262. proxy.post("/productClassify/tree", { parentId: "", name: "", definition: "2" }).then((res) => {
  263. classification.value = res.data;
  264. let classList = treeToList(res.data);
  265. if (route.query.id) {
  266. proxy.post("/productInfo/detail", { id: route.query.id }).then((resDetail) => {
  267. formData.value.id = route.query.id;
  268. formData.value.productClassifyId = resDetail.data.productClassifyId;
  269. let data = classList.filter((item) => item.id === resDetail.data.productClassifyId);
  270. if (data && data.length > 0) {
  271. formData.value.productClassifyName = data[0].label;
  272. }
  273. formData.value.code = resDetail.data.code;
  274. formData.value.customCode = resDetail.data.customCode;
  275. formData.value.type = resDetail.data.type;
  276. let typeNameList = typeList.value.filter((item) => item.value == resDetail.data.type);
  277. if (typeNameList && typeNameList.length > 0) {
  278. formData.value.typeName = typeNameList[0].text;
  279. }
  280. formData.value.name = resDetail.data.name;
  281. formData.value.spec = resDetail.data.spec;
  282. formData.value.unitName = unitList.value.filter((item) => item.value == resDetail.data.unit)[0].text;
  283. formData.value.remark = resDetail.data.remark;
  284. });
  285. proxy.post("/fileInfo/getList", { businessIdList: [route.query.id] }).then((res) => {
  286. if (res.data[route.query.id] && res.data[route.query.id].length > 0) {
  287. formData.value.fileList = res.data[route.query.id];
  288. fileList.value = res.data[route.query.id].map((item) => {
  289. return {
  290. ...item,
  291. url: item.fileUrl,
  292. };
  293. });
  294. } else {
  295. formData.value.fileList = [];
  296. fileList.value = [];
  297. }
  298. });
  299. }
  300. });
  301. });
  302. </script>