Payment.vue 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609
  1. <template>
  2. <a-spin :spinning="confirmLoading">
  3. <j-form-container :disabled="formDisabled">
  4. <a-form-model
  5. ref="form"
  6. :model="model"
  7. :rules="validatorRules"
  8. slot="detail"
  9. >
  10. <a-row>
  11. <a-col :span="24">
  12. <a-form-model-item
  13. label="结账应收"
  14. :labelCol="labelCol"
  15. :wrapperCol="wrapperCol"
  16. prop="billAmount"
  17. >
  18. {{ model.billAmount.toFixed(2) }}元
  19. <a-switch v-model="model.coupon" />优惠
  20. </a-form-model-item>
  21. </a-col>
  22. <template v-if="model.coupon">
  23. <a-col :span="24">
  24. <a-form-model-item
  25. label="优惠方式"
  26. :labelCol="labelCol"
  27. :wrapperCol="wrapperCol"
  28. prop="refund"
  29. >
  30. <a-radio-group v-model="model.preferentialType">
  31. <a-radio :value="1"> 抹零 </a-radio>
  32. <a-radio :value="2"> 减现 </a-radio>
  33. <a-radio :value="3"> 打折 </a-radio>
  34. </a-radio-group>
  35. <template v-if="model.preferentialType === 3"
  36. >打<a-input-number
  37. style="width: 50px"
  38. v-model="model.discount"
  39. :min="1"
  40. :max="9"
  41. ></a-input-number
  42. >折
  43. </template>
  44. </a-form-model-item>
  45. </a-col>
  46. <a-col :span="24" v-if="model.preferentialType == 2">
  47. <a-form-model-item
  48. label="优惠金额"
  49. :labelCol="labelCol"
  50. :wrapperCol="wrapperCol"
  51. prop="couponFirstAmount"
  52. >
  53. <a-input-number
  54. style="width: 100px"
  55. :min="0"
  56. v-model="model.couponFirstAmount"
  57. placeholder="请输入优惠金额"
  58. ></a-input-number
  59. >元
  60. </a-form-model-item>
  61. </a-col>
  62. <a-col :span="24">
  63. <a-form-model-item
  64. label="惠后金额"
  65. :labelCol="labelCol"
  66. :wrapperCol="wrapperCol"
  67. >
  68. {{ couponAmount.toFixed(2) }}元
  69. </a-form-model-item>
  70. </a-col>
  71. <a-col :span="24">
  72. <a-form-model-item
  73. label="优惠券"
  74. :labelCol="labelCol"
  75. :wrapperCol="wrapperCol"
  76. prop="refund"
  77. >
  78. <a-select
  79. v-if="model.couponCard"
  80. v-model="model.couponId"
  81. style="width: 200px"
  82. placeholder="优惠券"
  83. :allowClear="true"
  84. >
  85. <a-select-option
  86. :value="couponItem.id"
  87. v-for="couponItem in memeberCouponList"
  88. :key="couponItem.id"
  89. >{{ couponItem.couponsName }}</a-select-option
  90. >
  91. </a-select>
  92. <a-switch v-model="model.couponCard" />使用优惠券
  93. </a-form-model-item>
  94. </a-col>
  95. </template>
  96. <a-col :span="24">
  97. <a-form-model-item
  98. label="实收金额"
  99. :labelCol="labelCol"
  100. :wrapperCol="wrapperCol"
  101. >
  102. {{ realityAmount.toFixed(2) }}元
  103. </a-form-model-item>
  104. </a-col>
  105. <a-col :span="24">
  106. <a-form-model-item
  107. label="收款金额"
  108. :labelCol="labelCol"
  109. :wrapperCol="wrapperCol"
  110. >
  111. <div v-for="(item, index) in payList" :key="index">
  112. <a-row type="flex" :key="index">
  113. <a-col :span="6">
  114. <a-input-number
  115. style="width: 100px"
  116. v-model="item.money"
  117. :min="0"
  118. ></a-input-number>
  119. </a-col>
  120. <a-col :span="6">
  121. <a-select
  122. v-model="item.payType"
  123. placeholder="收款方式"
  124. @change="(event) => onChange(event, item)"
  125. >
  126. <a-select-option
  127. :value="item2.id"
  128. v-for="item2 in payTypeList"
  129. :key="item2.id"
  130. :disabled="item2.delFlag == 99"
  131. >
  132. {{ item2.name }}
  133. </a-select-option>
  134. </a-select></a-col
  135. >
  136. <a-col :span="6">
  137. <a-icon
  138. v-if="index == payList.length - 1"
  139. type="plus-circle"
  140. class="dynamic-delete-button"
  141. @click="puls()" />
  142. <a-icon
  143. v-if="payList.length > 1"
  144. type="minus-circle"
  145. style="color: #f56c6c"
  146. class="dynamic-delete-button"
  147. @click="() => remove(index)"
  148. /></a-col>
  149. </a-row>
  150. <a-row type="flex" v-if="item.isVipMemmber">
  151. <a-col :span="12"> 姓名:{{ memberCard.name }} </a-col>
  152. <a-col :span="12"> 卡号:{{ memberCard.cardNo }} </a-col>
  153. <a-col :span="12">
  154. 会员级别: {{ memberCard.gradeName }}</a-col
  155. >
  156. <a-col :span="12"> 余额:{{ memberCard.balance }} </a-col>
  157. <a-col :span="12"> 积分:{{ memberCard.integral }} </a-col>
  158. <!-- <a-col :span="12"> 本次扣后剩余: </a-col>
  159. <a-col :span="12"> 本次新增积分: </a-col> -->
  160. </a-row>
  161. <a-row type="flex" v-if="item.isDanwei">
  162. <a-col :span="12">
  163. 协议单位:{{ agreementUnitData.customerName }}
  164. </a-col>
  165. <a-col :span="12">
  166. 签约开始日期:{{ danwei.signTime }}
  167. </a-col>
  168. <a-col :span="12">
  169. 签约结束日期: {{ danwei.effective }}</a-col
  170. >
  171. <a-col :span="12">
  172. 可用额度:{{ agreementUnitData.balance || 0 }}
  173. </a-col>
  174. </a-row>
  175. </div>
  176. </a-form-model-item>
  177. </a-col>
  178. <a-col :span="24">
  179. <a-form-model-item
  180. label="实收合计"
  181. :labelCol="labelCol"
  182. :wrapperCol="wrapperCol"
  183. >
  184. {{ sumAmount.toFixed(2) }}元
  185. </a-form-model-item>
  186. </a-col>
  187. <a-col :span="24" style="text-align: end">
  188. <a-checkbox default-checked>打印结账单</a-checkbox>
  189. <a-checkbox default-checked>打印发票二维码</a-checkbox>
  190. </a-col>
  191. </a-row>
  192. </a-form-model>
  193. </j-form-container>
  194. </a-spin>
  195. </template>
  196. <script>
  197. import { httpAction, getAction } from "@/api/manage";
  198. import { validateDuplicateValue } from "@/utils/util";
  199. export default {
  200. name: "Payment",
  201. components: {},
  202. props: {
  203. //表单禁用
  204. disabled: {
  205. type: Boolean,
  206. default: false,
  207. required: false,
  208. },
  209. showYinshou: {
  210. type: Boolean,
  211. default: true
  212. },
  213. },
  214. data() {
  215. return {
  216. model: {
  217. coupon: false,
  218. discount: 1,
  219. couponCard: false,
  220. couponType: 1,
  221. couponFirstAmount: 0,
  222. billAmount: 0,
  223. selectedFeeIds: [],
  224. },
  225. labelCol: {
  226. xs: { span: 24 },
  227. sm: { span: 5 },
  228. },
  229. wrapperCol: {
  230. xs: { span: 24 },
  231. sm: { span: 16 },
  232. },
  233. confirmLoading: false,
  234. validatorRules: {
  235. mobile: [
  236. {
  237. required: true,
  238. pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/,
  239. message: "请输入手机号!",
  240. },
  241. ],
  242. cardNo: [{ required: true, message: "请输入会员卡号!" }],
  243. gradeId: [{ required: true, message: "请输入等级类型!" }],
  244. payType: [{ required: true, message: "请输入付款类型!" }],
  245. paymentMethod: [{ required: true, message: "请输入付款方式!" }],
  246. customerName: [{ required: true, message: "请输入会员姓名!" }],
  247. sex: [{ required: true, message: "请输入性别!" }],
  248. certificateType: [{ required: true, message: "请输入证件类型!" }],
  249. validity: [{ required: true, message: "请输入有效期!" }],
  250. },
  251. url: {
  252. add: "/business/busRoomBookingOrders/booking-to-live",
  253. edit: "/business/busMemberCard/edit",
  254. queryById: "/business/busMemberCard/queryById",
  255. },
  256. gradeList: [],
  257. paymentMethodList: [],
  258. staffList: [],
  259. customerList: [],
  260. oldcustomerList: [],
  261. payTypeList: [],
  262. memberCard: {},
  263. danwei: {},
  264. isVipMemmber: false,
  265. isDanwei: false,
  266. payList: [],
  267. memeberCouponList: [],
  268. agreementUnitData: {},
  269. copyRealityAmount: '',
  270. };
  271. },
  272. computed: {
  273. formDisabled() {
  274. return this.disabled;
  275. },
  276. sumAmount() {
  277. var sum = this.payList.reduce(function (total, item) {
  278. return total + item.money;
  279. }, 0);
  280. return sum;
  281. },
  282. couponAmount() {
  283. var sum = 0;
  284. if (this.model.coupon) {
  285. if (this.model.preferentialType == 1) {
  286. sum = Math.floor(this.model.billAmount);
  287. } else if (this.model.preferentialType == 2) {
  288. sum = this.model.billAmount - (this.model.couponFirstAmount || 0);
  289. } else if (this.model.preferentialType == 3) {
  290. sum = parseFloat(
  291. ((this.model.billAmount * this.model.discount) / 10).toFixed(2)
  292. );
  293. }
  294. } else {
  295. sum = this.model.billAmount;
  296. }
  297. return sum;
  298. },
  299. realityAmount() {
  300. let result = this.couponAmount
  301. if (this.model.couponCard) {
  302. var find = this.memeberCouponList.find(
  303. (t) => t.id == this.model.couponId
  304. );
  305. if (find) {
  306. result = this.couponAmount - find.cost;
  307. }
  308. }
  309. if (this.model.coupon) {
  310. var find = this.memeberCouponList.find(
  311. (t) => t.id == this.model.couponId
  312. );
  313. if (find) {
  314. result = this.couponAmount - find.cost;
  315. }
  316. if (this.payList && this.payList.length > 0 && this.copyRealityAmount != result) {
  317. this.payList = [this.payList[0]]
  318. this.payList[0].money = result
  319. }
  320. this.copyRealityAmount = result
  321. }
  322. this.$forceUpdate()
  323. return result;
  324. },
  325. },
  326. created() {
  327. var _info = JSON.parse(localStorage.getItem("storeInfo"));
  328. if (_info) {
  329. this.model.hotelId = _info.id;
  330. }
  331. //备份model原始值
  332. this.modelDefault = JSON.parse(JSON.stringify(this.model));
  333. // getAction("/business/busRoomPayType/list", {
  334. // pageSize: 99999,
  335. // pageNo: 1,
  336. // }).then((res) => {
  337. // if (res.success) {
  338. // this.payTypeList = res.result.records;
  339. // }
  340. // });
  341. },
  342. methods: {
  343. getbusRoomPayType() {
  344. getAction("/business/busRoomPayType/list", {
  345. pageSize: 99999,
  346. pageNo: 1,
  347. }).then((res) => {
  348. if (res.success) {
  349. this.payTypeList = res.result.records;
  350. if (this.payTypeList && this.payTypeList.length > 0) {
  351. if (
  352. !this.model.vipCustomerId ||
  353. this.model.vipCustomerId.length == 0
  354. ) {
  355. var index = this.payTypeList.findIndex((t) =>
  356. t.name.includes("会员")
  357. );
  358. if (index >= 0) {
  359. this.payTypeList[index].delFlag = 99;
  360. }
  361. }
  362. if (
  363. !this.model.contractTeamId ||
  364. this.model.contractTeamId.length == 0 ||
  365. !this.model.contractTeamProtocolId ||
  366. this.model.contractTeamProtocolId.length == 0
  367. ) {
  368. var index = this.payTypeList.findIndex((t) =>
  369. t.name.includes("单位")
  370. );
  371. if (index >= 0) {
  372. this.payTypeList[index].delFlag = 99;
  373. }
  374. }
  375. this.$set(this.model, "payType", this.payTypeList[0].id);
  376. this.payList = [
  377. {
  378. money: this.realityAmount,
  379. payType: this.payTypeList[0].id,
  380. isVipMemmber: false,
  381. isDanwei: false,
  382. },
  383. ];
  384. }
  385. }
  386. });
  387. },
  388. puls() {
  389. var sum = this.payList.reduce(function (total, item) {
  390. return total + item.money;
  391. }, 0);
  392. var money = this.realityAmount - sum;
  393. if (money < 0) {
  394. money = 0;
  395. }
  396. this.payList.push({
  397. money: money,
  398. payType: this.payTypeList[0].id,
  399. isVipMemmber: false,
  400. isDanwei: false,
  401. });
  402. },
  403. remove(index) {
  404. this.payList.splice(index, 1);
  405. },
  406. onChange(e, value) {
  407. console.log("value", value);
  408. console.log("e", e);
  409. var find = this.payTypeList.find((t) => t.id == value.payType);
  410. value.isVipMemmber = find && find.name.includes("会员");
  411. value.isDanwei = find && find.name.includes("单位");
  412. },
  413. handleSearch(value) {
  414. let result;
  415. if (!value) {
  416. result = this.oldcustomerList;
  417. } else {
  418. result = this.oldcustomerList.filter((t) => t.name.includes(value));
  419. }
  420. this.customerList = result;
  421. },
  422. handleSelectMember(e) {
  423. var find = this.customerList.find((t) => t.id === e);
  424. this.model.phone = find.phone;
  425. this.model.customerName = find.name;
  426. this.model.customerId = find.id;
  427. },
  428. getMemeberCouponList() {
  429. getAction("/business/busMarketCouponsCashUsed/memeberCouponList", {
  430. pageNo: 1,
  431. pageSize: 99,
  432. conditions: 900,
  433. mobile: this.model.vipCustomerId,
  434. }).then((res) => {
  435. if (res.success) {
  436. this.memeberCouponList = res.result.records;
  437. }
  438. });
  439. },
  440. add(livingOrderId, roomId) {
  441. this.modelDefault.livingOrderId = livingOrderId;
  442. this.modelDefault.roomId = roomId;
  443. this.edit(this.modelDefault);
  444. },
  445. edit(record) {
  446. let data = Object.assign({}, record);
  447. this.model = JSON.parse(JSON.stringify(data))
  448. if (record.preferentialMoney !== 0 && record.preferentialMoney !== null) {
  449. this.model.preferentialType = 2
  450. this.model.couponFirstAmount = record.preferentialMoney;
  451. }
  452. this.getbusRoomPayType();
  453. if (this.model.vipCustomerId) {
  454. this.getMemeberCouponList();
  455. }
  456. if (this.model.vipCustomerId) {
  457. getAction("/business/busMemberCard/list", {
  458. id: this.model.vipCustomerId,
  459. }).then((res) => {
  460. if (res.success) {
  461. if (res.result.records && res.result.records.length > 0) {
  462. this.memberCard = res.result.records[0];
  463. }
  464. }
  465. });
  466. }
  467. if (this.model.contractTeamId && this.model.contractTeamProtocolId) {
  468. getAction("/business/busMarketAgreementUnit/list", {
  469. id: this.model.contractTeamId,
  470. }).then((res) => {
  471. if (res.success) {
  472. var list = res.result.records;
  473. if (list.length > 0) {
  474. this.agreementUnitData = list[0];
  475. getAction("/business/busMarketAgreementCustomer/list", {
  476. agreementId: this.model.contractTeamId,
  477. }).then((res2) => {
  478. if (res2.success) {
  479. var list2 = res2.result.records;
  480. if (list2 && list2.length > 0) {
  481. this.danwei = list2.find(
  482. (t) => t.id == this.model.contractTeamProtocolId
  483. );
  484. }
  485. }
  486. });
  487. }
  488. }
  489. });
  490. }
  491. // this.visible = true;
  492. },
  493. submitForm() {
  494. debugger
  495. const that = this;
  496. // 触发表单验证
  497. this.$refs.form.validate((valid) => {
  498. if (valid) {
  499. if (this.model.couponFirstAmount > this.model.consumption) {
  500. this.model.couponFirstAmount = 0
  501. this.$message.warning('优惠金额不能大于消费')
  502. return
  503. }
  504. if (this.realityAmount !== this.sumAmount) {
  505. that.$message.warning('实收金额和实收合计必须相等');
  506. return;
  507. }
  508. var obj = {};
  509. var fees = [];
  510. if (this.model.coupon) {
  511. fees.push({
  512. feeType: this.model.feeType,
  513. preferentialType: this.model.preferentialType,
  514. money: this.couponAmount.toFixed(2),
  515. custorerOrderRemark: "优惠金额",
  516. isPreferential: true,
  517. });
  518. }
  519. if (this.model.couponCard && this.model.couponId) {
  520. var find = this.memeberCouponList.find(
  521. (t) => t.id == this.model.couponId
  522. );
  523. if (find) {
  524. fees.push({
  525. feeType: this.model.feeType,
  526. money: find.cost.toFixed(2),
  527. custorerOrderRemark: "优惠券",
  528. isPreferential: true,
  529. });
  530. }
  531. }
  532. this.payList.forEach((item) => {
  533. fees.push({
  534. feeType: this.model.feeType,
  535. money: item.money.toFixed(2),
  536. payType: item.payType,
  537. custorerOrderRemark: "结账退房",
  538. isPreferential: this.model.isPreferential,
  539. preferentialMoney: this.model.preferentialMoney
  540. });
  541. });
  542. that.confirmLoading = true;
  543. var url =
  544. "/business/busRoomBookingOrders/settle-checkout?bookingOrderId=" +
  545. this.model.bookingOrderId;
  546. if (this.model.livingOrderId) {
  547. url =
  548. "/business/busRoomBookingOrders/living-settle-checkout?livingOrderId=" +
  549. this.model.livingOrderId;
  550. }
  551. if (
  552. this.model.selectedFeeIds &&
  553. this.model.selectedFeeIds.length > 0
  554. ) {
  555. url = "/business/busRoomBookingOrders/partial-settle";
  556. obj = {
  557. fees: fees,
  558. livingOrderId: this.model.livingOrderId,
  559. selectedFeeIds: this.model.selectedFeeIds,
  560. };
  561. }
  562. httpAction(
  563. url,
  564. this.model.selectedFeeIds && this.model.selectedFeeIds.length > 0
  565. ? obj
  566. : fees,
  567. "post"
  568. )
  569. .then((res) => {
  570. if (res.success) {
  571. that.$message.success("结账成功");
  572. that.$emit("ok");
  573. } else {
  574. that.$message.warning(res.message);
  575. }
  576. })
  577. .finally(() => {
  578. that.confirmLoading = false;
  579. });
  580. }
  581. });
  582. },
  583. },
  584. };
  585. </script>
  586. <style scoped>
  587. .dynamic-delete-button {
  588. cursor: pointer;
  589. position: relative;
  590. /* top: 4px; */
  591. margin-left: 5px;
  592. font-size: 18px;
  593. color: #1890ff;
  594. transition: all 0.3s;
  595. }
  596. .dynamic-delete-button:hover {
  597. color: #777;
  598. }
  599. .dynamic-delete-button[disabled] {
  600. cursor: not-allowed;
  601. opacity: 0.5;
  602. }
  603. </style>