finstlbillsitems.vue 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504
  1. <template>
  2. <div>
  3. <!--:row-style="{height:'20px',padding:'0px',fontSize:'12px'}"-->
  4. <avue-crud :option="option" :data="tableData" id="out-table" ref="crud"
  5. @selection-change="handleSelectionChange" :header-cell-style="tableHeaderCellStyle"
  6. :row-class-name="rowClassName" :cell-style="cellStyle"
  7. @resetColumn="resetColumn('crud', 'option', 'optionBack', 492)"
  8. @saveColumn="saveColumn('crud', 'option', 'optionBack', 492)">
  9. <template slot="menuLeft">
  10. <slot name="menuLeft"></slot>
  11. </template>
  12. <tempalte slot="currentStlAmountRMB" slot-scope="{ row }">
  13. <el-input-number v-if="brfalse" v-model="row.currentStlAmountRMB" @change="armbChange(row)"
  14. :controls="false" placeholder="请输入 本次对账CNY" size="mini" style="width: 100%;"
  15. :disabled="row.currentStlCurCode != getLocalCurrency()"></el-input-number>
  16. <span v-else>{{ row.currentStlAmountRMB }}</span>
  17. </tempalte>
  18. <tempalte slot="currentStlAmountUSD" slot-scope="{ row }">
  19. <el-input-number v-if="brfalse" v-model="row.currentStlAmountUSD" @change="ausdChange(row)"
  20. :controls="false" placeholder="请输入 本次对账USD" size="mini" style="width: 100%;"
  21. :disabled="row.currentStlCurCode == getLocalCurrency()"></el-input-number>
  22. <span v-else>{{ row.currentStlAmountUSD }}</span>
  23. </tempalte>
  24. <template slot="stlAmountDr" slot-scope="{ row }">
  25. <span v-if="row.dc == 'D'">{{ row.stlAmountDr }}</span>
  26. <span v-if="row.dc == 'C'">{{ row.stlAmountCr }}</span>
  27. </template>
  28. <template slot="stlAmountDrUSD" slot-scope="{ row }">
  29. <span v-if="row.dc == 'D'">{{ row.stlAmountDrUSD }}</span>
  30. <span v-if="row.dc == 'C'">{{ row.stlAmountCrUSD }}</span>
  31. </template>
  32. <template slot="remarkss" slot-scope="{ row }">
  33. <el-input style="width: 100%;" v-model="row.remarkss" v-if="brfalse" size="mini" autocomplete="off"
  34. clearable placeholder="请输入 备注">
  35. </el-input>
  36. <span v-else>{{ row.remarkss }}</span>
  37. </template>
  38. </avue-crud>
  39. </div>
  40. </template>
  41. <script>
  42. import { getWorkDicts } from "@/api/system/dictbiz";
  43. import SearchQuery from "@/components/iosbasic-data/searchquery.vue";
  44. import costDetails from "../assembly/costDetails.vue"
  45. import { getRateList } from "@/api/iosBasicData/rateManagement";
  46. import { feecenterSelectByAccNoList } from "@/api/iosBasicData/finstlbills";
  47. export default {
  48. components: { SearchQuery, costDetails },
  49. props: {
  50. tableData: {
  51. type: Array,
  52. default: [],
  53. },
  54. brfalse: {
  55. type: Boolean,
  56. default: true,
  57. },
  58. handleSelectionData: {
  59. type: Array,
  60. default: [],
  61. },
  62. form: {
  63. type: Object,
  64. default: {},
  65. },
  66. editSave: {
  67. type: Boolean,
  68. default: false
  69. }
  70. },
  71. data() {
  72. return {
  73. ifInvoiceData: [], // 是否数据
  74. invoicelosDara: [],// 发票
  75. curCodeData: [], // 币种
  76. option: {},
  77. optionBack: {
  78. maxHeight:'300px',
  79. calcHeight: 30,
  80. menuWidth: 60,
  81. // tip: false,
  82. menu: false,
  83. border: true,
  84. addBtn: false,
  85. viewBtn: false,
  86. editBtn: false,
  87. delBtn: false,
  88. refreshBtn: false,
  89. index: true,
  90. selection: true,
  91. align: 'center',
  92. column: [
  93. {
  94. label: "所属公司",
  95. prop: "branchName",
  96. width: 120,
  97. overHidden: true
  98. },
  99. {
  100. label: "收付",
  101. prop: "dc",
  102. width: 60,
  103. type: 'select',
  104. dicData: [{
  105. label: '收',
  106. value: 'D'
  107. }, {
  108. label: '付',
  109. value: 'C'
  110. }],
  111. overHidden: true,
  112. },
  113. {
  114. label: "费用名称",
  115. prop: "feeCnName",
  116. width: 80,
  117. overHidden: true
  118. },
  119. {
  120. label: "结算单位",
  121. prop: "corpCnName",
  122. width: 120,
  123. overHidden: true
  124. },
  125. {
  126. label: "HB/L NO",
  127. prop: "hblno",
  128. width: 100,
  129. overHidden: true
  130. },
  131. {
  132. label: "MB/L NO",
  133. prop: "mblno",
  134. width: 100,
  135. overHidden: true
  136. },
  137. {
  138. label: "本次对账本币",
  139. prop: "currentStlAmountRMB",
  140. width: 100,
  141. overHidden: true
  142. },
  143. {
  144. label: "本次对账外币",
  145. prop: "currentStlAmountUSD",
  146. width: 100,
  147. overHidden: true
  148. },
  149. {
  150. label: "币种",
  151. prop: "currentStlCurCode",
  152. width: 60,
  153. overHidden: true
  154. },
  155. {
  156. label: "汇率",
  157. prop: "currentStlExrate",
  158. width: 80,
  159. overHidden: true
  160. },
  161. {
  162. label: "ETD",
  163. prop: "etd",
  164. width: 100,
  165. overHidden: true
  166. },
  167. {
  168. label: "船名",
  169. prop: "vesselCnName",
  170. width: 80,
  171. overHidden: true
  172. },
  173. {
  174. label: "航次",
  175. prop: "voyageNo",
  176. width: 80,
  177. overHidden: true
  178. },
  179. {
  180. label: "箱量",
  181. prop: "quantityCntrTypesDescr",
  182. width: 80,
  183. overHidden: true
  184. },
  185. {
  186. label: "应对账本币",
  187. prop: "unsettledAmountRMB",
  188. width: 100,
  189. overHidden: true
  190. },
  191. {
  192. label: "应对账外币",
  193. prop: "unsettledAmountUSD",
  194. width: 100,
  195. overHidden: true
  196. },
  197. {
  198. label: "备注",
  199. prop: "remarkss",
  200. width: 120,
  201. overHidden: true
  202. }
  203. ]
  204. },
  205. }
  206. },
  207. async created() {
  208. this.option = await this.getColumnData(this.getColumnName(492), this.optionBack);
  209. this.isSignforWorkDicts()
  210. this.invoicelosWorkDictsfun()
  211. },
  212. methods: {
  213. armbChange(row) {
  214. if (Number(row.amount - row.reconciliationAmount) > 0) {
  215. if (Number(row.currentStlAmountRMB) < 0) {
  216. row.currentStlAmountRMB = 0
  217. return this.$message.error("本次对账金额不能输入负数");
  218. }
  219. if (Number(row.currentStlAmountRMB) > Number(row.amount - row.reconciliationAmount)) {
  220. row.currentStlAmountRMB = 0
  221. return this.$message.error("本次对账金额不能超过未对账金额");
  222. }
  223. }
  224. if (Number(row.amount - row.reconciliationAmount) < 0) {
  225. if (row.currentStlAmountRMB >= 0) {
  226. row.currentStlAmountRMB = Number(row.amount - row.reconciliationAmount)
  227. return this.$message.error("本次对账金额不能输入非负数");
  228. }
  229. if (Number(row.currentStlAmountRMB) < Number(row.amount - row.reconciliationAmount)) {
  230. row.currentStlAmountRMB = Number(row.amount - row.reconciliationAmount)
  231. return this.$message.error("本次对账金额不能超过未对账金额");
  232. }
  233. }
  234. },
  235. ausdChange(row) {
  236. if (Number(row.amount - row.reconciliationAmount) > 0) {
  237. if (Number(row.currentStlAmountUSD) < 0) {
  238. row.currentStlAmountUSD = 0
  239. return this.$message.error("本次对账金额不能输入负数");
  240. }
  241. if (Number(row.currentStlAmountUSD) > Number(row.amount - row.reconciliationAmount)) {
  242. row.currentStlAmountUSD = 0
  243. return this.$message.error("本次对账金额不能超过未对账金额");
  244. }
  245. }
  246. if (Number(row.amount - row.reconciliationAmount) < 0) {
  247. if (row.currentStlAmountUSD >= 0) {
  248. row.currentStlAmountUSD = Number(row.amount - row.reconciliationAmount)
  249. return this.$message.error("本次对账金额不能输入非负数");
  250. }
  251. if (Number(row.currentStlAmountUSD) < Number(row.amount - row.reconciliationAmount)) {
  252. row.currentStlAmountUSD = Number(row.amount - row.reconciliationAmount)
  253. return this.$message.error("本次对账金额不能超过未对账金额");
  254. }
  255. }
  256. },
  257. // 币别选择监听
  258. corpChange(value, row) {
  259. for (let item of this.curCodeData) {
  260. if (item.code == value) {
  261. this.$set(row, 'currentStlCurCode', value)
  262. if (value == this.getLocalCurrency()) {
  263. delete row.currentStlAmountUSD
  264. this.$set(row, 'currentStlAmountRMB', row.unsettledAmount)
  265. } else {
  266. delete row.currentStlAmountRMB
  267. this.$set(row, 'currentStlAmountUSD', row.unsettledAmount)
  268. }
  269. }
  270. }
  271. },
  272. // 展开行或者关闭
  273. expandChange(row, expandedRows) {
  274. let accBillId = ''
  275. if (this.form.id) {
  276. accBillId = row.accBillId
  277. } else {
  278. accBillId = row.id
  279. }
  280. feecenterSelectByAccNoList({ accBillId }).then(res => {
  281. row.costDate = res.data.data.map(item => {
  282. if (item.curCode == this.getLocalCurrency()) {
  283. this.$set(item, 'rmbAmount', item.amount)
  284. this.$set(item, 'usdAmount', '')
  285. this.$set(item, 'rmbAmountNet', item.amountNet)
  286. this.$set(item, 'usdAmountNet', '')
  287. } else {
  288. this.$set(item, 'usdAmount', item.amount)
  289. this.$set(item, 'rmbAmount', '')
  290. this.$set(item, 'usdAmountNet', item.amountNet)
  291. this.$set(item, 'rmbAmountNet', '')
  292. }
  293. return item
  294. })
  295. })
  296. },
  297. // 接口请求
  298. // 是否接口
  299. isSignforWorkDicts() {
  300. getWorkDicts('ifInvoice').then(res => {
  301. this.ifInvoiceData = res.data.data
  302. })
  303. },
  304. // 发票
  305. invoicelosWorkDictsfun() {
  306. getWorkDicts('reconciliation_invoice_los').then(res => {
  307. this.invoicelosDara = res.data.data
  308. })
  309. },
  310. // 获取币别数据
  311. async getRateListfun(cnName) {
  312. await this.checkRate(null, null, null, 2)
  313. this.curCodeData = this.getCheckRate()
  314. },
  315. // 表头样式
  316. tableHeaderCellStyle({ row, column, rowIndex, columnIndex }) {
  317. return "padding:4px 0px;fontSize:12px;color:#000;background:#ecf5ff"
  318. },
  319. // Element UI 表格点击选中行/取消选中 快捷多选 以及快捷连续多选,高亮选中行 ——-------------------------------------——
  320. // 多选选择的数据
  321. handleSelectionChange(arr) {
  322. // // 全选
  323. // if (arr.length == this.tableData.length) {
  324. // for (let item of arr) {
  325. // this.$set(item,'tableSelect',1)
  326. // }
  327. // }
  328. // // 清除全选
  329. // if (arr.length == 0) {
  330. // for (let item of this.tableData) {
  331. // this.$set(item,'tableSelect',0)
  332. // }
  333. // }
  334. this.$emit('handleSelectionChange', arr)
  335. },
  336. // // 多选
  337. // toggleSelection(rows){
  338. // if (rows) {
  339. // rows.forEach(row => {
  340. // this.$refs.tableRef.toggleRowSelection(row);
  341. // });
  342. // } else {
  343. // this.$refs.tableRef.clearSelection();
  344. // }
  345. // },
  346. // 监听点击表格事件
  347. rowClick(row, column, event) {
  348. let refsElTable = this.$refs.tableRef; // 获取表格对象
  349. if (this.CtrlDown) {
  350. refsElTable.toggleRowSelection(row); // ctrl多选 如果点击两次同样会取消选中
  351. return;
  352. }
  353. if (this.shiftOrAltDown && this.handleSelectionData.length > 0) {
  354. // 通过rowIndex判断已选择的行中最上面和最下面的是哪行,再对比按住shift/alt点击的当前行得到新的最上面和最下面的行,把这两行中间的行进行循环选中。
  355. let topAndBottom = this.getTopAndBottom(row, this.bottomSelectionRow, this.topSelectionRow);
  356. refsElTable.clearSelection(); //先清空 不然会导致在这两行中间之外的行状态不变
  357. for (let index = topAndBottom.top; index <= topAndBottom.bottom; index++) { //选中两行之间的所有行
  358. refsElTable.toggleRowSelection(this.tableData[index], true);
  359. }
  360. } else {
  361. let findRow = this.handleSelectionData.find(c => c.rowIndex == row.rowIndex); //找出当前选中行
  362. //如果只有一行且点击的也是这一行则取消选择 否则清空再选中当前点击行
  363. if (findRow && this.handleSelectionData.length === 1) {
  364. refsElTable.toggleRowSelection(row, false);
  365. return;
  366. }
  367. // refsElTable.clearSelection(); // 清空之前选择的数据(如果放开,选择之前会变成单选)
  368. refsElTable.toggleRowSelection(row); // 调用选中行方法
  369. }
  370. },
  371. // 行的 style 的回调方法
  372. rowStyle({ row, rowIndex }) {
  373. // 直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象
  374. // object: 要添加或者修改属性的目标对象;prop: 要定义或修改属性的名称;descript: 是一个对象,里面是我们上述的对象属性的特性;
  375. Object.defineProperty(row, 'rowIndex', { //给每一行添加不可枚举属性rowIndex来标识当前行
  376. value: rowIndex, // 设置age的值,不设置的话默认为undefined
  377. writable: true, // 表示属性的值true可以修改,false不可以被修改
  378. enumerable: false, // 设置为false表示不能通过 for-in 循环返回
  379. // configurable: false, // configurable 设置为 false,意味着这个属性不能从对象上删除
  380. })
  381. },
  382. keyDown(event) {
  383. let key = event.keyCode;
  384. if (key == 17) this.CtrlDown = true;
  385. if (key == 16 || key == 18) this.shiftOrAltDown = true;
  386. },
  387. keyUp(event) {
  388. let key = event.keyCode;
  389. if (key == 17) this.CtrlDown = false;
  390. if (key == 16 || key == 18) this.shiftOrAltDown = false;
  391. },
  392. // 文章说明 https://www.jianshu.com/p/48f2c522d2a2
  393. getTopAndBottom(row, bottom, top) {
  394. let n = row.rowIndex,
  395. mx = bottom.rowIndex,
  396. mi = top.rowIndex;
  397. if (n > mx) {
  398. return {
  399. top: mi,
  400. bottom: n
  401. };
  402. } else if (n < mx && n > mi) {
  403. return {
  404. top: mi,
  405. bottom: n
  406. };
  407. } else if (n < mi) {
  408. return {
  409. top: n,
  410. bottom: mx
  411. };
  412. } else if (n == mi || n == mx) {
  413. return {
  414. top: mi,
  415. bottom: mx
  416. };
  417. }
  418. },
  419. // 给选中行加上current-row这个class类,所以要使用row-class-name这个属性(其实给每一行添加rowIndex也可以用这个属性),
  420. // 判断方式也是通过判断rowIndex对比
  421. rowClassName({ row, rowIndex }) {
  422. let rowName = "",
  423. findRow = this.handleSelectionData.find(c => {
  424. return c.rowIndex === row.rowIndex
  425. });
  426. if (findRow) {
  427. rowName = "current-row "; // elementUI 默认高亮行的class类 不用再样式了^-^,也可通过css覆盖改变背景颜色
  428. }
  429. return rowName; //也可以再加上其他类名 如果有需求的话
  430. },
  431. // 收付展示不一样的颜色
  432. cellStyle({ row, rowIndex, columnIndex }) {
  433. let rowStyle = ''
  434. if (row.dc == 'D') {
  435. rowStyle = 'color:#8cb24b;'
  436. } else if (row.dc == 'C') {
  437. rowStyle = 'color:#F56C6C;'
  438. }
  439. return rowStyle + 'padding:0px;fontSize:12px'
  440. },
  441. //自定义列保存
  442. async saveColumn(ref, option, optionBack, code) {
  443. const inSave = await this.saveColumnData(this.getColumnName(code), this[option]);
  444. if (inSave) {
  445. this.$message.success("保存成功");
  446. //关闭窗口
  447. this.$refs[ref].$refs.dialogColumn.columnBox = false;
  448. }
  449. },
  450. //自定义列重置
  451. async resetColumn(ref, option, optionBack, code) {
  452. this[option] = this[optionBack];
  453. const inSave = await this.delColumnData(this.getColumnName(code), this[optionBack]);
  454. if (inSave) {
  455. this.$message.success("重置成功");
  456. this.$refs[ref].$refs.dialogColumn.columnBox = false;
  457. }
  458. },
  459. },
  460. mounted() {
  461. // 按住ctrl实现多选 设置监听keydown事件,以及keyup事件,
  462. addEventListener("keydown", this.keyDown, false);
  463. addEventListener("keyup", this.keyUp, false);
  464. },
  465. beforeDestroy() { //解绑
  466. removeEventListener("keydown", this.keyDown);
  467. removeEventListener("keyup", this.keyUp);
  468. },
  469. computed: { //实时得到最上行和最下行
  470. bottomSelectionRow() {
  471. if (this.handleSelectionData.length == 0) return null;
  472. return this.handleSelectionData.reduce((start, end) => {
  473. return start.rowIndex > end.rowIndex ? start : end;
  474. });
  475. },
  476. topSelectionRow() {
  477. if (this.handleSelectionData.length == 0) return null;
  478. return this.handleSelectionData.reduce((start, end) => {
  479. return start.rowIndex < end.rowIndex ? start : end;
  480. });
  481. }
  482. },
  483. }
  484. </script>
  485. <style scoped>
  486. .textHide {
  487. width: 100%;
  488. overflow: hidden;
  489. white-space: nowrap;
  490. text-overflow: ellipsis;
  491. }
  492. ::v-deep .current-row {
  493. background: #ecf3ff;
  494. }
  495. </style>