305 lines
		
	
	
		
			8.0 KiB
		
	
	
	
		
			Vue
		
	
	
	
			
		
		
	
	
			305 lines
		
	
	
		
			8.0 KiB
		
	
	
	
		
			Vue
		
	
	
	
| <template>
 | ||
|   <view class="container">
 | ||
|     <!-- <view class="search-bar">
 | ||
|       <u-search
 | ||
|         placeholder="请输入会员编号或姓名查询"
 | ||
|         v-model="keyword"
 | ||
|         @custom="search"
 | ||
|         @search="search"
 | ||
|       ></u-search>
 | ||
|     </view> -->
 | ||
| 
 | ||
|     <!-- 特殊会员信息 -->
 | ||
|     <view class="top-member-card" v-if="topMember">
 | ||
|       <view class="member-info-header">
 | ||
|         <text>会员信息:</text>
 | ||
|         <text class="member-info-text">{{ formatMemberInfo(topMember) }}</text>
 | ||
|       </view>
 | ||
|       <view class="stats-grid">
 | ||
|         <view class="stat-item">
 | ||
|           <text class="stat-value">{{ toInt(topMember.todayBox) }}</text>
 | ||
|           <text class="stat-label">今日盒数</text>
 | ||
|         </view>
 | ||
|         <view class="stat-item">
 | ||
|           <text class="stat-value">{{ topMember.yesterdayBox }}</text>
 | ||
|           <text class="stat-label">昨日盒数</text>
 | ||
|         </view>
 | ||
|         <view class="stat-item">
 | ||
|           <text class="stat-value">{{ topMember.monthBox }}</text>
 | ||
|           <text class="stat-label">本月盒数</text>
 | ||
|         </view>
 | ||
|         <view class="stat-item">
 | ||
|           <text class="stat-value">{{ topMember.lastMonthBox }}</text>
 | ||
|           <text class="stat-label">上月盒数</text>
 | ||
|         </view>
 | ||
|       </view>
 | ||
|     </view>
 | ||
| 
 | ||
|     <!-- 列表 -->
 | ||
|     <view class="member-list">
 | ||
|       <view class="member-item" v-for="item in memberList" :key="item.memberId">
 | ||
|         <view class="member-info-header list-header">
 | ||
|           <text>会员信息:</text>
 | ||
|           <text>{{ formatMemberInfo(item) }}</text>
 | ||
|         </view>
 | ||
|         <view class="stats-grid list-grid">
 | ||
|           <view class="stat-item">
 | ||
|             <text class="stat-value">{{ toInt(item.todayBox) }}</text>
 | ||
|             <text class="stat-label">今日盒数</text>
 | ||
|           </view>
 | ||
|           <view class="stat-item">
 | ||
|             <text class="stat-value">{{ item.yesterdayBox }}</text>
 | ||
|             <text class="stat-label">昨日盒数</text>
 | ||
|           </view>
 | ||
|           <view class="stat-item">
 | ||
|             <text class="stat-value">{{ item.monthBox }}</text>
 | ||
|             <text class="stat-label">本月盒数</text>
 | ||
|           </view>
 | ||
|           <view class="stat-item">
 | ||
|             <text class="stat-value">{{ item.lastMonthBox }}</text>
 | ||
|             <text class="stat-label">上月盒数</text>
 | ||
|           </view>
 | ||
|         </view>
 | ||
|       </view>
 | ||
|     </view>
 | ||
| 
 | ||
|     <u-loadmore :status="loadStatus" />
 | ||
|   </view>
 | ||
| </template>
 | ||
| 
 | ||
| <script>
 | ||
| // 假设的API方法,您需要替换为真实实现
 | ||
| // import { getMarketBoxTop, getMarketBoxList } from '@/config/mine.js';
 | ||
| 
 | ||
| export default {
 | ||
|   data() {
 | ||
|     return {
 | ||
|       keyword: '',
 | ||
|       topMember: null, // 置顶的特殊会员
 | ||
|       memberList: [], // 成员列表
 | ||
|       page: 1,
 | ||
|       pageSize: 10,
 | ||
|       loadStatus: 'loadmore', // loadmore, loading, nomore
 | ||
|     }
 | ||
|   },
 | ||
|   onLoad() {
 | ||
|     this.fetchTopMember()
 | ||
|     this.fetchMemberList(true)
 | ||
|   },
 | ||
|   onReachBottom() {
 | ||
|     if (this.loadStatus === 'nomore' || this.loadStatus === 'loading') {
 | ||
|       return
 | ||
|     }
 | ||
|     this.page++
 | ||
|     this.fetchMemberList()
 | ||
|   },
 | ||
|   methods: {
 | ||
|     toInt(value) {
 | ||
|       const intValue = parseInt(value, 10)
 | ||
|       return isNaN(intValue) ? value : intValue
 | ||
|     },
 | ||
|     formatMemberInfo(member) {
 | ||
|       if (!member) return ''
 | ||
|       const { memberCode, nickName, grade, award } = member
 | ||
|       return `${memberCode}/${nickName || '未知'}/${grade}/${award}`
 | ||
|     },
 | ||
|     search() {
 | ||
|       this.memberList = []
 | ||
|       this.page = 1
 | ||
|       this.fetchTopMember()
 | ||
|       this.fetchMemberList(true)
 | ||
|     },
 | ||
|     // 获取置顶会员数据
 | ||
|     async fetchTopMember() {
 | ||
|       // --- MOCK DATA from screenshot ---
 | ||
|       this.topMember = {
 | ||
|         memberId: 'HZS55197913',
 | ||
|         memberCode: 'HZS55197913',
 | ||
|         nickName: '未知', // Screenshot has no name, API might
 | ||
|         grade: 'V5',
 | ||
|         award: 'S2',
 | ||
|         todayBox: 3361.0,
 | ||
|         yesterdayBox: 114,
 | ||
|         monthBox: 3475,
 | ||
|         lastMonthBox: 3206,
 | ||
|       }
 | ||
|       // --- REAL API CALL ---
 | ||
|       // try {
 | ||
|       //   const res = await getMarketBoxTop({ keyword: this.keyword });
 | ||
|       //   if (res.code === 200) {
 | ||
|       //     // Real data mapping from fields like realizedBox, upMonthBox
 | ||
|       //     this.topMember = { ...res.data, todayBox: res.data.realizedBox, lastMonthBox: res.data.upMonthBox };
 | ||
|       //   }
 | ||
|       // } catch (e) {
 | ||
|       //   console.error(e);
 | ||
|       // }
 | ||
|     },
 | ||
|     // 获取会员列表数据
 | ||
|     async fetchMemberList(isRefresh = false) {
 | ||
|       if (isRefresh) {
 | ||
|         this.page = 1
 | ||
|         this.memberList = []
 | ||
|       }
 | ||
|       this.loadStatus = 'loading'
 | ||
| 
 | ||
|       // --- MOCK DATA from screenshot ---
 | ||
|       const mockData = [
 | ||
|         {
 | ||
|           memberId: 'HZS931295626',
 | ||
|           memberCode: 'HZS931295626',
 | ||
|           nickName: '未知',
 | ||
|           grade: 'V5',
 | ||
|           award: 'S1',
 | ||
|           todayBox: 38.0,
 | ||
|           yesterdayBox: 0,
 | ||
|           monthBox: 38,
 | ||
|           lastMonthBox: 503,
 | ||
|         },
 | ||
|         {
 | ||
|           memberId: 'HZS938173516',
 | ||
|           memberCode: 'HZS938173516',
 | ||
|           nickName: '未知',
 | ||
|           grade: 'V3',
 | ||
|           award: 'S0',
 | ||
|           todayBox: 25.0,
 | ||
|           yesterdayBox: 0,
 | ||
|           monthBox: 25,
 | ||
|           lastMonthBox: 0,
 | ||
|         },
 | ||
|         {
 | ||
|           memberId: 'HZS61632161',
 | ||
|           memberCode: 'HZS61632161',
 | ||
|           nickName: '未知',
 | ||
|           grade: 'V3',
 | ||
|           award: 'S0',
 | ||
|           todayBox: 16.0,
 | ||
|           yesterdayBox: 0,
 | ||
|           monthBox: 16,
 | ||
|           lastMonthBox: 0,
 | ||
|         },
 | ||
|         {
 | ||
|           memberId: 'HZS978982363',
 | ||
|           memberCode: 'HZS978982363',
 | ||
|           nickName: '未知',
 | ||
|           grade: 'V3',
 | ||
|           award: 'S0',
 | ||
|           todayBox: 15.0,
 | ||
|           yesterdayBox: 0,
 | ||
|           monthBox: 15,
 | ||
|           lastMonthBox: 0,
 | ||
|         },
 | ||
|       ]
 | ||
| 
 | ||
|       // Simulate network delay and pagination
 | ||
|       setTimeout(() => {
 | ||
|         // Mock: stop after 2 pages
 | ||
|         if (this.page > 2) {
 | ||
|           this.loadStatus = 'nomore'
 | ||
|           return
 | ||
|         }
 | ||
| 
 | ||
|         const moreData = mockData.map(item => ({
 | ||
|           ...item,
 | ||
|           memberId: item.memberId + this.page, // unique key for v-for
 | ||
|         }))
 | ||
|         this.memberList = [...this.memberList, ...moreData]
 | ||
| 
 | ||
|         // After adding data, check if we should be able to load more
 | ||
|         this.loadStatus = this.page >= 2 ? 'nomore' : 'loadmore'
 | ||
|       }, 500)
 | ||
| 
 | ||
|       // --- REAL API CALL ---
 | ||
|       // try {
 | ||
|       //   const res = await getMarketBoxList({ page: this.page, size: this.pageSize, keyword: this.keyword });
 | ||
|       //   if (res.code === 200) {
 | ||
|       //     const newList = res.data.records.map(item => ({ ...item, todayBox: item.realizedBox, lastMonthBox: item.upMonthBox }));
 | ||
|       //     this.memberList = [...this.memberList, ...newList];
 | ||
|       //     if (res.data.records.length < this.pageSize) {
 | ||
|       //       this.loadStatus = 'nomore';
 | ||
|       //     } else {
 | ||
|       //       this.loadStatus = 'loadmore';
 | ||
|       //     }
 | ||
|       //   }
 | ||
|       // } catch(e) {
 | ||
|       //   this.loadStatus = 'loadmore';
 | ||
|       //   console.error(e);
 | ||
|       // }
 | ||
|     },
 | ||
|   },
 | ||
| }
 | ||
| </script>
 | ||
| 
 | ||
| <style lang="scss" scoped>
 | ||
| .container {
 | ||
|   padding: 20rpx;
 | ||
|   background-color: #f5f5f5;
 | ||
|   min-height: 100vh;
 | ||
| }
 | ||
| 
 | ||
| .search-bar {
 | ||
|   margin-bottom: 20rpx;
 | ||
| }
 | ||
| 
 | ||
| .top-member-card {
 | ||
|   background: linear-gradient(135deg, #005bac, #007bff);
 | ||
|   border-radius: 16rpx;
 | ||
|   padding: 20rpx;
 | ||
|   color: #ffffff;
 | ||
|   margin-bottom: 20rpx;
 | ||
|   box-shadow: 0 4rpx 12rpx rgba(0, 91, 172, 0.3);
 | ||
| }
 | ||
| 
 | ||
| .member-info-header {
 | ||
|   font-size: 28rpx;
 | ||
|   margin-bottom: 20rpx;
 | ||
|   .member-info-text {
 | ||
|     font-weight: bold;
 | ||
|   }
 | ||
| }
 | ||
| 
 | ||
| .stats-grid {
 | ||
|   display: flex;
 | ||
|   justify-content: space-around;
 | ||
|   text-align: center;
 | ||
| }
 | ||
| 
 | ||
| .stat-item {
 | ||
|   display: flex;
 | ||
|   flex-direction: column;
 | ||
|   gap: 10rpx;
 | ||
| }
 | ||
| 
 | ||
| .stat-value {
 | ||
|   font-size: 32rpx;
 | ||
|   font-weight: bold;
 | ||
| }
 | ||
| 
 | ||
| .stat-label {
 | ||
|   font-size: 24rpx;
 | ||
|   opacity: 0.9;
 | ||
| }
 | ||
| 
 | ||
| .member-list {
 | ||
|   .member-item {
 | ||
|     background: #ffffff;
 | ||
|     border-radius: 16rpx;
 | ||
|     padding: 20rpx;
 | ||
|     margin-bottom: 20rpx;
 | ||
|     box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.05);
 | ||
| 
 | ||
|     .list-header {
 | ||
|       color: #333;
 | ||
|       font-size: 26rpx;
 | ||
|     }
 | ||
|     .list-grid {
 | ||
|       .stat-value {
 | ||
|         color: #333;
 | ||
|       }
 | ||
|       .stat-label {
 | ||
|         color: #666;
 | ||
|       }
 | ||
|     }
 | ||
|   }
 | ||
| }
 | ||
| </style>
 |