diff --git a/api/dashboard.js b/api/dashboard.js index ca47a9a..4ed89ba 100644 --- a/api/dashboard.js +++ b/api/dashboard.js @@ -34,8 +34,15 @@ export const getDashboardBrief = ({ joinUserId, keys }) => { * 获取客户统计排行榜 * @returns {Promise} 返回排行榜数据,包含 today、week、month 三个时间段的数据 */ -export const getCustomerStatistics = () => { - return uni.$uv.http.get('/dashboard/customer/statistics', { +export const getCustomerStatistics = (params = {}) => { + // 期望传入为数组: [start, end] 或 [day, day] + const dateRange = Array.isArray(params) ? params : []; + const query = + dateRange.length > 0 + ? `?${dateRange.map(d => `queryDateRange=${encodeURIComponent(d)}`).join('&')}` + : ''; + + return uni.$uv.http.get(`/dashboard/customer/statistics${query}`, { custom: { auth: true // 启用 token 认证 } diff --git a/components/index/RankingBoard.vue b/components/index/RankingBoard.vue index a941e18..deaa2d3 100644 --- a/components/index/RankingBoard.vue +++ b/components/index/RankingBoard.vue @@ -3,8 +3,22 @@ - 排行榜 - 🏆 + + + 排行榜 + 🏆 + + {{ dayLabel }} + {{ weekLabel }} + {{ monthLabel }} + + + 今日 + 昨日 + + 往期 + + @@ -130,83 +144,124 @@ import { ref, computed, onMounted } from 'vue'; import { getCustomerStatistics } from '@/api/dashboard'; import { useUserStore } from '@/store/user'; -// 当前选中的tab const currentTab = ref('today'); - -// 加载状态 const loading = ref(false); -// 排行榜数据 -const rankingData = ref({ - today: [], - week: [], - month: [] -}); - -// 当前用户ID const userStore = useUserStore(); const currentUserId = computed(() => { - const userId = userStore.userInfo?.user.userId; - console.log('userId',userStore.userInfo.user.userId); - - return String(userId); // 确保返回字符串类型,与接口数据一致 + const userId = userStore.userInfo?.user?.userId; + return userId != null ? String(userId) : ''; }); -// 当前显示的排行榜列表(原始数据,不修改) +const formatDate = (date) => { + const year = date.getFullYear(); + const month = `${date.getMonth() + 1}`.padStart(2, '0'); + const day = `${date.getDate()}`.padStart(2, '0'); + return `${year}-${month}-${day}`; +}; + +const addDays = (date, days) => { + const next = new Date(date); + next.setDate(next.getDate() + days); + return next; +}; + +const getWeekRange = (date) => { + const temp = new Date(date); + const day = temp.getDay(); + const diffToMonday = day === 0 ? -6 : 1 - day; + const startDate = addDays(temp, diffToMonday); + const endDate = addDays(startDate, 6); + return { + start: formatDate(startDate), + end: formatDate(endDate) + }; +}; + +const getMonthRange = (date) => { + const startDate = new Date(date.getFullYear(), date.getMonth(), 1); + const endDate = new Date(date.getFullYear(), date.getMonth() + 1, 0); + return { + start: formatDate(startDate), + end: formatDate(endDate) + }; +}; + +const todayStr = formatDate(new Date()); +const yesterdayStr = formatDate(addDays(new Date(), -1)); +const selectedDate = ref(todayStr); + +const weekRange = ref(getWeekRange(new Date())); +const monthRange = ref(getMonthRange(new Date())); + +const dayRanking = ref([]); +const weekRanking = ref([]); +const monthRanking = ref([]); + +const isToday = computed(() => selectedDate.value === todayStr); +const isYesterday = computed(() => selectedDate.value === yesterdayStr); + +const dayLabel = computed(() => { + if (isToday.value) return '统计日期:今日'; + if (isYesterday.value) return '统计日期:昨日'; + return `统计日期:${selectedDate.value}`; +}); +const weekLabel = computed(() => `统计周期:${weekRange.value.start} ~ ${weekRange.value.end}`); +const monthLabel = computed(() => `统计周期:${monthRange.value.start} ~ ${monthRange.value.end}`); + const currentRankingList = computed(() => { - return rankingData.value[currentTab.value] || []; + if (currentTab.value === 'today') return dayRanking.value; + if (currentTab.value === 'week') return weekRanking.value; + return monthRanking.value; }); -// 当前用户的排名信息(从排行榜数据中查找并提取,不修改原数据) const currentUserRank = computed(() => { const list = currentRankingList.value; const userId = currentUserId.value; - - // 如果没有用户ID,返回null - if (!userId) return null; - - // 在排行榜数据中查找自己的ID - const userItem = list.find(item => String(item.userId) === String(userId)); - - // 如果找不到,返回null - if (!userItem) return null; - - // 计算排名(索引+1) - const rank = list.findIndex(item => String(item.userId) === String(userId)) + 1; - - console.log('userrank',rank); - // 返回用户信息的副本,添加排名信息(不修改原数据) + if (!userId || !Array.isArray(list) || list.length === 0) return null; + const index = list.findIndex(item => String(item.userId) === String(userId)); + if (index === -1) return null; return { - ...userItem, - rank: rank + ...list[index], + rank: index + 1 }; }); -// 切换tab -const switchTab = (tab) => { - currentTab.value = tab; +const normalizeList = (res) => { + if (!res) return []; + if (Array.isArray(res)) return res; + if (Array.isArray(res.data)) return res.data; + if (Array.isArray(res.rows)) return res.rows; + return []; }; -// 获取头像文字(取姓名最后一个字) -const getAvatarText = (name) => { - if (!name) return '?'; - return name.length > 1 ? name.slice(-1) : name; +const buildRangeParams = (start, end) => ([start, end]); + +const fetchDayRanking = async (date) => { + const res = await getCustomerStatistics(buildRangeParams(date, date)); + dayRanking.value = normalizeList(res); }; -// 加载排行榜数据 -const loadRankingData = async () => { +const fetchWeekRanking = async () => { + const { start, end } = weekRange.value; + const res = await getCustomerStatistics(buildRangeParams(start, end)); + weekRanking.value = normalizeList(res); +}; + +const fetchMonthRanking = async () => { + const { start, end } = monthRange.value; + const res = await getCustomerStatistics(buildRangeParams(start, end)); + monthRanking.value = normalizeList(res); +}; + +const init = async () => { + loading.value = true; try { - loading.value = true; - const res = await getCustomerStatistics(); - console.log('排行榜数据:', res); - - if (res ) { - rankingData.value = { - today: res.today || [], - week: res.week || [], - month: res.month || [] - }; - } + await Promise.all([ + fetchDayRanking(selectedDate.value), + fetchWeekRanking(), + fetchMonthRanking() + ]); } catch (err) { console.error('加载排行榜数据失败:', err); uni.showToast({ @@ -218,9 +273,43 @@ const loadRankingData = async () => { } }; -// 组件挂载时加载数据 +const refreshDayRanking = async () => { + loading.value = true; + try { + await fetchDayRanking(selectedDate.value); + } catch (err) { + console.error('加载日排行失败:', err); + uni.showToast({ + title: '加载数据失败', + icon: 'none' + }); + } finally { + loading.value = false; + } +}; + +const switchTab = (tab) => { + currentTab.value = tab; +}; + +const setDay = (date) => { + if (!date || selectedDate.value === date) return; + selectedDate.value = date; + refreshDayRanking(); +}; + +const handleDateChange = (event) => { + const value = event?.detail?.value; + if (value) { + setDay(value); + } +}; + +const onTodayClick = () => setDay(todayStr); +const onYesterdayClick = () => setDay(yesterdayStr); + onMounted(() => { - loadRankingData(); + init(); }); @@ -278,6 +367,50 @@ onMounted(() => { font-weight: bold; color: #ffffff; } +.header-content { + display: flex; + justify-content: space-between; + align-items: flex-start; + gap: 24rpx; +} +.header-info { + display: flex; + flex-direction: column; + gap: 12rpx; +} +.title-row { + display: flex; + align-items: center; + gap: 12rpx; +} +.date-label { + font-size: 24rpx; + color: rgba(255, 255, 255, 0.9); +} +.header-actions { + display: flex; + align-items: center; + gap: 16rpx; +} +.quick-btn, +.history-btn { + padding: 12rpx 28rpx; + border-radius: 999rpx; + font-size: 24rpx; + color: #ffffff; + border: 1rpx solid rgba(255, 255, 255, 0.6); + background: rgba(255, 255, 255, 0.2); +} +.quick-btn.active { + background: #ffffff; + color: #ff6b35; + border-color: #ffffff; +} +.history-btn { + display: inline-flex; + align-items: center; + justify-content: center; +} .trophy-icon { font-size: 80rpx; diff --git a/utils/request/index.js b/utils/request/index.js index 1a9501b..a397cd6 100644 --- a/utils/request/index.js +++ b/utils/request/index.js @@ -11,7 +11,7 @@ export const Request = () => { uni.$uv.http.setConfig((config) => { /* config 为默认全局配置*/ config.baseURL = 'http://192.168.1.5:4001'; /* 根域名 */ - // config.baseURL = 'https://pm.ccttiot.com/prod-api'; /* 根域名 */ + config.baseURL = 'https://pm.ccttiot.com/prod-api'; /* 根域名 */ return config })