spendAndSaveCoupon_large.vue 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381
  1. <script lang="ts" setup>
  2. import { computed, ref } from 'vue'
  3. import ShortLinkModal from '@/components/ShortLinkModal.vue'
  4. import { getLastPartAfterSlash } from '@/utils/couponClassFormat'
  5. import { getImageUrl } from '@/utils/imageUtil'
  6. import { useCouponShare } from '../hooks/useCouponShare'
  7. import { getPlatformSource } from '@/utils/platformSource'
  8. const props = defineProps({
  9. coupon: {
  10. type: Object,
  11. default: () => ({
  12. ruleReductionAmount: '0',
  13. ruleMinSpendAmount: '0',
  14. }),
  15. },
  16. scrollViewId: {
  17. type: String,
  18. default: '',
  19. },
  20. enableCustomShare: {
  21. type: Boolean,
  22. default: false,
  23. }
  24. })
  25. const emit = defineEmits(['shareClick'])
  26. const coupon = computed(() => props.coupon)
  27. const couponTemplateId = computed(() => coupon.value.templateId || '')
  28. const deadline = computed(() => {
  29. const type = props.coupon.validityType
  30. if (type === '2') {
  31. return `自领取之日起${props.coupon.validDays}日内使用`
  32. }
  33. else if (type === '1') {
  34. return `限${props.coupon.validStartTime}到${props.coupon.validEndTime}日内使用`
  35. }
  36. return '长期有效'
  37. })
  38. const category = computed(() => {
  39. const relatedType = props.coupon.relatedType
  40. if (coupon.value?.relatedName && coupon.value?.relatedName !== 'null') {
  41. const relatedName = getLastPartAfterSlash(props.coupon.relatedName)
  42. if (relatedType === '2') {
  43. return `限${relatedName}分类商品使用`
  44. }
  45. else {
  46. return `限${relatedName}商品使用`
  47. }
  48. }
  49. return '不限商品分类'
  50. })
  51. // 分享弹窗相关 - 使用v-model控制弹窗显示
  52. const showShareModal = ref(false)
  53. const couponShareLink = ref('')
  54. const isExpand = ref(false);
  55. const { shareCoupon, ...shareHooks } = useCouponShare()
  56. // 调用分享弹窗
  57. async function handleShareCoupon() {
  58. // 确保有优惠券数据
  59. if (coupon.value.templateId) {
  60. // uni.showLoading({
  61. // title: '获取分享链接中...',
  62. // mask: true,
  63. // })
  64. try {
  65. const shareLink = await shareCoupon(couponTemplateId.value)
  66. if (shareLink) {
  67. couponShareLink.value = shareLink
  68. showShareModal.value = true
  69. if (props.enableCustomShare) {
  70. emit('shareClick', couponShareLink.value, shareHooks)
  71. }
  72. }
  73. }
  74. finally {
  75. // uni.hideLoading()
  76. }
  77. }
  78. }
  79. // 关闭分享弹窗
  80. function handleCloseShareModal() {
  81. console.log('分享弹窗已关闭')
  82. }
  83. </script>
  84. <template>
  85. <view class="discount-coupon">
  86. <image class="coupon-bg" :src="getImageUrl('@img/index/coupon3.png')" mode="aspectFit" />
  87. <view class="coupon-content-container">
  88. <view class="coupon-content">
  89. <view class="coupon-amount">
  90. <view class="coupon-amount-count">
  91. <view class="coupon-amount-count-icon">
  92. ¥
  93. </view>
  94. <view class="coupon-amount-count-number">
  95. {{ coupon?.ruleReductionAmount }}
  96. </view>
  97. </view>
  98. <view class="coupon-amount-text">
  99. 满{{ coupon?.ruleMinSpendAmount }}元可用
  100. </view>
  101. </view>
  102. <view class="coupon-info">
  103. <view class="coupon-info-category">
  104. {{ category }}
  105. </view>
  106. <view class="flex flex-row flex-nowrap text-[24rpx] text-[#666]">
  107. <view>使用规则:</view>
  108. <view class="text-blue" @tap="isExpand = !isExpand">{{ isExpand ? '收起' : '展开' }}</view>
  109. </view>
  110. <view class="coupon-info-time">
  111. <template v-if="coupon.validityType === '2'">
  112. <view>{{ deadline }}</view>
  113. </template>
  114. <template v-else-if="coupon.validityType === '1'">
  115. <!-- <view>使用日期</view> -->
  116. <view>{{ deadline }}</view>
  117. </template>
  118. <template v-else>
  119. <view>{{ deadline }}</view>
  120. </template>
  121. </view>
  122. </view>
  123. </view>
  124. <view class="discount-btn">
  125. <button class="coupon-btn-container" @click="handleShareCoupon">
  126. <view>立即</view>
  127. <view>发券</view>
  128. </button>
  129. <template v-if="!enableCustomShare">
  130. <ShortLinkModal v-model:show-modal="showShareModal" :coupon-id="couponTemplateId"
  131. :share-link="couponShareLink" :scroll-view-id="scrollViewId" :share-hooks="shareHooks"
  132. @close="handleCloseShareModal" />
  133. </template>
  134. </view>
  135. </view>
  136. <view :class="['coupon-express-info', isExpand ? 'expanded' : 'collapsed']">
  137. <view class="info-content">
  138. <view class="info-item">
  139. <view class="item-title">券类型:</view>
  140. <view class="item-content">{{ coupon.type === '2' ? '折扣券' : '满减券' }}</view>
  141. </view>
  142. <view class="info-item">
  143. <view class="item-title">限定地区:</view>
  144. <view class="item-content">
  145. {{ coupon?.locality && coupon?.locality !== 'null' ?
  146. `仅可在${coupon?.locality}地区的商户使用` : '不限地区' }}
  147. </view>
  148. </view>
  149. <view class="info-item">
  150. <view class="item-title">限定商户:</view>
  151. <view class="item-content">
  152. {{ coupon?.storeName && coupon?.storeName !== 'null' ?
  153. `仅限${coupon?.storeName}商户使用` : '不限商户' }}
  154. </view>
  155. </view>
  156. <view class="info-item">
  157. <view class="item-title">限定商品:</view>
  158. <view class="item-content">{{ category }}</view>
  159. </view>
  160. <view class="info-item">
  161. <view class="item-title">限定平台:</view>
  162. <view class="item-content">{{ getPlatformSource(coupon?.platformSource) }}</view>
  163. </view>
  164. </view>
  165. </view>
  166. </view>
  167. </template>
  168. <style lang="scss" scoped>
  169. .discount-coupon {
  170. // width: 670rpx;
  171. width: 100%;
  172. max-width: 800rpx;
  173. min-height: 200rpx;
  174. position: relative;
  175. overflow: hidden;
  176. .coupon-bg {
  177. position: absolute;
  178. top: 0;
  179. left: 0;
  180. right: 0;
  181. width: 100%;
  182. height: 200rpx;
  183. z-index: 1;
  184. object-fit: cover;
  185. }
  186. .coupon-content-container {
  187. // position: absolute;
  188. width: 100%;
  189. height: 200rpx;
  190. display: flex;
  191. flex-direction: row;
  192. flex-wrap: nowrap;
  193. .coupon-content {
  194. height: 161.5rpx;
  195. width: calc(100% - 27.68%);
  196. padding-top: 18rpx;
  197. padding-left: 20rpx;
  198. padding-bottom: 20rpx;
  199. display: flex;
  200. flex-direction: row;
  201. gap: 3rpx;
  202. z-index: 2;
  203. .coupon-amount {
  204. height: 100%;
  205. width: 32%;
  206. display: flex;
  207. flex-direction: column;
  208. justify-content: center;
  209. align-items: center;
  210. .coupon-amount-count {
  211. display: flex;
  212. flex-direction: row;
  213. flex-wrap: nowrap;
  214. align-items: baseline;
  215. .coupon-amount-count-icon {
  216. font-weight: 500;
  217. font-size: 27rpx;
  218. color: #f83003;
  219. }
  220. .coupon-amount-count-number {
  221. font-weight: 500;
  222. font-size: 70rpx;
  223. color: #f83003;
  224. clear: both;
  225. }
  226. }
  227. .coupon-amount-text {
  228. font-weight: 400;
  229. font-size: 24rpx;
  230. color: #f3513b;
  231. }
  232. }
  233. .coupon-info {
  234. height: 100%;
  235. width: 68%;
  236. display: flex;
  237. flex-direction: column;
  238. justify-content: space-evenly;
  239. padding-left: 18rpx;
  240. .coupon-info-category {
  241. font-weight: bold;
  242. font-size: 28rpx;
  243. color: #333333;
  244. }
  245. .coupon-info-time {
  246. // padding-top: 14rpx;
  247. display: flex;
  248. flex-direction: column;
  249. gap: 5rpx;
  250. font-weight: 400;
  251. font-size: 22rpx;
  252. color: #888888;
  253. }
  254. }
  255. }
  256. .discount-btn {
  257. z-index: 2;
  258. height: 100%;
  259. width: 27.68%;
  260. display: flex;
  261. justify-content: center;
  262. align-items: center;
  263. .coupon-btn-container {
  264. width: 115rpx;
  265. height: 115rpx;
  266. transform: translateX(7rpx);
  267. padding: 17rpx 20rpx 18rpx 20rpx;
  268. background-color: transparent;
  269. border: none;
  270. font-weight: 500;
  271. font-size: 28rpx;
  272. color: #ffffff;
  273. line-height: 41rpx;
  274. &::after {
  275. border: none;
  276. position: unset;
  277. height: inherit;
  278. }
  279. }
  280. }
  281. }
  282. .coupon-express-info {
  283. margin-top: -15rpx;
  284. padding: 20rpx 30rpx;
  285. padding-top: 35rpx;
  286. width: calc(100% - 82rpx);
  287. border-left: 11rpx solid #ff792f;
  288. border-right: 11rpx solid #ff2c43;
  289. // border-bottom: 11rpx solid transparent;
  290. // border-image-slice: 1;
  291. // border-image: linear-gradient(to right, #ff792f, #ff2c43);
  292. position: relative;
  293. background-color: #f9f9f9;
  294. border-bottom-left-radius: 21rpx;
  295. border-bottom-right-radius: 21rpx;
  296. overflow: hidden;
  297. transition: all 0.6s cubic-bezier(0.34, 1.56, 0.64, 1);
  298. &::after {
  299. content: '';
  300. position: absolute;
  301. left: 0;
  302. bottom: 0;
  303. width: 100%;
  304. height: 11rpx; // 底部边框宽度
  305. background: linear-gradient(to right, #ff792f, #ff2c43);
  306. z-index: 0;
  307. // 处理圆角
  308. border-bottom-left-radius: 21rpx;
  309. border-bottom-right-radius: 21rpx;
  310. }
  311. .info-content {
  312. display: flex;
  313. flex-direction: column;
  314. align-items: flex-start;
  315. gap: 20rpx;
  316. .info-item {
  317. display: flex;
  318. flex-direction: row;
  319. flex-wrap: nowrap;
  320. align-items: center;
  321. justify-content: flex-start;
  322. gap: 10rpx;
  323. color: #666;
  324. font-weight: bold;
  325. font-size: 26rpx;
  326. .item-title {
  327. flex: 1;
  328. width: 160rpx;
  329. font-weight: bolder;
  330. }
  331. }
  332. }
  333. }
  334. /* 收起状态 */
  335. .coupon-express-info.collapsed {
  336. opacity: 0;
  337. max-height: 0;
  338. padding-top: 0;
  339. padding-bottom: 0;
  340. border-top-width: 0;
  341. border-bottom-width: 0;
  342. }
  343. /* 展开状态 */
  344. .coupon-express-info.expanded {
  345. opacity: 1;
  346. max-height: 500rpx;
  347. /* 设置一个足够大的值以容纳所有内容 */
  348. }
  349. }
  350. </style>