paymentPlanModule.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382
  1. <template>
  2. <!-- 回款计划 -->
  3. <el-form ref="form" label-width="206px" class="payment-plan-container">
  4. <el-form-item class="payment-plan-line" label-width="156px" label="回款次数" :required="required.payback">
  5. <number-input
  6. :value="pageForm.paybackTimes"
  7. @input="onPaybackChange"
  8. placeholder="请输入"
  9. :min="0"
  10. maxlength="2">
  11. <template #append>次</template>
  12. </number-input>
  13. <div class="payback-table-container" v-if="payBackTimesMoreThan1">
  14. <el-table
  15. :data="paybackTableData"
  16. border
  17. stripe
  18. :summary-method="getSummaries"
  19. show-summary>
  20. <el-table-column
  21. type="index"
  22. header-align="center"
  23. align="center"
  24. width="100"
  25. label="序号">
  26. </el-table-column>
  27. <el-table-column
  28. prop="name"
  29. header-align="center"
  30. align="center"
  31. label="预计回款时间">
  32. <template slot-scope="scope">
  33. <el-date-picker
  34. :value="paybackTableData[scope.$index].time"
  35. @input="onChangeTableLineData('time', scope.$index, $event)"
  36. value-format="timestamp"
  37. type="date"
  38. placeholder="请选择日期">
  39. </el-date-picker>
  40. </template>
  41. </el-table-column>
  42. <el-table-column
  43. prop="money"
  44. header-align="center"
  45. align="center"
  46. label="预计回款金额(元)">
  47. <template slot-scope="scope">
  48. <number-input
  49. :value="paybackTableData[scope.$index].money"
  50. @input="onPaybackSplitMoneyChange(scope, $event)"
  51. type="number"
  52. placeholder="请输入"
  53. :min="0"
  54. :disabled="scope.$index === paybackTableData.length - 1"
  55. ></number-input>
  56. </template>
  57. </el-table-column>
  58. </el-table>
  59. </div>
  60. </el-form-item>
  61. <el-form-item class="payment-plan-line" :label="paybackTimeLabel" :required="required.paymentDeadline" v-if="!payBackTimesMoreThan1">
  62. <number-input
  63. :value="pageForm.paymentDeadline"
  64. @input="onPaymentDeadlineChange"
  65. placeholder="请输入"
  66. maxlength="3">
  67. <template #append>个工作日回款,预计回款时间:<span style="color: #36a3f7">{{ expectedPaymentDeadlineTimeString }}</span></template>
  68. </number-input>
  69. </el-form-item>
  70. </el-form>
  71. </template>
  72. <script>
  73. import { debounce } from 'lodash'
  74. import {dateFormatter} from '@/assets/js/date'
  75. import { toNumber } from '@/utils/utils'
  76. import { selectorVModelMixin } from '@/utils/mixins/selector-v-model'
  77. import { agreeStatusOptions } from '@/views/create-order/data/index.js'
  78. import NumberInput from '@/views/create-order/ui/NumberInput.vue'
  79. import { getWorkDay } from '@/api/modules'
  80. import { pageFormState } from '@/views/create-order/mixins'
  81. import { mapState, mapGetters } from 'vuex'
  82. import { PayBackTableRow } from '@/views/create-order/data/interface'
  83. import { add, sub } from '@/utils/number'
  84. export default {
  85. name: 'PaymentPlanModule',
  86. mixins: [selectorVModelMixin, pageFormState],
  87. components: {
  88. NumberInput
  89. },
  90. props: {
  91. contractStatus: {
  92. type: [String, Number],
  93. default: 0,
  94. validator(v) {
  95. return agreeStatusOptions.map(a => a.value).concat(-1).includes(v)
  96. }
  97. },
  98. contractTime: {
  99. type: [String, Number],
  100. default: ''
  101. }
  102. },
  103. data() {
  104. return {
  105. conf: {
  106. paybackMin: 1,
  107. paybackMax: 5,
  108. },
  109. required: {
  110. payback: true,
  111. paymentDeadline: true,
  112. },
  113. form: {
  114. // payback: '1',
  115. // paymentDeadline: '',
  116. },
  117. // paybackTableData: [],
  118. expectedPaymentDeadlineTime: '',
  119. }
  120. },
  121. computed: {
  122. ...mapState({
  123. pageForm: state => state.order.pageForm,
  124. }),
  125. ...mapGetters('order', ['pageTotalMoney', 'exceptPaybackMoney']),
  126. buySubject() {
  127. return this.pageForm.buySubject
  128. },
  129. payBackTimesMoreThan1() {
  130. return this.pageForm.paybackTimes > 1
  131. },
  132. paybackTableData() {
  133. return this.pageForm.paybackTableData
  134. },
  135. exceptedPayBackMoney() {
  136. return this.exceptPaybackMoney
  137. },
  138. requiredList() {
  139. return [
  140. {
  141. field: 'payback',
  142. message: '回款次数为必填项', // 错误提示文案
  143. rank: 2, // 提示优先级,值越小优先级越高
  144. required: this.required.payback,
  145. },
  146. {
  147. field: 'paymentDeadline',
  148. message: '回款时间为必填项', // 错误提示文案
  149. rank: 2,
  150. required: this.required.paymentDeadline && !this.payBackTimesMoreThan1,
  151. },
  152. ].filter(f => f.required)
  153. },
  154. expectedPaymentDeadlineTimeString() {
  155. return this.pageForm.expectedPaymentDeadlineTime || '-'
  156. },
  157. paybackTimeLabel() {
  158. return this.contractStatus === 1 ? '自协议签订之日起': '自订单创建之日起'
  159. }
  160. },
  161. watch: {
  162. contractTime() {
  163. if (this.pageForm.paymentDeadline) {
  164. this.onPaymentDeadlineChangeCallback()
  165. }
  166. },
  167. buySubject() {
  168. this.reset()
  169. }
  170. },
  171. methods: {
  172. reset() {
  173. this.clearPaybackTableData()
  174. this.onPaybackChange(1)
  175. },
  176. validate() {
  177. return new Promise((resolve, reject) => {
  178. const { payback, paymentDeadline } = this.form
  179. const pass = payback && paymentDeadline
  180. if (pass) {
  181. resolve()
  182. } else {
  183. reject()
  184. }
  185. })
  186. },
  187. getState() {
  188. return Object.assign({}, this.form)
  189. },
  190. setState(t) {
  191. if (!t) return
  192. Object.assign(this.form, t)
  193. },
  194. onPaybackChange(i) {
  195. const max = this.conf.paybackMax
  196. const min = this.conf.paybackMin
  197. if (i > max) {
  198. this.setPageFormData('paybackTimes', max)
  199. this.$message({
  200. message: `最大值为${max}`,
  201. type: 'warning'
  202. })
  203. } else if (i < min && i !== '') {
  204. this.$message({
  205. message: `最小值为${min}`,
  206. type: 'warning'
  207. })
  208. this.setPageFormData('paybackTimes', 1)
  209. } else {
  210. this.setPageFormData('paybackTimes', i)
  211. }
  212. if (i > 1) {
  213. this.initPaybackTableData()
  214. } else {
  215. this.clearPaybackTableData()
  216. }
  217. },
  218. calcLastColumnMoney() {
  219. // 1. 计算最后一个格子的金额
  220. // 1.1 先计算除了最后一个的总和
  221. let eNum = 0
  222. this.paybackTableData.forEach((p, index) => {
  223. if (index <= this.paybackTableData.length - 2) {
  224. // eNum += Number(p.money)
  225. // 高精度计算
  226. eNum = add(eNum, Number(p.money))
  227. }
  228. })
  229. // const lastMoney = this.exceptedPayBackMoney - eNum
  230. // 高精度计算
  231. const lastMoney = sub(this.exceptedPayBackMoney ,eNum)
  232. return lastMoney
  233. },
  234. onPaybackSplitMoneyChange(scope, e) {
  235. const index = scope.$index
  236. this.onChangeTableLineData('money', index, e)
  237. if (!this.pageTotalMoney.hasContract) {
  238. this.onChangeTableLineData('money', index, '')
  239. return this.$message({
  240. message: '请先输入合同金额',
  241. type: 'warning'
  242. })
  243. }
  244. if (scope.row.money === 0 || scope.row.money === '0') {
  245. this.onChangeTableLineData('money', index, '')
  246. return this.$message({
  247. message: '不可为0',
  248. type: 'warning'
  249. })
  250. }
  251. let lastMoney = this.calcLastColumnMoney()
  252. // 1.2 限制当前格子的金额
  253. if (lastMoney < 0) {
  254. this.$message({
  255. message: '需小于应收金额',
  256. type: 'warning'
  257. })
  258. this.onChangeTableLineData('money', index, '')
  259. lastMoney = this.calcLastColumnMoney()
  260. }
  261. this.onChangeTableLineData('money', this.paybackTableData.length - 1, lastMoney)
  262. },
  263. onPaymentDeadlineChange(e) {
  264. this.setPageFormData('paymentDeadline', e)
  265. this.onPaymentDeadlineChangeCallback()
  266. },
  267. // 回款计划,工作日变更
  268. onPaymentDeadlineChangeCallback: debounce(function() {
  269. this.expectedPaymentDeadlineTime = ''
  270. // 签协议:预计回款时间=协议签订时间+填写的工作日
  271. // 不签协议:预计回款时间=订单创建时间+填写的工作日
  272. // 回款工作日为0
  273. const paymentDeadline = toNumber(this.pageForm.paymentDeadline)
  274. if (paymentDeadline === 0) {
  275. if (this.contractStatus === 1) {
  276. this.expectedPaymentDeadlineTime = dateFormatter(this.contractTime || new Date(), 'yyyy-MM-dd')
  277. }else{
  278. this.expectedPaymentDeadlineTime = dateFormatter(new Date(), 'yyyy-MM-dd')
  279. }
  280. this.setPageFormData('expectedPaymentDeadlineTime', this.expectedPaymentDeadlineTime)
  281. } else {
  282. let start = ''
  283. if (this.contractStatus === 1) { // 签协议
  284. start = dateFormatter(this.contractTime || new Date(), 'yyyy-MM-dd')
  285. } else { // 不签协议
  286. start = dateFormatter(new Date(), 'yyyy-MM-dd')
  287. }
  288. if (!paymentDeadline || !start) {
  289. return
  290. }
  291. const params = {
  292. inputTime: start,
  293. workDayNum: toNumber(paymentDeadline)
  294. }
  295. getWorkDay(params).then((res) => {
  296. if (res.data) {
  297. // this.expectedPaymentDeadlineTime = res.data
  298. this.setPageFormData('expectedPaymentDeadlineTime', res.data)
  299. }
  300. })
  301. }
  302. }, 700),
  303. clearPaybackTableData() {
  304. this.setPageFormData('paybackTableData', [])
  305. },
  306. initPaybackTableData() {
  307. const arr = new Array(this.pageForm.paybackTimes - 0).fill(undefined).map(() => new PayBackTableRow())
  308. // this.paybackTableData = arr
  309. this.setPageFormData('paybackTableData', arr)
  310. },
  311. getSummaries(param) {
  312. const { columns } = param
  313. const sums = [];
  314. columns.forEach((column, index) => {
  315. if (index === 0) {
  316. sums[index] = '合计';
  317. return;
  318. }
  319. if (index === 1) {
  320. sums[index] = '-';
  321. return
  322. }
  323. if (index === 2) {
  324. sums[index] = this.exceptedPayBackMoney || '-';
  325. return
  326. }
  327. });
  328. return sums;
  329. },
  330. onChangeTableLineData(key, index, e) {
  331. // this.paybackTableData[index].time = e
  332. this.updatePageFormArrayObjectValue({
  333. arrayName: 'paybackTableData',
  334. index,
  335. key,
  336. newValue: e
  337. })
  338. },
  339. }
  340. }
  341. </script>
  342. <style lang="scss" scoped>
  343. .payment-plan-line {
  344. $radius: 4px;
  345. ::v-deep {
  346. .el-input-group__append {
  347. background: transparent;
  348. border: none;
  349. color: $gray_10;
  350. }
  351. .el-input-group--append {
  352. width: auto;
  353. .el-input__inner {
  354. width: 128px;
  355. border-top-right-radius: $radius;
  356. border-bottom-right-radius: $radius;
  357. }
  358. }
  359. }
  360. }
  361. .payback-table-container {
  362. margin-top: 8px;
  363. ::v-deep {
  364. .el-table {
  365. border-radius: 6px;
  366. }
  367. .el-table__header {
  368. tr,
  369. th.el-table__cell {
  370. background: #f5f7fa;
  371. }
  372. }
  373. }
  374. }
  375. </style>