coupon.vue 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723
  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. uni.showToast({
  277. icon:'none',
  278. title:res.data.message
  279. })
  280. }
  281. }
  282. })
  283. }
  284. }
  285. })
  286. }
  287. },
  288. confirm(e) {
  289. let data = {
  290. beginTime: this.selectRow.beginTime,
  291. endTime: this.selectRow.endTime,
  292. consumerId: this.selectRow.id,
  293. type: this.currentTab == '0' ? '3' : this.currentTab
  294. }
  295. if (e[0].value == 1) {
  296. uni.navigateTo({
  297. url: '/pages/coupon/storeUsers?params=' + encodeURIComponent(JSON.stringify(data))
  298. })
  299. } else {
  300. uni.navigateTo({
  301. url: '/pages/coupon/activity?row=' + encodeURIComponent(JSON.stringify(data))
  302. })
  303. }
  304. },
  305. manage() {
  306. if (this.currentTab == '0') {
  307. uni.navigateTo({
  308. url: '/pages/coupon/creatcoupon'
  309. })
  310. }
  311. if (this.currentTab == '1') {
  312. uni.navigateTo({
  313. url: '/pages/coupon/creatReduction'
  314. })
  315. }
  316. if (this.currentTab == '2') {
  317. uni.navigateTo({
  318. url: '/pages/coupon/creatDiscount'
  319. })
  320. }
  321. this.$store.state.shopSelectedIds = []
  322. },
  323. onTabChange(index) {
  324. this.dataList={
  325. couponList0: [],
  326. couponList1: [],
  327. couponList2: [],
  328. }
  329. let page = {
  330. num: 1,
  331. size: 10
  332. }
  333. this.currentTab = index
  334. if (index == 0) {
  335. this.getList(page)
  336. } else {
  337. this.getList1(page)
  338. }
  339. },
  340. // 详情
  341. handleDetail(id) {
  342. uni.navigateTo({
  343. url: `/pages/coupon/couponDetail?id=${id}&tab=${this.currentTab}`
  344. })
  345. },
  346. mescrollInit(mescroll) {
  347. this.mescroll = mescroll;
  348. },
  349. handleEdit(id) {
  350. // TODO: 实现编辑逻辑
  351. if (this.currentTab == '0') {
  352. uni.navigateTo({
  353. url: `/pages/coupon/creatcoupon?id=${id}`
  354. })
  355. }
  356. if (this.currentTab == '1') {
  357. uni.navigateTo({
  358. url: `/pages/coupon/creatReduction?id=${id}`
  359. })
  360. }
  361. if (this.currentTab == '2') {
  362. uni.navigateTo({
  363. url: `/pages/coupon/creatDiscount?id=${id}`
  364. })
  365. }
  366. this.$store.state.shopSelectedIds = []
  367. }
  368. },
  369. onLoad(options) {
  370. if (options && options.tab) {
  371. this.currentTab = options.tab
  372. } else {
  373. this.currentTab = 0
  374. }
  375. },
  376. onShow() {
  377. let page = {
  378. num: 1,
  379. size: 10
  380. }
  381. this.showPaymentPopup = false
  382. // if (this.currentTab == 1 || this.currentTab == 2) {
  383. // this.getList1(page)
  384. // }
  385. },
  386. }
  387. </script>
  388. <style lang="scss" scoped>
  389. .coupon-page {
  390. width: 100%;
  391. height: 100vh;
  392. background: #F7F8FC;
  393. display: flex;
  394. flex-direction: column;
  395. position: fixed;
  396. }
  397. .tab-container {
  398. padding: 16rpx 32rpx;
  399. background-color: #ffffff;
  400. }
  401. .tab-bar {
  402. position: relative;
  403. .tab-item {
  404. // padding: 12rpx 40rpx;
  405. height: 60rpx;
  406. line-height: 60rpx;
  407. text-align: center;
  408. width: 33.33%;
  409. font-size: 28rpx;
  410. color: #666;
  411. position: relative;
  412. border-radius: 8px;
  413. // margin-right: 20rpx;
  414. transition: all 0.3s;
  415. &.active {
  416. color: #449AFF;
  417. background: rgba(68, 154, 255, 0.05);
  418. font-weight: 500;
  419. border: 1px solid #449AFF;
  420. }
  421. &:last-child {
  422. margin-right: 0;
  423. }
  424. }
  425. }
  426. .coupon-card {
  427. background: linear-gradient(to right, #ffffff, #f8fbff);
  428. border-radius: 12rpx;
  429. // padding: 30rpx;
  430. margin: 26rpx 32rpx;
  431. box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.05);
  432. .card-header {
  433. display: flex;
  434. justify-content: space-between;
  435. align-items: center;
  436. // margin-bottom: 20rpx;
  437. padding: 10rpx 18rpx;
  438. image {
  439. width: 230rpx;
  440. height: 50rpx;
  441. }
  442. .status {
  443. font-size: 26rpx;
  444. color: #999;
  445. }
  446. }
  447. .amount-section {
  448. width: 40%;
  449. text-align: center;
  450. .amount {
  451. font-size: 80rpx;
  452. font-weight: bold;
  453. color: #02C1AB
  454. }
  455. .unit {
  456. font-size: 22rpx;
  457. color: #999999;
  458. margin-left: 4rpx;
  459. }
  460. .use-condition {
  461. margin-top: 10rpx;
  462. font-size: 22rpx;
  463. color: #888888;
  464. }
  465. }
  466. .info-section {
  467. .info-item {
  468. display: flex;
  469. align-items: center;
  470. margin-bottom: 16rpx;
  471. font-size: 26rpx;
  472. color: #666;
  473. .dot {
  474. color: #999;
  475. margin-right: 8rpx;
  476. }
  477. .label {
  478. color: #999;
  479. }
  480. .value {
  481. color: #333;
  482. }
  483. }
  484. }
  485. .backg-color1 {
  486. color: #2BC0AE;
  487. background: linear-gradient(90deg, #EFFFFE 0%, #F8FFFF 100%);
  488. }
  489. .backg-color2 {
  490. color: #5399D6;
  491. background: linear-gradient(90deg, #F4FAFF 0%, #FAFDFF 100%);
  492. }
  493. .backg-color3 {
  494. color: #E97C4F;
  495. background: linear-gradient(90deg, #FFF7F3 0%, #FFFBF8 100%);
  496. }
  497. .stats-section {
  498. display: flex;
  499. margin: 0 16rpx 13rpx 16rpx;
  500. padding: 13rpx 0;
  501. font-size: 24rpx;
  502. .stat-item {
  503. // margin-right: 40rpx;
  504. width: 33.33%;
  505. border-right: 1px solid #D4ECEA;
  506. text-align: center;
  507. &:last-child {
  508. margin-right: 0;
  509. }
  510. }
  511. .stat-item:last-child {
  512. border-right: none;
  513. }
  514. }
  515. .action-section {
  516. display: flex;
  517. justify-content: flex-end;
  518. // margin-top: 30rpx;
  519. border-top: 1px solid #EEEEEE;
  520. padding: 16rpx;
  521. .action-btn {
  522. border-radius: 4px 4px 4px 4px;
  523. margin-left: 27rpx;
  524. width: 190rpx;
  525. height: 43rpx;
  526. line-height: 43rpx;
  527. font-size: 24rpx;
  528. color: #333333;
  529. text-align: center;
  530. border: 1px solid #CCCCCC;
  531. }
  532. }
  533. }
  534. .handle {
  535. // height: 112rpx;
  536. display: flex;
  537. justify-content: space-between;
  538. align-items: center;
  539. padding: 78rpx 24rpx 32rpx 24rpx;
  540. position: relative;
  541. background: linear-gradient(90deg, #D8EAFF 4%, #E6F8F8 67%, #DDF1FA 100%), linear-gradient(#FFFFFF 0%, rgba(247, 248, 252, 0) 100%);
  542. .head_left {
  543. font-size: 40rpx;
  544. }
  545. .center {
  546. position: absolute;
  547. left: 50%;
  548. top: 65%;
  549. transform: translate(-50%, -50%);
  550. font-size: 36rpx;
  551. font-weight: 600;
  552. }
  553. .head_right {
  554. display: flex;
  555. justify-content: space-between;
  556. align-items: center;
  557. span {
  558. width: 40rpx;
  559. height: 40rpx;
  560. display: flex;
  561. justify-content: center;
  562. align-items: center;
  563. }
  564. .manage {
  565. // width: 150rpx;
  566. margin-left: 28rpx;
  567. }
  568. }
  569. }
  570. .payment-popup {
  571. padding: 30rpx;
  572. width: 570rpx;
  573. background: #FFFFFF;
  574. border-radius: 16rpx;
  575. .popup-header {
  576. display: flex;
  577. justify-content: space-between;
  578. align-items: center;
  579. padding-bottom: 20rpx;
  580. border-bottom: 1px solid #EEEEEE;
  581. .popup-title {
  582. font-size: 34rpx;
  583. color: #333;
  584. font-weight: 500;
  585. transform: translateX(180rpx);
  586. }
  587. .popup-icon {
  588. background: #DEDEDE;
  589. width: 39rpx;
  590. height: 39rpx;
  591. text-align: center;
  592. border-radius: 50%
  593. }
  594. }
  595. .popup-concant {
  596. height: 180rpx;
  597. font-weight: 500;
  598. font-size: 32rpx;
  599. color: #333333;
  600. flex-direction: column;
  601. view {
  602. margin: 16rpx;
  603. }
  604. }
  605. .payment-title {
  606. font-size: 28rpx;
  607. color: #333;
  608. margin-bottom: 20rpx;
  609. }
  610. .action-buttons {
  611. display: flex;
  612. margin-top: 20rpx;
  613. gap: 20rpx;
  614. padding-top: 20rpx;
  615. border-top: 1rpx solid #EEEEEE;
  616. .cancel-btn,
  617. .confirm-btn {
  618. flex: 1;
  619. height: 78rpx;
  620. line-height: 78rpx;
  621. text-align: center;
  622. border-radius: 44rpx;
  623. font-size: 28rpx;
  624. }
  625. .cancel-btn {
  626. background: #F5F6FA;
  627. color: #666;
  628. }
  629. .confirm-btn {
  630. background: #5B9CF9;
  631. color: #FFFFFF;
  632. }
  633. }
  634. }
  635. .fix {
  636. width: 100%;
  637. height: auto;
  638. background: #F7F8FC;
  639. position: sticky;
  640. top: 0px;
  641. /*#ifdef APP-PLUS*/
  642. .top {
  643. width: 100%;
  644. height: var(--status-bar-height);
  645. background: linear-gradient(87deg, #E2F4F8 0%, #A3CDFF 100%), linear-gradient(to bottom, #FFFFFF, #FFFFFF);
  646. }
  647. /* #endif */
  648. }
  649. .list {
  650. flex: 1;
  651. width: 100%;
  652. overflow-y: auto;
  653. background: #FFFFFF;
  654. }
  655. </style>