index.vue 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782
  1. <template>
  2. <div>
  3. <FullPage
  4. :title="$route.query.title"
  5. :list="list"
  6. @init="init"
  7. :loading="loading"
  8. @searchData="init"
  9. @changePage="changePage"
  10. @changeSize="changeSize"
  11. :tableColums="tableColums"
  12. :tableData="tableData"
  13. :pageIndex="pageIndex"
  14. :total="total"
  15. >
  16. <div slot="titleButton" style="display:flex;">
  17. <Upload
  18. v-if="persimissionData['批量导入'] || persimissionData.all"
  19. name="your_file"
  20. :show-upload-list="false"
  21. :headers="headers"
  22. :on-error="uploadError"
  23. :on-success="uploadSuccess"
  24. :action="$store.state.ip + '/api/product_import'"
  25. >
  26. <Button type="success" ghost icon="md-exit" style="margin-right:10px;"
  27. >批量导入</Button
  28. >
  29. </Upload>
  30. <Button
  31. v-if="persimissionData['批量导出'] || persimissionData.all"
  32. @click="exportData"
  33. type="warning"
  34. ghost
  35. icon="md-return-left"
  36. style="margin-right:10px;"
  37. >批量导出</Button
  38. >
  39. <!-- v-if="persimissionData['批改替换项'] || persimissionData.all" -->
  40. <Button
  41. type="primary"
  42. ghost
  43. @click="showModal = true"
  44. style="margin-right:10px;"
  45. >批改替换项</Button
  46. >
  47. <Button
  48. v-if="persimissionData['新增产品'] || persimissionData.all"
  49. type="primary"
  50. ghost
  51. icon="md-add"
  52. @click="goPage(1)"
  53. >新增产品</Button
  54. >
  55. </div>
  56. <div slot="navButton"></div>
  57. <template slot="set" slot-scope="{ row }">
  58. <div class="table-set">
  59. <svg
  60. style="font-size:20px"
  61. color="#3764FF"
  62. @click="goPage(4, row)"
  63. class="icon icon-nav"
  64. aria-hidden="true"
  65. >
  66. <use xlink:href="#iconcopy-01"></use>
  67. </svg>
  68. <svg
  69. v-if="persimissionData['编辑'] || persimissionData.all"
  70. style="font-size:20px"
  71. color="#3764FF"
  72. @click="goPage(2, row)"
  73. class="icon icon-nav"
  74. aria-hidden="true"
  75. >
  76. <use xlink:href="#iconbianji"></use>
  77. </svg>
  78. <svg
  79. style="font-size:20px"
  80. color="green"
  81. @click="goPage(3, row)"
  82. class="icon icon-nav"
  83. aria-hidden="true"
  84. >
  85. <use xlink:href="#iconxiangqing"></use>
  86. </svg>
  87. <svg
  88. v-if="persimissionData['删除'] || persimissionData.all"
  89. @click="delItems(row)"
  90. class="icon icon-nav"
  91. style="font-size:20px"
  92. color="red"
  93. aria-hidden="true"
  94. >
  95. <use xlink:href="#iconshanchu"></use>
  96. </svg>
  97. </div>
  98. </template>
  99. </FullPage>
  100. <Modal
  101. v-model="showModal"
  102. :title="'批改替换项:' + $route.query.title"
  103. width="1300"
  104. >
  105. <div class="show_modal_content">
  106. <div class="show_modal_content_left">
  107. <div class="show_modal_content_left_item">
  108. <div class="show_modal_content_left_item_title">
  109. <Button
  110. type="primary"
  111. style="cursor:default;border-radius:0"
  112. :ghost="!isSelectAll"
  113. @click="handleProductAllClick(tableData)"
  114. >产品名称</Button
  115. >
  116. </div>
  117. <div class="show_modal_content_left_item_detail_warp">
  118. <div
  119. class="show_modal_content_left_item_detail"
  120. v-for="product in tableData"
  121. :key="product.id"
  122. >
  123. <Button
  124. type="primary"
  125. :ghost="!product.isSelect"
  126. style="border-radius:10px"
  127. @click="handleProductClick(product, 2)"
  128. >{{ product.title }}</Button
  129. >
  130. </div>
  131. </div>
  132. </div>
  133. <div class="show_modal_content_left_item">
  134. <div class="show_modal_content_left_item_title">
  135. <Button
  136. type="primary"
  137. style="cursor:default;border-radius:0"
  138. ghost
  139. >部件名称</Button
  140. >
  141. </div>
  142. <div v-if="productPartList.length < 1">
  143. <Button type="primary" ghost style="border-radius:10px"
  144. >无</Button
  145. >
  146. </div>
  147. <div v-else class="show_modal_content_left_item_detail_warp">
  148. <div
  149. class="show_modal_content_left_item_detail"
  150. v-for="part in productPartList"
  151. :key="part.id"
  152. >
  153. <Button
  154. type="primary"
  155. :ghost="!part.isSelect"
  156. style="border-radius:10px"
  157. @click="handlePartClick(part, 3)"
  158. >{{ part.title }}</Button
  159. >
  160. </div>
  161. </div>
  162. </div>
  163. </div>
  164. <div class="show_modal_content_right">
  165. <div class="show_modal_content_right_top">
  166. <Button type="primary" @click="handleAddChangeable"
  167. >新增替换部件</Button
  168. >
  169. </div>
  170. <div class="show_modal_content_right_body">
  171. <Table
  172. border
  173. max-height="500"
  174. :columns="changeableColumns"
  175. :data="changeableTableData"
  176. ></Table>
  177. </div>
  178. </div>
  179. </div>
  180. <div slot="footer">
  181. <Button
  182. type="primary"
  183. style="margin-right:10px;"
  184. @click="showModal = false"
  185. >取消</Button
  186. >
  187. <Button
  188. type="primary"
  189. style="margin-right:10px;"
  190. @click="handleChangeableConfirm"
  191. >确定</Button
  192. >
  193. </div>
  194. </Modal>
  195. <Modal
  196. v-model="showKey"
  197. :width="1250"
  198. :mask-closable="false"
  199. :closable="false"
  200. >
  201. <div>
  202. <KeyBoard
  203. :rightData="measureList"
  204. @cancel="cancelKey"
  205. @success="successKey"
  206. class="key-co"
  207. />
  208. </div>
  209. <div slot="footer"></div>
  210. </Modal>
  211. </div>
  212. </template>
  213. <script>
  214. import { mapState } from "vuex";
  215. import KeyBoard from "../../components/keyboard/index";
  216. export default {
  217. components: { KeyBoard },
  218. data() {
  219. return {
  220. list: [
  221. {
  222. title: "产品名称",
  223. name: "Input",
  224. value: "",
  225. serverName: "title",
  226. placeholder: "请输入产品名称",
  227. },
  228. {
  229. title: "产品型号",
  230. name: "Input",
  231. value: "",
  232. serverName: "model",
  233. placeholder: "请输入产品型号",
  234. },
  235. {
  236. title: "图号",
  237. name: "Input",
  238. value: "",
  239. serverName: "url_number",
  240. placeholder: "请输入图号",
  241. },
  242. ],
  243. tableColums: [
  244. {
  245. title: "序号",
  246. type: "index",
  247. align: "center",
  248. key: "",
  249. width: "100",
  250. },
  251. { title: "分类名称", align: "center", key: "type_name" },
  252. { title: "产品名称", align: "center", key: "title" },
  253. { title: "计量单位", align: "center", key: "unit" },
  254. { title: "型号", align: "center", key: "model" },
  255. { title: "图号", align: "center", key: "url_number" },
  256. {
  257. title: "产品图片",
  258. align: "center",
  259. key: "company",
  260. render: (h, params) => {
  261. const { row } = params;
  262. return h("img", {
  263. attrs: {
  264. src: this.$store.state.ip + params.row.img_url,
  265. style:
  266. "max-width:50px;max-height:50px;position:relative;top:3px;",
  267. },
  268. on: {
  269. click: (e) => {
  270. this.axios("/api/orders_img", {
  271. params: { id: row.id, type: 0 },
  272. }).then((res) => {
  273. console.log(
  274. "this.$store.state.ip :>> ",
  275. this.$store.state.ip
  276. );
  277. if (res.code == 200) {
  278. row.imgs = res.data;
  279. this.$previewImg({
  280. list: res.data,
  281. baseUrl: this.$store.state.ip,
  282. baseImgField: "img_url",
  283. baseTitleField: "",
  284. });
  285. }
  286. });
  287. // if(row.imgs&&row.imgs.length>0){//优化处理考虑到图纸我就暂时不处理了
  288. // this.$previewImg({
  289. // list:row.imgs,
  290. // baseUrl:this.$store.state.ip,
  291. // baseImgField:'img_url',
  292. // baseTitleField:''
  293. // })
  294. // }else{
  295. // this.axios('/api/orders_img',{params:{id:row.id,type:0}}).then(res=>{
  296. // if(res.code == 200){
  297. // row.imgs = res.data
  298. // this.$previewImg({
  299. // list:row.imgs,
  300. // baseUrl:this.$store.state.ip,
  301. // baseImgField:'img_url',
  302. // baseTitleField:''
  303. // })
  304. // }
  305. // })
  306. // }
  307. },
  308. },
  309. });
  310. },
  311. },
  312. {
  313. title: "图纸",
  314. align: "center",
  315. key: "url",
  316. render: (h, params) => {
  317. const { row } = params;
  318. return h("img", {
  319. attrs: {
  320. src: this.$store.state.ip + params.row.url,
  321. style:
  322. "max-width:50px;max-height:50px;position:relative;top:3px;",
  323. },
  324. on: {
  325. click: (e) => {
  326. this.axios("/api/orders_img", {
  327. params: { id: row.id, type: 1 },
  328. }).then((res) => {
  329. if (res.code == 200) {
  330. row.imgs = res.data;
  331. this.$previewImg({
  332. list: row.imgs,
  333. baseUrl: this.$store.state.ip,
  334. baseImgField: "img_url",
  335. baseTitleField: "",
  336. });
  337. }
  338. });
  339. },
  340. },
  341. });
  342. },
  343. },
  344. { title: "操作", align: "center", slot: "set", width: "150" },
  345. ],
  346. tableData: [],
  347. pageIndex: 1,
  348. total: 0,
  349. pageSize: 10,
  350. proxyObj: {
  351. page_index: 1,
  352. page_size: 10,
  353. },
  354. loading: false,
  355. headers: { Authorization: localStorage.getItem("token") },
  356. showModal: false,
  357. productPartList: [],
  358. currentProductList: [],
  359. changeableColumns: [
  360. {
  361. title: "替换部件",
  362. align: "center",
  363. key: "part_id",
  364. render: (h, params) => {
  365. const { index } = params;
  366. const currencyRow = this.changeableTableData[index];
  367. return h(
  368. "Select",
  369. {
  370. props: {
  371. value: currencyRow.part_id,
  372. size: "small",
  373. transfer: true,
  374. clearable: true,
  375. filterable: true,
  376. },
  377. on: {
  378. "on-change": (e) => {
  379. currencyRow.part_id = e;
  380. },
  381. },
  382. },
  383. [
  384. this.partsList.map((item) => {
  385. return h("Option", {
  386. props: { label: item.title, value: item.id },
  387. });
  388. }),
  389. ]
  390. );
  391. },
  392. },
  393. {
  394. title: "高",
  395. align: "center",
  396. key: "formula_l",
  397. width: "100px",
  398. render: (h, params) => {
  399. const { index } = params;
  400. const currencyRow = this.changeableTableData[index];
  401. return h("Input", {
  402. props: {
  403. placeholder: "请输入高",
  404. value: currencyRow.formula_l,
  405. disabled: this.isChecked,
  406. },
  407. on: {
  408. "on-focus": () => {
  409. this.openKey(index, "formula_l", currencyRow);
  410. },
  411. },
  412. });
  413. },
  414. },
  415. {
  416. title: "宽",
  417. align: "center",
  418. key: "formula_w",
  419. width: "100px",
  420. render: (h, params) => {
  421. const { index } = params;
  422. const currencyRow = this.changeableTableData[index];
  423. return h("Input", {
  424. props: {
  425. placeholder: "请输入宽",
  426. value: currencyRow.formula_w,
  427. },
  428. on: {
  429. "on-focus": () => {
  430. this.openKey(index, "formula_w", currencyRow);
  431. },
  432. },
  433. });
  434. },
  435. },
  436. {
  437. title: "厚",
  438. align: "center",
  439. key: "formula_h",
  440. width: "100px",
  441. render: (h, params) => {
  442. const { index } = params;
  443. const currencyRow = this.changeableTableData[index];
  444. return h("Input", {
  445. props: {
  446. placeholder: "请输入厚",
  447. value: currencyRow.formula_h,
  448. },
  449. on: {
  450. "on-focus": () => {
  451. this.openKey(index, "formula_h", currencyRow);
  452. },
  453. },
  454. });
  455. },
  456. },
  457. {
  458. title: "操作",
  459. align: "center",
  460. key: "set",
  461. width: "100px",
  462. render: (h, params) => {
  463. const { index } = params;
  464. // const currencyRow = this.changeableTableData[index];
  465. return h(
  466. "a",
  467. {
  468. on: {
  469. click: () => {
  470. this.changeableTableData.splice(index, 1);
  471. },
  472. },
  473. },
  474. "删除"
  475. );
  476. },
  477. },
  478. ],
  479. changeableTableData: [],
  480. partsList: [],
  481. showKey: false,
  482. measureList: [],
  483. currencyChoose: {},
  484. attrindex: null,
  485. attrName: "",
  486. isSelectAll: false,
  487. };
  488. },
  489. beforeRouteLeave(to, from, next) {
  490. if (to.path == "/cms/product/edit") {
  491. this.$route.meta.keepAlive = true;
  492. } else {
  493. this.$route.meta.keepAlive = false;
  494. }
  495. next();
  496. },
  497. beforeRouteEnter(to, from, next) {
  498. next((vm) => {
  499. vm.getData(vm.proxyObj);
  500. });
  501. },
  502. created() {
  503. // 获取部件列表
  504. this.axios("/api/parts_index").then((res) => {
  505. this.partsList = res.data.data;
  506. });
  507. // 获取产品分类测量字段
  508. this.axios("/api/basics_product_list", {
  509. params: { id: this.$route.query.id },
  510. }).then((res) => {
  511. if (res.code == 200) {
  512. const { data } = res;
  513. const result = data.filter((rows) => rows.id == this.$route.query.id);
  514. this.measureList = result[0].measure;
  515. }
  516. });
  517. },
  518. mounted() {
  519. this.proxyObj.type_id = this.$route.query.id;
  520. this.getData(this.proxyObj);
  521. },
  522. computed: {
  523. ...mapState(["persimissionData"]),
  524. },
  525. watch: {
  526. "$route.query.title": {
  527. handler() {
  528. this.proxyObj.type_id = this.$route.query.id;
  529. this.list.forEach((element) => {
  530. element.value = "";
  531. });
  532. this.proxyObj.model = "";
  533. this.proxyObj.title = "";
  534. this.getData(this.proxyObj);
  535. },
  536. },
  537. },
  538. methods: {
  539. init(row) {
  540. this.pageIndex = 1;
  541. row.page_index = this.pageIndex;
  542. row.page_size = this.pageSize;
  543. row.type_id = this.$route.query.id; //产品管理因为无法使用id 所以用type_id替代
  544. this.proxyObj = row;
  545. this.getData(row);
  546. },
  547. getData(row) {
  548. this.loading = true;
  549. this.axios("/api/product", { params: row }).then((res) => {
  550. this.loading = false;
  551. this.tableData = res.data.data;
  552. this.total = res.data.total;
  553. this.tableData.map((item) => (item.isSelect = false));
  554. });
  555. },
  556. delItems(row) {
  557. this.confirmDelete({
  558. content: "确认删除么?",
  559. then: () => {
  560. this.axios
  561. .post("/api/product", { id: row.id, state: 0 })
  562. .then((res) => {
  563. if (res.code == 200) {
  564. this.$Message.success(res.msg);
  565. this.getData(this.proxyObj);
  566. }
  567. });
  568. },
  569. });
  570. },
  571. handleProductAllClick(product) {
  572. this.isSelectAll = !this.isSelectAll;
  573. // let flag
  574. product.map((item) => {
  575. item.isSelect = this.isSelectAll;
  576. });
  577. let ids = product.map((item) => item.id);
  578. this.isSelectAll &&
  579. this.axios
  580. .post("/api/support_product_get_part", {
  581. type: 2,
  582. basic_product_id: [this.$route.query.id],
  583. product_id: ids,
  584. part_id: [],
  585. })
  586. .then((res) => {
  587. console.log(res);
  588. this.productPartList = res.data;
  589. this.productPartList.map((item) => (item.isSelect = false));
  590. });
  591. },
  592. handleProductClick(product, type) {
  593. product.isSelect = !product.isSelect;
  594. this.currentProductList = product;
  595. const temp_product = this.tableData.filter((item) => item.isSelect);
  596. const product_id = temp_product.map((item) => item.id);
  597. // 判断是否全选,全选标题选中
  598. let flag = true;
  599. this.tableData.map((item) => {
  600. if (!item.isSelect) {
  601. flag = false;
  602. }
  603. });
  604. this.isSelectAll = flag;
  605. this.axios
  606. .post("/api/support_product_get_part", {
  607. type,
  608. basic_product_id: [this.$route.query.id],
  609. product_id,
  610. part_id: [],
  611. })
  612. .then((res) => {
  613. console.log(res);
  614. this.productPartList = res.data;
  615. this.productPartList.map((item) => (item.isSelect = false));
  616. });
  617. this.$forceUpdate();
  618. },
  619. handlePartClick(part, type) {
  620. // 部件单选
  621. this.productPartList.map((item) => (item.isSelect = false));
  622. part.isSelect = !part.isSelect;
  623. const temp_product = this.tableData.filter((item) => item.isSelect);
  624. const product_id = temp_product.map((item) => item.id);
  625. const temp_part = this.productPartList.filter((item) => item.isSelect);
  626. const part_id = temp_part.map((item) => item.id);
  627. this.axios
  628. .post("/api/support_product_get_part", {
  629. type,
  630. basic_product_id: [this.$route.query.id],
  631. product_id,
  632. part_id,
  633. })
  634. .then((res) => {
  635. console.log(res);
  636. this.changeableTableData = res.data;
  637. });
  638. this.$forceUpdate();
  639. },
  640. handleAddChangeable() {
  641. const temp = this.productPartList.filter((item) => item.isSelect);
  642. if (temp.length > 0) {
  643. this.changeableTableData.push({
  644. id: "",
  645. formula_h: "",
  646. formula_l: "",
  647. formula_w: "",
  648. });
  649. } else {
  650. this.$Message.warning("请选择部件名称");
  651. }
  652. },
  653. handleChangeableConfirm() {
  654. const temp_product = this.tableData.filter((item) => item.isSelect);
  655. const product_id = temp_product.map((item) => item.id);
  656. const temp_part = this.productPartList.filter((item) => item.isSelect);
  657. const part_id = temp_part.map((item) => item.id);
  658. this.axios
  659. .post("/api/support_product_batch", {
  660. type: 3,
  661. basic_product_id: [this.$route.query.id],
  662. product_id,
  663. part_id,
  664. change: this.changeableTableData,
  665. })
  666. .then((res) => {
  667. if (res.code == 200) {
  668. this.$Message.success(res.msg);
  669. this.tableData.map((item) => (item.isSelect = false));
  670. this.productPartList = [];
  671. this.changeableTableData = [];
  672. this.showModal = false;
  673. }
  674. });
  675. },
  676. openKey(row, attr, cur) {
  677. this.showKey = true;
  678. this.attrindex = row;
  679. this.attrName = attr;
  680. this.currencyChoose = cur;
  681. },
  682. successKey(str) {
  683. // this.info.part[this.attrindex][this.attrName] = str;
  684. this.currencyChoose[this.attrName] = str;
  685. this.showKey = false;
  686. },
  687. cancelKey() {
  688. this.showKey = false;
  689. },
  690. changePage(e) {
  691. this.pageIndex = e;
  692. this.proxyObj.page_index = this.pageIndex;
  693. // const sortList = this.sortList.filter((item) => item.sort);
  694. // this.proxyObj.sortList = sortList;
  695. this.getData(this.proxyObj);
  696. },
  697. changeSize(e) {
  698. this.pageSize = e;
  699. this.proxyObj.page_size = this.pageSize;
  700. // const sortList = this.sortList.filter((item) => item.sort);
  701. // this.proxyObj.sortList = sortList;
  702. this.getData(this.proxyObj);
  703. },
  704. goPage(n, row) {
  705. //n = 1 新增 2 编辑 3 查看
  706. let id = row ? row.id : "";
  707. this.$router.push({
  708. path: "/cms/product/edit",
  709. query: {
  710. type: n,
  711. id: id,
  712. back_id: this.$route.query.id,
  713. title: this.$route.query.title,
  714. },
  715. });
  716. },
  717. async exportData() {
  718. const res = await this.axios("/api/product_export", {
  719. params: { ...this.proxyObj },
  720. });
  721. if (res.code == 200) {
  722. let url = `${this.$store.state.ip}/api/storage/${res.data.file}`;
  723. location.href = url;
  724. }
  725. },
  726. uploadSuccess(res) {
  727. if (res.code == 200) {
  728. this.$Message.success(res.msg || "上传成功");
  729. } else {
  730. this.$Message.warning(res.msg || "上传失败");
  731. }
  732. this.getData(this.proxyObj);
  733. },
  734. uploadError(err) {
  735. this.$Message.error(err.msg || "上传失败");
  736. },
  737. },
  738. };
  739. </script>
  740. <style lang="scss" scoped>
  741. .show_modal_content {
  742. display: flex;
  743. .show_modal_content_left {
  744. width: 50%;
  745. min-height: 500px;
  746. overflow: hidden;
  747. overflow-y: auto;
  748. border-right: 1px solid #e8eaec;
  749. padding-top: 20px;
  750. .show_modal_content_left_item {
  751. width: 100%;
  752. display: flex;
  753. .show_modal_content_left_item_title,
  754. .show_modal_content_left_item_detail {
  755. margin-bottom: 10px;
  756. margin-right: 20px;
  757. }
  758. .show_modal_content_left_item_detail_warp {
  759. display: flex;
  760. justify-content: flex-start;
  761. align-items: flex-start;
  762. flex-wrap: wrap;
  763. .show_modal_content_left_item_detail {
  764. }
  765. }
  766. }
  767. }
  768. .show_modal_content_right {
  769. width: 50%;
  770. padding-left: 20px;
  771. .show_modal_content_right_top {
  772. display: flex;
  773. justify-content: flex-end;
  774. margin-top: 50px;
  775. margin-bottom: 10px;
  776. }
  777. }
  778. }
  779. </style>