coupon.vue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719
  1. <template>
  2. <view class="coupon-page">
  3. <view class="fix">
  4. <view class="top"></view>
  5. <view class="handle">
  6. <view class="head_left">
  7. <span class="cuIcon-back" @click="back"></span>
  8. </view>
  9. <span class="center">商家优惠券</span>
  10. <view class="head_right">
  11. <!-- <span class="cuIcon-search" @click="goSearch"></span> -->
  12. <view class="manage" @click="manage">
  13. 添加
  14. </view>
  15. </view>
  16. </view>
  17. <!-- 顶部标签页 -->
  18. <view class="tab-container ">
  19. <view class="tab-bar flex justify-between items-center">
  20. <view v-for="(item, index) in tabList" :key="index" class="tab-item" :class="{ active: currentTab === index }"
  21. @click="onTabChange(index)">
  22. {{ item.name }}
  23. </view>
  24. </view>
  25. </view>
  26. </view>
  27. <mescroll-uni class="list" :fixed="false" ref="mescrollRef" @up="getList" @init="mescrollInit" :use="false">
  28. <!-- 代金券列表 -->
  29. <view class="coupon-card" v-for="(item, index) in dataList[`couponList${currentTab}`]" :key="item.id"
  30. @click="handleDetail(item.id)" :class="{ 'disabled': item.status === 'expired' }">
  31. <!-- 顶部标题栏 -->
  32. <view class="card-header"
  33. :style="currentTab == 0 ? 'background: #EFFFFE' : currentTab == 1 ? 'background: #F4FAFF ' : 'background: #FFF7F3'">
  34. <image style=" vertical-align: top" :src="`/static/coupon/titlebg${currentTab + 1}.png`" mode="">
  35. </image>
  36. <view class="status" v-if="item.delFlag == '1'"
  37. :style="currentTab == 0 ? 'color: #2DAC9F' : currentTab == 1 ? 'color: #4183BC' : 'color: #DB6332'">
  38. 销售中
  39. </view>
  40. <view class="status" v-else>{{ item.delFlag == '0' ? '待上架' : item.delFlag == '3' ? '已失效' : '' }}
  41. </view>
  42. </view>
  43. <view class="flex" style="padding: 14rpx 18rpx;">
  44. <!-- 优惠券金额 -->
  45. <view class="amount-section">
  46. <text class="amount" v-if="currentTab == 0">{{ item.parValue }}</text>
  47. <text class="amount" v-else :style="currentTab == 1 ? 'color: #278BE5' : 'color: #FB5308'">{{
  48. item.contentInfo }}</text>
  49. <text class="unit" v-if="currentTab == 2">折</text>
  50. <text class="unit" v-else>元</text>
  51. <view class="use-condition" v-if="currentTab == 0 && item.voucherWay == '1'">售价{{
  52. item.voucherWayInfo
  53. }}元</view>
  54. <view class="use-condition" v-if="currentTab == 1 && item.contentConditions !== '0'">满{{
  55. item.contentConditions }}元可抵扣</view>
  56. <view class="use-condition" v-if="currentTab == 2 && item.contentConditions !== '0'">满{{
  57. item.contentConditions }}元可使用</view>
  58. <view class="use-condition" v-if="currentTab !== 0 && item.contentConditions == '0'">不限制条件使用
  59. </view>
  60. </view>
  61. <!-- 优惠券信息 -->
  62. <view class="info-section">
  63. <view class="info-item">
  64. <text class="dot">•</text>
  65. <text class="label" v-if="currentTab == 0">获取方式:</text>
  66. <text class="label" v-else>领取限制:</text>
  67. <text class="value" v-if="currentTab == 0">{{ item.voucherWay == '1' ? '购买' : '消费满' +
  68. item.voucherWayInfo + '元可领取' }}</text>
  69. <text class="value" v-else>{{ item.couponWay == '1' ? '所有人可领取' : '本店消费可领' }}</text>
  70. </view>
  71. <view class="info-item">
  72. <text class="dot">•</text>
  73. <text class="label" v-if="currentTab == 0">使用条件:</text>
  74. <text class="label" v-else>适用范围:</text>
  75. <text class="value" v-if="currentTab == 0">{{ item.conditions == '0' ? '不限制' : '最低消费' +
  76. item.conditions + '元' }}</text>
  77. <text class="value" v-else>{{
  78. item.couponRange == '1' ? '本店可用' : item.couponRange == '2' ? '部分分类商品可用' : '部分分类商品不可用'
  79. }}</text>
  80. </view>
  81. <view class="info-item">
  82. <text class="dot">•</text>
  83. <text class="label">有效期:</text>
  84. <text class="value">{{ item.beginTime + '/' + item.endTime }}</text>
  85. </view>
  86. </view>
  87. </view>
  88. <!-- 数量统计 -->
  89. <view class="stats-section flex"
  90. :class="currentTab == 0 ? 'backg-color1' : currentTab == 1 ? 'backg-color2' : 'backg-color3'">
  91. <text class="stat-item" v-if="currentTab == 0 && item.voucherWay == '1'">已购买:{{ item.payNumber }}</text>
  92. <text class="stat-item" v-else>已领取:{{ item.payNumber }}</text>
  93. <text class="stat-item">已使用:{{ item.useNumber }}</text>
  94. <text class="stat-item">总库存:{{ item.number }}</text>
  95. </view>
  96. <!-- 操作按钮 -->
  97. <view class="action-section">
  98. <text class="action-btn" v-if="item.delFlag == '0' || item.delFlag == '3'"
  99. @click.stop="handleAction('up', item)">上架</text>
  100. <text class="action-btn" v-if="item.delFlag == '1'" @click.stop="handleAction('down', item)">下架</text>
  101. <text class="action-btn" v-if="item.delFlag == '1' && item.voucherWay !== 1"
  102. @click.stop="handleAction('grant', item)">发放</text>
  103. <text class="action-btn" v-if="item.delFlag == '0' || item.delFlag == '3'"
  104. @click.stop="handleEdit(item.id)">编辑</text>
  105. </view>
  106. </view>
  107. </mescroll-uni>
  108. <u-select mode="single-column" :list="grantoptions" label-name="label" value-name="value" v-model="show"
  109. @confirm="confirm($event)"></u-select>
  110. <!-- 底部支付弹框 -->
  111. <u-popup v-model="showPaymentPopup" mode="center" :round="10">
  112. <view class="payment-popup">
  113. <view class="popup-header">
  114. <text class="popup-title">上架优惠券</text>
  115. <view class="popup-icon">
  116. <u-icon name="close" size="20" @click="closePaymentPopup"></u-icon>
  117. </view>
  118. </view>
  119. <view class="popup-concant flex align-center justify-center">
  120. <view>当前优惠券上架</view>
  121. <view>需重新设置有效时间</view>
  122. </view>
  123. <view class="action-buttons">
  124. <view class="cancel-btn" @click="closePaymentPopup">取消</view>
  125. <view class="confirm-btn" @click="handleEdit(selectRow.id)">去设置</view>
  126. </view>
  127. </view>
  128. </u-popup>
  129. </view>
  130. </template>
  131. <script>
  132. import {
  133. USER_INFO
  134. } from "@/common/util/constants"
  135. export default {
  136. data() {
  137. return {
  138. showPaymentPopup: false,
  139. show: false,
  140. grantoptions: [{
  141. value: '1',
  142. label: '本店消费用户'
  143. },
  144. {
  145. value: '2',
  146. label: '本店特定商品消费用户'
  147. }
  148. ],
  149. currentTab: 0,
  150. tabList: [{
  151. name: '代金券'
  152. },
  153. {
  154. name: '满减券'
  155. },
  156. {
  157. name: '折扣券'
  158. }
  159. ],
  160. activeItemStyle: {
  161. backgroundColor: 'rgba(41, 121, 255, 0.1)',
  162. borderRadius: '32rpx',
  163. transition: 'all 0.3s'
  164. },
  165. dataList: {
  166. couponList0: [],
  167. couponList1: [],
  168. couponList2: [],
  169. },
  170. reductionList: [],
  171. discountList: [],
  172. selectRow: {},
  173. upOption: {
  174. page: {
  175. num: 0,
  176. size: 10 // 每页数据的数量,默认10
  177. },
  178. noMoreSize: 5, // 配置列表的总数量要大于等于5条才显示'-- END --'的提示
  179. empty: {
  180. tip: '暂无相关数据'
  181. }
  182. },
  183. }
  184. },
  185. methods: {
  186. closePaymentPopup() {
  187. this.showPaymentPopup = false
  188. },
  189. getList(page) {
  190. this.$http.post('/merchant/localVoucherInfo/list', {
  191. merchantId: uni.getStorageSync(USER_INFO).merchantId,
  192. pageSize: page.size,
  193. pageNo: page.num
  194. }).then(res => {
  195. if (res.data.success) {
  196. if (res.data.result.records == null && page.num == 1) {
  197. this.dataList.couponList0 = []
  198. } else {
  199. this.dataList.couponList0 = res.data.result.pages ? this.dataList.couponList0.concat(res.data.result
  200. .records) : this.dataList.couponList0
  201. }
  202. this.mescroll.endSuccess(res.data.result.records.length, res.data.result.total);
  203. uni.showTabBar()
  204. } else {
  205. this.dataList.couponList0 = []
  206. this.mescroll.endErr()
  207. }
  208. }).catch(() => {
  209. this.mescroll.endErr()
  210. })
  211. },
  212. getList1(page) {
  213. this.$http.post('/merchant/localCouponInfo/list', {
  214. merchantId: uni.getStorageSync(USER_INFO).merchantId,
  215. type: this.currentTab,
  216. pageSize: page.size,
  217. pageNo: page.num
  218. }).then(res => {
  219. if (res.data.success) {
  220. this.dataList['couponList' + this.currentTab] = res.data.result.pages ? this.dataList['couponList' + this
  221. .currentTab].concat(res.data.result.records) : this.dataList['couponList' + this.currentTab]
  222. } else {
  223. this.$tip.error(res.data.message);
  224. }
  225. })
  226. },
  227. //返回
  228. back() {
  229. uni.navigateBack({
  230. delta: 1
  231. });
  232. },
  233. handleAction(type, item) {
  234. this.selectRow = item
  235. if (type == 'grant') {
  236. this.show = true
  237. }
  238. if (type == 'up' || type == 'down') {
  239. uni.showModal({
  240. title: type == 'up' ? '上架优惠券' : '下架优惠券',
  241. content: type == 'up' ? '当前优惠券确定上架?' : '当前优惠券确定下架?',
  242. success: (res) => {
  243. if (res.confirm) {
  244. let upDown = ['/merchant/localVoucherInfo/editUpper', '/merchant/localCouponInfo/editUpper',
  245. '/merchant/localCouponInfo/editUpper'
  246. ]
  247. this.$http.get(upDown[this.currentTab], {
  248. params: {
  249. id: item.id,
  250. delFlag: type == 'up' ? '1' : '0'
  251. }
  252. }).then(res => {
  253. if (res.data.success) {
  254. let page = {
  255. num: 1,
  256. size: 10
  257. }
  258. if (this.currentTab == 0) {
  259. this.dataList.couponList0 = []
  260. this.getList(page)
  261. } else {
  262. this.dataList['couponList' + this.currentTab] = []
  263. this.getList1(page)
  264. }
  265. } else {
  266. if (res.data.message == "当前优惠卷上架需重新设置有效时间") {
  267. this.showPaymentPopup = true
  268. // uni.showModal({
  269. // title: '上架优惠券' ,
  270. // content:`当前优惠卷上架}`,
  271. // success: (res) => {
  272. // }
  273. // })
  274. } else {
  275. this.$tip.error(res.data.message);
  276. }
  277. }
  278. })
  279. }
  280. }
  281. })
  282. }
  283. },
  284. confirm(e) {
  285. let data = {
  286. beginTime: this.selectRow.beginTime,
  287. endTime: this.selectRow.endTime,
  288. consumerId: this.selectRow.id,
  289. type: this.currentTab == '0' ? '3' : this.currentTab
  290. }
  291. if (e[0].value == 1) {
  292. uni.navigateTo({
  293. url: '/pages/coupon/storeUsers?params=' + encodeURIComponent(JSON.stringify(data))
  294. })
  295. } else {
  296. uni.navigateTo({
  297. url: '/pages/coupon/activity?row=' + encodeURIComponent(JSON.stringify(data))
  298. })
  299. }
  300. },
  301. manage() {
  302. if (this.currentTab == '0') {
  303. uni.navigateTo({
  304. url: '/pages/coupon/creatcoupon'
  305. })
  306. }
  307. if (this.currentTab == '1') {
  308. uni.navigateTo({
  309. url: '/pages/coupon/creatReduction'
  310. })
  311. }
  312. if (this.currentTab == '2') {
  313. uni.navigateTo({
  314. url: '/pages/coupon/creatDiscount'
  315. })
  316. }
  317. this.$store.state.shopSelectedIds = []
  318. },
  319. onTabChange(index) {
  320. this.dataList={
  321. couponList0: [],
  322. couponList1: [],
  323. couponList2: [],
  324. }
  325. let page = {
  326. num: 1,
  327. size: 10
  328. }
  329. this.currentTab = index
  330. if (index == 0) {
  331. this.getList(page)
  332. } else {
  333. this.getList1(page)
  334. }
  335. },
  336. // 详情
  337. handleDetail(id) {
  338. uni.navigateTo({
  339. url: `/pages/coupon/couponDetail?id=${id}&tab=${this.currentTab}`
  340. })
  341. },
  342. mescrollInit(mescroll) {
  343. this.mescroll = mescroll;
  344. },
  345. handleEdit(id) {
  346. // TODO: 实现编辑逻辑
  347. if (this.currentTab == '0') {
  348. uni.navigateTo({
  349. url: `/pages/coupon/creatcoupon?id=${id}`
  350. })
  351. }
  352. if (this.currentTab == '1') {
  353. uni.navigateTo({
  354. url: `/pages/coupon/creatReduction?id=${id}`
  355. })
  356. }
  357. if (this.currentTab == '2') {
  358. uni.navigateTo({
  359. url: `/pages/coupon/creatDiscount?id=${id}`
  360. })
  361. }
  362. this.$store.state.shopSelectedIds = []
  363. }
  364. },
  365. onLoad(options) {
  366. if (options && options.tab) {
  367. this.currentTab = options.tab
  368. } else {
  369. this.currentTab = 0
  370. }
  371. },
  372. onShow() {
  373. let page = {
  374. num: 1,
  375. size: 10
  376. }
  377. this.showPaymentPopup = false
  378. // if (this.currentTab == 1 || this.currentTab == 2) {
  379. // this.getList1(page)
  380. // }
  381. },
  382. }
  383. </script>
  384. <style lang="scss" scoped>
  385. .coupon-page {
  386. width: 100%;
  387. height: 100vh;
  388. background: #F7F8FC;
  389. display: flex;
  390. flex-direction: column;
  391. position: fixed;
  392. }
  393. .tab-container {
  394. padding: 16rpx 32rpx;
  395. background-color: #ffffff;
  396. }
  397. .tab-bar {
  398. position: relative;
  399. .tab-item {
  400. // padding: 12rpx 40rpx;
  401. height: 60rpx;
  402. line-height: 60rpx;
  403. text-align: center;
  404. width: 33.33%;
  405. font-size: 28rpx;
  406. color: #666;
  407. position: relative;
  408. border-radius: 8px;
  409. // margin-right: 20rpx;
  410. transition: all 0.3s;
  411. &.active {
  412. color: #449AFF;
  413. background: rgba(68, 154, 255, 0.05);
  414. font-weight: 500;
  415. border: 1px solid #449AFF;
  416. }
  417. &:last-child {
  418. margin-right: 0;
  419. }
  420. }
  421. }
  422. .coupon-card {
  423. background: linear-gradient(to right, #ffffff, #f8fbff);
  424. border-radius: 12rpx;
  425. // padding: 30rpx;
  426. margin: 26rpx 32rpx;
  427. box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.05);
  428. .card-header {
  429. display: flex;
  430. justify-content: space-between;
  431. align-items: center;
  432. // margin-bottom: 20rpx;
  433. padding: 10rpx 18rpx;
  434. image {
  435. width: 230rpx;
  436. height: 50rpx;
  437. }
  438. .status {
  439. font-size: 26rpx;
  440. color: #999;
  441. }
  442. }
  443. .amount-section {
  444. width: 40%;
  445. text-align: center;
  446. .amount {
  447. font-size: 80rpx;
  448. font-weight: bold;
  449. color: #02C1AB
  450. }
  451. .unit {
  452. font-size: 22rpx;
  453. color: #999999;
  454. margin-left: 4rpx;
  455. }
  456. .use-condition {
  457. margin-top: 10rpx;
  458. font-size: 22rpx;
  459. color: #888888;
  460. }
  461. }
  462. .info-section {
  463. .info-item {
  464. display: flex;
  465. align-items: center;
  466. margin-bottom: 16rpx;
  467. font-size: 26rpx;
  468. color: #666;
  469. .dot {
  470. color: #999;
  471. margin-right: 8rpx;
  472. }
  473. .label {
  474. color: #999;
  475. }
  476. .value {
  477. color: #333;
  478. }
  479. }
  480. }
  481. .backg-color1 {
  482. color: #2BC0AE;
  483. background: linear-gradient(90deg, #EFFFFE 0%, #F8FFFF 100%);
  484. }
  485. .backg-color2 {
  486. color: #5399D6;
  487. background: linear-gradient(90deg, #F4FAFF 0%, #FAFDFF 100%);
  488. }
  489. .backg-color3 {
  490. color: #E97C4F;
  491. background: linear-gradient(90deg, #FFF7F3 0%, #FFFBF8 100%);
  492. }
  493. .stats-section {
  494. display: flex;
  495. margin: 0 16rpx 13rpx 16rpx;
  496. padding: 13rpx 0;
  497. font-size: 24rpx;
  498. .stat-item {
  499. // margin-right: 40rpx;
  500. width: 33.33%;
  501. border-right: 1px solid #D4ECEA;
  502. text-align: center;
  503. &:last-child {
  504. margin-right: 0;
  505. }
  506. }
  507. .stat-item:last-child {
  508. border-right: none;
  509. }
  510. }
  511. .action-section {
  512. display: flex;
  513. justify-content: flex-end;
  514. // margin-top: 30rpx;
  515. border-top: 1px solid #EEEEEE;
  516. padding: 16rpx;
  517. .action-btn {
  518. border-radius: 4px 4px 4px 4px;
  519. margin-left: 27rpx;
  520. width: 190rpx;
  521. height: 43rpx;
  522. line-height: 43rpx;
  523. font-size: 24rpx;
  524. color: #333333;
  525. text-align: center;
  526. border: 1px solid #CCCCCC;
  527. }
  528. }
  529. }
  530. .handle {
  531. // height: 112rpx;
  532. display: flex;
  533. justify-content: space-between;
  534. align-items: center;
  535. padding: 78rpx 24rpx 32rpx 24rpx;
  536. position: relative;
  537. background: linear-gradient(90deg, #D8EAFF 4%, #E6F8F8 67%, #DDF1FA 100%), linear-gradient(#FFFFFF 0%, rgba(247, 248, 252, 0) 100%);
  538. .head_left {
  539. font-size: 40rpx;
  540. }
  541. .center {
  542. position: absolute;
  543. left: 50%;
  544. top: 65%;
  545. transform: translate(-50%, -50%);
  546. font-size: 36rpx;
  547. font-weight: 600;
  548. }
  549. .head_right {
  550. display: flex;
  551. justify-content: space-between;
  552. align-items: center;
  553. span {
  554. width: 40rpx;
  555. height: 40rpx;
  556. display: flex;
  557. justify-content: center;
  558. align-items: center;
  559. }
  560. .manage {
  561. // width: 150rpx;
  562. margin-left: 28rpx;
  563. }
  564. }
  565. }
  566. .payment-popup {
  567. padding: 30rpx;
  568. width: 570rpx;
  569. background: #FFFFFF;
  570. border-radius: 16rpx;
  571. .popup-header {
  572. display: flex;
  573. justify-content: space-between;
  574. align-items: center;
  575. padding-bottom: 20rpx;
  576. border-bottom: 1px solid #EEEEEE;
  577. .popup-title {
  578. font-size: 34rpx;
  579. color: #333;
  580. font-weight: 500;
  581. transform: translateX(180rpx);
  582. }
  583. .popup-icon {
  584. background: #DEDEDE;
  585. width: 39rpx;
  586. height: 39rpx;
  587. text-align: center;
  588. border-radius: 50%
  589. }
  590. }
  591. .popup-concant {
  592. height: 180rpx;
  593. font-weight: 500;
  594. font-size: 32rpx;
  595. color: #333333;
  596. flex-direction: column;
  597. view {
  598. margin: 16rpx;
  599. }
  600. }
  601. .payment-title {
  602. font-size: 28rpx;
  603. color: #333;
  604. margin-bottom: 20rpx;
  605. }
  606. .action-buttons {
  607. display: flex;
  608. margin-top: 20rpx;
  609. gap: 20rpx;
  610. padding-top: 20rpx;
  611. border-top: 1rpx solid #EEEEEE;
  612. .cancel-btn,
  613. .confirm-btn {
  614. flex: 1;
  615. height: 78rpx;
  616. line-height: 78rpx;
  617. text-align: center;
  618. border-radius: 44rpx;
  619. font-size: 28rpx;
  620. }
  621. .cancel-btn {
  622. background: #F5F6FA;
  623. color: #666;
  624. }
  625. .confirm-btn {
  626. background: #5B9CF9;
  627. color: #FFFFFF;
  628. }
  629. }
  630. }
  631. .fix {
  632. width: 100%;
  633. height: auto;
  634. background: #F7F8FC;
  635. position: sticky;
  636. top: 0px;
  637. /*#ifdef APP-PLUS*/
  638. .top {
  639. width: 100%;
  640. height: var(--status-bar-height);
  641. background: linear-gradient(87deg, #E2F4F8 0%, #A3CDFF 100%), linear-gradient(to bottom, #FFFFFF, #FFFFFF);
  642. }
  643. /* #endif */
  644. }
  645. .list {
  646. flex: 1;
  647. width: 100%;
  648. overflow-y: auto;
  649. background: #FFFFFF;
  650. }
  651. </style>