add.vue 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746
  1. <template>
  2. <el-dialog
  3. top="5vh"
  4. :visible.sync="visible"
  5. :title="isView ? '查看收发明细表明细' : '选择收发明细表明细'"
  6. width="90vw"
  7. >
  8. <el-card shadow="never" style="height: 70vh">
  9. <!-- 数据表格 -->
  10. <div>
  11. <el-form
  12. ref="formRef"
  13. label-position="left"
  14. class="ele-form-search"
  15. :model="formData"
  16. :rules="rules"
  17. @keyup.enter.native="search"
  18. @submit.native.prevent
  19. >
  20. <el-row :gutter="15">
  21. <el-col :span="5">
  22. <el-form-item label-width="60px" label="编码:" prop="code">
  23. <el-input
  24. disabled
  25. v-model="formData.code"
  26. placeholder="请输入"
  27. ></el-input>
  28. </el-form-item>
  29. </el-col>
  30. <el-col :span="5">
  31. <el-form-item label-width="60px" label="名称:" prop="name">
  32. <el-input
  33. :disabled="isView"
  34. v-model="formData.name"
  35. placeholder="请输入"
  36. ></el-input>
  37. </el-form-item>
  38. </el-col>
  39. <el-col :span="7">
  40. <el-form-item label-width="90px" label="起止时间:" prop="time">
  41. <el-date-picker
  42. :disabled="isView"
  43. style="width: 100%"
  44. class="w100"
  45. size="small"
  46. v-model="formData.time"
  47. type="daterange"
  48. range-separator="至"
  49. start-placeholder="开始日期"
  50. end-placeholder="结束日期"
  51. value-format="yyyy-MM-dd"
  52. :picker-options="pickerOptions"
  53. ></el-date-picker>
  54. </el-form-item>
  55. </el-col>
  56. <el-col :span="4">
  57. <el-form-item label-width="60px" label="关键词:" prop="keyWord">
  58. <el-input
  59. :disabled="isView"
  60. v-model="formData.keyWord"
  61. placeholder="请输入关键词"
  62. ></el-input>
  63. </el-form-item>
  64. </el-col>
  65. <el-col :span="5">
  66. <el-form-item label-width="60px" label="出入库:" prop="type">
  67. <el-select
  68. filterable
  69. placeholder="请选择"
  70. v-model="formData.type"
  71. clearable
  72. :disabled="isView"
  73. @change="handleOutInChange"
  74. >
  75. <el-option
  76. v-for="item in outInOption"
  77. :key="item.code"
  78. :value="item.code + ''"
  79. :label="item.label"
  80. ></el-option>
  81. </el-select>
  82. </el-form-item>
  83. </el-col>
  84. <el-col :span="5">
  85. <el-form-item :label="formData.type == 2 ? '出库类型:' : '入库类型:'" prop="bizType">
  86. <el-select
  87. filterable
  88. placeholder="请选择"
  89. v-model="formData.bizType"
  90. :disabled="isView"
  91. clearable
  92. >
  93. <el-option
  94. v-for="item in outInStateOption"
  95. :key="item.code"
  96. :value="item.code + ''"
  97. :label="item.label"
  98. ></el-option>
  99. </el-select>
  100. </el-form-item>
  101. </el-col>
  102. <el-col :span="5">
  103. <el-form-item label="物品类型" prop="categoryLevelId">
  104. <el-select
  105. filterable
  106. placeholder="请选择"
  107. v-model="formData.categoryLevelId"
  108. :disabled="isView"
  109. clearable
  110. >
  111. <el-option
  112. v-for="item in codeOption"
  113. :key="item.dictCode"
  114. :value="item.dictCode"
  115. :label="item.dictValue"
  116. ></el-option>
  117. </el-select>
  118. </el-form-item>
  119. </el-col>
  120. <el-col v-if="!isView" :span="3">
  121. <div class="ele-form-actions">
  122. <el-button
  123. type="primary"
  124. icon="el-icon-search"
  125. class="ele-btn-icon"
  126. @click="search"
  127. size="small"
  128. >
  129. 查询
  130. </el-button>
  131. <el-button
  132. @click="reset"
  133. icon="el-icon-refresh-left"
  134. size="small"
  135. type="primary"
  136. >重置</el-button
  137. >
  138. </div>
  139. </el-col>
  140. </el-row>
  141. </el-form>
  142. </div>
  143. <ele-pro-table
  144. ref="table"
  145. class="table"
  146. :needPage="!isView"
  147. :columns="columns"
  148. :datasource="datasource"
  149. height="calc(100% - 305px)"
  150. full-height="calc(100vh - 56px)"
  151. tool-class="ele-toolbar-form"
  152. style="margin-top: 18px"
  153. >
  154. <!-- 状态 -->
  155. <!-- <template v-slot:verifyStatus="{ row }">
  156. <span :class="status[row.verifyStatus].class">
  157. {{ status[row.verifyStatus].label }}
  158. </span>
  159. </template> -->
  160. <template v-slot:bizType="{ row }">
  161. {{ handleBizType(row.bizType, row.type) }}
  162. </template>
  163. <template v-slot:assetType="{ row }">
  164. {{ handleAssetType(row?.extInfo?.assetType) }}
  165. </template>
  166. </ele-pro-table>
  167. </el-card>
  168. <div slot="footer" class="dialog-footer" style="margin-right: 2%">
  169. <el-button
  170. v-if="!isView"
  171. size="small"
  172. @click="downLoad('statistics')"
  173. :loading="loading"
  174. type="primary"
  175. >统计导出</el-button
  176. >
  177. <el-button
  178. v-if="!isView"
  179. size="small"
  180. @click="downLoad('detail')"
  181. :loading="loading"
  182. type="primary"
  183. >明细导出</el-button
  184. >
  185. <el-button v-else size="small" @click="visible = false" type="primary"
  186. >确定</el-button
  187. >
  188. <el-button size="small" @click="visible = false">关闭</el-button>
  189. </div>
  190. </el-dialog>
  191. </template>
  192. <script>
  193. import { getCode } from '@/api/codeManagement/index.js';
  194. import ItemSearch from './components/item-search.vue';
  195. import {
  196. sendReceiveExcel,
  197. sendReceiveDetailListExcel,
  198. outintwoPage
  199. } from '@/api/warehouseManagement/statisticalReports';
  200. import storageApi from '@/api/warehouseManagement';
  201. import { allCategoryLevel } from '@/api/classifyManage';
  202. import { getTreeByGroup } from '@/api/classifyManage';
  203. import {
  204. warehousingType,
  205. sceneState,
  206. outputSceneState,
  207. auditStatus,
  208. useDict
  209. } from '@/utils/dict/index';
  210. export default {
  211. components: { ItemSearch },
  212. data() {
  213. return {
  214. auditStatus,
  215. outputSceneState,
  216. warehousingType,
  217. sceneState,
  218. status: [
  219. { label: '未审核', class: 'ele-text-info' },
  220. { label: '审核中', class: 'ele-text-primary' },
  221. { label: '审核通过', class: 'ele-text-success' },
  222. { label: '驳回', class: 'ele-text-danger' }
  223. ],
  224. outInOption: [
  225. { code: '2', label: '出库' },
  226. { code: '1', label: '入库' }
  227. ],
  228. codeOption: [],
  229. loading: false,
  230. isView: false,
  231. formData: {
  232. code: '',
  233. name: '',
  234. time: [],
  235. status: 2,
  236. keyWord: '',
  237. bizType: '',
  238. categoryLevelId: '',
  239. type: ''
  240. },
  241. // 表单验证规则
  242. rules: {
  243. name: [
  244. { required: true, message: '请输入库存余额名称', trigger: 'blur' }
  245. ],
  246. time: [
  247. { required: true, message: '请选择起止时间', trigger: 'change' }
  248. ]
  249. },
  250. pickerOptions: {
  251. shortcuts: [
  252. {
  253. text: '最近一周',
  254. onClick(picker) {
  255. const end = new Date();
  256. const start = new Date();
  257. start.setTime(start.getTime() - 3600 * 1000 * 24 * 7);
  258. picker.$emit('pick', [start, end]);
  259. }
  260. },
  261. {
  262. text: '最近一个月',
  263. onClick(picker) {
  264. const end = new Date();
  265. const start = new Date();
  266. start.setTime(start.getTime() - 3600 * 1000 * 24 * 30);
  267. picker.$emit('pick', [start, end]);
  268. }
  269. },
  270. {
  271. text: '最近三个月',
  272. onClick(picker) {
  273. const end = new Date();
  274. const start = new Date();
  275. start.setTime(start.getTime() - 3600 * 1000 * 24 * 90);
  276. picker.$emit('pick', [start, end]);
  277. }
  278. },
  279. {
  280. text: '最近一年',
  281. onClick(picker) {
  282. const end = new Date();
  283. const start = new Date();
  284. start.setTime(start.getTime() - 3600 * 1000 * 24 * 365);
  285. picker.$emit('pick', [start, end]);
  286. }
  287. }
  288. ]
  289. },
  290. visible: false
  291. };
  292. },
  293. computed: {
  294. // 表格列配置
  295. columns() {
  296. console.log(this.isView);
  297. let arr = [
  298. {
  299. type: 'index',
  300. label: '序号',
  301. width: 50,
  302. align: 'center'
  303. },
  304. {
  305. prop: 'bizNo',
  306. label: '单号',
  307. align: 'center',
  308. slot: 'bizNo',
  309. showOverflowTooltip: true,
  310. width: 150
  311. },
  312. {
  313. prop: 'bizType',
  314. slot: 'bizType',
  315. label: '出入库类型',
  316. align: 'center',
  317. showOverflowTooltip: true,
  318. width: 150
  319. },
  320. {
  321. prop: 'assetType',
  322. slot: 'assetType',
  323. label: '物品类型',
  324. align: 'center',
  325. showOverflowTooltip: true,
  326. width: 150
  327. },
  328. {
  329. prop: 'categoryNames',
  330. label: '物品名称',
  331. align: 'center',
  332. showOverflowTooltip: true,
  333. width: 150
  334. },
  335. {
  336. prop: 'categoryCodes',
  337. label: '物品编码',
  338. align: 'center',
  339. showOverflowTooltip: true,
  340. width: 150
  341. },
  342. {
  343. prop: 'sourceBizNo',
  344. label: '来源单据',
  345. align: 'center',
  346. showOverflowTooltip: true
  347. },
  348. {
  349. prop: 'createUserName',
  350. label: '操作人',
  351. align: 'center',
  352. showOverflowTooltip: true
  353. },
  354. {
  355. width: 160,
  356. prop: 'storageTime',
  357. label: '出入库时间',
  358. align: 'center',
  359. showOverflowTooltip: true
  360. },
  361. {
  362. prop: 'verifyName',
  363. label: '审核人',
  364. align: 'center',
  365. showOverflowTooltip: true
  366. }
  367. // {
  368. // prop: 'verifyStatus',
  369. // label: '状态',
  370. // align: 'center',
  371. // slot: 'verifyStatus',
  372. // showOverflowTooltip: true,
  373. // width: 100
  374. // }
  375. ];
  376. // if (!this.isView) {
  377. return arr.filter((item) => item != '');
  378. // }
  379. // if (this.isView) {
  380. // return [
  381. // {
  382. // type: 'index',
  383. // label: '序号',
  384. // width: 50,
  385. // align: 'center'
  386. // },
  387. // {
  388. // prop: 'categoryCode',
  389. // label: '物品编码',
  390. // align: 'center',
  391. // showOverflowTooltip: true,
  392. // width: 150
  393. // },
  394. // {
  395. // prop: 'categoryName',
  396. // label: '物品名称',
  397. // align: 'center',
  398. // showOverflowTooltip: true,
  399. // width: 150
  400. // },
  401. // {
  402. // prop: 'categoryLevelPath',
  403. // label: '物品类型',
  404. // align: 'center',
  405. // showOverflowTooltip: true,
  406. // width: 150
  407. // },
  408. // {
  409. // prop: 'specification',
  410. // label: '规格',
  411. // align: 'center',
  412. // showOverflowTooltip: true,
  413. // width: 150
  414. // },
  415. // {
  416. // width: 160,
  417. // prop: 'inStorageTime',
  418. // label: '出入库时间',
  419. // align: 'center',
  420. // showOverflowTooltip: true
  421. // },
  422. // {
  423. // prop: 'bizNo',
  424. // label: '单号',
  425. // align: 'center',
  426. // slot: 'bizNo',
  427. // showOverflowTooltip: true,
  428. // width: 150
  429. // },
  430. // {
  431. // prop: 'inBizType',
  432. // slot: 'inBizType',
  433. // label: '出入库类型',
  434. // align: 'center',
  435. // showOverflowTooltip: true,
  436. // width: 150,
  437. // formatter: (row) => {
  438. // return (
  439. // sceneState.find((item) => item.code == row.inBizType).label ??
  440. // ''
  441. // );
  442. // }
  443. // },
  444. // {
  445. // prop: 'supplierName',
  446. // label: '往来单位',
  447. // align: 'center',
  448. // showOverflowTooltip: true
  449. // },
  450. // {
  451. // prop: 'warehouseName',
  452. // label: '仓库名称',
  453. // align: 'center',
  454. // showOverflowTooltip: true
  455. // },
  456. // {
  457. // prop: 'remark',
  458. // label: '备注',
  459. // align: 'center',
  460. // showOverflowTooltip: true
  461. // },
  462. // {
  463. // prop: 'inQuantity',
  464. // label: '入库数量',
  465. // align: 'center',
  466. // showOverflowTooltip: true
  467. // },
  468. // {
  469. // prop: 'inUnitPrice',
  470. // label: '入库单价',
  471. // align: 'center',
  472. // showOverflowTooltip: true
  473. // },
  474. // {
  475. // prop: 'inPrice',
  476. // label: '入库成本小计',
  477. // align: 'center',
  478. // showOverflowTooltip: true
  479. // },
  480. // {
  481. // prop: 'outQuantity',
  482. // label: '出库数量',
  483. // align: 'center',
  484. // showOverflowTooltip: true
  485. // },
  486. // {
  487. // prop: 'outUnitPrice',
  488. // label: '出库单价',
  489. // align: 'center',
  490. // showOverflowTooltip: true
  491. // },
  492. // {
  493. // prop: 'outPrice',
  494. // label: '出库成本小计',
  495. // align: 'center',
  496. // showOverflowTooltip: true
  497. // },
  498. // {
  499. // prop: 'totalQuantity',
  500. // label: '结存数量',
  501. // align: 'center',
  502. // showOverflowTooltip: true
  503. // },
  504. // {
  505. // prop: 'totalUnitPrice',
  506. // label: '结存单位成本',
  507. // align: 'center',
  508. // showOverflowTooltip: true
  509. // },
  510. // {
  511. // prop: 'totalPrice',
  512. // label: '结存成本',
  513. // align: 'center',
  514. // showOverflowTooltip: true
  515. // }
  516. // ];
  517. // }
  518. },
  519. clientEnvironmentId() {
  520. return this.$store.state.user.info.clientEnvironmentId;
  521. },
  522. outInStateOption() {
  523. return this.formData.type == 2 ? this.outputSceneState : this.formData.type == 1 ? this.sceneState : []
  524. }
  525. },
  526. created() {
  527. this.getTypeList();
  528. this.getAssetTypeList()
  529. },
  530. methods: {
  531. // 获取物品类型下拉选择树
  532. async getAssetTypeList() {
  533. const { data } = await getTreeByGroup({ type: 2 });
  534. this.codeOption = data.map((item) => {
  535. return { dictCode: item.id, dictValue: item.name };
  536. });
  537. },
  538. handleOutInChange() {
  539. // this.formData.bizType = '';
  540. },
  541. async getTypeList() {
  542. const { data } = await allCategoryLevel();
  543. this.codeList = data.map((item) => {
  544. return { dictCode: item.id, dictValue: item.name };
  545. });
  546. },
  547. handleAssetType(r) {
  548. const code = this.codeList.find((item) => item.dictCode == r);
  549. return code?.dictValue;
  550. },
  551. handleBizType(code, type) {
  552. // console.log(this.sceneState);
  553. // console.log(code, type);
  554. if (type == 1) {
  555. // 入库
  556. for (const key in this.sceneState) {
  557. if (this.sceneState[key].code == code) {
  558. return this.sceneState[key].label;
  559. }
  560. }
  561. } else {
  562. // 出库
  563. for (const key in this.outputSceneState) {
  564. if (this.outputSceneState[key].code == code) {
  565. return this.outputSceneState[key].label;
  566. }
  567. }
  568. }
  569. },
  570. // 获取时间函数
  571. getDate(date) {
  572. console.log(date);
  573. let obj = {
  574. year: date.getFullYear(), //获取完整的年份(4位)
  575. month: date.getMonth() + 1, //获取当前月份(0-11,0代表1月)
  576. strDate: date.getDate() // 获取当前日(1-31)
  577. };
  578. Object.keys(obj).forEach((key) => {
  579. if (obj[key] < 10) obj[key] = `0${obj[key]}`;
  580. });
  581. return `${obj.year}-${obj.month}-${obj.strDate}`;
  582. },
  583. downLoad(type) {
  584. if (!this.formData.name) {
  585. return this.$message.error('请输入名称');
  586. }
  587. if (this.formData.time.length <= 0) {
  588. return this.$message.error('请选择时间');
  589. }
  590. this.loading = true;
  591. const params = Object.assign({}, this.formData);
  592. if (params.time?.length) {
  593. params.startTime = params.time[0];
  594. params.endTime = params.time[1];
  595. }
  596. delete params.time;
  597. const requestApi = type == 'statistics' ? sendReceiveExcel : sendReceiveDetailListExcel;
  598. requestApi(params).then((data) => {
  599. try {
  600. let objectUrl1 = window.URL.createObjectURL(new Blob([data]));
  601. let elink = document.createElement('a');
  602. elink.setAttribute(
  603. 'download',
  604. decodeURI(decodeURI('收发明细表.xlsx'))
  605. );
  606. elink.style.display = 'none';
  607. elink.href = objectUrl1;
  608. document.body.appendChild(elink);
  609. elink.click();
  610. document.body.removeChild(elink);
  611. window.URL.revokeObjectURL(elink.href);
  612. this.loading = false;
  613. this.visible = false;
  614. this.$emit('reload');
  615. } catch (err) {
  616. this.$message.error('导出失败,请联系管理员!');
  617. }
  618. });
  619. },
  620. async getList(row) {
  621. const res = await outintwoPage({
  622. type: 1,
  623. code: row.code,
  624. name: row.name,
  625. startTime: row.startTime,
  626. endTime: row.endTime,
  627. pageNum: 1,
  628. size: -1
  629. });
  630. this.tableList = res.data;
  631. console.log(this.tableList);
  632. },
  633. async open(isView, row) {
  634. console.log('open', row, this.$refs.formRef);
  635. if(this.$refs.formRef) {
  636. this.$refs.formRef.resetFields()
  637. }
  638. if (isView) {
  639. // await this.getList(row);
  640. // this.tableList = row.info.map((item) => {
  641. // return {
  642. // ...item,
  643. // startTime: this.getDate(new Date(Number(item.startTime)))
  644. // };
  645. // });
  646. // console.log(this.tableList);
  647. this.formData.code = row.code;
  648. this.formData.name = row.name;
  649. this.formData.status = 2;
  650. this.formData.time =
  651. row.startTime && row.endTime ? [row.startTime, row.endTime] : [];
  652. this.formData.keyWord = row.keyWord;
  653. this.formData.type = (row.isType == 0 || !row.isType) ? '' : row.isType;
  654. this.formData.bizType = (row.bizType == 0 || !row.bizType) ? '' : row.bizType;
  655. this.formData.categoryLevelId = (row.categoryLevelId == 0 || !row.categoryLevelId) ? '' : row.categoryLevelId;
  656. } else {
  657. this.tableList = [];
  658. this.formData = {
  659. code: await getCode('statistics_log_code'),
  660. name: '',
  661. status: 2,
  662. time: [],
  663. keyWord: '',
  664. type: '',
  665. bizType: '',
  666. categoryLevelId: ''
  667. };
  668. }
  669. this.isView = isView;
  670. this.visible = true;
  671. this.$nextTick(() => {
  672. this.$refs.table.reload();
  673. });
  674. },
  675. /* 表格数据源 */
  676. async datasource({ page, limit, where, order }) {
  677. // if (this.isView) {
  678. // return this.tableList;
  679. // } else {
  680. const params = Object.assign({}, this.formData);
  681. if (params.time?.length) {
  682. params.startTime = params.time[0];
  683. params.endTime = params.time[1];
  684. }
  685. delete params.time;
  686. const data = await storageApi.getInboundGoodsList({
  687. ...params,
  688. ...where,
  689. ...order,
  690. pageNum: page,
  691. size: limit
  692. });
  693. console.log(data);
  694. this.tableList = data;
  695. return data;
  696. // }
  697. },
  698. search() {
  699. this.$refs.table.reload();
  700. },
  701. reset() {
  702. this.formData.time = [];
  703. this.formData.keyWord = '';
  704. this.formData.type = '';
  705. this.formData.bizType = '';
  706. this.formData.categoryLevelId = '';
  707. this.$refs.formRef.resetFields()
  708. this.search();
  709. }
  710. }
  711. };
  712. </script>
  713. <style lang="scss" scoped>
  714. #inventoryBalance {
  715. height: 100%;
  716. width: 100%;
  717. padding: 10px;
  718. box-sizing: border-box;
  719. .ele-form-actions {
  720. display: flex;
  721. justify-content: flex-end;
  722. }
  723. }
  724. :deep(.table) {
  725. height: calc(100% - 100px);
  726. }
  727. </style>