caiyuqin il y a 2 mois
Parent
commit
3a1290d7da

+ 30 - 0
src/api/home.ts

@@ -121,6 +121,7 @@ export function getCategoryList() {
     })
 }
 
+//首页券列表
 export function getNewCouponList(params) {
     return http.Post('/couponCenter/APP/couponTemplate/getTemplatesPageByCondition', params, {
         headers: {
@@ -154,3 +155,32 @@ export function getIssuanceSituation(params = {}) {
     })
 }
 
+//优惠券详情
+export function queryTemplateByIdDetails(params = {}) {
+    return http.Get('/couponCenter/APP/couponTemplate/queryTemplateByIdDetails', {
+        params,
+    })
+}
+
+
+//浏览记录
+export function getBrowsingRecordList(params = {}) {
+    return http.Get('/couponCenter/APP/couponBrowsingHistory/getBrowsingRecordList', {
+        params,
+    })
+}
+
+//累计未领取
+
+export function getUnCouponList(params = {}) {
+    return http.Get('/couponCenter/APP/couponBrowsingHistory/getUnCouponList', {
+        params,
+    })
+}
+
+//累计领取、累计未核销、累计核销列表信息
+export function getCouponIssueList(params = {}) {
+    return http.Get('/couponCenter/APP/couponUserAsset/getCouponIssueList', {
+        params,
+    })
+}

+ 8 - 0
src/api/income.ts

@@ -93,3 +93,11 @@ export function getBatchRelaPullDetailByBatchId(params) {
         }
     })
 }
+
+//当前账户余额统计数据
+export function queryByUserId(params = {}) {
+    return http.Get('/couponCenter/APP/couponIssuerAccount/queryByUserId', {
+        params,
+    })
+}
+

+ 12 - 0
src/api/receiveCoupon.ts

@@ -42,3 +42,15 @@ export function markSuccess(shareId: string) {
         }
     })
 }
+
+//生成短链的接口
+export function createWechatUrlCoupon(params) {
+    return http.Get('/couponCenter/APP/shareRecord/createWechatUrlCoupon', {
+        params:{
+            templateId: params.templateId,
+            pathUrl: params.pathUrl,
+            version: import.meta.env.VITE_WEIXIN_MINIAPP_VERSION
+        }
+    
+    })
+}

+ 3 - 3
src/components/exchangeCoupon.vue

@@ -92,9 +92,9 @@ function handleCloseShareModal() {
     console.log('分享弹窗已关闭')
 }
 
-function goDetail(){
+function goDetail(item){
     uni.navigateTo({
-    url: "/pages-C/share/shareInfo",
+    url: `/pages-C/share/shareInfo?templateId=${item.templateId}`,
   });
 }
 
@@ -107,7 +107,7 @@ function goDetail(){
             <view class="discount-coupon-info-container">
                 <view class="discount-coupon-info-content">
                     <view class="discount-coupon-info-desc" >
-                        <view class="desc-text" @click='goDetail'>
+                        <view class="desc-text" @click='goDetail(coupon)'>
                             {{ coupon.name }}
                         </view>
                         <view class="desc-type" @tap="isExpand = !isExpand">

+ 1 - 2
src/components/filter/filter.vue

@@ -58,8 +58,7 @@ const props = defineProps({
 // 日期
 const tabListDate = ref([
   { label: "今天", type: "1", isSelected: false },
-  { label: "7天", type: "2", isSelected: false },
-  { label: "30天", type: "3", isSelected: false },
+  { label: "30天", type: "2", isSelected: false },
 ]);
 
 // 类型

+ 3 - 3
src/components/templateCoupon.vue

@@ -96,9 +96,9 @@ function handleCloseShareModal() {
     console.log('分享弹窗已关闭')
 }
 
-function goDetail(){
+function goDetail(item){
     uni.navigateTo({
-    url: "/pages-C/share/shareInfo",
+    url: `/pages-C/share/shareInfo?templateId=${item.templateId}`,
   });
 }
 </script>
@@ -118,7 +118,7 @@ function goDetail(){
                         </view>
                     </view>
                     <view class="discount-coupon-info-desc"  >
-                        <view class="desc-text" @click='goDetail'>
+                        <view class="desc-text" @click='goDetail(coupon)'>
                             {{ coupon.name }}
                         </view>
                         <view class="desc-type" @tap="isExpand = !isExpand">

+ 85 - 160
src/pages-A/shareCoupon/index.vue

@@ -75,8 +75,8 @@ import { useRequest } from 'alova/client'
 import { storeToRefs } from 'pinia'
 import { nextTick, ref } from 'vue'
 import CustomNavigationBar from '@/components/CustomNavigationBar.vue'
-import { getCouponDetail } from '@/api/home'
-import { getCouponShareLink, getWxQcCode, markSuccess } from '@/api/receiveCoupon'
+import { queryTemplateByIdDetails } from '@/api/home'
+import { createWechatUrlCoupon, getWxQcCode, markSuccess } from '@/api/receiveCoupon'
 import { useInviteCodeStore } from '@/store/inviteQCCode'
 import { parseUrlParams, safeAreaInsets, isPcWeixinMp } from '@/utils'
 import { getLastPartAfterSlash } from '@/utils/couponClassFormat'
@@ -113,19 +113,8 @@ const systemInfo = ref({})
 const shareId = ref('')
 const shareRecordId = ref('')
 
-const { send, data: couponDetail } = useRequest(getCouponDetail, {
+const { send, data: couponDetail } = useRequest(queryTemplateByIdDetails, {
   immediate: false,
-  initialData: {
-    name: '',
-    type: '2',
-    relatedName: '',
-    ruleMinSpendAmount: '',
-    ruleReductionAmount: '',
-    validityType: '1',
-    validDays: '',
-    validStartTime: '',
-    validEndTime: '',
-  }
 })
 
 // 生命周期
@@ -298,7 +287,9 @@ async function drawCompleteShareImage(ctx, canvas, qrCodeImg) {
       const yScale = height / posterDesignHeight // Figma 1627高稿纵向缩放
 
       // 1. 加载并绘制远程背景图片
-      let backgroundImgName = couponDetail.value.platformSource === '1' ? 'local_share_poster' : 'gyy_share_poster'
+      // let backgroundImgName = couponDetail.value.platformSource === '1' ? 'local_share_poster' : 'gyy_share_poster'
+      let backgroundImgName = 'local_share_poster'
+
       const backgroundImgUrl = getImageUrl(`@img/share/${backgroundImgName}.png`)
       const backgroundImg = await loadRemoteImage(canvas, backgroundImgUrl)
       ctx.drawImage(backgroundImg, 0, 0, width, height)
@@ -343,6 +334,10 @@ async function drawCompleteShareImage(ctx, canvas, qrCodeImg) {
 // 加载远程图片的函数
 async function loadRemoteImage(canvas, imageUrl) {
   return new Promise((resolve, reject) => {
+    if (!imageUrl) {
+      reject(new Error('图片URL为空'))
+      return
+    }
     const image = canvas.createImage()
     const timeout = setTimeout(() => {
       reject(new Error('图片加载超时'))
@@ -462,114 +457,12 @@ function getPosterRuleText() {
 }
 
 function getGoodsText() {
-  const relatedName = normalizeText(couponDetail.value.relatedName)
-  if (!relatedName)
-    return '适用商品:全部适用'
-
-  if (couponDetail.value.relatedType === '2')
-    return `适用商品:${getLastPartAfterSlash(relatedName)}`
-
-  return `适用商品:${relatedName}`
-}
-
-function getMerchantText() {
-  const storeName = normalizeText(couponDetail.value.storeName) || '不限商家'
-  const merchantCount = getMerchantCountValue()
-  return `适用商家:${storeName}${merchantCount ? `  ${merchantCount}+` : ''}`
-}
-
-function getMerchantCountValue() {
-  return getFirstValidField([
-    'merchantCount',
-    'merchantNum',
-    'storeCount',
-    'storeNum',
-    'shopCount',
-    'shopNum',
-    'applicableStoreCount',
-    'applicableStoreNum',
-    'applicableMerchantCount',
-    'applicableMerchantNum',
-  ])
-}
-
-function getMerchantCountText() {
-  const merchantCount = getMerchantCountValue()
-  return merchantCount ? `${merchantCount}+` : ''
-}
-
-function getMerchantAvatarList() {
-  const avatarSourceKeys = [
-    'merchantAvatarList',
-    'merchantLogoList',
-    'merchantImageList',
-    'merchantList',
-    'storeAvatarList',
-    'storeLogoList',
-    'storeImageList',
-    'storeLogoUrlList',
-    'storeList',
-    'storeInfoList',
-    'shopAvatarList',
-    'shopLogoList',
-    'shopList',
-    'applicableStoreLogoList',
-    'applicableStoreList',
-  ]
-  const avatarFieldKeys = [
-    'avatar',
-    'avatarUrl',
-    'headImg',
-    'headImgUrl',
-    'logo',
-    'logoUrl',
-    'image',
-    'imageUrl',
-    'pic',
-    'picUrl',
-    'storeLogo',
-    'storeLogoUrl',
-    'storeImage',
-    'storeImageUrl',
-    'shopLogo',
-    'shopLogoUrl',
-  ]
-
-  for (const key of avatarSourceKeys) {
-    const source = couponDetail.value?.[key]
-    let list = []
-
-    if (Array.isArray(source)) {
-      list = source
-    }
-    else {
-      const sourceText = normalizeText(source)
-      if (sourceText) {
-        list = sourceText.split(',').map(item => item.trim()).filter(Boolean)
-      }
-    }
-
-    const avatars = list
-      .map((item) => {
-        if (typeof item === 'string')
-          return normalizeImageUrl(item)
-
-        for (const fieldKey of avatarFieldKeys) {
-          const imageUrl = normalizeImageUrl(item?.[fieldKey])
-          if (imageUrl)
-            return imageUrl
-        }
+  const title = couponDetail.value.relatedType == 3 ? '不适用商品' : '适用商品'
+  const productName = normalizeText(couponDetail.value.productName)
+  return `${title}:${productName || '--'}`
+}
 
-        return ''
-      })
-      .filter(Boolean)
 
-    if (avatars.length)
-      return avatars
-  }
-
-  return []
-}
 
 function normalizeImageUrl(value) {
   const imageUrl = normalizeText(value)
@@ -584,12 +477,11 @@ function normalizeImageUrl(value) {
 
 function getAreaText() {
   const locality = normalizeText(couponDetail.value.locality)
-  return `适用地区:${locality || '不限地区使用不限地区使用不限地区使用不限地区使用不限地区使用不限地区使用'}`
+  return `适用地区:${locality || '--'}`
 }
 
 function getReceiveLimitText() {
-  const limit = getFirstValidField(['dailyLimit', 'limitQuantity', 'perDayLimit', 'receiveLimit'])
-  return `每日限领${limit || 0}张`
+  return `每日限领${couponDetail.value.claimLimitDay || 0}张`
 }
 
 function getValidityText() {
@@ -604,6 +496,9 @@ function getValidityText() {
     const validDays = normalizeText(couponDetail.value.validDays)
     return validDays ? `领取后${validDays}日内有效` : ''
   }
+  if (validityType == '4') {
+    return "三方赠送"
+  }
 
   return '长期有效'
 }
@@ -621,7 +516,7 @@ function drawAmountText(ctx, width, scale, yScale) {
   const amountFont = `700 ${88 * scale}px D-DIN Exp-DINExp, PingFang SC`
   const unitFont = `400 ${26 * scale}px PingFang SC`
   const { amountBaselineY } = getPosterLayout(scale, yScale)
-  const baselineY = amountBaselineY +40 * yScale 
+  const baselineY = amountBaselineY + 40 * yScale
   const gap = 3 * scale
 
   ctx.save()
@@ -665,60 +560,94 @@ async function drawPosterBottomContent(ctx, canvas, width, scale, yScale) {
 }
 //头像绘制
 async function drawMerchantLine(ctx, canvas, centerX, y, maxWidth, scale) {
-  const avatars = getMerchantAvatarList().slice(0, 5)
-  const countText = getMerchantCountText()
-
+//   const avatars = couponDetail.value.merchantInfoVOList
+//     ?.filter(item => item?.logo)
+//     ?.map(item => item.logo) || [];
+ const avatars=['https://life.baoxianzhanggui.com/pro-img/securities/index/rank.png','https://life.baoxianzhanggui.com/pro-img/securities/index/rank.png','https://life.baoxianzhanggui.com/pro-img/securities/index/rank.png']
   const label = '适用商家:'
   const avatarSize = 36 * scale
   const overlap = 12 * scale
-  const avatarGroupWidth = avatars.length
-    ? avatarSize + Math.max(avatars.length - 1, 0) * (avatarSize - overlap)
-    : 0
   const gap = 8 * scale
 
+  // ✅ 最多显示 3 个头像
+  const MAX_AVATARS = 3
+  const displayAvatars = avatars.slice(0, MAX_AVATARS)
+
+  // ✅ 检查是否有 GIF 格式图片
+  const hasGifAvatar = displayAvatars.some(avatarUrl => /\.gif$/i.test(avatarUrl))
+  if (hasGifAvatar) {
+    uni.showToast({
+      title: '商家头像暂不支持GIF格式图片',
+      icon: 'none'
+    })
+    console.warn('检测到GIF图片,小程序Canvas不支持GIF格式,跳过头像绘制')
+  }
+
+  // ✅ 如果有 GIF 图片,不绘制头像
+  const hasAvatars = displayAvatars.length > 0 && !hasGifAvatar
+
+  // ✅ 如果有超出,显示 "+N"
+  const countText = couponDetail.value.numberMerchants
+  const extraText = countText > 99 ? `+${countText}` : ''
+  const displayCountText = extraText || countText
+
+  // 计算各部分的宽度
   ctx.save()
   ctx.font = `400 ${20 * scale}px PingFang SC`
-  ctx.fillStyle = '#333333'
   ctx.textAlign = 'left'
   ctx.textBaseline = 'middle'
 
   const labelWidth = ctx.measureText(label).width
-  const countWidth = countText ? ctx.measureText(countText).width : 0
-  const avatarGap = avatars.length ? 4 * scale : 0
-  const countGap = countText && (avatars.length || labelWidth) ? gap : 0
-  const totalWidth = labelWidth + avatarGap + avatarGroupWidth + (countText ? countGap + countWidth : 0)
+  const countWidth = displayCountText ? ctx.measureText(displayCountText).width : 0
 
-  //   if (totalWidth > maxWidth || (!avatars.length && !countText)) {
-  //     ctx.restore()
-  //     drawCenterEllipsisText(ctx, getMerchantText(), centerX, y, maxWidth, 20, scale, '#333333')
-  //     return
-  //   }
+  const avatarGroupWidth = hasAvatars
+    ? avatarSize + (displayAvatars.length - 1) * (avatarSize - overlap)
+    : 0
+  const avatarGap = hasAvatars ? 4 * scale : 0
+  const countGap = displayCountText && (hasAvatars || labelWidth) ? gap : 0
 
+  const totalWidth = labelWidth + avatarGap + avatarGroupWidth + countGap + countWidth
   let currentX = centerX - totalWidth / 2
 
+  // 绘制标签
+  ctx.fillStyle = '#333333'
   ctx.fillText(label, currentX, y)
   currentX += labelWidth + avatarGap
   ctx.restore()
 
-  for (let index = 0; index < avatars.length; index++) {
-    const avatarX = currentX + index * (avatarSize - overlap)
-    await drawCircleImage(ctx, canvas, avatars[index], avatarX, y - avatarSize / 2, avatarSize, scale)
+  // 绘制头像(最多 3 个)
+  if (!hasGifAvatar) {
+    for (let index = 0; index < displayAvatars.length; index++) {
+      const avatarX = currentX + index * (avatarSize - overlap)
+      await drawCircleImage(ctx, canvas, displayAvatars[index], avatarX, y - avatarSize / 2, avatarSize, scale)
+    }
   }
 
-  if (countText) {
+
+  // 绘制数量文字(优先显示超出数)
+  if (displayCountText) {
     ctx.save()
     ctx.font = `400 ${20 * scale}px PingFang SC`
     ctx.fillStyle = '#333333'
     ctx.textAlign = 'left'
-    ctx.textBaseline = 'middle'
-    ctx.fillText(countText, currentX + avatarGroupWidth + countGap, y)
+    // 使用 bottom 基线,配合字体高度实现精确垂直居中
+    ctx.textBaseline = 'bottom'
+    const fontSize = 20 * scale
+    const lineHeight = fontSize * 1.2  // 文字行高
+    // 从 y 向上偏移半行高,实现垂直居中
+    const textY = y + lineHeight / 2
+    // 如果有头像,文本在头像组后面;如果没有,直接在标签后面
+    const textX = hasAvatars ? currentX + avatarGroupWidth + countGap : currentX
+    ctx.fillText(displayCountText, textX, textY)
     ctx.restore()
   }
 }
 
 async function drawCircleImage(ctx, canvas, imageUrl, x, y, size, scale) {
+
   try {
-    const image = await loadRemoteImage(canvas, imageUrl)
+    const encodedUrl = encodeURI(imageUrl);
+    const image = await loadRemoteImage(canvas, encodedUrl)
     ctx.save()
     ctx.beginPath()
     ctx.arc(x + size / 2, y + size / 2, size / 2, 0, Math.PI * 2)
@@ -1125,11 +1054,14 @@ function handleImagePreview() {
 
 // 小程序分享钩子 - 控制分享后的跳转页面
 onShareAppMessage(() => ({
-  title: '优惠券来了',
-  path: `/pages-C/share/shareInfo?from=share&name=${encodeURIComponent('券中心')}`,
+  title: '你的好友送你的专属优惠,先到先得!',
+  path: `/pages-C/share/shareInfo?templateId=${shareId.value}&shareType=2`,
   imageUrl: shareImageUrl.value || '',
 }))
 
+
+
+
 // 保存图片到相册
 async function handleSaveImage() {
   if (!shareImageUrl.value) {
@@ -1186,21 +1118,14 @@ async function handleCopyShareLink() {
   if (copyLinkLoading.value)
     return
 
-  if (!shareId.value) {
-    uni.showToast({
-      title: '缺少优惠券信息',
-      icon: 'none',
-    })
-    return
-  }
-
   copyLinkLoading.value = true
 
   try {
     if (!shareLink.value) {
-      const result = await getCouponShareLink({
+      const result = await createWechatUrlCoupon({
         templateId: shareId.value,
-        pathUrl: 'pages/home/index',
+        //pathUrl: `pages-C/share/shareInfo`,
+        pathUrl: `pages/home/index`,
       })
       shareLink.value = result || ''
     }

+ 119 - 86
src/pages-C/home/browse.vue

@@ -2,6 +2,8 @@
 import { ref } from "vue";
 import { getImageUrl } from "@/utils/imageUtil";
 import FilterSelect from "@/components/filter/filter.vue";
+import LsvList from "@/components/listScrollView/index.vue";
+import { getBrowsingRecordList } from "@/api/home";
 
 definePage({
   style: {
@@ -10,47 +12,70 @@ definePage({
   },
 });
 
-// 当前选中的tab
-const currentTab = ref("0");
-
-// 点击tab事件
-const handleTabClick = (value) => {
-  currentTab.value = value;
-  console.log("选中tab:", value);
+// Task 2: 定义 API 函数
+const getBrowseListApi = (params: any) => {
+  return getBrowsingRecordList({
+    pageNo: params.pageNo,
+    pageSize: params.pageSize,
+    browseBy: params.browseBy || "",
+    category: params.category ?? "",
+    startTime: params.startTime || "",
+    endTime: params.endTime || "",
+  });
 };
 
-const keyword = ref("");
-async function search() {}
-async function clear() {}
+// Task 4: 筛选功能
+const filterObj = ref({ type: "", dataFilter: null });
+const filterParams = ref({});
+const listRef = ref();
+const isMounted = ref(false);
+
+const couponTypeMap: Record<string, string> = {
+  "1": "权益券",
+  "2": "折扣券",
+  "3": "满减券",
+  "4": "兑换券",
+};
 
-const isOpen = ref(false);
-const popupRef = ref();
-function clickSelect() {
-  isOpen.value = !isOpen.value;
-  isOpen.value ? popupRef.value?.show() : popupRef.value?.close();
-}
+const statusTypeMap: Record<string, string> = {
+  "0": "浏览未领取",
+  "1": "待核销",
+  "2": "已核销",
+};
 
-const rewardTabs = ref([
-  { label: "美食", type: "1" },
-  { label: "车服务", type: "2" },
-]);
+// Task 3: 搜索功能
+const browseBy = ref("");
+const search = () => {
+  reloadListRef();
+};
 
-const classIndex = ref(-1);
-const classItem = ref({
-  label: "",
-  type: "",
-});
-function classClick(index, item) {
-  classIndex.value = index;
-  classItem.value = item;
-  clickSelect();
-}
+const clear = () => {
+  browseBy.value = "";
+  reloadListRef();
+};
 
-const filter = ["type", "dataFilter"];
+// Task 4: 筛选处理
+const selectValue = (selected: any) => {
+  if (!isMounted.value) {
+    isMounted.value = true;
+    return;
+  }
+  filterParams.value = selected;
+  reloadListRef();
+};
 
-function selectValue(item) {
-  console.log(item);
-}
+const reloadListRef = (extraParams = {}) => {
+  listRef.value.reloadList({
+    browseBy: browseBy.value,
+    category: filterParams.value.type?.type,
+    startTime: filterParams.value.dataFilter
+      ? filterParams.value.dataFilter?.startDate + " 23:59:59"
+      : "",
+    endTime: filterParams.value.dataFilter
+      ? filterParams.value.dataFilter?.endDate + " 23:59:59"
+      : "",
+  });
+};
 </script>
 
 <template>
@@ -59,66 +84,75 @@ function selectValue(item) {
       :title-style="{ fontWeight: 'bold', color: '#000' }" leftIconColor="#000"></u-navbar>
 
     <view class="invite-content-search">
-      <u-search :showAction="true" actionText="搜索" bgColor="#F7F8FA" v-model="keyword" color='#333'
-        placeholder='搜索昵称/手机号' :actionStyle='{ color: "#FF5365", fontSize: "32rpx" }'></u-search>
+      <u-search :showAction="true" actionText="搜索" bgColor="#F7F8FA" v-model="browseBy" color='#333'
+        placeholder='搜索昵称/手机号' :actionStyle='{ color: "#FF5365", fontSize: "32rpx" }' @search="search" @clear='clear'
+        :clearabled="true" @custom="search"></u-search>
     </view>
 
-    <FilterSelect :filter="filter" @selectValue='selectValue'></FilterSelect>
+    <FilterSelect :filter="filterObj" @selectValue='selectValue'></FilterSelect>
 
     <view class="send-content">
-      <view class="send-card">
-        <view class="send-header">
-          <view class="coupon-info">
-            <text class="coupon-name">满100减50优惠券</text>
-            <view class="coupon-tag status-red">折扣券</view>
-          </view>
-          <!-- <text class="send-count send-red">免费兑换</text> -->
-          <!-- <text class="send-number-box">
-            <text class="send-number">9</text>
-            <text class="send-unit">折</text>
-          </text> -->
-          <view class="send-number-box">
-            <text class='add-title'>满100减</text>
-            <text class="send-number-box">
-              <text class="send-number">30</text>
-              <text class="send-unit">元</text>
-            </text>
-          </view>
-
-        </view>
-        <view class="send-divider"></view>
-        <view class="send-detail">
-          <view class="detail-row">
-            <text class="detail-label">核销门店</text>
-            <text class="detail-value">2026-05-20 10:30:00</text>
-          </view>
-          <view class="detail-row">
-            <text class="detail-label">我的佣金</text>
-            <text class="detail-value highlight">2026-05-20 10:30:00</text>
-          </view>
+      <LsvList ref="listRef" :api="getBrowseListApi" key-name="records">
+        <template #list="{ data }">
+          <view v-for="(item, index) in data" :key="item.templateId || index" class="send-card">
+            <view class="send-header">
+              <view class="coupon-info">
+                <text class="coupon-name">{{ item.templateName }}</text>
+                <view class="coupon-tag"
+                  :class="['coupon-tag', item.status =='0' ? 'status-red' : item.status == '1' ? 'status-yellow' : 'status-settled']">
+                  {{ statusTypeMap[item.type] }}</view>
+              </view>
+              <view class="send-number-box">
+                <template v-if="item.type === '2'">
+                  <text class="send-number">{{ item.ruleDiscountRate }}</text>
+                  <text class="send-unit">折</text>
+                </template>
+                <template v-else-if="item.type === '3'">
+                  <text class='add-title'>满{{ item.ruleMinSpendAmount }}减</text>
+                  <view class="send-number-box">
+                    <text class="send-number">{{ item.ruleReductionAmount }}</text>
+                    <text class="send-unit">元</text>
+                  </view>
+                </template>
+                <text v-else class="send-red">免费兑换</text>
+              </view>
+            </view>
+            <view class="send-divider"></view>
+            <view class="send-detail">
+              <template v-if='item.status==2'>
+                <view class="detail-row">
+                  <text class="detail-label">核销门店</text>
+                  <text class="detail-value">{{ item.writeOffStores || '--' }}</text>
+                </view>
+                <view class="detail-row">
+                  <text class="detail-label">我的佣金</text>
+                  <text class="detail-value highlight">{{ item.commission || 0 }}元</text>
+                </view>
+              </template>
+              <view class="detail-row">
+                <text class="detail-label">浏览人</text>
+                <view class="income-person">
+                  <u--image class='income-phone' :src="item.browseByAvatarUrl||getImageUrl('@img/me/head.png')"
+                    width="42rpx" height="42rpx" shape="circle"></u--image>
+                  <text class="detail-value">{{ item.browseBy }}</text>
+                </view>
+              </view>
+              <view class="detail-row">
+                <text class="detail-label">联系方式</text>
+                <text class="detail-value">{{ item.browseByPhone }}</text>
+              </view>
+              <view class="detail-row">
+                <text class="detail-label">{{item.status==0?'浏览':item.status==1?'领取':"核销"}}时间</text>
+                <text
+                  class="detail-value">{{ item.status==0?item.browseTime :item.status==1?item.receiveTime:item.useTime}}</text>
+              </view>
 
-          <view class="detail-row">
-            <text class="detail-label">浏览人</text>
-            <view class="income-person">
-              <u--image class='income-phone' :src="getImageUrl('@img/me/head.png')" width="42rpx" height="42rpx"
-                shape="circle">
-              </u--image>
-              <view>林雨欣</view>
             </view>
           </view>
-          <view class="detail-row">
-            <text class="detail-label">联系方式</text>
-            <text class="detail-value">2026-05-20 10:30:00</text>
-          </view>
-          <view class="detail-row">
-            <text class="detail-label">领取日期</text>
-            <text class="detail-value">微信朋友圈</text>
-          </view>
-        </view>
-      </view>
+        </template>
+      </LsvList>
     </view>
   </view>
-
 </template>
 
 <style lang="scss" scoped>
@@ -209,7 +243,6 @@ function selectValue(item) {
     }
   }
 
-
   .classification-cont {
     padding: 0 32rpx;
     box-sizing: border-box;

+ 106 - 91
src/pages-C/home/sendCancelWriteOff.vue

@@ -4,8 +4,10 @@ import { getImageUrl } from "@/utils/imageUtil";
 
 import PopupLayer from "@/components/popupLayer/index.vue";
 import FilterSelect from "@/components/filter/filter.vue";
+import LsvList from "@/components/listScrollView/index.vue";
+import { getCouponIssueList } from "@/api/home";
 
-const type = ref()
+const type = ref();
 definePage({
   style: {
     navigationBarTitleText: "累计待核销",
@@ -13,115 +15,128 @@ definePage({
   },
 });
 
-// 生命周期
-onLoad(async (options) => {
-  type.value = options.type
-})
+// Task 2: 定义 API 函数
+const getCancelWriteOffListApi = (params: any) => {
+  return getCouponIssueList({
+    pageNo: params.pageNo,
+    pageSize: params.pageSize,
+    dayType: params.dayType || 1,
+    category: params.category,
+    startTime: params.startTime || "",
+    endTime: params.endTime || "",
+    type: type.value,
+  });
+};
 
-// 当前选中的tab
-const currentTab = ref("0");
+// Task 1: 定义 listRef、isMounted 等变量
+const listRef = ref();
+const isMounted = ref(false);
+const filterParams = ref({});
 
-// 点击tab事件
-const handleTabClick = (value) => {
-  currentTab.value = value;
-  console.log("选中tab:", value);
+// 券类型映射
+const couponTypeMap: Record<string, string> = {
+  "1": "权益券",
+  "2": "折扣券",
+  "3": "满减券",
+  "4": "兑换券",
 };
 
-const keyword = ref("");
-async function search() {}
-async function clear() {}
-
-const isOpen = ref(false);
-const popupRef = ref();
-function clickSelect() {
-  isOpen.value = !isOpen.value;
-  isOpen.value ? popupRef.value?.show() : popupRef.value?.close();
-}
+// 生命周期
+onLoad(async (options) => {
+  type.value = options.type;
+});
 
-const rewardTabs = ref([
-  { label: "全部", type: "0" },
-  { label: "折扣券", type: "1" },
-  { label: "兑换券", type: "2" },
-  { label: "满减券", type: "3" },
-]);
+const reloadListRef = (extraParams = {}) => {
+  listRef.value.reloadList({
+    dayType: filterParams.value.date?.type,
+    category: filterParams.value.type?.type,
+    startTime: filterParams.value.dataFilter
+      ? filterParams.value.dataFilter?.startDate + " 23:59:59"
+      : "",
+    endTime: filterParams.value.dataFilter
+      ? filterParams.value.dataFilter?.endDate + " 23:59:59"
+      : "",
+  });
+};
 
-const classIndex = ref(-1);
-const classItem = ref({
-  label: "",
-  type: "",
-});
-function classClick(index, item) {
-  classIndex.value = index;
-  classItem.value = item;
-  clickSelect();
-}
+// Task 3: 筛选处理
+const selectValue = (selected: any) => {
+  if (!isMounted.value) {
+    isMounted.value = true;
+    return;
+  }
+  filterParams.value = selected;
+  reloadListRef();
+};
 
-const filter = ["type", "date", "dataFilter"];
-function selectValue(item) {
-  console.log(item);
-}
+// Task 4: filter 改为 Object 格式
+const filterObj = ref({ type: "", date: "1", dataFilter: null });
 </script>
 
 <template>
   <view class="income-cumulative-container">
     <u-navbar :title="type==1?'累计待核销':'累计已核销'" :autoBack="true" :placeholder="true" :border-bottom="false"
       :title-style="{ fontWeight: 'bold', color: '#000' }" leftIconColor="#000"></u-navbar>
-    <FilterSelect :filter='filter' @selectValue='selectValue'></FilterSelect>
+    <FilterSelect :filter='filterObj' @selectValue='selectValue'></FilterSelect>
     <view class="send-content">
-      <view class="send-card">
-        <view class="send-header">
-          <view class="coupon-info">
-            <text class="coupon-name">满100减50优惠券</text>
-            <view class="coupon-tag">折扣券</view>
-          </view>
-          <!-- <text class="send-count send-red">免费兑换</text> -->
-          <!-- <text class="send-number-box">
-            <text class="send-number">9</text>
-            <text class="send-unit">折</text>
-          </text> -->
-          <view class="send-number-box">
-            <text class='add-title'>满100减</text>
-            <text class="send-number-box">
-              <text class="send-number">30</text>
-              <text class="send-unit">元</text>
-            </text>
-          </view>
-
-        </view>
-        <view class="send-divider"></view>
-        <view class="send-detail">
-          <template v-if="type==2">
-            <view class="detail-row">
-              <text class="detail-label">核销门店</text>
-              <text class="detail-value">微信朋友圈</text>
-            </view>
-            <view class="detail-row">
-              <text class="detail-label">我的佣金</text>
-              <text class="detail-value">预计<text class="highlight">20元</text></text>
+      <LsvList ref="listRef" :api="getCancelWriteOffListApi" key-name="records">
+        <template #list="{ data }">
+          <view v-for="(item, index) in data" :key="index" class="send-card">
+            <view class="send-header">
+              <view class="coupon-info">
+                <text class="coupon-name">{{ item.couponName }}</text>
+                <!-- <view class="coupon-tag">{{ couponTypeMap[item.couponType] }}</view> -->
+              </view>
+              <view class="send-number-box">
+                <template v-if="item.couponType === '2'">
+                  <text class="send-number">{{ item.ruleDiscountRate }}</text>
+                  <text class="send-unit">折</text>
+                </template>
+                <template v-else-if="item.couponType === '3'">
+                  <text class='add-title'>满{{ item.ruleMinSpendAmount }}减</text>
+                  <view class="send-number-box">
+                    <text class="send-number">{{ item.ruleReductionAmount }}</text>
+                    <text class="send-unit">元</text>
+                  </view>
+                </template>
+                <text v-else class="send-red">免费兑换</text>
+              </view>
             </view>
-          </template>
-          <view class="detail-row">
-            <text class="detail-label">领取人</text>
-            <view class="income-person">
-              <u--image class='income-phone' :src="getImageUrl('@img/me/head.png')" width="42rpx" height="42rpx"
-                shape="circle">
-              </u--image>
-              <view>林雨欣</view>
+            <view class="send-divider"></view>
+            <view class="send-detail">
+              <template v-if="type==2">
+                <view class="detail-row">
+                  <text class="detail-label">核销门店</text>
+                  <text class="detail-value">{{ item.writeOffStores || '--' }}</text>
+                </view>
+                <view class="detail-row">
+                  <text class="detail-label">核销时间</text>
+                  <text class="detail-value">{{ item.writeOffDate || '--' }}</text>
+                </view>
+              </template>
+              <view class="detail-row">
+                <text class="detail-label">领取人</text>
+                <view class="income-person">
+                  <u--image class='income-phone' :src="item.avatarUrl || getImageUrl('@img/me/head.png')" width="42rpx"
+                    height="42rpx" shape="circle">
+                  </u--image>
+                  <text>{{ item.claimUser || '--' }}</text>
+                </view>
+              </view>
+              <view class="detail-row">
+                <text class="detail-label">联系方式</text>
+                <text class="detail-value">{{ item.phone || '--' }}</text>
+              </view>
+              <view class="detail-row">
+                <text class="detail-label">{{type==2?'核销':'领取'}}日期</text>
+                <text class="detail-value">{{ type == 2 ? item.writeOffDate : item.receiveTime }}</text>
+              </view>
             </view>
           </view>
-          <view class="detail-row">
-            <text class="detail-label">联系方式</text>
-            <text class="detail-value">微信朋友圈</text>
-          </view>
-          <view class="detail-row">
-            <text class="detail-label">领取日期</text>
-            <text class="detail-value">微信朋友圈</text>
-          </view>
-        </view>
-      </view>
+        </template>
+      </LsvList>
     </view>
   </view>
-
 </template>
 
 <style lang="scss" scoped>

+ 4 - 2
src/pages-C/home/sendCoupon.vue

@@ -126,9 +126,11 @@ const couponTypeMap = {
                 <text class="detail-value">{{ item.totalNum }}张</text>
               </view>
             </view>
-            <u--image class='coupon1-icon' :src="getImageUrl('@img/me/coupon1.png')" mode="aspectFit" width="66rpx"
-              height="60rpx">
+
+            <u--image class='coupon1-icon' :src="getImageUrl(`@img/me/coupon${item.type}.png`)" mode="aspectFit"
+              width="66rpx" height="60rpx">
             </u--image>
+
           </view>
         </template>
       </LsvList>

+ 111 - 62
src/pages-C/home/sendWriteOff.vue

@@ -4,9 +4,10 @@ import { getImageUrl } from "@/utils/imageUtil";
 
 import PopupLayer from "@/components/popupLayer/index.vue";
 import FilterSelect from "@/components/filter/filter.vue";
+import LsvList from "@/components/listScrollView/index.vue";
+import { getUnCouponList, getCouponIssueList } from "@/api/home";
 
-
-const type = ref()
+const type = ref();
 definePage({
   style: {
     navigationBarTitleText: "累计领取",
@@ -14,26 +15,72 @@ definePage({
   },
 });
 
+// Task 2: 定义 API 函数
+const getWriteOffListApi = (params: any) => {
+  let paramsObj = {
+    pageNo: params.pageNo,
+    pageSize: params.pageSize,
+    dayType: params.dayType || 1,
+    category: params.category,
+    startTime: params.startTime || "",
+    endTime: params.endTime || "",
+  };
+  if (type.value == 1) {
+    return getCouponIssueList({
+      ...paramsObj,
+      type: 3,
+    });
+  } else {
+    return getUnCouponList({
+      ...paramsObj,
+    });
+  }
+};
+
+// Task 1: 定义 listRef、isMounted 等变量
+const listRef = ref();
+const isMounted = ref(false);
+const filterParams = ref({});
+
+// 券类型映射
+const couponTypeMap: Record<string, string> = {
+  "1": "权益券",
+  "2": "折扣券",
+  "3": "满减券",
+  "4": "兑换券",
+};
+
 // 生命周期
 onLoad(async (options) => {
-  type.value = options.type
-})
-// 定义tab列表
-const tabList = ref([
-  { label: "今天", value: "0" },
-  { label: "近7天", value: "1" },
-  { label: "近30天", value: "2" },
-]);
+  type.value = options.type;
+});
 
-// 当前选中的tab
-const currentTab = ref("0");
+const reloadListRef = (extraParams = {}) => {
+  listRef.value.reloadList({
+    dayType: filterParams.value.date?.type,
+    category: filterParams.value.type?.type,
+    startTime: filterParams.value.dataFilter
+      ? filterParams.value.dataFilter?.startDate + " 23:59:59"
+      : "",
+    endTime: filterParams.value.dataFilter
+      ? filterParams.value.dataFilter?.endDate + " 23:59:59"
+      : "",
+  });
+};
 
-// 点击tab事件
-const handleTabClick = (value) => {
-  currentTab.value = value;
-  console.log("选中tab:", value);
+// 筛选处理
+const selectValue = (selected: any) => {
+  if (!isMounted.value) {
+    isMounted.value = true;
+    return;
+  }
+  filterParams.value = selected;
+  reloadListRef();
 };
 
+// 当前选中的tab
+const currentTab = ref("0");
+
 const keyword = ref("");
 async function search() {}
 async function clear() {}
@@ -63,10 +110,7 @@ function classClick(index, item) {
   clickSelect();
 }
 
-const filter = ["type", "date", "dataFilter"];
-function selectValue(item) {
-  console.log(item);
-}
+const filterObj = ref({ type: "", date: "1", dataFilter: null });
 </script>
 
 <template>
@@ -74,51 +118,56 @@ function selectValue(item) {
     <u-navbar :title="type==1?'累计领取':'累计未领取'" :autoBack="true" :placeholder="true" :border-bottom="false"
       :title-style="{ fontWeight: 'bold', color: '#000' }" leftIconColor="#000"></u-navbar>
 
-    <FilterSelect :filter='filter' @selectValue='selectValue'></FilterSelect>
+    <FilterSelect :filter='filterObj' @selectValue='selectValue'></FilterSelect>
     <view class="send-content">
-      <view class="send-card">
-        <view class="send-header">
-          <view class="coupon-info">
-            <text class="coupon-name">满100减50优惠券</text>
-            <view class="coupon-tag">折扣券</view>
-          </view>
-          <!-- <text class="send-count send-red">免费兑换</text> -->
-          <!-- <text class="send-number-box">
-            <text class="send-number">9</text>
-            <text class="send-unit">折</text>
-          </text> -->
-          <view class="send-number-box">
-            <text class='add-title'>满100减</text>
-            <text class="send-number-box">
-              <text class="send-number">30</text>
-              <text class="send-unit">元</text>
-            </text>
-          </view>
-
-        </view>
-        <view class="send-divider"></view>
-        <view class="send-detail">
-          <view class="detail-row">
-            <text class="detail-label">领取人</text>
-            <view class="income-person">
-              <u--image class='income-phone' :src="getImageUrl('@img/me/head.png')" width="42rpx" height="42rpx"
-                shape="circle">
-              </u--image>
-              <view>林雨欣</view>
+      <LsvList ref="listRef" :api="getWriteOffListApi" key-name="records">
+        <template #list="{ data }">
+          <view v-for="(item, index) in data" :key="index" class="send-card">
+            <view class="send-header">
+              <view class="coupon-info">
+                <text class="coupon-name">{{ item.couponName }}</text>
+                <!-- <view class="coupon-tag">{{ couponTypeMap[item.couponType] }}</view> -->
+              </view>
+              <view class="send-number-box">
+                <template v-if="item.couponType === '2'">
+                  <text class="send-number">{{ item.ruleDiscountRate }}</text>
+                  <text class="send-unit">折</text>
+                </template>
+                <template v-else-if="item.couponType === '3'">
+                  <text class='add-title'>满{{ item.ruleMinSpendAmount }}减</text>
+                  <view class="send-number-box">
+                    <text class="send-number">{{ item.ruleReductionAmount }}</text>
+                    <text class="send-unit">元</text>
+                  </view>
+                </template>
+                <text v-else class="send-red">免费兑换</text>
+              </view>
             </view>
+            <view class="send-divider"></view>
+            <view class="send-detail">
+              <view class="detail-row">
+                <text class="detail-label">领取人</text>
+                <view class="income-person">
+                  <u--image class='income-phone' :src="item.avatarUrl || getImageUrl('@img/me/head.png')" width="42rpx"
+                    height="42rpx" shape="circle">
+                  </u--image>
+                  <text>{{ item.claimUser || '--' }}</text>
+                </view>
+              </view>
+              <view class="detail-row">
+                <text class="detail-label">联系方式</text>
+                <text class="detail-value">{{ item.phone || '--' }}</text>
+              </view>
+              <view class="detail-row">
+                <text class="detail-label">领取日期</text>
+                <text class="detail-value">{{ item.receiveTime || '--' }}</text>
+              </view>
+            </view>
+            <u--image v-if='type==1' class='write-off-icon' :src="getImageUrl('@img/me/writeOff.png')" mode="aspectFit"
+              width="188rpx" height="150rpx"></u--image>
           </view>
-          <view class="detail-row">
-            <text class="detail-label">联系方式</text>
-            <text class="detail-value">微信朋友圈</text>
-          </view>
-          <view class="detail-row">
-            <text class="detail-label">领取日期</text>
-            <text class="detail-value">微信朋友圈</text>
-          </view>
-        </view>
-        <u--image v-if='type==1' class='write-off-icon' :src="getImageUrl('@img/me/writeOff.png')" mode="aspectFit" width="188rpx"
-          height="150rpx"></u--image>
-      </view>
+        </template>
+      </LsvList>
     </view>
   </view>
 

+ 182 - 132
src/pages-C/share/shareInfo.vue

@@ -1,22 +1,49 @@
 <script setup lang="ts">
 import { onLoad } from "@dcloudio/uni-app";
-import { ref } from "vue";
+import { ref, computed } from "vue";
 import { getImageUrl } from "@/utils/imageUtil";
 import Upopup from "@/components/popup/index.vue";
 import StarRating from "@/components/start/start.vue";
 import { storeToRefs } from "pinia";
 import { useTokenStore } from "@/store/token";
 import { toLoginPage } from "@/utils/toLoginPage";
-import { useCouponShare } from '@/hooks/useCouponShare'
+import { useCouponShare } from "@/hooks/useCouponShare";
+import { queryTemplateByIdDetails, getShareInfo } from "@/api/home";
+import { getEnvField } from '@/utils/envField'
 
 const tokenStore = useTokenStore();
 const { hasLogin } = storeToRefs(tokenStore);
 
-// 接收分享卡片传入的参数
-onLoad((options: any) => {
-  console.log("onLoad options:", options);
-  // 例如:options.couponId, options.from 等
+// 定义 templateId 存储传入的 id
+const templateId = ref<string>("");
+const shareId = ref();
+
+// 定义 couponDetail 存储接口返回数据
+const couponDetail = ref<any>(null);
+
+const shareType = ref(); //2来自分享
+onLoad(async (options: any) => {
+  templateId.value = options.templateId;
+  shareType.value = options.shareType;
+  // 调用接口获取优惠券详情
+  await fetchCouponDetail();
 });
+
+// 获取优惠券详情
+async function fetchCouponDetail() {
+  try {
+    uni.showLoading({ title: "加载中..." });
+    const res = await queryTemplateByIdDetails({
+      templateId: templateId.value,
+    });
+    couponDetail.value = res;
+  } catch (error) {
+    uni.showToast({ title: "获取详情失败", icon: "none" });
+  } finally {
+    uni.hideLoading();
+  }
+}
+
 definePage({
   style: {
     navigationBarTitleText: "优惠券详情",
@@ -24,20 +51,60 @@ definePage({
   },
 });
 
-const couponData = ref({
-  discount: "7",
-  unit: "折",
-  name: "顺溜早餐折扣券",
-  validity: "长期有效",
-});
+// 计算优惠券类型显示
+const couponTypeDisplay = computed(() => {
+  if (!couponDetail.value)
+    return { discount: "", unit: "", name: "", validity: "" };
+
+  const detail = couponDetail.value;
+  const type = detail.type;
+
+  // 有效期显示
+  let validity = "";
+  const validityType = detail.validityType;
+  if (validityType == 1) {
+    validity = `有效期至 ${detail.validEndTime}`;
+  } else if (validityType == 2) {
+    validity = `领券后 ${detail.validDays} 天有效`;
+  } else if (validityType == 3) {
+    validity = "长期有效";
+  } else if (validityType == 4) {
+    validity = "三方赠送";
+  }
 
-const couponDetails = ref({
-  applicableProducts: "部分商品",
-  merchantCount: "99+",
-  usageRules: "满20元打8折,最高优惠10元",
-  usagePeriod: "长期有效",
-  dailyLimit: "20张",
-  applicableArea: "山西省-太原市-小店区、山西省-太原市-迎泽区",
+  // 根据类型显示不同内容
+  if (type == 1) {
+    // 兑换券
+    return {
+      discount: "",
+      unit: "",
+      name: detail.name,
+      validity: validity,
+      type: 1,
+    };
+  } else if (type == 2) {
+    // 折扣券
+    return {
+      discount: detail.ruleDiscountRate,
+      unit: "折",
+      name: detail.name,
+      validity: validity,
+      capAmount: detail.ruleDiscountCapAmount || "0",
+      type: 2,
+    };
+  } else if (type == 3) {
+    // 满减券
+    return {
+      discount: detail.ruleReductionAmount || "0",
+      unit: "元",
+      name: detail.name,
+      validity: validity,
+      minSpend: detail.ruleMinSpendAmount || "0",
+      type: 3,
+    };
+  }
+
+  return { discount: "", unit: "", name: "", validity: "" };
 });
 
 const rules = [
@@ -59,20 +126,28 @@ function navigateToMiniProgram() {
   // #ifdef MP-WEIXIN
   uni.navigateToMiniProgram({
     appId: "wxab9634bf98628a03", // TODO: 替换为目标小程序的 AppId
-    path: "pages/home/home", // TODO: 替换为目标小程序的页面路径
-    envVersion: "trial",
+    path: `pages/home/home?CCShareId=${shareId.value}`, // TODO: 替换为目标小程序的页面路径
+    envVersion: getEnvField(),
     success: () => {
       console.log("跳转其他小程序成功");
     },
     fail: (err) => {
-      console.error("跳转失败", JSON.stringify(err));
-      uni.showToast({ title: err.errMsg || "跳转失败", icon: "none" });
+      uni.showToast({ title: "跳转失败", icon: "none" });
     },
   });
   // #endif
 }
 
-function receive() {
+//获取分享ID
+async function getShareId() {
+  const res = await getShareInfo({
+    shareContentId: templateId.value,
+    shareType: "COUPON",
+  });
+  shareId.value = res;
+}
+
+async function receive() {
   if (!hasLogin.value) {
     // 未登录 → 去登录,登录后回到当前页
     const currentPage = getCurrentPages()[getCurrentPages().length - 1];
@@ -80,26 +155,18 @@ function receive() {
     toLoginPage({
       queryString: `?redirect=${encodeURIComponent(redirectUrl)}`,
     });
+    fetchCouponDetail();
+    getShareId();
     return;
   }
   // 已登录 → 跳转其他小程序领券
+  await getShareId();
   navigateToMiniProgram();
 }
 
-const { shareCoupon, ...shareHooks } = useCouponShare()
+const { shareCoupon, ...shareHooks } = useCouponShare();
 function clickShare() {
-  try {
-    // const shareLink = await shareCoupon(couponTemplateId.value);
-    // if (shareLink) {
-    //   couponShareLink.value = shareLink;
-    //   showShareModal.value = true;
-    //   if (props.enableCustomShare) {
-    //     emit("shareClick", couponShareLink.value, shareHooks);
-    //   }
-    // }
-  } finally {
-    // uni.hideLoading()
-  }
+  shareCoupon(templateId.value);
 }
 </script>
 
@@ -111,7 +178,7 @@ function clickShare() {
     <view class="share-info-content">
       <view class="coupon-card">
         <!-- 折扣券 -->
-        <!-- <view class="card-background" :style="{
+        <view v-if="couponTypeDisplay.type ==2" class="card-background" :style="{
                     backgroundImage: `url(${getImageUrl('@img/income/share-bg.png')})`,
                     backgroundRepeat: 'no-repeat',
                     backgroundSize: 'contain',
@@ -121,19 +188,22 @@ function clickShare() {
           <view class="card-content">
             <view class="discount-section">
               <view class="discount-value">
-                <text class="discount-number">{{ couponData.discount }}</text>
-                <text class="discount-unit">{{ couponData.unit }}</text>
+                <text class="discount-number">{{ couponTypeDisplay.discount }}</text>
+                <text class="discount-unit">{{ couponTypeDisplay.unit }}</text>
               </view>
             </view>
 
             <view class="info-section">
-              <text class="coupon-name">{{ couponData.name }}</text>
-              <text class="validity-text">{{ couponData.validity }}</text>
+              <text class="coupon-name">{{ couponTypeDisplay.name }}</text>
+              <view>
+                <view class='coupon-red'>最高优惠{{ couponTypeDisplay.capAmount }}元</view>
+                <view class="validity-text">{{ couponTypeDisplay.validity }}</view>
+              </view>
             </view>
           </view>
-        </view> -->
+        </view>
         <!-- 满减券 -->
-        <!-- <view class="card-background" :style="{
+        <view v-else-if="couponTypeDisplay.type == 3" class="card-background" :style="{
                     backgroundImage: `url(${getImageUrl('@img/income/share-bg.png')})`,
                     backgroundRepeat: 'no-repeat',
                     backgroundSize: 'contain',
@@ -143,29 +213,29 @@ function clickShare() {
           <view class="card-content">
             <view class="discount-section">
               <view class="discount-value">
-                <text class="discount-number">{{ couponData.discount }}</text>
-                <text class="discount-unit"></text>
+                <text class="discount-number">{{ couponTypeDisplay.discount }}</text>
+                <text class="discount-unit">{{ couponTypeDisplay.unit }}</text>
               </view>
             </view>
 
             <view class="info-section">
-              <text class="coupon-name">{{ couponData.name }}</text>
+              <text class="coupon-name">{{ couponTypeDisplay.name }}</text>
               <view>
-                <view class='coupon-red'>满200减8元</view>
-                <view class="validity-text">{{ couponData.validity }}</view>
+                <view class='coupon-red'>满{{ couponTypeDisplay.minSpend }}减{{ couponTypeDisplay.discount }}元</view>
+                <view class="validity-text">{{ couponTypeDisplay.validity }}</view>
               </view>
             </view>
           </view>
-        </view> -->
+        </view>
         <!-- 兑换券 -->
-        <view class="card-background">
+        <view v-else-if="couponTypeDisplay.type ==1" class="card-background">
 
           <view class="card-content change-content">
             <view class="info-section">
-              <text class="coupon-name">{{ couponData.name }}</text>
+              <text class="coupon-name">{{ couponTypeDisplay.name }}</text>
               <view>
                 <view class='coupon-red'>免费兑换</view>
-                <view class="validity-text">{{ couponData.validity }}</view>
+                <view class="validity-text">{{ couponTypeDisplay.validity }}</view>
               </view>
             </view>
           </view>
@@ -176,97 +246,60 @@ function clickShare() {
         <view class="detail-item has-arrow" @click='storeShow = true'>
           <text class="detail-label">适用分类</text>
           <view class="detail-right">
-            <text class="detail-value clamp">{{ couponDetails.applicableProducts }}</text>
+            <text class="detail-value clamp">{{ couponDetail?.relatedName  }}</text>
             <u--image class='income-right' :src="getImageUrl('@img/income/arrow-right.png')" mode="aspectFit"
               width="32rpx" height="32rpx"></u--image>
           </view>
         </view>
 
         <view class="detail-item has-arrow" @click='shopShow = true'>
-          <text class="detail-label">适用商品</text>
+          <text class="detail-label">{{ couponDetail?.relatedType == 3 ? '不适用商品' : '适用商品' }}</text>
           <view class="detail-right">
-            <text class="detail-value clamp">{{ couponDetails.applicableProducts }}</text>
+            <text class="detail-value clamp">{{ couponDetail?.productName }}</text>
             <u--image class='income-right' :src="getImageUrl('@img/income/arrow-right.png')" mode="aspectFit"
               width="32rpx" height="32rpx"></u--image>
           </view>
         </view>
+
       </view>
 
       <!-- 适用商家卡片 -->
       <view class="merchant-card-content">
         <view class="merchant-title">商家信息</view>
-        <view class="merchant-card">
-          <view class="merchant-thumb">
-            <image class="merchant-thumb-img" src="" mode="aspectFill" />
-          </view>
-          <view class="merchant-info">
-            <view class="merchant-name-row">
-              <text class="merchant-name">雪蜜冰城</text>
+        <view class="merchant-box"
+          v-if="couponDetail?.merchantInfoVOList && couponDetail.merchantInfoVOList.length > 0">
+          <view class="merchant-card" v-for="(merchant, index) in couponDetail.merchantInfoVOList" :key="index">
+            <view class="merchant-thumb">
+              <image class="merchant-thumb-img" :src="merchant.logo || ''" mode="aspectFill" />
             </view>
-            <view class="merchant-meta-row">
-              <view class="merchant-rating-group">
-                <view class="merchant-stars">
-                  <StarRating :rating="2" />
-                </view>
-                <text class="merchant-score">4.8超赞</text>
-                <text class="merchant-price">人均¥10</text>
-              </view>
-              <text class="merchant-distance">190m</text>
-            </view>
-            <view class="merchant-tags">
-              <view class="merchant-tag tag-orange">
-                <text>消费人数500+</text>
-              </view>
-              <view class="merchant-tag tag-red">
-                <text>收藏800+</text>
+            <view class="merchant-info">
+              <view class="merchant-name-row">
+                <text class="merchant-name">{{ merchant.storeName }}</text>
               </view>
-              <view class="merchant-tag tag-blue">
-                <text>好评率90%</text>
-              </view>
-              <view class="merchant-image">
-                <u--image :src="getImageUrl('@img/index/interests.png')" width="86rpx" height="26rpx"></u--image>
-              </view>
-            </view>
-            <view class="hot">
-              <view class="merchant-tag tag-gold">
-                <u--image :src="getImageUrl('@img/index/rank-f.png')" width="36rpx" height="33rpx"></u--image>
-                <text>万柏林区西餐厅热销榜第8名</text>
-              </view>
-            </view>
-          </view>
-        </view>
-        <view class="merchant-card">
-          <view class="merchant-thumb">
-            <image class="merchant-thumb-img" src="" mode="aspectFill" />
-          </view>
-          <view class="merchant-info">
-            <view class="merchant-name-row">
-              <text class="merchant-name">雪蜜冰城</text>
-            </view>
-            <view class="merchant-meta-row">
-              <view class="merchant-rating-group">
-                <view class="merchant-stars">
-                  <text class="star-icon" v-for="i in 5" :key="i">★</text>
+              <view class="merchant-meta-row">
+                <view class="merchant-rating-group">
+                  <view class="merchant-stars">
+                    <StarRating :rating="merchant.commentGradeAvg || 0" />
+                  </view>
+                  <text class="merchant-score">{{ merchant.commentGradeAvg || 0 }}超赞</text>
+                  <text class="merchant-price">人均¥{{ merchant.shopPriceAvg || 0 }}</text>
                 </view>
-                <text class="merchant-score">4.8超赞</text>
-                <text class="merchant-price">人均¥10</text>
-              </view>
-              <text class="merchant-distance">190m</text>
-            </view>
-            <view class="merchant-tags">
-              <view class="merchant-tag tag-orange">
-                <text>消费人数500+</text>
+                <text class="merchant-distance">{{ merchant.distance?merchant.distance.toFixed(2)+'km':"" }}</text>
               </view>
-              <view class="merchant-tag tag-red">
-                <text>收藏800+</text>
-              </view>
-              <view class="merchant-tag tag-blue">
-                <text>好评率90%</text>
+              <view class="merchant-tags">
+                <view class="merchant-tag tag-orange">
+                  <text>消费人数{{ merchant.consumptionNumber || 0 }}</text>
+                </view>
+                <view class="merchant-tag tag-red">
+                  <text>收藏{{ merchant.collectNumber || 0 }}</text>
+                </view>
               </view>
-
             </view>
           </view>
         </view>
+        <view v-else class="merchant-empty">
+          <text>暂无商家信息</text>
+        </view>
       </view>
 
       <!-- 温馨提示 -->
@@ -284,22 +317,24 @@ function clickShare() {
     </view>
 
     <view class="share-info">
-      <view class="share-btn" @click='clickShare'>去分享</view>
-      <!-- <view class="share-btn" @click='receive'>去领取</view> -->
+
+      <view class="share-btn" v-if='shareType==2' @click='receive'>去领取</view>
+      <view class="share-btn" v-else @click='clickShare'>去分享</view>
     </view>
   </view>
 
-  <!-- 适用商品 -->
-  <Upopup :isShow="storeShow" title='适用分类' @close='storeShow = false' :isFooter='false'>
+  <!-- 适用分类/商品 -->
+  <Upopup :isShow="storeShow" title="适用分类" @close='storeShow = false' :isFooter='false'>
     <view class="store-cont">
-      大同刀削面 | 水蒸蛋 | 水煮肉片 | 葱爆羊肉 | 打卤面 |葱爆羊肉 | 打卤面 |葱爆羊肉 | 打卤面
+      {{couponDetail?.relatedName}}
     </view>
   </Upopup>
 
-  <!-- 适用商家 -->
-  <Upopup :isShow="shopShow" title='适用商品' @close='shopShow = false' :isFooter='false'>
+  <!-- 适用商品 -->
+  <Upopup :isShow="shopShow" :title="couponDetail?.relatedType == 3 ? '不适用商品' : '适用商品'" @close='shopShow = false'
+    :isFooter='false'>
     <view class="store-cont">
-      大同刀削面 | 水蒸蛋 | 水煮肉片 | 葱爆羊肉 | 打卤面 |葱爆羊肉 | 打卤面 |葱爆羊肉 | 打卤面
+      {{couponDetail?.productName}}
     </view>
   </Upopup>
 </template>
@@ -333,10 +368,14 @@ function clickShare() {
         display: flex;
         align-items: center;
         height: 100%;
-        padding: 0 58rpx;
+        // padding: 0 58rpx;
         box-sizing: border-box;
 
         .discount-section {
+          width: 170rpx;
+          display: flex;
+          align-items: center;
+          justify-content: center;
           .discount-value {
             display: flex;
             align-items: baseline;
@@ -360,7 +399,7 @@ function clickShare() {
         }
 
         .info-section {
-          margin-left: 80rpx;
+          margin-left: 33rpx;
           display: flex;
           flex-direction: column;
           gap: 24rpx;
@@ -374,7 +413,7 @@ function clickShare() {
           .coupon-red {
             color: #ff5365;
             font-size: 24rpx;
-            margin-bottom: 8rpx;
+            margin-bottom: 12rpx;
           }
           .validity-text {
             font-weight: 400;
@@ -469,7 +508,7 @@ function clickShare() {
   .merchant-card-content {
     border-radius: 12rpx;
     background: #fff;
-    padding: 20rpx;
+    padding: 20rpx 20rpx 32rpx 20rpx;
     box-sizing: border-box;
     display: flex;
     flex-direction: column;
@@ -482,6 +521,17 @@ function clickShare() {
       border-bottom: 1rpx solid #eaeaea;
       box-sizing: border-box;
     }
+    .merchant-empty {
+      text-align: center;
+      padding: 40rpx 0;
+      color: #999;
+      font-size: 28rpx;
+    }
+  }
+  .merchant-box {
+    display: flex;
+    flex-direction: column;
+    gap: 40rpx;
   }
   .merchant-card {
     display: flex;

+ 6 - 6
src/store/area.ts

@@ -85,8 +85,10 @@ export const useAreaStore = defineStore('area', () => {
                 fail: async (err) => {
                     console.error('获取GPS地理位置失败,降级使用IP定位:', err)
                     
-                    await getIPLocation()
-                    // IP定位成功后更新当前城市
+                    let res: any =await getIPLocation()
+                    
+                     // 天地图逆地理编码 (经纬度 -> 获取城市信息)
+                    await updateGeocode(res.lat || 37.860262, res.lng || 112.556272);  
                     if (initCurrentCity.value.name !== '全部地区') {
                             currentCity.value = initCurrentCity.value
                         }
@@ -107,11 +109,9 @@ export const useAreaStore = defineStore('area', () => {
                         latitude: res.lat, 
                         longitude: res.lng 
                     })
-                    
-                    // 天地图逆地理编码 (经纬度 -> 获取城市信息)
-                    await updateGeocode(res.lat || 37.860262, res.lng || 112.556272);  
+                
                 }
-                resolve();
+                resolve(res);
             } catch (e) {
                 console.error('IP定位失败:', e)
                 resolve();