finstlbillsitems.vue 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698
  1. <template>
  2. <div>
  3. <avue-crud
  4. :option="option"
  5. :data="pageData2"
  6. id="out-table"
  7. ref="crud"
  8. @selection-change="handleSelectionChange"
  9. :header-cell-style="tableHeaderCellStyle"
  10. :row-class-name="rowClassName"
  11. :cell-style="cellStyle"
  12. :page.sync="page"
  13. @size-change="sizeChange"
  14. @current-change="currentChange"
  15. @resetColumn="resetColumn('crud', 'option', 'optionBack', 455)"
  16. @saveColumn="saveColumn('crud', 'option', 'optionBack', 455)"
  17. >
  18. <template slot="menuLeft">
  19. <slot name="menuLeft"></slot>
  20. </template>
  21. <tempalte slot="currentStlAmountRMB" slot-scope="{ row }">
  22. <el-input-number
  23. v-if="brfalse"
  24. v-model="row.currentStlAmountRMB"
  25. @change="armbChange(row)"
  26. :controls="false"
  27. placeholder="请输入 本次对账CNY"
  28. size="mini"
  29. style="width: 100%;"
  30. :disabled="row.currentStlCurCode != 'CNY'"
  31. ></el-input-number>
  32. <span v-else>{{ row.currentStlAmountRMB }}</span>
  33. </tempalte>
  34. <tempalte slot="currentStlAmountUSD" slot-scope="{ row }">
  35. <el-input-number
  36. v-if="brfalse"
  37. v-model="row.currentStlAmountUSD"
  38. @change="ausdChange(row)"
  39. :controls="false"
  40. placeholder="请输入 本次对账USD"
  41. size="mini"
  42. style="width: 100%;"
  43. :disabled="row.currentStlCurCode != 'USD'"
  44. ></el-input-number>
  45. <span v-else>{{ row.currentStlAmountUSD }}</span>
  46. </tempalte>
  47. <template slot="stlAmountDr" slot-scope="{ row }">
  48. <span v-if="row.dc == 'D'">{{ row.stlAmountDr }}</span>
  49. <span v-if="row.dc == 'C'">{{ row.stlAmountCr }}</span>
  50. </template>
  51. <template slot="stlAmountDrUSD" slot-scope="{ row }">
  52. <span v-if="row.dc == 'D'">{{ row.stlAmountDrUSD }}</span>
  53. <span v-if="row.dc == 'C'">{{ row.stlAmountCrUSD }}</span>
  54. </template>
  55. <template slot="remarkss" slot-scope="{ row }">
  56. <el-input style="width: 100%;" v-model="row.remarkss" v-if="brfalse" size="mini" autocomplete="off" clearable placeholder="请输入 备注">
  57. </el-input>
  58. <span v-else>{{ row.remarkss }}</span>
  59. </template>
  60. </avue-crud>
  61. </div>
  62. </template>
  63. <script>
  64. import { getWorkDicts } from "@/api/system/dictbiz";
  65. import SearchQuery from "@/components/iosbasic-data/searchquery.vue";
  66. import costDetails from "../assembly/costDetails.vue";
  67. import { getRateList } from "@/api/iosBasicData/rateManagement";
  68. import { feecenterSelectByAccNoList } from "@/api/iosBasicData/finstlbills";
  69. export default {
  70. components: { SearchQuery, costDetails },
  71. props: {
  72. queryData: {
  73. type: Array,
  74. default: []
  75. },
  76. brfalse: {
  77. type: Boolean,
  78. default: true
  79. },
  80. handleSelectionData: {
  81. type: Array,
  82. default: []
  83. },
  84. form: {
  85. type: Object,
  86. default: {}
  87. },
  88. editSave: {
  89. type: Boolean,
  90. default: false
  91. }
  92. },
  93. data() {
  94. return {
  95. ifInvoiceData: [], // 是否数据
  96. invoicelosDara: [], // 发票
  97. curCodeData: [], // 币种
  98. option: {},
  99. optionBack: {
  100. height: "auto",
  101. calcHeight: 30,
  102. menuWidth: 60,
  103. tip: false,
  104. menu: false,
  105. border: true,
  106. addBtn: false,
  107. viewBtn: false,
  108. editBtn: false,
  109. delBtn: false,
  110. refreshBtn: false,
  111. index: true,
  112. selection: true,
  113. align: "center",
  114. column: [
  115. {
  116. label: "原业务编号",
  117. prop: "billNo",
  118. width: 120,
  119. overHidden: true
  120. },
  121. {
  122. label: "发票号",
  123. prop: "invoiceNo",
  124. width: 80,
  125. overHidden: true
  126. },
  127. {
  128. label: "结算单位",
  129. prop: "corpCnName",
  130. width: 120,
  131. overHidden: true
  132. },
  133. {
  134. label: "MB/L NO",
  135. prop: "mblno",
  136. width: 100,
  137. overHidden: true
  138. },
  139. {
  140. label: "本次对账CNY",
  141. prop: "currentStlAmountRMB",
  142. width: 100,
  143. overHidden: true
  144. },
  145. {
  146. label: "本次对账USD",
  147. prop: "currentStlAmountUSD",
  148. width: 100,
  149. overHidden: true
  150. },
  151. {
  152. label: "币种",
  153. prop: "currentStlCurCode",
  154. width: 60,
  155. overHidden: true
  156. },
  157. {
  158. label: "汇率",
  159. prop: "currentStlExrate",
  160. width: 80,
  161. overHidden: true
  162. },
  163. {
  164. label: "对账",
  165. prop: "isChecked",
  166. width: 60,
  167. overHidden: true,
  168. type: "select",
  169. dicData: [
  170. {
  171. label: "否",
  172. value: 0
  173. },
  174. {
  175. label: "是",
  176. value: 1
  177. }
  178. ]
  179. },
  180. {
  181. label: "签收",
  182. prop: "isSignfor",
  183. width: 60,
  184. overHidden: true,
  185. type: "select",
  186. dicData: [
  187. {
  188. label: "否",
  189. value: 0
  190. },
  191. {
  192. label: "是",
  193. value: 1
  194. }
  195. ]
  196. },
  197. {
  198. label: "发票状态",
  199. prop: "isInvoice",
  200. width: 80,
  201. type: "select",
  202. dicData: [
  203. {
  204. label: "待开发票",
  205. value: 1
  206. },
  207. {
  208. label: "确认开票",
  209. value: 2
  210. },
  211. {
  212. label: "不开发票",
  213. value: 3
  214. }
  215. ],
  216. overHidden: true
  217. },
  218. {
  219. label: "ETD",
  220. prop: "etd",
  221. width: 100,
  222. overHidden: true
  223. },
  224. {
  225. label: "账单编号",
  226. prop: "accBillNo",
  227. width: 100,
  228. overHidden: true
  229. },
  230. {
  231. label: "签收人",
  232. prop: "signforName",
  233. width: 80,
  234. overHidden: true
  235. },
  236. {
  237. label: "签收日期",
  238. prop: "signforDate",
  239. width: 100,
  240. overHidden: true
  241. },
  242. {
  243. label: "操作人",
  244. prop: "operatorName",
  245. width: 80,
  246. overHidden: true
  247. },
  248. {
  249. label: "BOOKINGNO",
  250. prop: "bookingNo",
  251. width: 100,
  252. overHidden: true
  253. },
  254. {
  255. label: "HB/L NO",
  256. prop: "hblno",
  257. width: 100,
  258. overHidden: true
  259. },
  260. {
  261. label: "船名",
  262. prop: "vesselCnName",
  263. width: 80,
  264. overHidden: true
  265. },
  266. {
  267. label: "航次",
  268. prop: "voyageNo",
  269. width: 80,
  270. overHidden: true
  271. },
  272. {
  273. label: "发票CNY",
  274. prop: "currentInvoiceAmountRMB",
  275. width: 80,
  276. overHidden: true
  277. },
  278. {
  279. label: "发票USD",
  280. prop: "currentInvoiceAmountUSD",
  281. width: 80,
  282. overHidden: true
  283. },
  284. {
  285. label: "箱量",
  286. prop: "quantityCntrTypesDescr",
  287. width: 80,
  288. overHidden: true
  289. },
  290. {
  291. label: "收付",
  292. prop: "dc",
  293. width: 60,
  294. type: "select",
  295. dicData: [
  296. {
  297. label: "收",
  298. value: "D"
  299. },
  300. {
  301. label: "付",
  302. value: "C"
  303. }
  304. ],
  305. overHidden: true
  306. },
  307. {
  308. label: "应对账CNY",
  309. prop: "unsettledAmountRMB",
  310. width: 100,
  311. overHidden: true
  312. },
  313. {
  314. label: "应对账USD",
  315. prop: "unsettledAmountUSD",
  316. width: 100,
  317. overHidden: true
  318. },
  319. {
  320. label: "已对账CNY",
  321. prop: "reconciliationAmount",
  322. width: 100,
  323. overHidden: true
  324. },
  325. {
  326. label: "已对账USD",
  327. prop: "reconciliationAmountUsd",
  328. width: 100,
  329. overHidden: true
  330. },
  331. {
  332. label: "已结算CNY",
  333. prop: "stlAmountDr",
  334. width: 90,
  335. overHidden: true
  336. },
  337. {
  338. label: "已结算USD",
  339. prop: "stlAmountDrUSD",
  340. width: 90,
  341. overHidden: true
  342. },
  343. // {
  344. // label: "费用名称",
  345. // prop: "feeCnName",
  346. // width: 80,
  347. // overHidden: true
  348. // },
  349. {
  350. label: "业务员",
  351. prop: "srcCnName",
  352. width: 80,
  353. overHidden: true
  354. },
  355. {
  356. label: "备注",
  357. prop: "remarkss",
  358. width: 120,
  359. overHidden: true
  360. }
  361. ]
  362. },
  363. page: {
  364. currentPage: 1,
  365. total: 0,
  366. pageSize: 20,
  367. pageSizes: [20, 50, 100, 200, 500]
  368. },
  369. pageData2: []
  370. };
  371. },
  372. async created() {
  373. this.option = await this.getColumnData(this.getColumnName(455), this.optionBack);
  374. this.isSignforWorkDicts();
  375. this.invoicelosWorkDictsfun();
  376. },
  377. methods: {
  378. sizeChange(val) {
  379. this.page.currentPage = 1;
  380. this.page.pageSize = val;
  381. this.getList2();
  382. },
  383. currentChange(val) {
  384. this.page.currentPage = val;
  385. this.getList2();
  386. },
  387. getList2() {
  388. this.page.total = this.queryData.length;
  389. const start = (this.page.currentPage - 1) * this.page.pageSize;
  390. const end = start + this.page.pageSize;
  391. this.pageData2 = this.queryData.slice(start, end);
  392. },
  393. armbChange(row) {
  394. if (Number(row.amount - row.reconciliationAmount) > 0) {
  395. if (Number(row.currentStlAmountRMB) < 0) {
  396. row.currentStlAmountRMB = 0;
  397. return this.$message.error("本次对账金额不能输入负数");
  398. }
  399. if (Number(row.currentStlAmountRMB) > Number(row.amount - row.reconciliationAmount)) {
  400. row.currentStlAmountRMB = 0;
  401. return this.$message.error("本次对账金额不能超过未对账金额");
  402. }
  403. }
  404. if (Number(row.amount - row.reconciliationAmount) < 0) {
  405. if (row.currentStlAmountRMB >= 0) {
  406. row.currentStlAmountRMB = Number(row.amount - row.reconciliationAmount);
  407. return this.$message.error("本次对账金额不能输入非负数");
  408. }
  409. if (Number(row.currentStlAmountRMB) < Number(row.amount - row.reconciliationAmount)) {
  410. row.currentStlAmountRMB = Number(row.amount - row.reconciliationAmount);
  411. return this.$message.error("本次对账金额不能超过未对账金额");
  412. }
  413. }
  414. },
  415. ausdChange(row) {
  416. if (Number(row.amount - row.reconciliationAmount) > 0) {
  417. if (Number(row.currentStlAmountUSD) < 0) {
  418. row.currentStlAmountUSD = 0;
  419. return this.$message.error("本次对账金额不能输入负数");
  420. }
  421. if (Number(row.currentStlAmountUSD) > Number(row.amount - row.reconciliationAmount)) {
  422. row.currentStlAmountUSD = 0;
  423. return this.$message.error("本次对账金额不能超过未对账金额");
  424. }
  425. }
  426. if (Number(row.amount - row.reconciliationAmount) < 0) {
  427. if (row.currentStlAmountUSD >= 0) {
  428. row.currentStlAmountUSD = Number(row.amount - row.reconciliationAmount);
  429. return this.$message.error("本次对账金额不能输入非负数");
  430. }
  431. if (Number(row.currentStlAmountUSD) < Number(row.amount - row.reconciliationAmount)) {
  432. row.currentStlAmountUSD = Number(row.amount - row.reconciliationAmount);
  433. return this.$message.error("本次对账金额不能超过未对账金额");
  434. }
  435. }
  436. },
  437. // 币别选择监听
  438. corpChange(value, row) {
  439. for (let item of this.curCodeData) {
  440. if (item.code == value) {
  441. this.$set(row, "currentStlCurCode", value);
  442. if (value == "CNY") {
  443. delete row.currentStlAmountUSD;
  444. this.$set(row, "currentStlAmountRMB", row.unsettledAmount);
  445. } else {
  446. delete row.currentStlAmountRMB;
  447. this.$set(row, "currentStlAmountUSD", row.unsettledAmount);
  448. }
  449. }
  450. }
  451. },
  452. // 展开行或者关闭
  453. expandChange(row, expandedRows) {
  454. let accBillId = "";
  455. if (this.form.id) {
  456. accBillId = row.accBillId;
  457. } else {
  458. accBillId = row.id;
  459. }
  460. feecenterSelectByAccNoList({ accBillId }).then(res => {
  461. row.costDate = res.data.data.map(item => {
  462. if (item.curCode == "CNY") {
  463. this.$set(item, "rmbAmount", item.amount);
  464. this.$set(item, "usdAmount", "");
  465. this.$set(item, "rmbAmountNet", item.amountNet);
  466. this.$set(item, "usdAmountNet", "");
  467. } else {
  468. this.$set(item, "usdAmount", item.amount);
  469. this.$set(item, "rmbAmount", "");
  470. this.$set(item, "usdAmountNet", item.amountNet);
  471. this.$set(item, "rmbAmountNet", "");
  472. }
  473. return item;
  474. });
  475. });
  476. },
  477. // 接口请求
  478. // 是否接口
  479. isSignforWorkDicts() {
  480. getWorkDicts("ifInvoice").then(res => {
  481. this.ifInvoiceData = res.data.data;
  482. });
  483. },
  484. // 发票
  485. invoicelosWorkDictsfun() {
  486. getWorkDicts("reconciliation_invoice_los").then(res => {
  487. this.invoicelosDara = res.data.data;
  488. });
  489. },
  490. // 获取币别数据
  491. getRateListfun(cnName) {
  492. getRateList({ current: 1, size: 10, cnName }).then(res => {
  493. this.curCodeData = res.data.data.records;
  494. });
  495. },
  496. // 表头样式
  497. tableHeaderCellStyle({ row, column, rowIndex, columnIndex }) {
  498. return "padding:4px 0px;fontSize:12px;color:#000;background:#ecf5ff";
  499. },
  500. // Element UI 表格点击选中行/取消选中 快捷多选 以及快捷连续多选,高亮选中行 ——-------------------------------------——
  501. // 多选选择的数据
  502. handleSelectionChange(arr) {
  503. // // 全选
  504. // if (arr.length == this.queryData.length) {
  505. // for (let item of arr) {
  506. // this.$set(item,'tableSelect',1)
  507. // }
  508. // }
  509. // // 清除全选
  510. // if (arr.length == 0) {
  511. // for (let item of this.queryData) {
  512. // this.$set(item,'tableSelect',0)
  513. // }
  514. // }
  515. this.$emit("handleSelectionChange", arr);
  516. },
  517. // // 多选
  518. // toggleSelection(rows){
  519. // if (rows) {
  520. // rows.forEach(row => {
  521. // this.$refs.tableRef.toggleRowSelection(row);
  522. // });
  523. // } else {
  524. // this.$refs.tableRef.clearSelection();
  525. // }
  526. // },
  527. // 监听点击表格事件
  528. rowClick(row, column, event) {
  529. let refsElTable = this.$refs.tableRef; // 获取表格对象
  530. if (this.CtrlDown) {
  531. refsElTable.toggleRowSelection(row); // ctrl多选 如果点击两次同样会取消选中
  532. return;
  533. }
  534. if (this.shiftOrAltDown && this.handleSelectionData.length > 0) {
  535. // 通过rowIndex判断已选择的行中最上面和最下面的是哪行,再对比按住shift/alt点击的当前行得到新的最上面和最下面的行,把这两行中间的行进行循环选中。
  536. let topAndBottom = this.getTopAndBottom(row, this.bottomSelectionRow, this.topSelectionRow);
  537. refsElTable.clearSelection(); //先清空 不然会导致在这两行中间之外的行状态不变
  538. for (let index = topAndBottom.top; index <= topAndBottom.bottom; index++) {
  539. //选中两行之间的所有行
  540. refsElTable.toggleRowSelection(this.queryData[index], true);
  541. }
  542. } else {
  543. let findRow = this.handleSelectionData.find(c => c.rowIndex == row.rowIndex); //找出当前选中行
  544. //如果只有一行且点击的也是这一行则取消选择 否则清空再选中当前点击行
  545. if (findRow && this.handleSelectionData.length === 1) {
  546. refsElTable.toggleRowSelection(row, false);
  547. return;
  548. }
  549. // refsElTable.clearSelection(); // 清空之前选择的数据(如果放开,选择之前会变成单选)
  550. refsElTable.toggleRowSelection(row); // 调用选中行方法
  551. }
  552. },
  553. // 行的 style 的回调方法
  554. rowStyle({ row, rowIndex }) {
  555. // 直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象
  556. // object: 要添加或者修改属性的目标对象;prop: 要定义或修改属性的名称;descript: 是一个对象,里面是我们上述的对象属性的特性;
  557. Object.defineProperty(row, "rowIndex", {
  558. //给每一行添加不可枚举属性rowIndex来标识当前行
  559. value: rowIndex, // 设置age的值,不设置的话默认为undefined
  560. writable: true, // 表示属性的值true可以修改,false不可以被修改
  561. enumerable: false // 设置为false表示不能通过 for-in 循环返回
  562. // configurable: false, // configurable 设置为 false,意味着这个属性不能从对象上删除
  563. });
  564. },
  565. keyDown(event) {
  566. let key = event.keyCode;
  567. if (key == 17) this.CtrlDown = true;
  568. if (key == 16 || key == 18) this.shiftOrAltDown = true;
  569. },
  570. keyUp(event) {
  571. let key = event.keyCode;
  572. if (key == 17) this.CtrlDown = false;
  573. if (key == 16 || key == 18) this.shiftOrAltDown = false;
  574. },
  575. // 文章说明 https://www.jianshu.com/p/48f2c522d2a2
  576. getTopAndBottom(row, bottom, top) {
  577. let n = row.rowIndex,
  578. mx = bottom.rowIndex,
  579. mi = top.rowIndex;
  580. if (n > mx) {
  581. return {
  582. top: mi,
  583. bottom: n
  584. };
  585. } else if (n < mx && n > mi) {
  586. return {
  587. top: mi,
  588. bottom: n
  589. };
  590. } else if (n < mi) {
  591. return {
  592. top: n,
  593. bottom: mx
  594. };
  595. } else if (n == mi || n == mx) {
  596. return {
  597. top: mi,
  598. bottom: mx
  599. };
  600. }
  601. },
  602. // 给选中行加上current-row这个class类,所以要使用row-class-name这个属性(其实给每一行添加rowIndex也可以用这个属性),
  603. // 判断方式也是通过判断rowIndex对比
  604. rowClassName({ row, rowIndex }) {
  605. let rowName = "",
  606. findRow = this.handleSelectionData.find(c => {
  607. return c.rowIndex === row.rowIndex;
  608. });
  609. if (findRow) {
  610. rowName = "current-row "; // elementUI 默认高亮行的class类 不用再样式了^-^,也可通过css覆盖改变背景颜色
  611. }
  612. return rowName; //也可以再加上其他类名 如果有需求的话
  613. },
  614. // 收付展示不一样的颜色
  615. cellStyle({ row, rowIndex, columnIndex }) {
  616. let rowStyle = "";
  617. if (row.dc == "D") {
  618. rowStyle = "color:#8cb24b;";
  619. } else if (row.dc == "C") {
  620. rowStyle = "color:#F56C6C;";
  621. }
  622. return rowStyle + "padding:0px;fontSize:12px";
  623. },
  624. //自定义列保存
  625. async saveColumn(ref, option, optionBack, code) {
  626. const inSave = await this.saveColumnData(this.getColumnName(code), this[option]);
  627. if (inSave) {
  628. this.$message.success("保存成功");
  629. //关闭窗口
  630. this.$refs[ref].$refs.dialogColumn.columnBox = false;
  631. }
  632. },
  633. //自定义列重置
  634. async resetColumn(ref, option, optionBack, code) {
  635. this[option] = this[optionBack];
  636. const inSave = await this.delColumnData(this.getColumnName(code), this[optionBack]);
  637. if (inSave) {
  638. this.$message.success("重置成功");
  639. this.$refs[ref].$refs.dialogColumn.columnBox = false;
  640. }
  641. }
  642. },
  643. mounted() {
  644. // 按住ctrl实现多选 设置监听keydown事件,以及keyup事件,
  645. addEventListener("keydown", this.keyDown, false);
  646. addEventListener("keyup", this.keyUp, false);
  647. },
  648. beforeDestroy() {
  649. //解绑
  650. removeEventListener("keydown", this.keyDown);
  651. removeEventListener("keyup", this.keyUp);
  652. },
  653. watch: {
  654. queryData: {
  655. // 执行方法
  656. handler(oldValue, newValue) {
  657. this.page.currentPage = 1;
  658. this.pageData2 = [];
  659. this.getList2();
  660. },
  661. deep: true, // 深度监听
  662. immediate: true // 第一次改变就执行
  663. }
  664. },
  665. computed: {
  666. //实时得到最上行和最下行
  667. bottomSelectionRow() {
  668. if (this.handleSelectionData.length == 0) return null;
  669. return this.handleSelectionData.reduce((start, end) => {
  670. return start.rowIndex > end.rowIndex ? start : end;
  671. });
  672. },
  673. topSelectionRow() {
  674. if (this.handleSelectionData.length == 0) return null;
  675. return this.handleSelectionData.reduce((start, end) => {
  676. return start.rowIndex < end.rowIndex ? start : end;
  677. });
  678. }
  679. }
  680. };
  681. </script>
  682. <style scoped>
  683. .textHide {
  684. width: 100%;
  685. overflow: hidden;
  686. white-space: nowrap;
  687. text-overflow: ellipsis;
  688. }
  689. ::v-deep .current-row {
  690. background: #ecf3ff;
  691. }
  692. </style>