SelectMaterial.vue 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485
  1. <template>
  2. <div class="user">
  3. <div class="tree">
  4. <treeList title="物料分类" submitType="2" :data="treeListData" v-model="sourceList.pagination.productClassifyId" @change="treeChange"
  5. @changeTreeList="getTreeList">
  6. </treeList>
  7. </div>
  8. <div class="content">
  9. <byTable :source="sourceList.data" :pagination="sourceList.pagination" :config="config" :loading="loading" highlight-current-row
  10. :selectConfig="selectConfig" :table-events="{
  11. //element talbe事件都能传
  12. select: select,
  13. }" :action-list="[]" @get-list="getList">
  14. <template #pic="{ item }">
  15. <div v-if="item.fileList.length > 0">
  16. <img :src="item.fileList[0].fileUrl" class="pic" @click="handleClickFile(item.fileList[0])" />
  17. </div>
  18. <div v-else></div>
  19. </template>
  20. </byTable>
  21. </div>
  22. <div class="right">
  23. <div style="margin-bottom:30px">
  24. <TitleInfo :content="'已选择配件'"></TitleInfo>
  25. </div>
  26. <el-tag style="margin-right: 10px; margin-bottom: 10px" type="info" v-for="(good, index) in goodList" :key="good.productId">
  27. {{ good.productName }}
  28. </el-tag>
  29. </div>
  30. <el-dialog :title="modalType == 'add' ? '添加' : '编辑'" v-model="dialogVisible" width="500" v-loading="loading">
  31. <byForm :formConfig="formConfig" :formOption="formOption" v-model="formData.data" :rules="rules" ref="byform">
  32. <template #productPic>
  33. <div>
  34. <el-upload v-model:fileList="fileList" action="https://winfaster.obs.cn-south-1.myhuaweicloud.com" :data="uploadData"
  35. list-type="picture-card" :on-remove="handleRemove" :on-success="handleSuccess" :before-upload="handleBeforeUpload">
  36. <el-icon>
  37. <Plus />
  38. </el-icon>
  39. </el-upload>
  40. </div>
  41. </template>
  42. </byForm>
  43. <template #footer>
  44. <el-button @click="dialogVisible = false" size="large">取 消</el-button>
  45. <el-button type="primary" @click="submitForm('byform')" size="large" :loading="submitLoading">
  46. 确 定
  47. </el-button>
  48. </template>
  49. </el-dialog>
  50. <el-dialog title="Excel导入" v-model="openExcelDialog" width="400" v-loading="loading">
  51. <template #footer>
  52. <el-button @click="openExcelDialog = false" size="large">取 消</el-button>
  53. <el-button type="primary" @click="submitExcel()" size="large" :loading="submitLoading">
  54. 确 定
  55. </el-button>
  56. </template>
  57. </el-dialog>
  58. </div>
  59. </template>
  60. <script setup>
  61. /* eslint-disable vue/no-unused-components */
  62. import { ElMessage, ElMessageBox } from "element-plus";
  63. import byTable from "@/components/byTable/index";
  64. import byForm from "@/components/byForm/index";
  65. import treeList from "@/components/product/treeList";
  66. import TitleInfo from "@/components/TitleInfo/index.vue";
  67. const { proxy } = getCurrentInstance();
  68. const props = defineProps({
  69. alreadySelectData: Array,
  70. });
  71. const goodList = ref([]);
  72. onMounted(() => {
  73. goodList.value = proxy.deepClone(props.alreadySelectData);
  74. });
  75. const loading = ref(false);
  76. const submitLoading = ref(false);
  77. const materialUnit = ref([]);
  78. const materialType = ref([]);
  79. const sourceList = ref({
  80. data: [],
  81. pagination: {
  82. total: 3,
  83. pageNum: 1,
  84. pageSize: 10,
  85. type: "",
  86. productClassifyId: "",
  87. keyword: "",
  88. definition: "2",
  89. },
  90. });
  91. let dialogVisible = ref(false);
  92. let openExcelDialog = ref(false);
  93. let modalType = ref("add");
  94. let rules = ref({
  95. productClassifyId: [
  96. { required: true, message: "请选择物料分类", trigger: "change" },
  97. ],
  98. type: [{ required: true, message: "请选择物料类型", trigger: "change" }],
  99. name: [{ required: true, message: "请输入物料名称", trigger: "blur" }],
  100. unit: [{ required: true, message: "请选择单位", trigger: "change" }],
  101. });
  102. const selectConfig = computed(() => {
  103. return [
  104. {
  105. label: "物料类型",
  106. prop: "type",
  107. data: materialType.value,
  108. },
  109. ];
  110. });
  111. const config = computed(() => {
  112. return [
  113. {
  114. attrs: {
  115. label: "物料类型",
  116. prop: "type",
  117. },
  118. render(type) {
  119. return proxy.dictValueLabel(type, materialType.value);
  120. },
  121. },
  122. {
  123. attrs: {
  124. label: "物料编码",
  125. prop: "code",
  126. },
  127. },
  128. {
  129. attrs: {
  130. label: "物料名称",
  131. prop: "name",
  132. },
  133. },
  134. {
  135. attrs: {
  136. label: "图片",
  137. slot: "pic",
  138. },
  139. },
  140. {
  141. attrs: {
  142. label: "单位",
  143. prop: "unit",
  144. },
  145. render(unit) {
  146. return proxy.dictValueLabel(unit, materialUnit.value);
  147. },
  148. },
  149. {
  150. attrs: {
  151. label: "规格型号",
  152. prop: "spec",
  153. },
  154. },
  155. {
  156. attrs: {
  157. label: "物料备注",
  158. prop: "remark",
  159. },
  160. },
  161. {
  162. attrs: {
  163. label: "操作",
  164. width: "60",
  165. align: "center",
  166. fixed: "right",
  167. },
  168. // 渲染 el-button,一般用在最后一列。
  169. renderHTML(row) {
  170. return [
  171. {
  172. attrs: {
  173. label: "选择",
  174. type: "primary",
  175. text: true,
  176. },
  177. el: "button",
  178. click() {
  179. handleSelect(row);
  180. },
  181. },
  182. ];
  183. },
  184. },
  185. ];
  186. });
  187. let formData = reactive({
  188. data: {},
  189. });
  190. const formOption = reactive({
  191. inline: true,
  192. labelWidth: 100,
  193. itemWidth: 100,
  194. rules: [],
  195. });
  196. const byform = ref(null);
  197. const treeListData = ref([]);
  198. const formConfig = computed(() => {
  199. return [
  200. {
  201. type: "treeSelect",
  202. prop: "productClassifyId",
  203. label: "物料分类",
  204. data: [],
  205. },
  206. {
  207. type: "select",
  208. prop: "type",
  209. label: "物料类型",
  210. required: true,
  211. data: [
  212. {
  213. label: "原料",
  214. id: "1",
  215. },
  216. {
  217. label: "辅料",
  218. id: "2",
  219. },
  220. {
  221. label: "配件",
  222. id: "3",
  223. },
  224. {
  225. label: "包材",
  226. id: "4",
  227. },
  228. {
  229. label: "其他",
  230. id: "5",
  231. },
  232. ],
  233. },
  234. {
  235. type: "input",
  236. prop: "name",
  237. label: "物料名称",
  238. },
  239. {
  240. type: "input",
  241. prop: "spec",
  242. label: "规格型号",
  243. },
  244. {
  245. type: "select",
  246. prop: "unit",
  247. label: "单位",
  248. required: true,
  249. data: [
  250. {
  251. label: "个",
  252. id: "个",
  253. },
  254. {
  255. label: "双",
  256. id: "双",
  257. },
  258. ],
  259. },
  260. {
  261. type: "slot",
  262. slotName: "productPic",
  263. prop: "fileList",
  264. label: "产品图片",
  265. },
  266. {
  267. type: "input",
  268. prop: "remark",
  269. label: "备注",
  270. itemType: "textarea",
  271. },
  272. ];
  273. });
  274. const newPassword = () => {
  275. formData.data.password = generatePassword();
  276. };
  277. const generatePassword = () => {
  278. var length = 12,
  279. charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789",
  280. password = "";
  281. for (var i = 0, n = charset.length; i < length; ++i) {
  282. password += charset.charAt(Math.floor(Math.random() * n));
  283. }
  284. return password;
  285. };
  286. const getList = async (req) => {
  287. sourceList.value.pagination = { ...sourceList.value.pagination, ...req };
  288. loading.value = true;
  289. proxy
  290. .post("/productInfo/page", sourceList.value.pagination)
  291. .then((message) => {
  292. console.log(message);
  293. sourceList.value.data = message.rows.map((x) => ({ ...x, fileList: [] }));
  294. sourceList.value.pagination.total = message.total;
  295. setTimeout(() => {
  296. loading.value = false;
  297. }, 200);
  298. const productIdList = message.rows.map((x) => x.id);
  299. // 请求文件数据并回显
  300. if (productIdList.length > 0) {
  301. proxy
  302. .post("/fileInfo/getList", { businessIdList: productIdList })
  303. .then((fileObj) => {
  304. for (let i = 0; i < sourceList.value.data.length; i++) {
  305. const e = sourceList.value.data[i];
  306. for (const key in fileObj) {
  307. if (e.id === key) {
  308. e.fileList = fileObj[key];
  309. }
  310. }
  311. }
  312. });
  313. }
  314. });
  315. };
  316. const uploadData = ref({});
  317. const fileList = ref([]);
  318. const fileListCopy = ref([]);
  319. const treeChange = (e) => {
  320. console.log(e);
  321. sourceList.value.pagination.productClassifyId = e.id;
  322. getList({ productClassifyId: e.id });
  323. };
  324. const openModal = () => {
  325. dialogVisible.value = true;
  326. modalType.value = "add";
  327. formData.data = {
  328. definition: "2",
  329. fileList: [],
  330. };
  331. fileList.value = [];
  332. fileListCopy.value = [];
  333. };
  334. const openExcel = () => {
  335. openExcelDialog.value = true;
  336. };
  337. const submitExcel = () => {
  338. openExcelDialog.value = false;
  339. };
  340. const TreetenantId = ref("");
  341. const selection = ref({
  342. data: [],
  343. });
  344. const select = (_selection, row) => {
  345. selection.value.data = _selection;
  346. console.log(_selection.length);
  347. };
  348. const tree = ref(null);
  349. const submitForm = () => {
  350. console.log(byform.value);
  351. byform.value.handleSubmit((valid) => {
  352. formData.data.fileList = fileListCopy.value.map((x) => ({
  353. id: x.id,
  354. fileName: x.fileName,
  355. }));
  356. submitLoading.value = true;
  357. proxy.post("/productInfo/" + modalType.value, formData.data).then(
  358. (res) => {
  359. ElMessage({
  360. message: modalType.value == "add" ? "添加成功" : "编辑成功",
  361. type: "success",
  362. });
  363. dialogVisible.value = false;
  364. submitLoading.value = false;
  365. getList();
  366. },
  367. (err) => {
  368. submitLoading.value = false;
  369. }
  370. );
  371. });
  372. };
  373. const getTreeList = () => {
  374. proxy
  375. .post("/productClassify/tree", { parentId: "", name: "", definition: "2" })
  376. .then((message) => {
  377. treeListData.value = message;
  378. formConfig.value[0].data = message;
  379. });
  380. };
  381. const getDtl = (row) => {
  382. modalType.value = "edit";
  383. proxy.post("/productInfo/detail", { id: row.id }).then((res) => {
  384. fileList.value = row.fileList.map((x) => ({ ...x, url: x.fileUrl }));
  385. fileListCopy.value = [...fileList.value];
  386. res.type = res.type + "";
  387. res.definition = "2";
  388. formData.data = res;
  389. dialogVisible.value = true;
  390. });
  391. };
  392. getTreeList();
  393. getList();
  394. const handleBeforeUpload = async (file) => {
  395. const res = await proxy.post("/fileInfo/getSing", { fileName: file.name });
  396. uploadData.value = res.uploadBody;
  397. fileListCopy.value.push({
  398. id: res.id,
  399. fileName: res.fileName,
  400. path: res.fileUrl,
  401. url: res.fileUrl,
  402. uid: file.uid,
  403. });
  404. };
  405. const handleSuccess = (res, file, files) => {
  406. // 查当前file的index值去赋值对应的copy变量的值
  407. // let uid = file.uid;
  408. // const index = fileList.value.findIndex((x) => x.uid === uid);
  409. // fileListCopy.value[index].uid = uid;
  410. };
  411. const handleRemove = (file) => {
  412. const index = fileListCopy.value.findIndex(
  413. (x) => x.uid === file.uid || x.id === file.id
  414. );
  415. fileListCopy.value.splice(index, 1);
  416. };
  417. const handleClickFile = (file) => {
  418. window.open(file.fileUrl, "_blank");
  419. };
  420. const handleSelect = (row) => {
  421. goodList.value.push({
  422. ...row,
  423. productName: row.name,
  424. });
  425. proxy.$emit("handleSelect", row);
  426. };
  427. const getDict = () => {
  428. proxy.getDictOne(["material_unit", "material_type"]).then((res) => {
  429. materialUnit.value = res["material_unit"].map((x) => ({
  430. label: x.dictValue,
  431. value: x.dictKey,
  432. }));
  433. materialType.value = res["material_type"].map((x) => ({
  434. label: x.dictValue,
  435. value: x.dictKey,
  436. }));
  437. });
  438. };
  439. getDict();
  440. </script>
  441. <style lang="scss" scoped>
  442. .user {
  443. padding: 20px;
  444. display: flex;
  445. justify-content: space-between;
  446. .tree {
  447. width: 300px;
  448. }
  449. .content {
  450. width: calc(100% - 320px - 170px);
  451. }
  452. .right {
  453. padding-left: 10px;
  454. width: 170px;
  455. border-left: 1px solid #eee;
  456. }
  457. }
  458. .pic {
  459. object-fit: contain;
  460. width: 50px;
  461. height: 50px;
  462. cursor: pointer;
  463. vertical-align: middle;
  464. }
  465. </style>