index.vue 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818
  1. <template>
  2. <div class="box">
  3. <div class="tree">
  4. <treeList title="产品分类" submitType="1" :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" :tableHeight="tableHeight" :pagination="sourceList.pagination" :config="config" :loading="loading"
  10. highlight-current-row :selectConfig="selectConfig" :action-list="[
  11. {
  12. text: 'Excel导入',
  13. action: () => openExcel(),
  14. disabled: false,
  15. },
  16. {
  17. text: '添加',
  18. action: () => openModal('add'),
  19. disabled: false,
  20. },]" @get-list="getList">
  21. <template #name="{ item }">
  22. <div>
  23. <span class="el-click">{{ item.name }}</span>
  24. </div>
  25. </template>
  26. <template #pic="{ item }">
  27. <div v-if="item.fileList.length > 0">
  28. <img :src="item.fileList[0].fileUrl" class="pic" @click="handleClickFile(item.fileList[0])" />
  29. </div>
  30. <div v-else></div>
  31. </template>
  32. <template #size="{ item }">
  33. <div v-if="item['length'] && item.width && item.height">
  34. <span>{{ item['length'] }}cm</span>*
  35. <span>{{ item.width }}cm</span>*
  36. <span>{{ item.height }}cm</span>
  37. </div>
  38. <div v-else></div>
  39. </template>
  40. <template #price="{ item }">
  41. <div v-if="item.price">
  42. <span>{{ item.currency }} {{ moneyFormat(item.price ,2)}}</span>
  43. </div>
  44. <div v-else></div>
  45. </template>
  46. </byTable>
  47. </div>
  48. <el-dialog :title="modalType == 'add' ? '添加产品' : '编辑产品'" v-model="dialogVisible" width="80%" destroy-on-close>
  49. <div class="public_height_dialog">
  50. <byForm :formConfig="formConfig" :formOption="formOption" v-model="formData.data" :rules="rules" ref="formDom" v-loading="submitLoading">
  51. <template #nameEnglish>
  52. <div style="width: 100%">
  53. <el-input v-model="formData.data.nameEnglish" placeholder="请输入" onkeyup="value=value.replace(/[^\x00-\xff]/g, '')"></el-input>
  54. </div>
  55. </template>
  56. <template #productionFile>
  57. <div style="width: 100%">
  58. <span style="color:#409eff;cursor:pointer" @click="handleClickUpload('prodFilePath',true)"
  59. v-if="!formData.data.prodFilePath">点击上传</span>
  60. <span style="color:#409eff;cursor:pointer" @click="handleClickUpload('prodFilePath',false)" v-else>点击查看</span>
  61. </div>
  62. </template>
  63. <template #productionFileOne>
  64. <div style="width: 100%">
  65. <span style="color:#409eff;cursor:pointer" @click="handleClickUpload('prodImgPath',true)" v-if="!formData.data.prodImgPath">点击上传</span>
  66. <span style="color:#409eff;cursor:pointer" @click="handleClickUpload('prodImgPath',false)" v-else>点击查看</span>
  67. </div>
  68. </template>
  69. <template #size>
  70. <div style="width: 100%">
  71. <el-row>
  72. <el-col :span="8">
  73. <el-form-item prop="length" label-width="0px" class="margin-b-0 wid100">
  74. <el-input-number v-model="formData.data['length']" placeholder="长 (cm)" style="width: 100%" :precision="2" :controls="false"
  75. :min="0" onmousewheel="return false;" />
  76. </el-form-item>
  77. </el-col>
  78. <el-col :span="8">
  79. <el-form-item prop="width" label-width="0px" class="margin-b-0 wid100">
  80. <el-input-number v-model="formData.data.width" placeholder="宽 (cm)" style="width: 100%" :precision="2" :controls="false" :min="0"
  81. onmousewheel="return false;" />
  82. </el-form-item>
  83. </el-col>
  84. <el-col :span="8">
  85. <el-form-item prop="height" label-width="0px" class="margin-b-0 wid100">
  86. <el-input-number v-model="formData.data.height" placeholder="高 (cm)" style="width: 100%" :precision="2" :controls="false" :min="0"
  87. onmousewheel="return false;" />
  88. </el-form-item>
  89. </el-col>
  90. </el-row>
  91. </div>
  92. </template>
  93. </byForm>
  94. </div>
  95. <template #footer>
  96. <el-button @click="dialogVisible = false" size="defualt" v-debounce>取 消</el-button>
  97. <el-button type="primary" @click="submitForm()" size="defualt" v-debounce>确 定</el-button>
  98. </template>
  99. </el-dialog>
  100. <el-dialog :title="'BOM 配置'" v-model="bomDialog" width="50%" destroy-on-close>
  101. <!-- <div class="public_height_dialog"> -->
  102. <byForm :formConfig="bomFormConfig" :formOption="bomFormOption" v-model="formData.bomData" :rules="bomRules" ref="bomFormDom"
  103. v-loading="submitLoading">
  104. <template #accessories>
  105. <div style="width: 100%">
  106. <el-button type="primary" @click="openSelectMaterial = true" plain>选择</el-button>
  107. <el-table :data="formData.bomData.productBomDetailList" style="width: 100%; margin-top: 16px">
  108. <el-table-column prop="materialName" label="物料名称" min-width="130" />
  109. <el-table-column prop="materialCode" label="物料编码" width="150" />
  110. <el-table-column label="数量" width="150">
  111. <template #default="{ row, $index }">
  112. <div style="width: 100%">
  113. <el-form-item :prop="'productBomDetailList.' + $index + '.quantity'" :rules="bomRules.quantity" :inline-message="true"
  114. class="margin-b-0 wid100">
  115. <el-input-number onmousewheel="return false;" v-model="row.quantity" placeholder="请输入" style="width: 100%" :precision="0"
  116. :controls="false" :min="1" />
  117. </el-form-item>
  118. </div>
  119. </template>
  120. </el-table-column>
  121. <el-table-column label="操作" width="60" align="center" fixed="right">
  122. <template #default="{ $index }">
  123. <el-button type="primary" link @click="handleRemove($index)">删除</el-button>
  124. </template>
  125. </el-table-column>
  126. </el-table>
  127. </div>
  128. </template>
  129. </byForm>
  130. <!-- </div> -->
  131. <template #footer>
  132. <el-button @click="bomDialog = false" size="defualt" v-debounce>取 消</el-button>
  133. <el-button type="primary" @click="submitBomForm()" size="defualt" v-debounce>确 定</el-button>
  134. </template>
  135. </el-dialog>
  136. <el-dialog :title="'物料选择'" v-model="openSelectMaterial" width="90%" destroy-on-close>
  137. <SelectMaterial :isNeRawMaterial="'1'" @selectMaterial="selectMaterial"></SelectMaterial>
  138. <template #footer>
  139. <el-button @click="bomDialog = false" size="defualt" v-debounce>取 消</el-button>
  140. </template>
  141. </el-dialog>
  142. <el-dialog title="导入产品" v-model="openExcelDialog" width="400">
  143. <div v-loading="excelLoading">
  144. <el-upload :action="actionUrl + '/productInfo/excelImportByEhsd'" :headers="headers" :on-success="handleSuccess" :on-progress="handleProgress"
  145. :show-file-list="false" :on-error="handleError" accept=".xlsx">
  146. <el-button type="primary">点击导入</el-button>
  147. </el-upload>
  148. </div>
  149. <template #footer>
  150. <el-button @click="openExcelDialog = false" size="default">取 消</el-button>
  151. </template>
  152. </el-dialog>
  153. </div>
  154. </template>
  155. <script setup>
  156. import byTable from "@/components/byTable/index";
  157. import byForm from "@/components/byForm/index";
  158. import treeList from "@/components/product/treeList";
  159. import SelectMaterial from "@/components/product/SelectMaterial.vue";
  160. import { getToken } from "@/utils/auth";
  161. import { async } from "@antv/x6/lib/registry/marker/async";
  162. const { proxy } = getCurrentInstance();
  163. const actionUrl = import.meta.env.VITE_APP_BASE_API;
  164. const loading = ref(false);
  165. const submitLoading = ref(false);
  166. const treeData = ref([]);
  167. const treeListData = ref([]);
  168. const currencyData = computed(
  169. () => proxy.useUserStore().allDict["account_currency"]
  170. );
  171. const headers = ref({ Authorization: "Bearer " + getToken() });
  172. const tableHeight = ref(0);
  173. const getTableHeight = () => {
  174. tableHeight.value = window.innerHeight - 245;
  175. };
  176. getTableHeight();
  177. window.addEventListener("resize", () => {
  178. getTableHeight();
  179. });
  180. const sourceList = ref({
  181. data: [],
  182. pagination: {
  183. total: 3,
  184. pageNum: 1,
  185. pageSize: 10,
  186. type: "",
  187. productClassifyId: "",
  188. keyword: "",
  189. definition: "1",
  190. },
  191. });
  192. const dialogVisible = ref(false);
  193. const openExcelDialog = ref(false);
  194. const excelLoading = ref(false);
  195. const modalType = ref("add");
  196. const rules = ref({
  197. productClassifyId: [
  198. { required: true, message: "请选择产品分类", trigger: "change" },
  199. ],
  200. name: [{ required: true, message: "请输入产品名称", trigger: "blur" }],
  201. customCode: [{ required: true, message: "请输入产品编号", trigger: "blur" }],
  202. length: [{ required: true, message: "请输入长 (cm)", trigger: "blur" }],
  203. width: [{ required: true, message: "请输入宽 (cm)", trigger: "blur" }],
  204. height: [{ required: true, message: "请输入高 (cm)", trigger: "blur" }],
  205. });
  206. const props = defineProps({
  207. selectStatus: Boolean,
  208. });
  209. const selectConfig = computed(() => []);
  210. const config = computed(() => {
  211. return [
  212. {
  213. attrs: {
  214. label: "图片",
  215. slot: "pic",
  216. align: "center",
  217. width: 80,
  218. },
  219. },
  220. {
  221. attrs: {
  222. label: "产品分类",
  223. prop: "classifyName",
  224. "min-width": 150,
  225. },
  226. },
  227. {
  228. attrs: {
  229. label: "产品编码",
  230. prop: "customCode",
  231. width: 120,
  232. },
  233. },
  234. {
  235. attrs: {
  236. label: "产品名称",
  237. slot: "name",
  238. "min-width": 150,
  239. },
  240. },
  241. {
  242. attrs: {
  243. label: "产品英文名",
  244. prop: "nameEnglish",
  245. "min-width": 120,
  246. },
  247. },
  248. {
  249. attrs: {
  250. label: "产品规格",
  251. prop: "spec",
  252. width: 120,
  253. },
  254. },
  255. {
  256. attrs: {
  257. label: "尺寸",
  258. slot: "size",
  259. width: 180,
  260. },
  261. },
  262. {
  263. attrs: {
  264. label: "净重",
  265. prop: "netWeight",
  266. width: 100,
  267. },
  268. render(val) {
  269. if (val) {
  270. return val + " kg";
  271. }
  272. },
  273. },
  274. {
  275. attrs: {
  276. label: "销售价",
  277. slot: "price",
  278. width: 100,
  279. },
  280. },
  281. {
  282. attrs: {
  283. label: "海关编码",
  284. prop: "hsCode",
  285. width: 100,
  286. },
  287. },
  288. {
  289. attrs: {
  290. label: "原材料",
  291. prop: "rawMaterialName",
  292. width: 150,
  293. },
  294. },
  295. {
  296. attrs: {
  297. label: "原材料编码",
  298. prop: "rawMaterialCode",
  299. width: 120,
  300. },
  301. },
  302. {
  303. attrs: {
  304. label: "操作",
  305. width: "160",
  306. align: "center",
  307. fixed: "right",
  308. },
  309. renderHTML(row) {
  310. return [
  311. // {
  312. // attrs: {
  313. // label: "选择",
  314. // type: "primary",
  315. // text: true,
  316. // },
  317. // el: "button",
  318. // click() {
  319. // clickSelect(row);
  320. // },
  321. // }
  322. {
  323. attrs: {
  324. label: "BOM",
  325. type: "primary",
  326. text: true,
  327. },
  328. el: "button",
  329. click() {
  330. bomSetting(row);
  331. },
  332. },
  333. {
  334. attrs: {
  335. label: "修改",
  336. type: "primary",
  337. text: true,
  338. },
  339. el: "button",
  340. click() {
  341. getDtl(row);
  342. },
  343. },
  344. {
  345. attrs: {
  346. label: "删除",
  347. type: "danger",
  348. text: true,
  349. },
  350. el: "button",
  351. click() {
  352. proxy
  353. .msgConfirm()
  354. .then((res) => {
  355. proxy
  356. .post("/productInfo/delete", {
  357. id: row.id,
  358. })
  359. .then((res) => {
  360. proxy.msgTip("删除成功", 1);
  361. getList();
  362. });
  363. })
  364. .catch((err) => {});
  365. },
  366. },
  367. ];
  368. },
  369. },
  370. ];
  371. });
  372. const formData = reactive({
  373. data: {},
  374. bomData: {},
  375. });
  376. const formOption = reactive({
  377. disabled: false,
  378. inline: true,
  379. labelWidth: 100,
  380. itemWidth: 100,
  381. });
  382. const formDom = ref(null);
  383. const formConfig = computed(() => {
  384. return [
  385. {
  386. type: "title1",
  387. title: "基本信息",
  388. },
  389. {
  390. type: "treeSelect",
  391. prop: "productClassifyId",
  392. label: "产品分类",
  393. data: treeData.value,
  394. itemWidth: 100,
  395. disabled: false,
  396. },
  397. {
  398. type: "input",
  399. prop: "name",
  400. label: "产品名称",
  401. itemWidth: 50,
  402. disabled: false,
  403. },
  404. {
  405. type: "slot",
  406. slotName: "nameEnglish",
  407. label: "英文名",
  408. itemWidth: 50,
  409. },
  410. {
  411. type: "input",
  412. prop: "customCode",
  413. label: "产品编号",
  414. itemWidth: 50,
  415. disabled: false,
  416. },
  417. {
  418. type: "uploadImg",
  419. // listType: "picture-card",
  420. // limit: 1,
  421. // accept: ".gif, .jpeg, .jpg, .png",
  422. prop: "fileList",
  423. imgProp: "imageUrl",
  424. label: "产品缩略图",
  425. },
  426. {
  427. type: "slot",
  428. slotName: "productionFileOne",
  429. label: "产品原图",
  430. itemWidth: 100,
  431. },
  432. {
  433. type: "slot",
  434. slotName: "productionFile",
  435. label: "生产文件",
  436. itemWidth: 100,
  437. },
  438. {
  439. type: "title1",
  440. title: "属性信息",
  441. },
  442. {
  443. type: "selectInput",
  444. prop: "price",
  445. selectProp: "currency",
  446. label: "销售价",
  447. itemWidth: 50,
  448. disabledSelect: true,
  449. data: currencyData.value,
  450. },
  451. {
  452. type: "select",
  453. prop: "technologyId",
  454. label: "生产工艺",
  455. itemWidth: 50,
  456. data: [],
  457. filterable: true,
  458. disabled: false,
  459. },
  460. {
  461. type: "input",
  462. prop: "spec",
  463. label: "规格型号",
  464. itemWidth: 50,
  465. disabled: false,
  466. },
  467. {
  468. type: "slot",
  469. slotName: "size",
  470. prop: "size",
  471. label: "尺寸",
  472. itemWidth: 50,
  473. disabled: false,
  474. },
  475. // {
  476. // type: "select",
  477. // prop: "innerPackMethod",
  478. // label: "内包装方式",
  479. // required: true,
  480. // itemWidth: 50,
  481. // multiple: true,
  482. // data: innerMethon.value,
  483. // filterable: true,
  484. // placeholder: "内包装方式",
  485. // style: {
  486. // width: "100%",
  487. // },
  488. // disabled: false,
  489. // },
  490. // {
  491. // type: "select",
  492. // prop: "outerPackMethod",
  493. // label: "外包装方式",
  494. // required: true,
  495. // itemWidth: 50,
  496. // multiple: true,
  497. // data: outsideMethon.value,
  498. // filterable: true,
  499. // placeholder: "外包装方式",
  500. // style: {
  501. // width: "100%",
  502. // },
  503. // disabled: false,
  504. // },
  505. {
  506. type: "number",
  507. prop: "netWeight",
  508. label: "净重(kg)",
  509. precision: 2,
  510. min: 0,
  511. controls: false,
  512. itemWidth: 50,
  513. },
  514. {
  515. type: "input",
  516. prop: "hsCode",
  517. label: "海关编码",
  518. itemWidth: 50,
  519. disabled: false,
  520. },
  521. {
  522. type: "input",
  523. itemType: "textarea",
  524. prop: "remark",
  525. label: "备注",
  526. itemWidth: 100,
  527. },
  528. ];
  529. });
  530. const getList = (req) => {
  531. sourceList.value.pagination = { ...sourceList.value.pagination, ...req };
  532. loading.value = true;
  533. proxy.post("/productInfo/page", sourceList.value.pagination).then(
  534. (res) => {
  535. sourceList.value.data = res.rows.map((x) => ({
  536. ...x,
  537. fileList: [],
  538. }));
  539. sourceList.value.pagination.total = res.total;
  540. setTimeout(() => {
  541. loading.value = false;
  542. }, 200);
  543. let productIdList = res.rows.map((x) => x.id);
  544. // 请求文件数据并回显
  545. if (productIdList.length > 0) {
  546. proxy
  547. .post("/fileInfo/getList", {
  548. businessIdList: productIdList,
  549. })
  550. .then((fileObj) => {
  551. for (let i = 0; i < sourceList.value.data.length; i++) {
  552. let e = sourceList.value.data[i];
  553. for (let key in fileObj) {
  554. if (e.id == key) {
  555. e.fileList = fileObj[key];
  556. }
  557. }
  558. }
  559. });
  560. }
  561. },
  562. (err) => {
  563. loading.value = false;
  564. }
  565. );
  566. };
  567. const treeChange = (e) => {
  568. if (e.id != undefined) {
  569. sourceList.value.pagination.productClassifyId = e.id;
  570. getList({ productClassifyId: e.id });
  571. }
  572. };
  573. const openModal = () => {
  574. dialogVisible.value = true;
  575. modalType.value = "add";
  576. formData.data = {
  577. definition: "1",
  578. fileList: [],
  579. currency: "",
  580. };
  581. if (currencyData.value && currencyData.value.length > 0) {
  582. formData.data.currency = currencyData.value[0].dictKey;
  583. }
  584. };
  585. const openExcel = () => {
  586. openExcelDialog.value = true;
  587. };
  588. const submitForm = () => {
  589. formDom.value.handleSubmit((valid) => {
  590. if (!formData.data.fileList.length > 0) {
  591. return proxy.msgTip("请上传图片", 2);
  592. }
  593. // formData.data.fileList = formData.data.fileList.map((x) => ({
  594. // id: x.id,
  595. // fileName: x.fileName,
  596. // fileUrl: x.fileUrl,
  597. // }));
  598. submitLoading.value = true;
  599. proxy.post("/productInfo/" + modalType.value, formData.data).then(
  600. (res) => {
  601. proxy.msgTip("操作成功", 1);
  602. dialogVisible.value = false;
  603. submitLoading.value = false;
  604. getList();
  605. },
  606. (err) => {
  607. submitLoading.value = false;
  608. }
  609. );
  610. });
  611. };
  612. const getTreeList = () => {
  613. proxy
  614. .post("/productClassify/tree", { parentId: "", name: "", definition: "1" })
  615. .then((message) => {
  616. treeListData.value = [
  617. {
  618. id: "",
  619. label: "全部",
  620. parentId: "",
  621. children: message,
  622. },
  623. ];
  624. treeData.value = message;
  625. });
  626. };
  627. const getDtl = (row) => {
  628. modalType.value = "edit";
  629. proxy.post("/productInfo/detail", { id: row.id }).then((res) => {
  630. formData.data = res;
  631. formData.data.fileList = row.fileList.map((x) => ({
  632. ...x,
  633. url: x.fileUrl,
  634. name: x.fileName,
  635. }));
  636. if (formData.data.fileList.length > 0) {
  637. formData.data.imageUrl = formData.data.fileList[0].fileUrl;
  638. }
  639. dialogVisible.value = true;
  640. });
  641. };
  642. const rawMaterialData = ref([]);
  643. const getRawMaterialData = () => {
  644. proxy.post("/productInfo/page", { productClassifyId: 100 }).then((res) => {
  645. rawMaterialData.value = res.rows;
  646. });
  647. };
  648. getRawMaterialData();
  649. const bomDialog = ref(false);
  650. const bomFormDom = ref(null);
  651. const bomFormOption = reactive({
  652. disabled: false,
  653. inline: true,
  654. labelWidth: 100,
  655. itemWidth: 100,
  656. });
  657. const bomFormConfig = computed(() => {
  658. return [
  659. {
  660. type: "select",
  661. prop: "rawMaterialId",
  662. label: "原材料",
  663. itemWidth: 100,
  664. data: rawMaterialData.value,
  665. filterable: true,
  666. disabled: false,
  667. },
  668. {
  669. type: "slot",
  670. slotName: "accessories",
  671. label: "包材辅料",
  672. itemWidth: 100,
  673. },
  674. ];
  675. });
  676. const bomRules = ref({
  677. rawMaterialId: [
  678. { required: true, message: "请选择原材料", trigger: "change" },
  679. ],
  680. quantity: [{ required: true, message: "请输入数量", trigger: "blur" }],
  681. });
  682. const bomSetting = (row) => {
  683. bomDialog.value = true;
  684. proxy.post("/productBomInfo/detail", { id: row.id }).then((res) => {
  685. formData.bomData = res;
  686. });
  687. // formData.bomData = {
  688. // id: row.id,
  689. // rawMaterialId: "",
  690. // productBomDetailList: [],
  691. // };
  692. };
  693. const submitBomForm = () => {
  694. bomFormDom.value.handleSubmit((valid) => {
  695. if (!formData.bomData.productBomDetailList.length > 0) {
  696. return proxy.msgTip("请选择包材辅料", 2);
  697. }
  698. submitLoading.value = true;
  699. proxy.post("/productBomInfo/edit", formData.bomData).then(
  700. (res) => {
  701. proxy.msgTip("操作成功", 1);
  702. getList();
  703. bomDialog.value = false;
  704. submitLoading.value = false;
  705. },
  706. (err) => {
  707. submitLoading.value = false;
  708. }
  709. );
  710. });
  711. };
  712. const openSelectMaterial = ref(false);
  713. const selectMaterial = (row) => {
  714. let flag = formData.bomData.productBomDetailList.some(
  715. (x) => x.materialId == row.id
  716. );
  717. if (!flag) {
  718. formData.bomData.productBomDetailList.push({
  719. materialName: row.name,
  720. materialCode: row.customCode,
  721. materialId: row.id,
  722. quantity: null,
  723. });
  724. proxy.msgTip("选择成功");
  725. } else {
  726. proxy.msgTip("该物料已选择", 2);
  727. }
  728. };
  729. const handleRemove = (index) => {
  730. formData.bomData.productBomDetailList.splice(index, 1);
  731. };
  732. const handleClickFile = (file) => {
  733. window.open(file.fileUrl, "_blank");
  734. };
  735. const handleProgress = () => {
  736. excelLoading.value = true;
  737. };
  738. const handleError = (err) => {
  739. proxy.msgTip(`${err},请重试`, 2);
  740. openExcelDialog.value = false;
  741. excelLoading.value = false;
  742. };
  743. const handleSuccess = (res) => {
  744. if (res.code != 200) {
  745. return proxy.msgTip(`${err},请重试`, 2);
  746. } else {
  747. proxy.msgTip(`导入成功`, 1);
  748. openExcelDialog.value = false;
  749. excelLoading.value = false;
  750. getList();
  751. }
  752. };
  753. const clickSelect = (item) => {
  754. proxy.$emit("selectProduct", item);
  755. };
  756. const handleClickUpload = async (att, flag) => {
  757. let res = null;
  758. let path = "";
  759. if (flag) {
  760. proxy.msgTip("请稍后", 2);
  761. res = await proxy.post("/fileService/createTempFolder");
  762. if (res && res.path) {
  763. formData.data[att] = res.path;
  764. path = res.path;
  765. }
  766. } else {
  767. path = formData.data[att];
  768. }
  769. let a = document.createElement("a");
  770. a.href = "printer://" + "ftp://192.168.1.13/" + path + "/";
  771. a.style.display = "none";
  772. document.body.appendChild(a);
  773. a.click();
  774. document.body.removeChild(a);
  775. };
  776. getTreeList();
  777. getList();
  778. </script>
  779. <style lang="scss" scoped>
  780. .box {
  781. padding: 10px;
  782. display: flex;
  783. justify-content: space-between;
  784. .tree {
  785. width: 300px;
  786. }
  787. .content {
  788. width: calc(100% - 310px);
  789. }
  790. }
  791. .pic {
  792. object-fit: contain;
  793. width: 50px;
  794. height: 50px;
  795. cursor: pointer;
  796. vertical-align: middle;
  797. }
  798. </style>