index.vue 23 KB

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