product-list.vue 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401
  1. <template>
  2. <el-dialog
  3. title="选择产品"
  4. :visible.sync="visible"
  5. :before-close="handleClose"
  6. :close-on-click-modal="false"
  7. top="5vh"
  8. :close-on-press-escape="false"
  9. append-to-body
  10. width="70%"
  11. >
  12. <el-card shadow="never">
  13. <searchProduct @search="reload"></searchProduct>
  14. <ele-split-layout
  15. width="244px"
  16. allow-collapse
  17. :right-style="{ overflow: 'hidden' }"
  18. >
  19. <div class="ele-border-lighter split-layout-right-content">
  20. <productTree
  21. @handleNodeClick="handleNodeClick"
  22. :isFirstRefreshTable="false"
  23. ref="treeList"
  24. />
  25. </div>
  26. <!-- 表格 -->
  27. <template v-slot:content>
  28. <ele-pro-table
  29. ref="table"
  30. :columns="columns"
  31. :datasource="datasource"
  32. @row-dblclick="handleDoubleClick"
  33. row-key="id"
  34. height="calc(100vh - 480px)"
  35. class="dict-table"
  36. @cell-click="cellClick"
  37. :selection.sync="selection"
  38. >
  39. <!-- 表头工具栏 -->
  40. <template v-slot:action="{ row }">
  41. <el-radio class="radio" v-model="radio" :label="row.code"
  42. ><i></i
  43. ></el-radio>
  44. </template>
  45. <template v-slot:cz="{ row }">
  46. <el-button type="text" @click="handleDoubleClick(row)">
  47. 选择Bom
  48. </el-button>
  49. </template>
  50. </ele-pro-table>
  51. </template>
  52. </ele-split-layout>
  53. </el-card>
  54. <div slot="footer">
  55. <el-button type="primary" size="small" @click="selected">选择</el-button>
  56. <el-button size="small" @click="handleClose">关闭</el-button>
  57. </div>
  58. <c-bom-list
  59. v-if="cBomListDialogFlag"
  60. :cBomListDialogFlag.sync="cBomListDialogFlag"
  61. :current-row="current"
  62. ref="cBomRef"
  63. @changeParent="getSelectionCbom"
  64. ></c-bom-list>
  65. </el-dialog>
  66. </template>
  67. <script>
  68. import { getProductList } from '@/api/saleManage/quotation';
  69. import searchProduct from './searchProduct.vue';
  70. import productTree from '@/components/productTree';
  71. import { getInventoryTotalAPI } from '@/api/wms';
  72. import cBomList from './cBom-list.vue';
  73. import { getByCode } from '@/api/system/dictionary-data';
  74. export default {
  75. components: {
  76. productTree,
  77. searchProduct,
  78. cBomList
  79. },
  80. props: {
  81. /*是否需要获取仓库产品数量*/
  82. isGetInventoryTotal: {
  83. type: Boolean,
  84. default: false
  85. },
  86. /*已选择的产品*/
  87. data: {
  88. type: Array,
  89. default: () => []
  90. },
  91. /*是否需要cBom*/
  92. isShowCBom: {
  93. type: Boolean,
  94. default: false
  95. }
  96. },
  97. data() {
  98. return {
  99. visible: false,
  100. currentIndex: null,
  101. radio: null,
  102. cBomListDialogFlag: null,
  103. dictList: {},
  104. selection: []
  105. };
  106. },
  107. watch: {},
  108. computed: {
  109. columns() {
  110. return [
  111. {
  112. action: 'action',
  113. slot: 'action',
  114. align: 'center',
  115. label: '选择',
  116. reserveSelection: true,
  117. show: this.currentIndex != -1
  118. },
  119. {
  120. label: '选择',
  121. show: this.currentIndex == -1,
  122. width: 45,
  123. type: 'selection',
  124. columnKey: 'selection',
  125. align: 'center',
  126. reserveSelection: true,
  127. },
  128. {
  129. columnKey: 'index',
  130. type: 'index',
  131. width: 50,
  132. align: 'center',
  133. showOverflowTooltip: true,
  134. label: '序号'
  135. },
  136. {
  137. prop: 'code',
  138. label: '编码',
  139. align: 'center',
  140. showOverflowTooltip: true,
  141. minWidth: 110
  142. },
  143. {
  144. prop: 'name',
  145. label: '名称',
  146. align: 'center',
  147. showOverflowTooltip: true,
  148. minWidth: 110
  149. },
  150. {
  151. prop: 'imgCode',
  152. align: 'center',
  153. label: '图号/件号',
  154. showOverflowTooltip: true,
  155. minWidth: 110
  156. },
  157. {
  158. prop: 'produceType',
  159. align: 'center',
  160. label: '生产类型',
  161. showOverflowTooltip: true,
  162. formatter: (row, column) => {
  163. return row.produceType && row.produceType.length
  164. ? row.produceType
  165. .map((item) => this.getDictV('productionType', item))
  166. .join(',')
  167. : '';
  168. },
  169. minWidth: 110
  170. },
  171. {
  172. prop: 'extField.approvalNumber',
  173. align: 'center',
  174. label: '批准文号',
  175. showOverflowTooltip: true,
  176. minWidth: 110
  177. },
  178. {
  179. prop: 'extField.packingSpecification',
  180. align: 'center',
  181. label: '包装规格',
  182. showOverflowTooltip: true,
  183. minWidth: 110
  184. },
  185. {
  186. prop: 'brandNum',
  187. align: 'center',
  188. label: '牌号',
  189. showOverflowTooltip: true
  190. },
  191. {
  192. prop: 'modelType',
  193. label: '型号',
  194. align: 'center',
  195. showOverflowTooltip: true
  196. },
  197. {
  198. prop: 'specification',
  199. label: '规格',
  200. align: 'center',
  201. showOverflowTooltip: true
  202. },
  203. {
  204. prop: 'measuringUnit',
  205. label: '计量单位',
  206. showOverflowTooltip: true,
  207. align: 'center',
  208. minWidth: 90
  209. },
  210. {
  211. prop: 'weightUnit',
  212. label: '重量单位',
  213. showOverflowTooltip: true,
  214. align: 'center',
  215. minWidth: 90
  216. },
  217. {
  218. prop: 'roughWeight',
  219. label: '毛重',
  220. showOverflowTooltip: true,
  221. align: 'center',
  222. minWidth: 90
  223. },
  224. {
  225. prop: 'netWeight',
  226. label: '净重',
  227. showOverflowTooltip: true,
  228. align: 'center',
  229. minWidth: 90
  230. },
  231. {
  232. prop: 'packingUnit',
  233. align: 'center',
  234. label: '包装单位',
  235. showOverflowTooltip: true
  236. },
  237. {
  238. prop: 'categoryLevelPath',
  239. label: '分类',
  240. align: 'center',
  241. showOverflowTooltip: true
  242. },
  243. {
  244. slot: 'cz',
  245. align: 'center',
  246. minWidth: 90,
  247. fixed: 'right',
  248. label: '操作',
  249. show: this.isShowCBom
  250. }
  251. ];
  252. }
  253. },
  254. methods: {
  255. getDictV(code, val) {
  256. if (!this.dictList[code]) return '';
  257. return this.dictList[code].find((item) => item.value == val)?.label;
  258. },
  259. async getDictList(code) {
  260. let { data: res } = await getByCode(code);
  261. this.dictList[code] = res.map((item) => {
  262. let values = Object.keys(item);
  263. return {
  264. value: values[0],
  265. label: item[values[0]]
  266. };
  267. });
  268. },
  269. open(item, currentIndex) {
  270. this.currentIndex = currentIndex;
  271. this.visible = true;
  272. this.getDictList('productionType');
  273. },
  274. /* 表格数据源 */
  275. datasource({ page, limit, where, order }) {
  276. return getProductList({
  277. pageNum: page,
  278. size: limit,
  279. ...where
  280. });
  281. },
  282. /* 刷新表格 */
  283. reload(where) {
  284. where.categoryLevelId=this.curNodeData?.id
  285. this.$refs.table.reload({ pageNum: 1, where: where });
  286. },
  287. handleNodeClick(data, node) {
  288. this.curNodeData = data;
  289. this.reload({ categoryLevelId: data.id });
  290. },
  291. // 单击获取id
  292. cellClick(row) {
  293. if (this.currentIndex == -1) return;
  294. this.current = row;
  295. this.radio = row.id;
  296. },
  297. handleDoubleClick(row) {
  298. if (!this.isShowCBom) return;
  299. this.cBomListDialogFlag = true;
  300. this.current = row;
  301. this.$nextTick(() => {
  302. this.$refs.cBomRef.open(row);
  303. });
  304. },
  305. getSelectionCbom(rows = []) {
  306. this.$emit('getSelectionCbom', rows);
  307. this.handleClose();
  308. },
  309. handleClose() {
  310. this.visible = false;
  311. this.current = null;
  312. this.selection = [];
  313. this.$refs.table.clearSelection();
  314. this.radio = '';
  315. },
  316. async selected() {
  317. if (!this.current && !this.selection.length) {
  318. return this.$message.warning('请至少选择一条数据');
  319. }
  320. if (this.currentIndex != -1) {
  321. if (
  322. this.data
  323. .map((item) => item.productCode)
  324. .includes(this.current.code)
  325. ) {
  326. return this.$message.error('选择的产品已经存在列表了');
  327. }
  328. } else {
  329. if (
  330. this.selection.some((item) =>
  331. this.data.some((i) => i.productCode == item.code)
  332. )
  333. ) {
  334. return this.$message.error('选择的产品已经存在列表了');
  335. }
  336. }
  337. let codeList = [];
  338. let list = this.currentIndex == -1 ? this.selection : [this.current];
  339. //获取仓库库存
  340. if (this.isGetInventoryTotal) {
  341. codeList = list.map((item) => item.code);
  342. let inventoryTotalList = await getInventoryTotalAPI(codeList);
  343. list.forEach((item) => {
  344. let find =
  345. inventoryTotalList.find((key) => key.code == item.code) || {};
  346. item.availableCountBase = find.availableCountBase;
  347. });
  348. }
  349. this.$emit('changeParent', list, this.currentIndex);
  350. this.handleClose();
  351. }
  352. }
  353. };
  354. </script>
  355. <style lang="scss" scoped>
  356. .tree_col {
  357. border: 1px solid #eee;
  358. padding: 10px 0;
  359. box-sizing: border-box;
  360. height: 500px;
  361. overflow: auto;
  362. }
  363. .table_col {
  364. padding-left: 10px;
  365. ::v-deep .el-table th.el-table__cell {
  366. background: #f2f2f2;
  367. }
  368. }
  369. .pagination {
  370. text-align: right;
  371. padding: 10px 0;
  372. }
  373. .btns {
  374. text-align: center;
  375. padding: 10px 0;
  376. }
  377. .topsearch {
  378. margin-bottom: 15px;
  379. }
  380. </style>