Index.vue 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775
  1. <template>
  2. <el-form ref="form" :model="form" :rules="rules">
  3. <ele-pro-table
  4. ref="table"
  5. :needPage="false"
  6. :columns="columns"
  7. :datasource="form.datasource"
  8. :toolkit="[]"
  9. class="time-form"
  10. >
  11. <!-- 表头工具栏 -->
  12. <template v-slot:toolbar>
  13. <div class="headbox">
  14. <div>
  15. <el-button
  16. size="small"
  17. type="primary"
  18. icon="el-icon-plus"
  19. class="ele-btn-icon"
  20. @click="handlAdd"
  21. v-if="showAddBtn"
  22. >
  23. 新增
  24. </el-button>
  25. </div>
  26. <div class="pricebox">
  27. <span class="amount">比例合计:{{ allRatio }}%</span>
  28. <span class="amount">计划{{ menu === 'purchase' ? '付款' : '收款' }}金额合计:{{ allPrice }}元</span>
  29. <!-- <el-form-item
  30. style="width: 300px"
  31. label="优惠后总金额:"
  32. prop="discountTotalPrice"
  33. :rules="{
  34. required: true,
  35. message: '请输入优惠后总金额',
  36. trigger: 'change'
  37. }"
  38. >
  39. <el-input
  40. type="number"
  41. :min="0"
  42. :max="allPrice"
  43. :disabled="!allPrice"
  44. v-model="form.discountTotalPrice"
  45. style="width: 180px"
  46. placeholder="请输入"
  47. @input="discountInputByOrder(form.discountTotalPrice)"
  48. >
  49. <template slot="append">元</template>
  50. </el-input>
  51. </el-form-item> -->
  52. </div>
  53. </div>
  54. </template>
  55. <template v-slot:headerIssueNumber="{ column }">
  56. <span class="is-required">{{ column.label }}</span>
  57. </template>
  58. <template v-slot:headerType="{ column }">
  59. <span class="is-required">{{ column.label }}</span>
  60. </template>
  61. <template v-slot:issueNumber="scope">
  62. <span>第{{ scope.row.issueNumber }}期</span>
  63. </template>
  64. <template v-slot:moneyName="scope">
  65. <el-form-item
  66. style="margin-bottom: 20px"
  67. :prop="'datasource.' + scope.$index + '.moneyName'"
  68. :rules="{
  69. required: false,
  70. message: '请输入',
  71. trigger: 'blur'
  72. }"
  73. >
  74. <el-input
  75. v-model="scope.row.moneyName"
  76. placeholder="请输入"
  77. :disabled="type=='view'"
  78. ></el-input>
  79. </el-form-item>
  80. </template>
  81. <template v-slot:headerMoneyName="{ column }">
  82. <span class="is-required">{{ column.label }}</span>
  83. </template>
  84. <template v-slot:ratio="scope">
  85. <el-form-item
  86. style="margin-bottom: 20px"
  87. :prop="'datasource.' + scope.$index + '.ratio'"
  88. :rules="{
  89. required: true,
  90. pattern: numberReg,
  91. message: '请输入正确的比例',
  92. trigger: 'change'
  93. }"
  94. >
  95. <el-input
  96. v-model="scope.row.ratio"
  97. placeholder="请输入"
  98. :disabled="type=='view'"
  99. @input="(val) => ratioInput(val, scope.$index)"
  100. >
  101. <template slot="append">%</template>
  102. </el-input>
  103. </el-form-item>
  104. </template>
  105. <template v-slot:type="scope">
  106. <el-form-item
  107. style="margin-bottom: 20px"
  108. :prop="'datasource.' + scope.$index + '.type'"
  109. :rules="{
  110. required: true,
  111. message: '请选择款项类型',
  112. trigger: 'change'
  113. }"
  114. >
  115. <el-select
  116. v-model="scope.row.type"
  117. placeholder="请选择"
  118. style="width: 100%"
  119. :disabled="type=='view'"
  120. @change="(val) => typeChange(val, scope.$index)"
  121. >
  122. <el-option
  123. v-for="item in paymentTypeOp"
  124. :key="item.value"
  125. :label="item.label"
  126. :value="item.value"
  127. >
  128. </el-option>
  129. </el-select>
  130. </el-form-item>
  131. </template>
  132. <template v-slot:headerRatio="{ column }">
  133. <span class="is-required">{{ column.label }}</span>
  134. </template>
  135. <template v-slot:headerPrice="{ column }">
  136. <span class="is-required">{{ column.label }}</span>
  137. </template>
  138. <template v-slot:price="scope">
  139. <el-form-item
  140. style="margin-bottom: 20px"
  141. :prop="'datasource.' + scope.$index + '.price'"
  142. :rules="{
  143. required: true,
  144. pattern: numberReg,
  145. message: '请输入正确的金额',
  146. trigger: 'change'
  147. }"
  148. >
  149. <el-input
  150. type="number"
  151. :min="0"
  152. disabled
  153. v-model="scope.row.price"
  154. style="width: 100%"
  155. placeholder="请输入"
  156. >
  157. <template slot="append">元</template>
  158. </el-input>
  159. </el-form-item>
  160. </template>
  161. <template v-slot:deadLine="scope">
  162. <el-form-item
  163. style="margin-bottom: 20px"
  164. :prop="'datasource.' + scope.$index + '.deadLine'"
  165. :rules="{
  166. required: false,
  167. message: '请选择日期',
  168. trigger: 'change'
  169. }"
  170. >
  171. <el-date-picker
  172. style="width: 140px"
  173. v-model="scope.row.deadLine"
  174. :disabled="!showAddBtn"
  175. type="date"
  176. placeholder="选择日期"
  177. >
  178. </el-date-picker>
  179. </el-form-item>
  180. </template>
  181. <template v-slot:headerDeadLine="{ column }">
  182. <span class="is-required">{{ column.label }}</span>
  183. </template>
  184. <template v-slot:remark="scope">
  185. <el-form-item
  186. style="margin-bottom: 20px"
  187. :prop="'datasource.' + scope.$index + '.remark'"
  188. >
  189. <el-input
  190. v-model="scope.row.remark"
  191. type="textarea"
  192. placeholder="请输入"
  193. :disabled="type=='view'"
  194. ></el-input>
  195. </el-form-item>
  196. </template>
  197. <!-- 操作列 -->
  198. <template v-slot:action="{ row }">
  199. <el-popconfirm
  200. class="ele-action"
  201. title="确定要删除吗?"
  202. @confirm="remove(row)"
  203. >
  204. <template v-slot:reference>
  205. <el-link type="danger" :underline="false" icon="el-icon-delete">
  206. 删除
  207. </el-link>
  208. </template>
  209. </el-popconfirm>
  210. </template>
  211. </ele-pro-table>
  212. </el-form>
  213. </template>
  214. <script>
  215. import { emailReg, phoneReg, numberReg } from 'ele-admin';
  216. import { paymentTypeOp } from '@/enum/dict';
  217. import { formatPrice } from '@/BIZComponents/setProduct.js';
  218. export default {
  219. props: {
  220. delDetailIds: Array,
  221. type: String,
  222. menu: {
  223. type: String,
  224. default: 'sale'
  225. },
  226. discountTotalPrice: {
  227. type: [Number, String],
  228. default: 0
  229. },
  230. info: {
  231. type: Object,
  232. default: () => {}
  233. }
  234. },
  235. data() {
  236. const defaultForm = {
  237. key: null,
  238. deadLine: null,
  239. moneyName: '',
  240. price: null,
  241. ratio: null,
  242. remark: '',
  243. type: '',
  244. typeName: '',
  245. issueNumber: null
  246. };
  247. return {
  248. // allPrice: 0,
  249. // allRatio: 0,
  250. numberReg,
  251. defaultForm,
  252. discountAmount: 0,
  253. form: {
  254. datasource: []
  255. },
  256. paymentTypeOp,
  257. rules: {},
  258. isLoadingFromApi: false
  259. };
  260. },
  261. computed: {
  262. canHandl() {
  263. return this.form.datasource.length;
  264. },
  265. showAddBtn() {
  266. // console.log('showAddBtn~~~~', this.type, this.info);
  267. // console.log('showAddBtn!!!!',!['1', '2'].includes(this.info.settlementMode) || this.type != 'view');
  268. return !(['1', '2'].includes(this.info?.settlementMode)) && this.type != 'view'
  269. },
  270. columns() {
  271. return [
  272. {
  273. width: 45,
  274. type: 'index',
  275. columnKey: 'index',
  276. align: 'center',
  277. fixed: 'left'
  278. },
  279. {
  280. width: 180,
  281. prop: 'issueNumber',
  282. label: '期数',
  283. slot: 'issueNumber',
  284. headerSlot: 'headerIssueNumber',
  285. align: 'center'
  286. },
  287. {
  288. width: 150,
  289. prop: 'type',
  290. label: '款项类型',
  291. slot: 'type',
  292. headerSlot: 'headerType',
  293. align: 'center'
  294. },
  295. {
  296. prop: 'moneyName',
  297. label: '款项名称',
  298. slot: 'moneyName',
  299. // headerSlot: 'headerMoneyName',
  300. align: 'center',
  301. // width: 170
  302. },
  303. {
  304. width: 150,
  305. prop: 'ratio',
  306. label: '比例',
  307. slot: 'ratio',
  308. headerSlot: 'headerRatio',
  309. align: 'center'
  310. },
  311. {
  312. width: 170,
  313. prop: 'price',
  314. label: this.menu === 'purchase' ? '计划付款金额' : '计划收款金额',
  315. slot: 'price',
  316. align: 'center',
  317. headerSlot: 'headerPrice',
  318. },
  319. {
  320. width: 160,
  321. prop: 'deadLine',
  322. label: this.menu === 'purchase' ? '计划付款日期' : '计划收款日期',
  323. slot: 'deadLine',
  324. // headerSlot: 'headerDeadLine',
  325. align: 'center'
  326. },
  327. {
  328. // width: 220,
  329. prop: 'remark',
  330. label: '说明',
  331. slot: 'remark',
  332. align: 'center'
  333. },
  334. {
  335. columnKey: 'action',
  336. label: '操作',
  337. align: 'center',
  338. resizable: false,
  339. slot: 'action',
  340. showOverflowTooltip: true,
  341. show: this.showAddBtn
  342. }
  343. ];
  344. },
  345. allRatio() {
  346. return formatPrice(this.form.datasource.reduce((acc, cur) => acc + Number(cur.ratio), 0));
  347. },
  348. allPrice() {
  349. // 使用分进行计算,避免浮点数精度问题
  350. return formatPrice(this.form.datasource.reduce((acc, cur) => acc + Math.round(Number(cur.price) * 100), 0) / 100);
  351. },
  352. },
  353. watch: {
  354. discountAmount(newval) {
  355. if (newval && !this.isLoadingFromApi) {
  356. this.refreshprice();
  357. }
  358. },
  359. info: {
  360. handler(newval) {
  361. // if (newval && newval.receiptPaymentList) {
  362. // this.isLoadingFromApi = true;
  363. // this.form.datasource = newval.receiptPaymentList;
  364. // if (newval.payAmount) {
  365. // this.discountAmount = newval.payAmount;
  366. // }
  367. // setTimeout(() => {
  368. // this.isLoadingFromApi = false;
  369. // }, 100);
  370. // }
  371. },
  372. deep: true
  373. }
  374. },
  375. methods: {
  376. setDiscountAmount(val) {
  377. console.log(val, '000000');
  378. this.discountAmount = val;
  379. // 立即更新价格,无需设置isLoadingFromApi为true
  380. this.refreshprice();
  381. },
  382. typeChange(val, index = null) {
  383. // console.log(val, index, '55555');
  384. if (val) {
  385. this.$set(this.form.datasource[index], 'typeName', this.paymentTypeOp.find(item => item.value === val).label);
  386. }
  387. },
  388. //输入比例更新金额
  389. async ratioInput(val, index = null) {
  390. // console.log(this.discountAmount, '77777');
  391. // console.log(val, '5555555');
  392. val = Number(val);
  393. try {
  394. if (index != null) {
  395. await this.checkRatio();
  396. }
  397. let newval = (val / 100).toFixed(2);
  398. // console.log('newval~~~', newval)
  399. let price = formatPrice(this.discountAmount * newval);
  400. // console.log(newval, price, index, '88888');
  401. if (index != null) {
  402. // console.log(newval, price, index, '999999');
  403. this.$set(this.form.datasource[index], 'price', price);
  404. } else {
  405. return price;
  406. }
  407. } catch (error) {
  408. return 0;
  409. }
  410. //this.$set( this.form.datasource[index], 'price', price)
  411. },
  412. //检验比例
  413. checkRatio() {
  414. return new Promise((resolve, reject) => {
  415. let newData = this.form.datasource,
  416. sum = 0;
  417. newData.forEach((r) => {
  418. if (r.ratio) {
  419. sum += Number(r.ratio);
  420. }
  421. });
  422. // console.log(sum, '3333333');
  423. if (sum > 100) {
  424. this.$message.error('总共比例不能超过100');
  425. this.$set(
  426. this.form.datasource[this.form.datasource.length - 1],
  427. 'ratio',
  428. null
  429. );
  430. this.$set(
  431. this.form.datasource[this.form.datasource.length - 1],
  432. 'price',
  433. 0.0
  434. );
  435. reject(false);
  436. } else {
  437. resolve(true);
  438. }
  439. });
  440. },
  441. refreshprice() {
  442. // 如果正在从API加载数据,则不执行刷新操作
  443. if (this.isLoadingFromApi) {
  444. return;
  445. }
  446. // 创建一个新的数组,避免直接修改原数组
  447. let newData = JSON.parse(JSON.stringify(this.form.datasource));
  448. console.log('newData after copy:', newData);
  449. // 先根据比例计算所有价格
  450. for (let i = 0; i < newData.length; i++) {
  451. const r = newData[i];
  452. if (r.ratio) {
  453. // 直接计算价格,避免使用async/await的forEach
  454. let val = Number(r.ratio);
  455. let newval = (val / 100).toFixed(2);
  456. let price = formatPrice(this.discountAmount * newval);
  457. newData[i] = {
  458. ...r,
  459. price: price
  460. };
  461. }
  462. }
  463. // 验证并调整最后一行价格,确保总和等于优惠后的总金额
  464. // 使用分进行计算,避免浮点数精度问题
  465. const allPriceSum = newData.reduce((acc, cur) => acc + Math.round(Number(cur.price || 0) * 100), 0) / 100;
  466. const discountAmount = Number(this.discountAmount);
  467. // 直接计算比例总和,避免字符串转换问题
  468. const allRatio = newData.reduce((acc, cur) => acc + Number(cur.ratio || 0), 0);
  469. console.log('allPriceSum:', allPriceSum, 'discountAmount:', discountAmount, 'allRatio:', allRatio);
  470. // 检查是否所有数据都有price且比例合计为100%
  471. const allHavePrice = newData.every(item => item.price != null && item.price !== '');
  472. console.log('allHavePrice:', allHavePrice);
  473. if (allHavePrice && Math.abs(allRatio - 100) < 0.01 && Math.abs(allPriceSum - discountAmount) >= 0.01) {
  474. // 调整最后一行的价格
  475. if (newData.length > 0) {
  476. const lastIndex = newData.length - 1;
  477. // 使用分进行计算,避免浮点数精度问题
  478. const otherPriceSum = newData.slice(0, lastIndex).reduce((acc, cur) => acc + Math.round(Number(cur.price || 0) * 100), 0) / 100;
  479. // 计算最后一行应该有的价格
  480. const lastPrice = Math.round((discountAmount - otherPriceSum) * 100) / 100;
  481. newData[lastIndex] = {
  482. ...newData[lastIndex],
  483. price: formatPrice(lastPrice)
  484. };
  485. console.log('adjusted last item price:', lastPrice);
  486. }
  487. }
  488. console.log('newData before update:', newData);
  489. // 确保更新this.form.datasource,触发Vue的响应式更新
  490. this.form.datasource = newData;
  491. console.log('after update, datasource:', this.form.datasource);
  492. },
  493. // 返回列表数据
  494. getTableValue() {
  495. return this.form.datasource;
  496. },
  497. //修改回显
  498. putTableValue(data) {
  499. console.log('data~~~~111', data);
  500. if (data) {
  501. this.form.datasource = data.receiptPaymentList;
  502. this.setDiscountAmount(data.payAmount);
  503. }
  504. },
  505. remove(row) {
  506. let index = this.form.datasource.findIndex((n) => n.key == row.key);
  507. if (index !== -1) {
  508. this.form.datasource.splice(index, 1);
  509. this.setSort();
  510. if (row.id) {
  511. this.delDetailIds.push(row.id);
  512. }
  513. this.$emit('getIssueNumber', this.form.datasource.length);
  514. }
  515. },
  516. // 清空表格
  517. restTable() {
  518. this.form.datasource = [];
  519. },
  520. // 重新排序
  521. setSort() {
  522. this.form.datasource.forEach((n, index) => {
  523. n.key = index + 1;
  524. });
  525. },
  526. defaultList(method, issueNumber, dateRange) {
  527. // console.log('method, issueNumber', method, issueNumber, dateRange);
  528. const tempList = []
  529. if(dateRange) {
  530. this.setDefaultList(dateRange, issueNumber);
  531. return
  532. }
  533. if(method == 3) {
  534. let params = ['预付款', '交货款'];
  535. for(let i = 0; i < issueNumber; i++) {
  536. let item = JSON.parse(JSON.stringify(this.defaultForm));
  537. item.moneyName = i < params.length ? params[i] : '';
  538. item.type = i < params.length ? this.paymentTypeOp[i].value : '';
  539. item.typeName = i < params.length ? this.paymentTypeOp[i].label : '';
  540. item.key = i + 1;
  541. item.issueNumber = i + 1;
  542. tempList.push(item);
  543. }
  544. // params.forEach((item, index) => {
  545. // let i = JSON.parse(JSON.stringify(this.defaultForm));
  546. // i.moneyName = item;
  547. // i.type = this.paymentTypeOp[index].value;
  548. // i.key = index + 1;
  549. // i.issueNumber = index + 1;
  550. // tempList.push(i);
  551. // });
  552. } else {
  553. // method == 4 || method == 5 || method == 6 || method == 7 || method == 8
  554. // let params = [''];
  555. // params.forEach((item, index) => {
  556. // let i = JSON.parse(JSON.stringify(this.defaultForm));
  557. // i.key = index + 1;
  558. // i.issueNumber = index + 1;
  559. // tempList.push(i);
  560. // });
  561. for(let i = 0; i < issueNumber; i++) {
  562. let item = JSON.parse(JSON.stringify(this.defaultForm));
  563. item.moneyName = '';
  564. item.type = '';
  565. item.typeName = '';
  566. item.key = i + 1;
  567. item.issueNumber = i + 1;
  568. tempList.push(item);
  569. }
  570. }
  571. console.log('tempList~~~', tempList);
  572. // 清空原数组并逐个添加新元素,确保Vue能够检测到变化
  573. this.form.datasource = [];
  574. this.$nextTick(() => {
  575. this.form.datasource = tempList;
  576. console.log('form.datasource after update:', this.form.datasource);
  577. // 强制组件重新渲染
  578. this.$forceUpdate();
  579. console.log('forceUpdate called');
  580. });
  581. },
  582. transformDaysFun(date) {
  583. const startDate = new Date(date[0]);
  584. const endDate = new Date(date[1]);
  585. // 计算毫秒差并转换为天数,使用Math.ceil确保结果为整数
  586. const days = Math.ceil((endDate - startDate) / (1000 * 60 * 60 * 24)) + 1;
  587. console.log('包含两头的天数:', days);
  588. // 生成包括头尾在内的所有日期
  589. const allDates = [];
  590. const current = new Date(startDate);
  591. // 遍历从开始日期到结束日期的所有天数
  592. while (current <= endDate) {
  593. // 格式化日期为YYYY-MM-dd
  594. const year = current.getFullYear();
  595. const month = current.getMonth() + 1; // 月份从0开始,需要+1
  596. const day = current.getDate();
  597. const formattedMonth = String(month).padStart(2, '0');
  598. const formattedDay = String(day).padStart(2, '0');
  599. const formattedDateStr = `${year}-${formattedMonth}-${formattedDay}`;
  600. allDates.push(formattedDateStr);
  601. // 移动到下一天
  602. current.setDate(current.getDate() + 1);
  603. }
  604. return allDates;
  605. },
  606. transformMonthFun(date, day) {
  607. // 处理月份数据(转换为Date对象)
  608. const parseMonthDate = (dateStr) => {
  609. return dateStr instanceof Date ? dateStr : new Date(dateStr + '-01');
  610. };
  611. const start = parseMonthDate(date[0]);
  612. const end = parseMonthDate(date[1]);
  613. // 先生成所有月份的日期数组
  614. const allMonthDates = [];
  615. const currentDate = new Date(start);
  616. // 遍历从开始月份到结束月份的所有月份
  617. while (currentDate <= end) {
  618. const year = currentDate.getFullYear();
  619. const month = currentDate.getMonth() + 1; // 月份从0开始,需要+1
  620. const receiptDate = day;
  621. // 格式化日期为YYYY-MM-dd
  622. const formattedMonth = String(month).padStart(2, '0');
  623. const formattedDate = String(receiptDate).padStart(2, '0');
  624. const deadLine = receiptDate ? `${year}-${formattedMonth}-${formattedDate}` : '';
  625. allMonthDates.push(deadLine);
  626. // 使用Date对象的setMonth方法正确移动到下一个月(自动处理年份变化)
  627. currentDate.setMonth(currentDate.getMonth() + 1);
  628. }
  629. return allMonthDates;
  630. },
  631. setDefaultList(dateRange, issueNumber) {
  632. // console.log('setDefaultList-dateRange~~~', dateRange);
  633. const tempPeriod = issueNumber || 0;
  634. // 计算基本比例
  635. const basicRatio = 100 / tempPeriod;
  636. let totalRatio = 0;
  637. // 保存原有数据
  638. const existingData = [...this.form.datasource];
  639. // 生成付款计划列表项
  640. const tempList = [];
  641. // 根据传入的period参数生成付款计划
  642. for (let i = 0; i < tempPeriod; i++) {
  643. let item = JSON.parse(JSON.stringify(this.defaultForm));
  644. // let item;
  645. // // 如果原有数据中有对应项,则保留原有数据
  646. // if (i < existingData.length) {
  647. // item = JSON.parse(JSON.stringify(existingData[i]));
  648. // } else {
  649. // item = JSON.parse(JSON.stringify(this.defaultForm));
  650. // }
  651. // 获取日期:如果i小于日期数组长度则使用对应日期,否则设为空
  652. const deadLine = i < dateRange.length ? dateRange[i] : '';
  653. const ratio = parseFloat(basicRatio.toFixed(2));
  654. item.issueNumber = i + 1;
  655. item.deadLine = deadLine;
  656. // item.ratio = ratio;
  657. tempList.push(item);
  658. // totalRatio += ratio;
  659. }
  660. // 调整最后一项的比例,确保总和为100
  661. // if (tempList.length > 0) {
  662. // const difference = 100 - totalRatio;
  663. // if (difference !== 0) {
  664. // tempList[tempList.length - 1].ratio = parseFloat((tempList[tempList.length - 1].ratio + difference).toFixed(2));
  665. // }
  666. // }
  667. console.log('付款计划列表:~~', tempList);
  668. // this.$set(this.form, 'datasource', tempList);
  669. console.log('付款计划列表:', this.form.datasource);
  670. this.form.datasource = [];
  671. this.$nextTick(() => {
  672. this.form.datasource = tempList;
  673. console.log('form.datasource after update:', this.form.datasource);
  674. // 强制组件重新渲染
  675. this.$forceUpdate();
  676. console.log('forceUpdate called');
  677. });
  678. },
  679. // 添加
  680. handlAdd() {
  681. let item = JSON.parse(JSON.stringify(this.defaultForm));
  682. item.key = this.form.datasource.length + 1;
  683. item.issueNumber = this.form.datasource.length + 1;
  684. this.form.datasource.push(item);
  685. this.$emit('getIssueNumber', this.form.datasource.length);
  686. },
  687. // validateForm(callback) {
  688. // //开始表单校验
  689. // this.$refs.form.validate((valid) => {
  690. // callback(valid);
  691. // });
  692. // }
  693. validateForm(callback) {
  694. this.$refs.form.validate((valid, obj) => {
  695. if (obj) {
  696. let messages = Object.keys(obj).map((key) => obj[key][0]);
  697. if (messages.length > 0) {
  698. this.$message.warning(messages[0].message);
  699. }
  700. }
  701. callback(valid);
  702. });
  703. },
  704. }
  705. };
  706. </script>
  707. <style lang="scss" scoped>
  708. .time-form .el-form-item {
  709. margin-bottom: 0 !important;
  710. }
  711. .headbox {
  712. display: flex;
  713. justify-content: space-between;
  714. align-items: center;
  715. .amount {
  716. font-size: 14px;
  717. font-weight: bold;
  718. padding-right: 30px;
  719. }
  720. }
  721. .pricebox {
  722. display: flex;
  723. justify-content: flex-start;
  724. align-items: center;
  725. font-weight: bold;
  726. }
  727. :deep(.el-input-group__append) {
  728. padding: 0;
  729. }
  730. </style>