caiyuqin hai 2 meses
pai
achega
56511620a9

+ 20 - 0
src/api/home.ts

@@ -134,3 +134,23 @@ export function getCity() {
     return http.Get('/customer/home/current/city')
 }
 
+//首页统计
+export function getIssuerStatistics() {
+    return http.Get('/couponCenter/APP/couponUserAsset/getCouponDistributionData')
+}
+
+//排行榜
+export function getCouponDistributionDetailsList(params = {}) {
+    return http.Get('/couponCenter/APP/couponUserAsset/getCouponDistributionDetailsList', {
+        params,
+    })
+}
+
+
+//总发券数列表
+export function getIssuanceSituation(params = {}) {
+    return http.Get('/couponCenter/APP/couponUserAsset/getIssuanceSituation', {
+        params,
+    })
+}
+

+ 39 - 25
src/components/filter/filter.vue

@@ -47,8 +47,8 @@ import { getCategoryList } from "@/api/home";
 const emit = defineEmits(["selectValue"]);
 const props = defineProps({
   filter: {
-    type: Array,
-    default: () => [],
+    type: Object,
+    default: () => ({}),
   },
   className: {
     type: String,
@@ -57,8 +57,9 @@ const props = defineProps({
 
 // 日期
 const tabListDate = ref([
-  { label: "今天", value: "1", isSelected: false },
-  { label: "30天", value: "2", isSelected: false },
+  { label: "今天", type: "1", isSelected: false },
+  { label: "7天", type: "2", isSelected: false },
+  { label: "30天", type: "3", isSelected: false },
 ]);
 
 // 类型
@@ -70,9 +71,9 @@ const tabListType = ref([
 
 // 排行
 const tabListRank = ref([
-  { label: "按领取数", type: "1", isSelected: false },
-  { label: "按核销数", type: "2", isSelected: false },
-  { label: "按核销转换率", type: "3", isSelected: false },
+  { label: "按领取数", type: "receivedNum", isSelected: false },
+  { label: "按核销数", type: "writeOffAmount", isSelected: false },
+  { label: "按核销转换率", type: "writeOffRate", isSelected: false },
 ]);
 
 // 日期自定义
@@ -124,29 +125,41 @@ const groupConfig = ref([
 ]);
 
 const matchedDataList = ref([]);
-const setValue = (value) => {
-  const filterArray = props.filter;
-  if (!Array.isArray(filterArray) || filterArray.length === 0) {
-    return [];
+function initFilter() {
+  const filterObj = props.filter || {};
+  const keys = Object.keys(filterObj);
+  if (keys.length === 0) {
+    matchedDataList.value = [];
+    return;
   }
 
   const result = [];
-  for (const filterKey of filterArray) {
+  keys.forEach((filterKey) => {
     const matched = groupConfig.value.find((item) => item.key === filterKey);
-
-    if (matched) {
-      const rawData = matched.data;
-
-      result.push({
-        key: matched.key,
-        name: matched.name,
-        data: matched.data,
-        isOpen: matched.isOpen,
-      });
+    if (!matched) return;
+
+    const defaultValue = filterObj[filterKey];
+    if (defaultValue != null && Array.isArray(matched.data)) {
+      const matchedItem = matched.data.find(
+        (item) => String(item.type) === String(defaultValue)
+      );
+      if (matchedItem) {
+        matched.data.forEach((d) => (d.isSelected = false));
+        matchedItem.isSelected = true;
+        matched.name = matchedItem.label;
+        selectedValues.value[filterKey] = matchedItem;
+      }
     }
-  }
+
+    result.push({
+      key: matched.key,
+      name: matched.name,
+      data: matched.data,
+      isOpen: matched.isOpen,
+    });
+  });
   matchedDataList.value = result;
-};
+}
 
 const filterData = ref([]);
 const isOpen = ref(false);
@@ -224,7 +237,8 @@ onShow(async () => {
     isSelected: false,
     type: item.value,
   }));
-  setValue();
+  initFilter();
+  emit("selectValue", selectedValues.value);
 });
 
 // 暴露方法

+ 41 - 14
src/pages-C/home/ranking.vue

@@ -1,6 +1,7 @@
 <script lang="ts" setup>
 import { ref, computed } from "vue";
 import { storeToRefs } from "pinia";
+import { useRequest } from "alova/client";
 import { useUserStore } from "@/store/user";
 import { useTokenStore } from "@/store/token";
 import { safeAreaInsets, menuButtonInfo } from "@/utils";
@@ -11,6 +12,8 @@ import Upopup from "@/components/popup/index.vue";
 import DateRangePicker from "@/components/dateRangePicker/index.vue";
 import FilterSelect from "@/components/filter/filter.vue";
 
+import { getCouponDistributionDetailsList } from "@/api/home";
+
 definePage({
   style: {
     navigationStyle: "custom",
@@ -22,6 +25,15 @@ const userStore = useUserStore();
 const tokenStore = useTokenStore();
 const { hasLogin } = storeToRefs(tokenStore);
 
+const { send: getRankingListRequest, data: rankingList } = useRequest(
+  getCouponDistributionDetailsList,
+  {
+    immediate: false,
+  }
+);
+
+const filterRef = ref();
+
 //滚动
 const scrollTop = ref(0);
 onPageScroll((e) => {
@@ -67,10 +79,17 @@ const visibleNoticeList = computed(() => {
   ];
 });
 
-const filter = ["date", "dataFilter", "type", "rank"];
+function selectValue(selected) {
+  const params: Record<string, any> = {};
+  params.classification = selected?.type?.type;
+  params.sorting = selected?.rank?.type;
+  params.type = selected?.date?.type;
+  if (selected?.dataFilter) {
+    params.startTime = selected.dataFilter.startDate + " 00:00:00";
+    params.endTime = selected.dataFilter.endDate + " 23:59:59";
+  }
 
-function selectValue(item) {
-  console.log(item);
+  getRankingListRequest(params);
 }
 </script>
 
@@ -98,7 +117,9 @@ function selectValue(item) {
 
     <!-- 页面主内容 -->
     <view class="main-content">
-      <FilterSelect className='filter-select' :filter="filter" @selectValue='selectValue'></FilterSelect>
+      <FilterSelect ref='filterRef' className='filter-select'
+        :filter="{ date: '1', dataFilter: null, type: null, rank: 'receivedNum' }" @selectValue='selectValue'>
+      </FilterSelect>
 
       <view class="ranking-container-cont">
         <view class="ranking-container">
@@ -115,18 +136,24 @@ function selectValue(item) {
             height="44rpx">
           </u--image>
           <view class="ranking-list">
-            <view class="ranking-item">
-              <u--image class='selected-icon' :src="getImageUrl('@img/me/rank1.png')" mode="aspectFit" width="48rpx"
-                height="48rpx">
+            <view class="ranking-item" v-for="(item, index) in (rankingList || [])" :key="item.templateId || index">
+              <u--image v-if="item.serialNumber === 1" class='selected-icon' :src="getImageUrl('@img/me/rank1.png')"
+                mode="aspectFit" width="48rpx" height="48rpx">
+              </u--image>
+              <u--image v-else-if="item.serialNumber === 2" class='selected-icon'
+                :src="getImageUrl('@img/me/rank2.png')" mode="aspectFit" width="48rpx" height="48rpx">
               </u--image>
-              <text class="ranking-value">1256</text>
-              <text class="ranking-value">1256</text>
-              <text class="ranking-value">1256</text>
-              <text class="ranking-value">1256</text>
-              <text class="ranking-value">1256</text>
-              <text class="ranking-value">1256</text>
+              <u--image v-else-if="item.serialNumber === 3" class='selected-icon'
+                :src="getImageUrl('@img/me/rank3.png')" mode="aspectFit" width="48rpx" height="48rpx">
+              </u--image>
+              <text v-else class="ranking-value rank-num">{{ item.serialNumber }}</text>
+              <text class="ranking-value">{{ item.templateName }}</text>
+              <text class="ranking-value">{{ item.classification }}</text>
+              <text class="ranking-value">{{ item.browseNum }}</text>
+              <text class="ranking-value">{{ item.receivedNum }}</text>
+              <text class="ranking-value">{{ item.writeOffAmount }}</text>
+              <text class="ranking-value">{{ item.writeOffRate }}%</text>
             </view>
-
           </view>
         </view>
       </view>

+ 104 - 77
src/pages-C/home/sendCoupon.vue

@@ -1,7 +1,10 @@
 <script setup lang="ts">
 import { ref } from "vue";
+import { useRequest } from "alova/client";
 import { getImageUrl } from "@/utils/imageUtil";
 import FilterSelect from "@/components/filter/filter.vue";
+import LsvList from "@/components/listScrollView/index.vue";
+import { getIssuanceSituation } from "@/api/home";
 
 definePage({
   style: {
@@ -10,54 +13,68 @@ definePage({
   },
 });
 
-// 定义tab列表
-const tabList = ref([
-  { label: "今天", value: "0" },
-  { label: "近7天", value: "1" },
-  { label: "近30天", value: "2" },
-]);
+const totalAmount = ref();
+const templateName = ref("");
 
-// 当前选中的tab
-const currentTab = ref("0");
+const listRef = ref();
+const isMounted = ref(false);
+const filterObj = ref({ type: "", date: "1", dataFilter: null });
 
-// 点击tab事件
-const handleTabClick = (value) => {
-  currentTab.value = value;
-  console.log("选中tab:", value);
+const search = () => {
+  reloadListRef();
 };
 
-const keyword = ref("");
-async function search() {}
-async function clear() {}
+const filterParams = ref({});
+const selectValue = (selected) => {
+  if (!isMounted.value) {
+    isMounted.value = true;
+    return;
+  }
+  filterParams.value = selected;
+  reloadListRef();
+};
 
-const isOpen = ref(false);
-const popupRef = ref();
-function clickSelect() {
-  isOpen.value = !isOpen.value;
-  isOpen.value ? popupRef.value?.show() : popupRef.value?.close();
-}
+const clear = () => {
+  templateName.value = "";
+  reloadListRef();
+};
 
-const rewardTabs = ref([
-  { label: "美食", type: "1" },
-  { label: "车服务", type: "2" },
-]);
+const reloadListRef = (extraParams = {}) => {
+  listRef.value.reloadList({
+    templateName: templateName.value,
+    type: filterParams.value.date?.type,
+    classification: 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();
-}
+const getCouponListApi = (params) => {
+  return getIssuanceSituation({
+    pageNo: params.pageNo,
+    pageSize: params.pageSize,
+    templateName: params.templateName || "",
+    type: params.type ?? 1,
+    startTime: params.startTime || "",
+    endTime: params.endTime || "",
+    classification: params.classification || "",
+  });
+};
 
-const filter = ["type", "date", "dataFilter"];
+const afterFetch = (item) => {
+  totalAmount.value = item.totalAmount;
+};
 
-function selectValue(item) {
-  console.log(item);
-}
+const couponTypeMap = {
+  "1": "权益券",
+  "2": "折扣券",
+  "3": "满减券",
+  "4": "兑换券",
+};
 </script>
 
 <template>
@@ -66,49 +83,55 @@ 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="templateName" 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-total">合计领取:2384张</view>
-      <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>
-            <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 class="send-total">合计领取:{{ totalAmount || 0 }}张</view>
+      <LsvList ref="listRef" :api="getCouponListApi" key-name="detailList" @afterFetch='afterFetch'>
+        <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">{{ couponTypeMap[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">
+              <view class="detail-row">
+                <text class="detail-label">品类</text>
+                <text class="detail-value">{{ item.category || '全部' }}</text>
+              </view>
+              <view class="detail-row">
+                <text class="detail-label">用户领取</text>
+                <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>
           </view>
-        </view>
-        <u--image class='coupon1-icon' :src="getImageUrl('@img/me/coupon1.png')" mode="aspectFit" width="66rpx"
-          height="60rpx">
-        </u--image>
-      </view>
+        </template>
+      </LsvList>
     </view>
   </view>
 
@@ -181,6 +204,10 @@ function selectValue(item) {
         color: #ff5365;
         font-weight: 600;
       }
+      .discount-cap {
+        font-size: 24rpx;
+        color: #ff5365;
+      }
       .send-number-box {
         display: flex;
         align-items: baseline;

+ 2 - 2
src/pages-C/share/shareInfo.vue

@@ -19,7 +19,7 @@ onLoad((options: any) => {
 });
 definePage({
   style: {
-    navigationBarTitleText: "分享信息",
+    navigationBarTitleText: "优惠券详情",
     navigationStyle: "custom",
   },
 });
@@ -105,7 +105,7 @@ function clickShare() {
 
 <template>
   <view class="share-info-container">
-    <u-navbar title="分享信息" :autoBack="true" :placeholder="true" :border-bottom="false"
+    <u-navbar title="优惠券详情" :autoBack="true" :placeholder="true" :border-bottom="false"
       :title-style="{ fontWeight: 'bold', color: '#000' }" leftIconColor="#000"></u-navbar>
 
     <view class="share-info-content">

+ 18 - 13
src/pages/home/index.vue

@@ -2,7 +2,7 @@
 import { useRequest } from 'alova/client'
 import { storeToRefs } from 'pinia'
 import { ref, watch, computed } from 'vue'
-import { getAccountCount, getCouponDetail, getCouponSituation, getShareInfo } from '@/api/home'
+import { getAccountCount, getCouponDetail, getCouponSituation, getIssuerStatistics, getShareInfo } from '@/api/home'
 import CouponList from '@/components/couponList.vue'
 import { useShare } from '@/hooks/useShare'
 import { useNewCouponStore as useCouponStore } from '@/store/coupon'
@@ -52,6 +52,11 @@ const { send: getCouponSituationRequest, data: couponSituationData } = useReques
     dependencies: [],
 })
 
+// 获取首页发券统计数据
+const { send: getIssuerStatisticsRequest, data: issuerStatisticsData } = useRequest(getIssuerStatistics, {
+    immediate: false,
+})
+
 // 创建分享hook实例
 const { getShareConfig, getTimelineShareConfig } = useShare()
 
@@ -83,7 +88,7 @@ onShow((options) => {
     couponStore.getCouponListByType()
     // 登录后查询收益数据
     if (hasLogin.value) {
-        Promise.allSettled([getAccountCountRequest(), getCouponSituationRequest()])
+        Promise.allSettled([getAccountCountRequest(), getCouponSituationRequest(), getIssuerStatisticsRequest()])
     }
 })
 
@@ -137,6 +142,7 @@ async function onRefresh() {
         await userStore.fetchUserInfo()
         await getAccountCountRequest()
         await getCouponSituationRequest()
+        await getIssuerStatisticsRequest()
     }
     refreshing.value = false
 }
@@ -153,39 +159,38 @@ const headerOverlayOpacity = computed(() => {
 
 
 
-const form = ref({});
 const visibleNoticeList = computed(() => {
-  const data = form.value || {};
+  const data = issuerStatisticsData.value || {};
   return [
     {
       title: "累计领取(张)",
-      content: data.totalIncome || 0,
+      content: data.cumulativeNumberClaimants || 0,
       page: `/pages-C/home/sendWriteOff?type=1`,
     },
 
     {
       title: "累计未领取(张)",
-      content: data.bankCards || 0,
+      content: data.cumulativeUnclaimedNumber || 0,
       page: "/pages-C/home/sendWriteOff?type=2",
     },
     {
      title: "浏览领取转换率",
-      content: data.inviteIncome || 0,
+      content: data.viewToClaimRateRate ? data.viewToClaimRateRate + '%' : '0%',
       page: "",
     },
     {
        title: "累计待核销(张)",
-      content: data.shareIncome || 0,
+      content: data.accumulatedUnwritten || 0,
       page: "/pages-C/home/sendCancelWriteOff?type=1",
     },
     {
        title: "累计已核销(张)",
-      content: data.totalWithdraw || 0,
+      content: data.accumulatedWriteOffs || 0,
       page: "/pages-C/home/sendCancelWriteOff?type=2",
     },
     {
        title: "领取核销转换率",
-      content: data.writeOffIncome || 0,
+      content: data.claimToWriteOffRateRate ? data.claimToWriteOffRateRate + '%' : '0%',
       page: "",
     },
   ];
@@ -230,7 +235,7 @@ function handleViewDetail(item) {
                            <view @click='handleViewDetail({page:"/pages-C/home/sendCoupon"})'> 累计发券(张)</view>
                            <view class='number-count' @click='handleViewDetail({page:"/pages-C/home/browse"})'> 
                               <u--image class='income-phone' :src="getImageUrl('@img/index/eye.png')" width="24rpx" height="24rpx"></u--image>
-                              <view class="income-name">浏览人数:3985人</view>
+                              <view class="income-name">浏览人数:{{ issuerStatisticsData?.cumulativeViews || 0 }}人</view>
                              <u--image class='income-phone' :src="getImageUrl('@img/index/white-right.png')" width="32rpx" height="32rpx"></u--image>
                            </view>
                         </view>
@@ -240,7 +245,7 @@ function handleViewDetail(item) {
                                     <up-loading-icon size="65rpx" mode="semicircle" color="#fff" />
                                 </template>
                                 <template v-else>
-                                    {{ !hasLogin ? '********' : accountCountData?.balance || 0 }}
+                                    {{ !hasLogin ? '********' : issuerStatisticsData?.cumulativeIssuanceVouchers || 0 }}
                                 </template>
                             </view>
                         </view>
@@ -251,7 +256,7 @@ function handleViewDetail(item) {
                                 {{item.title}}
                             </view>
                             <view class="home-header-tips-item-num">
-                                {{item.content}}
+                                {{ !hasLogin ? '********' : item.content }}
                             </view>
                         </view>
                     </view>