index.vue 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597
  1. <template>
  2. <app-layout>
  3. <view>
  4. <view class="scan-head dir-top-nowrap main-center">
  5. <view class="order-name">订单金额</view>
  6. <view class="scan-price dir-left-nowrap cross-bottom" @click="openPriceModel">
  7. <view class="order-key">¥</view>
  8. <view class="order-value">{{list.price}}</view>
  9. </view>
  10. <view class="scan-line"></view>
  11. <!-- 优惠 -->
  12. <view class="dir-left-nowrap cross-center scan-offer">
  13. <view class="box-grow-1">订单优惠</view>
  14. <view class="box-grow-0">
  15. <view v-if="list.preferential_money > 0" class="red">
  16. -¥{{list.preferential_money}}
  17. </view>
  18. <view v-else-if="list.price > 0" class="gray">暂无优惠</view>
  19. </view>
  20. </view>
  21. <!-- 优惠券 -->
  22. <view class="dir-left-nowrap cross-center scan-offer">
  23. <view class="box-grow-1">优惠劵</view>
  24. <view class="box-grow-0 coupon-right">
  25. <view v-if="list.coupon_id" @click="setCoupon" class="red">
  26. -¥{{list.coupon_preferential_money}}
  27. </view>
  28. <view v-else-if="list.price > 0 && list.can_coupon_num > 0" class="gray"
  29. @click="setCoupon">选择优惠券
  30. </view>
  31. <view v-else-if="list.price > 0" class="gray">暂无可用优惠券</view>
  32. </view>
  33. <view class="box-grow-0 cross-center">
  34. <icon class="icon-right" type></icon>
  35. </view>
  36. </view>
  37. <!-- 积分抵扣 -->
  38. <view v-if="list.price > 0 && activity && integral.user_integral_num >= integral.member_integral && list.integral_deduction > 0"
  39. class="dir-left-nowrap cross-center scan-offer">
  40. <view class="box-grow-1 cross-center dir-left-nowrap">
  41. <view>
  42. <text>使用{{list.use_integral_num}}积分抵扣</text>
  43. <text class="red">{{list.integral_deduction}}</text>
  44. <text>元</text>
  45. </view>
  46. <view @click="getIntegralInfo" class="main-center cross-center">
  47. <icon class="scan-integral-icon" type></icon>
  48. </view>
  49. </view>
  50. <view class="box-grow-0" @click="handleUseIntegral">
  51. <icon v-if="list.use_integral == 1" class="scan-integral-switch check" type></icon>
  52. <icon v-else class="scan-integral-switch uncheck" type></icon>
  53. </view>
  54. </view>
  55. <!-- 备注 -->
  56. <view class="dir-left-nowrap scan-offer">
  57. <input @input="bindTextBlur" :value="remark" class="scan-input" placeholder="添加备注"/>
  58. </view>
  59. <view class="scan-line"></view>
  60. <view class="scan-remark cross-center dir-left-nowrap main-center">
  61. <view class="key">应付金额</view>
  62. <view class="value">¥{{list.pay_price}}</view>
  63. </view>
  64. </view>
  65. <view class="main-center cross-center scan-btn">
  66. <app-button @click="submit"
  67. color="#ffffff"
  68. font-size="32"
  69. height="88"
  70. width="702"
  71. :background="list.price > 0 ? '#ff4544': '#cdcdcd'"
  72. :disabled="list.price <= 0"
  73. round>已与店员确认,立即买单
  74. </app-button>
  75. </view>
  76. <view class="scan-end" v-if="activity.rules">
  77. <view class="dir-left-nowrap cross-center">
  78. <view class="icon"></view>
  79. <view>规则说明</view>
  80. </view>
  81. <text space="nbsp">{{activity.rules}}</text>
  82. </view>
  83. </view>
  84. <!-- MODEL -->
  85. <view v-if="price_modal" class="scan-modal show bt">
  86. <view class="scan-modal-bg"></view>
  87. <view class="scan-modal-pic main-center">
  88. <view class="info-model cross-center dir-top-nowrap">
  89. <view class="order-title">订单金额</view>
  90. <view class="info-box dir-left-nowrap cross-center">
  91. <input focus class="info-input" @input="setTempInput" :value="tmp_price" type="digit"
  92. placeholder-class="place" placeholder="输入支付金额"/>
  93. <view>元</view>
  94. </view>
  95. <view class="info-end dir-left-nowrap cross-center">
  96. <view @click="closePriceModel" class="box-grow-1 main-center cross-center">取消</view>
  97. <view class="box-grow-0 info-line"></view>
  98. <view @click="calcPrice" class="box-grow-1 red main-center cross-center">确认</view>
  99. </view>
  100. </view>
  101. </view>
  102. </view>
  103. </app-layout>
  104. </template>
  105. <script>
  106. export default {
  107. name: "index",
  108. components: {},
  109. data() {
  110. return {
  111. page_loading: true,
  112. tmp_price: '',
  113. clerk_user_id: 0,
  114. edit_status: true,
  115. price_modal: false,
  116. activity: {},
  117. remark: '',
  118. integral: {
  119. user_integral_num: '0',
  120. },
  121. list: {
  122. price: '',
  123. pay_price: 0.00,
  124. use_integral: 0,
  125. activity_id: 0,
  126. coupon_id: 0,
  127. can_coupon_num: 0,
  128. integral_explain: [],
  129. },
  130. clear: false,
  131. }
  132. },
  133. onShow: function () {
  134. const self = this;
  135. const userCoupon = self.$store.state.scanCode.userCoupon;
  136. if (userCoupon) {
  137. if (userCoupon == -1) {
  138. self.list.coupon_id = 0
  139. } else {
  140. self.list.coupon_id = userCoupon.id;
  141. }
  142. self.calcPrice();
  143. } else {
  144. self.list.coupon_id = 0
  145. }
  146. if (self.clear) {
  147. [
  148. self.edit_status,
  149. self.clear,
  150. self.remark,
  151. self.tmp_price,
  152. self.list,
  153. ] = [
  154. true,
  155. false,
  156. '',
  157. '',
  158. {
  159. price: '',
  160. pay_price: 0.00,
  161. use_integral: 0,
  162. activity_id: 0,
  163. coupon_id: 0,
  164. can_coupon_num: 0,
  165. integral_explain: [],
  166. }
  167. ]
  168. }
  169. },
  170. onLoad(options) { this.$commonLoad.onload(options);
  171. const self = this;
  172. self.$store.commit('scanCode/mutSetUserCoupon', 0);
  173. self.clear = true;
  174. if (options.clerk_user_id) {
  175. self.clerk_user_id = options.clerk_user_id;
  176. }
  177. if (options.price) {
  178. [self.edit_status, self.tmp_price,] = [false, options.price];
  179. self.calcPrice();
  180. }
  181. self.$showLoading({text: '加载中'});
  182. self.$request({
  183. url: self.$api.scan_code_pay.index
  184. }).then(info => {
  185. self.$hideLoading();
  186. if (info.code === 0) {
  187. [
  188. self.activity,
  189. self.goods,
  190. self.integral,
  191. self.setting
  192. ] = [
  193. info.data.activity ? info.data.activity : {},
  194. info.data.goods,
  195. info.data.integral,
  196. info.data.setting
  197. ];
  198. }
  199. }).catch(info => {
  200. self.$hideLoading();
  201. })
  202. },
  203. methods: {
  204. openPriceModel() {
  205. if (!this.edit_status) return;
  206. this.price_modal = true;
  207. },
  208. closePriceModel() {
  209. this.price_modal = false;
  210. },
  211. setTempInput: function (e) {
  212. this.tmp_price = this.money(e.detail.value);
  213. },
  214. money(val) {
  215. let num = val.toString(); //先转换成字符串类型
  216. if (num.indexOf('.') == 0) { //第一位就是 .
  217. num = '0' + num
  218. }
  219. num = num.replace(/[^\d.]/g, ""); //清除“数字”和“.”以外的字符
  220. num = num.replace(/\.{2,}/g, "."); //只保留第一个. 清除多余的
  221. num = num.replace(".", "$#$").replace(/\./g, "").replace("$#$", ".");
  222. num = num.replace(/^(\-)*(\d+)\.(\d\d).*$/, '$1$2.$3'); //只能输入两个小数
  223. if (num.indexOf(".") < 0 && num != "") {
  224. num = parseFloat(num);
  225. }
  226. return +num
  227. },
  228. priceChange() {
  229. if (this.tmp_price > 100000) {
  230. this.tmp_price = 100000.00;
  231. }
  232. },
  233. //总价
  234. calcPrice: function () {
  235. const self = this;
  236. self.priceChange();
  237. self.price_modal = false;
  238. self.$showLoading({text: '加载中'});
  239. self.$request({
  240. url: self.$api.scan_code_pay.preview,
  241. data: {
  242. price: self.tmp_price,
  243. coupon_id: self.list.coupon_id,
  244. use_integral: self.list.use_integral,
  245. clerk_user_id: self.clerk_user_id
  246. },
  247. method: 'POST',
  248. }).then(info => {
  249. self.$hideLoading();
  250. if (info.code === 0) {
  251. [self.list, self.tmp_price] = [info.data, info.data.price];
  252. } else {
  253. uni.showToast({icon: 'none', title: info.msg});
  254. }
  255. }).catch(info => {
  256. self.$hideLoading();
  257. })
  258. },
  259. //UseIntegral
  260. handleUseIntegral() {
  261. const self = this;
  262. let list = self.list;
  263. list.use_integral = list.use_integral == 1 ? 0 : 1;
  264. self.calcPrice();
  265. },
  266. //Remark
  267. bindTextBlur: function (e) {
  268. this.remark = e.detail.value;
  269. },
  270. //Integral
  271. getIntegralInfo: function (e) {
  272. let content = '';
  273. this.list.integral_explain.map(v => {
  274. content += '消费满' + v.consume_money + '元,';
  275. content += '积分最多可抵' + v.integral_deduction + '元';
  276. content += '\r\n';
  277. });
  278. uni.showModal({
  279. title: '积分抵扣说明',
  280. content: content.trim(),
  281. showCancel: false
  282. })
  283. },
  284. //navigate
  285. setCoupon: function (e) {
  286. this.clear = false;
  287. uni.navigateTo({
  288. url: '/plugins/scan_code/index/coupon?price=' + this.list.price + '&coupon_id=' + this.list.coupon_id,
  289. });
  290. },
  291. submit: function (e) {
  292. const self = this;
  293. if (!self.list.price) return
  294. self.$showLoading({text: '正在提交'});
  295. self.$request({
  296. url: self.$api.scan_code_pay.submit,
  297. method: 'post',
  298. data: {
  299. price: self.list.price,
  300. coupon_id: self.list.coupon_id,
  301. use_integral: self.list.use_integral,
  302. remark: self.remark,
  303. clerk_user_id: self.clerk_user_id
  304. },
  305. }).then(e => {
  306. self.$hideLoading();
  307. if (e.code === 0) {
  308. self.$payment.pay(e.data.pay_id).then(payMsg => {
  309. self.$store.commit('scanCode/mutSetUserCoupon', '');
  310. // 支付成功
  311. uni.showModal({
  312. title: '提示',
  313. content: "支付成功",
  314. showCancel: false,
  315. success() {
  316. uni.navigateTo({
  317. url: '/pages/order-submit/pay-result?payment_order_union_id=' + e.data.pay_id + '&plugin=scan_code_pay'
  318. })
  319. self.clear = true;
  320. },
  321. });
  322. }).catch(payMsg => {
  323. // 支付失败
  324. self.$showLoading({text: '取消中'});
  325. self.$request({
  326. url: self.$api.scan_code_pay.cancel,
  327. data: {
  328. pay_id: e.data.pay_id,
  329. },
  330. method: 'POST',
  331. }).then(info => {
  332. self.$hideLoading();
  333. }).catch(info => {
  334. self.$hideLoading();
  335. uni.showModal({title: '提示', content: info.msg});
  336. })
  337. });
  338. } else {
  339. uni.showModal({title: '提示', content: info.msg});
  340. }
  341. }).catch(e => {
  342. self.$hideLoading();
  343. });
  344. }
  345. }
  346. }
  347. </script>
  348. <style scoped lang="scss">
  349. .red {
  350. color: #ff4544;
  351. }
  352. .gray {
  353. color: #999999;
  354. }
  355. .scan-head {
  356. margin: #{20rpx} #{24rpx} 0 #{24rpx};
  357. background: #fff;
  358. border-radius: #{16rpx};
  359. padding: #{48rpx} #{40rpx} 0 #{40rpx};
  360. font-size: #{28rpx};
  361. color: #353535;
  362. .scan-line {
  363. height: 1px;
  364. margin-top: #{38rpx};
  365. background: #e2e2e2;
  366. }
  367. .scan-price {
  368. margin-top: #{32rpx};
  369. .order-key {
  370. font-size: #{50rpx};
  371. }
  372. .order-value {
  373. font-size: #{80rpx};
  374. padding-left: #{28rpx};
  375. height: #{98rpx};
  376. }
  377. }
  378. }
  379. .scan-offer {
  380. color: #666666;
  381. font-size: #{28rpx};
  382. margin-top: #{40rpx};
  383. .coupon-right {
  384. padding-right: #{12rpx};
  385. }
  386. .icon-right {
  387. background-size: 100% auto;
  388. background-repeat: no-repeat;
  389. background-image: url("../../../static/image/icon/arrow-right.png");
  390. width: #{12rpx};
  391. height: #{22rpx};
  392. }
  393. }
  394. .scan-integral-icon {
  395. height: #{36rpx};
  396. width: #{36rpx};
  397. background-image: url("../../../static/image/icon/warning.png");
  398. background-repeat: no-repeat;
  399. background-size: 100% auto;
  400. margin-left: #{20rpx};
  401. }
  402. .scan-integral-switch {
  403. width: #{44rpx};
  404. height: #{44rpx};
  405. background-size: 100% auto;
  406. background-repeat: no-repeat;
  407. float: left;
  408. }
  409. .scan-integral-switch.check {
  410. margin-left: #{5rpx};
  411. background-image: url("../../../static/image/icon/icon-checkbox-checked-a.png");
  412. }
  413. .scan-integral-switch.uncheck {
  414. margin-left: #{5rpx};
  415. background-image: url("../../../static/image/icon/icon-uncheck.png");
  416. }
  417. .scan-input {
  418. width: 100%;
  419. font-size: #{28rpx};
  420. color: #666;
  421. }
  422. .scan-remark {
  423. height: #{106rpx};
  424. .key {
  425. margin-left: auto;
  426. color: #353535;
  427. font-size: #{28rpx};
  428. }
  429. .value {
  430. margin-left: #{10rpx};
  431. color: #ff4544;
  432. font-size: #{36rpx};
  433. }
  434. }
  435. .scan-end {
  436. color: #666;
  437. background: #fff;
  438. margin: 0 #{24rpx};
  439. font-size: #{28rpx};
  440. border-radius: #{16rpx};
  441. padding: #{40rpx};
  442. text {
  443. word-break: break-all;
  444. text-align: justify;
  445. }
  446. }
  447. .scan-end > view {
  448. margin-bottom: #{12rpx};
  449. }
  450. .scan-end .icon {
  451. height: #{26rpx};
  452. width: #{8rpx};
  453. border-radius: #{4rpx};
  454. background: #ff4544;
  455. margin-right: #{16rpx};
  456. }
  457. .scan-btn {
  458. margin: #{40rpx} auto;
  459. }
  460. .scan-modal {
  461. position: fixed;
  462. left: 0;
  463. top: 0;
  464. width: 100%;
  465. height: 100%;
  466. z-index: 2001;
  467. transition: 200ms;
  468. }
  469. .scan-modal.show {
  470. visibility: visible;
  471. opacity: 1;
  472. }
  473. .scan-modal.bt {
  474. -webkit-animation-name: fadeIn; /*动画名称*/
  475. -webkit-animation-duration: 0.25s; /*动画持续时间*/
  476. -webkit-animation-iteration-count: 1; /*动画次数*/
  477. -webkit-animation-delay: 0s; /*延迟时间*/
  478. }
  479. .scan-modal .scan-modal-bg {
  480. background: rgba(0, 0, 0, 0.8);
  481. position: fixed;
  482. left: 0;
  483. top: 0;
  484. width: 100%;
  485. height: 100%;
  486. z-index: 1;
  487. }
  488. .scan-modal .scan-modal-pic {
  489. position: fixed;
  490. left: 0;
  491. top: #{188rpx};
  492. width: 100%;
  493. height: 100%;
  494. z-index: 1;
  495. }
  496. .scan-modal .scan-modal-close image {
  497. width: #{50rpx};
  498. height: #{50rpx};
  499. margin-top: #{50rpx};
  500. }
  501. .scan-modal .info-model {
  502. height: #{360rpx};
  503. width: #{620rpx};
  504. background: #fff;
  505. border-radius: #{16rpx};
  506. }
  507. .scan-modal .order-title {
  508. margin: #{48rpx} 0
  509. }
  510. .scan-modal .place {
  511. color: #cdcdcd
  512. }
  513. .scan-modal .info-box {
  514. height: #{88rpx};
  515. width: #{400rpx};
  516. margin-bottom: #{48rpx};
  517. border-radius: #{8rpx};
  518. padding: 0 #{24rpx};
  519. border: 1px solid #e2e2e2;
  520. }
  521. .scan-modal .info-input {
  522. font-size: #{32rpx};
  523. color: #353535;
  524. }
  525. .scan-modal .info-line {
  526. height: #{32rpx} !important;
  527. width: 1px !important;
  528. background: #e2e2e2;
  529. }
  530. .scan-modal .info-end {
  531. color: #666666;
  532. height: #{88rpx};
  533. font-size: #{32rpx};
  534. border-top: #{1rpx} solid #e2e2e2;
  535. width: 100%;
  536. }
  537. .scan-modal .info-end view {
  538. height: 100%;
  539. width: 100%;
  540. }
  541. </style>