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. </view>
  93. <view class="coupon-amount-count-number">
  94. {{ coupon?.ruleReductionAmount }}
  95. </view>
  96. </view>
  97. <view class="coupon-amount-text">
  98. 满{{ coupon?.ruleMinSpendAmount }}元可用
  99. </view>
  100. </view>
  101. <view class="coupon-info">
  102. <view class="coupon-info-category">
  103. {{ category }}
  104. </view>
  105. <view class="flex flex-row flex-nowrap text-[24rpx] text-[#666]">
  106. <view>使用规则:</view>
  107. <view class="text-blue" @tap="isExpand = !isExpand">{{ isExpand ? '收起' : '展开' }}</view>
  108. </view>
  109. <view class="coupon-info-time">
  110. <template v-if="coupon.validityType === '2'">
  111. <view>{{ deadline }}</view>
  112. </template>
  113. <template v-else-if="coupon.validityType === '1'">
  114. <!-- <view>使用日期</view> -->
  115. <view>{{ deadline }}</view>
  116. </template>
  117. <template v-else>
  118. <view>{{ deadline }}</view>
  119. </template>
  120. </view>
  121. </view>
  122. </view>
  123. <view class="discount-btn">
  124. <button class="coupon-btn-container" @click="handleShareCoupon">
  125. <view>立即</view>
  126. <view>发券</view>
  127. </button>
  128. <template v-if="!enableCustomShare">
  129. <ShortLinkModal v-model:show-modal="showShareModal" :coupon-id="couponTemplateId"
  130. :share-link="couponShareLink" :scroll-view-id="scrollViewId" :share-hooks="shareHooks"
  131. @close="handleCloseShareModal" />
  132. </template>
  133. </view>
  134. </view>
  135. <view :class="['coupon-express-info', isExpand ? 'expanded' : 'collapsed']">
  136. <view class="info-content">
  137. <view class="info-item">
  138. <view class="item-title">券类型:</view>
  139. <view class="item-content">{{ coupon.type === '2' ? '折扣券' : '满减券' }}</view>
  140. </view>
  141. <view class="info-item">
  142. <view class="item-title">限定地区:</view>
  143. <view class="item-content">
  144. {{ coupon?.locality && coupon?.locality !== 'null' ?
  145. `仅可在${coupon?.locality}地区的商户使用` : '不限地区' }}
  146. </view>
  147. </view>
  148. <view class="info-item">
  149. <view class="item-title">限定商户:</view>
  150. <view class="item-content">
  151. {{ coupon?.storeName && coupon?.storeName !== 'null' ?
  152. `仅限${coupon?.storeName}商户使用` : '不限商户' }}
  153. </view>
  154. </view>
  155. <view class="info-item">
  156. <view class="item-title">限定商品:</view>
  157. <view class="item-content">{{ category }}</view>
  158. </view>
  159. <view class="info-item">
  160. <view class="item-title">限定平台:</view>
  161. <view class="item-content">{{ getPlatformSource(coupon?.platformSource) }}</view>
  162. </view>
  163. </view>
  164. </view>
  165. </view>
  166. </template>
  167. <style lang="scss" scoped>
  168. .discount-coupon {
  169. // width: 670rpx;
  170. width: 100%;
  171. max-width: 800rpx;
  172. min-height: 200rpx;
  173. position: relative;
  174. overflow: hidden;
  175. .coupon-bg {
  176. position: absolute;
  177. top: 0;
  178. left: 0;
  179. right: 0;
  180. width: 100%;
  181. height: 200rpx;
  182. z-index: 1;
  183. object-fit: cover;
  184. }
  185. .coupon-content-container {
  186. // position: absolute;
  187. width: 100%;
  188. height: 200rpx;
  189. display: flex;
  190. flex-direction: row;
  191. flex-wrap: nowrap;
  192. .coupon-content {
  193. height: 161.5rpx;
  194. width: calc(100% - 27.68%);
  195. padding-top: 18rpx;
  196. padding-left: 20rpx;
  197. padding-bottom: 20rpx;
  198. display: flex;
  199. flex-direction: row;
  200. gap: 3rpx;
  201. z-index: 2;
  202. .coupon-amount {
  203. height: 100%;
  204. width: 32%;
  205. display: flex;
  206. flex-direction: column;
  207. justify-content: center;
  208. align-items: center;
  209. .coupon-amount-count {
  210. display: flex;
  211. flex-direction: row;
  212. flex-wrap: nowrap;
  213. align-items: baseline;
  214. .coupon-amount-count-icon {
  215. font-weight: 500;
  216. font-size: 27rpx;
  217. color: #f83003;
  218. }
  219. .coupon-amount-count-number {
  220. font-weight: 500;
  221. font-size: 70rpx;
  222. color: #f83003;
  223. clear: both;
  224. }
  225. }
  226. .coupon-amount-text {
  227. font-weight: 400;
  228. font-size: 24rpx;
  229. color: #f3513b;
  230. }
  231. }
  232. .coupon-info {
  233. height: 100%;
  234. width: 68%;
  235. display: flex;
  236. flex-direction: column;
  237. justify-content: space-evenly;
  238. padding-left: 18rpx;
  239. .coupon-info-category {
  240. font-weight: bold;
  241. font-size: 28rpx;
  242. color: #333333;
  243. }
  244. .coupon-info-time {
  245. // padding-top: 14rpx;
  246. display: flex;
  247. flex-direction: column;
  248. gap: 5rpx;
  249. font-weight: 400;
  250. font-size: 22rpx;
  251. color: #888888;
  252. }
  253. }
  254. }
  255. .discount-btn {
  256. z-index: 2;
  257. height: 100%;
  258. width: 27.68%;
  259. display: flex;
  260. justify-content: center;
  261. align-items: center;
  262. .coupon-btn-container {
  263. width: 115rpx;
  264. height: 115rpx;
  265. transform: translateX(7rpx);
  266. padding: 17rpx 20rpx 18rpx 20rpx;
  267. background-color: transparent;
  268. border: none;
  269. font-weight: 500;
  270. font-size: 28rpx;
  271. color: #ffffff;
  272. line-height: 41rpx;
  273. &::after {
  274. border: none;
  275. position: unset;
  276. height: inherit;
  277. }
  278. }
  279. }
  280. }
  281. .coupon-express-info {
  282. margin-top: -15rpx;
  283. padding: 20rpx 30rpx;
  284. padding-top: 35rpx;
  285. width: calc(100% - 82rpx);
  286. border-left: 11rpx solid #ff792f;
  287. border-right: 11rpx solid #ff2c43;
  288. // border-bottom: 11rpx solid transparent;
  289. // border-image-slice: 1;
  290. // border-image: linear-gradient(to right, #ff792f, #ff2c43);
  291. position: relative;
  292. background-color: #f9f9f9;
  293. border-bottom-left-radius: 21rpx;
  294. border-bottom-right-radius: 21rpx;
  295. overflow: hidden;
  296. transition: all 0.6s cubic-bezier(0.34, 1.56, 0.64, 1);
  297. &::after {
  298. content: '';
  299. position: absolute;
  300. left: 0;
  301. bottom: 0;
  302. width: 100%;
  303. height: 11rpx; // 底部边框宽度
  304. background: linear-gradient(to right, #ff792f, #ff2c43);
  305. z-index: 0;
  306. // 处理圆角
  307. border-bottom-left-radius: 21rpx;
  308. border-bottom-right-radius: 21rpx;
  309. }
  310. .info-content {
  311. display: flex;
  312. flex-direction: column;
  313. align-items: flex-start;
  314. gap: 20rpx;
  315. .info-item {
  316. display: flex;
  317. flex-direction: row;
  318. flex-wrap: nowrap;
  319. align-items: center;
  320. justify-content: flex-start;
  321. gap: 10rpx;
  322. color: #666;
  323. font-weight: bold;
  324. font-size: 26rpx;
  325. .item-title {
  326. flex: 1;
  327. width: 160rpx;
  328. font-weight: bolder;
  329. }
  330. }
  331. }
  332. }
  333. /* 收起状态 */
  334. .coupon-express-info.collapsed {
  335. opacity: 0;
  336. max-height: 0;
  337. padding-top: 0;
  338. padding-bottom: 0;
  339. border-top-width: 0;
  340. border-bottom-width: 0;
  341. }
  342. /* 展开状态 */
  343. .coupon-express-info.expanded {
  344. opacity: 1;
  345. max-height: 500rpx;
  346. /* 设置一个足够大的值以容纳所有内容 */
  347. }
  348. }
  349. </style>