index.vue 12 KB

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