feat(M08-B): 补保洁统计趋势
This commit is contained in:
+3
-1
@@ -240,7 +240,8 @@ const statistics = reactive<CleaningStatistics>({
|
||||
byStatus: [],
|
||||
byStore: [],
|
||||
settlements: [],
|
||||
members: []
|
||||
members: [],
|
||||
trend: []
|
||||
});
|
||||
|
||||
function saveToken() {
|
||||
@@ -301,6 +302,7 @@ async function loadStatistics() {
|
||||
statistics.byStore = result.byStore;
|
||||
statistics.settlements = result.settlements;
|
||||
statistics.members = result.members;
|
||||
statistics.trend = result.trend;
|
||||
}, '统计已刷新');
|
||||
loading.statistics = false;
|
||||
}
|
||||
|
||||
@@ -71,6 +71,30 @@
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<section class="stat-block">
|
||||
<header>
|
||||
<h3>每日趋势</h3>
|
||||
<span>任务 / 待验 / 发放</span>
|
||||
</header>
|
||||
<div class="trend-list">
|
||||
<div v-for="row in statistics.trend" :key="row.date" class="trend-row">
|
||||
<div class="trend-date">{{ row.date }}</div>
|
||||
<div class="trend-track" aria-label="每日任务趋势">
|
||||
<span class="trend-bar" :style="{ width: trendWidth(row.taskTotal) }" />
|
||||
</div>
|
||||
<div class="trend-meta">
|
||||
<strong>{{ row.taskTotal }}</strong>
|
||||
<span>待验 {{ row.pendingReview }}</span>
|
||||
<span>完成 {{ row.completed }}</span>
|
||||
<span>驳回 {{ row.rejected }}</span>
|
||||
<span>奖励 {{ money(row.rewardCents) }}</span>
|
||||
<span>发放 {{ money(row.paidSettlementCents) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<el-empty v-if="statistics.trend.length === 0" description="暂无趋势数据" :image-size="72" />
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="stat-block">
|
||||
<header>
|
||||
<h3>门店明细</h3>
|
||||
@@ -116,7 +140,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { reactive, watch } from 'vue';
|
||||
import { computed, reactive, watch } from 'vue';
|
||||
import { RefreshCw, Search } from '@lucide/vue';
|
||||
import { compactText, money } from '../format';
|
||||
import type { CleaningStatistics } from '../types';
|
||||
@@ -138,6 +162,7 @@ const quickOptions = [
|
||||
{ label: '近7天', value: '7d' },
|
||||
{ label: '本月', value: 'month' }
|
||||
];
|
||||
const maxTrendTotal = computed(() => Math.max(1, ...props.statistics.trend.map((row) => row.taskTotal)));
|
||||
|
||||
watch(
|
||||
() => props.filters,
|
||||
@@ -174,4 +199,8 @@ function formatDate(date: Date) {
|
||||
const day = String(date.getDate()).padStart(2, '0');
|
||||
return `${year}-${month}-${day}`;
|
||||
}
|
||||
|
||||
function trendWidth(total: number) {
|
||||
return `${Math.max(6, Math.round((total / maxTrendTotal.value) * 100))}%`;
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -314,6 +314,54 @@ textarea {
|
||||
background: #f5f8fb;
|
||||
}
|
||||
|
||||
.trend-list {
|
||||
display: grid;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.trend-row {
|
||||
display: grid;
|
||||
grid-template-columns: 92px minmax(80px, 1fr) minmax(360px, 2.4fr);
|
||||
gap: 12px;
|
||||
align-items: center;
|
||||
min-height: 38px;
|
||||
}
|
||||
|
||||
.trend-date {
|
||||
color: #334155;
|
||||
font-size: 13px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.trend-track {
|
||||
height: 8px;
|
||||
overflow: hidden;
|
||||
background: #e9eff5;
|
||||
border-radius: 999px;
|
||||
}
|
||||
|
||||
.trend-bar {
|
||||
display: block;
|
||||
height: 100%;
|
||||
background: #2563eb;
|
||||
border-radius: inherit;
|
||||
}
|
||||
|
||||
.trend-meta {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
align-items: center;
|
||||
min-width: 0;
|
||||
color: #60708a;
|
||||
font-size: 12px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.trend-meta strong {
|
||||
color: #101828;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.detail-grid strong {
|
||||
overflow: hidden;
|
||||
color: #18212f;
|
||||
@@ -421,6 +469,15 @@ textarea {
|
||||
.metric-grid {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.trend-row {
|
||||
grid-template-columns: 92px minmax(80px, 1fr);
|
||||
}
|
||||
|
||||
.trend-meta {
|
||||
grid-column: 1 / -1;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 560px) {
|
||||
@@ -447,8 +504,13 @@ textarea {
|
||||
|
||||
.member-form,
|
||||
.detail-grid,
|
||||
.trend-row,
|
||||
.stats-filter,
|
||||
.stats-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.trend-meta {
|
||||
grid-column: auto;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,6 +156,15 @@ export interface CleaningStatistics {
|
||||
pendingSettlementCents: number;
|
||||
settledRewardCents: number;
|
||||
}>;
|
||||
trend: Array<{
|
||||
date: string;
|
||||
taskTotal: number;
|
||||
pendingReview: number;
|
||||
completed: number;
|
||||
rejected: number;
|
||||
rewardCents: number;
|
||||
paidSettlementCents: number;
|
||||
}>;
|
||||
}
|
||||
|
||||
export type WechatTransferPreflightStatus = 'PASS' | 'WARN' | 'FAIL';
|
||||
|
||||
Reference in New Issue
Block a user