feat(M08-B): 补统计保洁员筛选

This commit is contained in:
Codex
2026-06-30 17:56:35 +08:00
parent e6bb5e6dc6
commit 78fb6ed2d0
12 changed files with 95 additions and 23 deletions
+5 -3
View File
@@ -137,6 +137,7 @@
:loading="loading.statistics"
:statistics="statistics"
:filters="statisticsFilters"
:cleaners="cleaners.items"
@refresh="loadStatistics"
@filter="changeStatisticsFilters"
/>
@@ -232,7 +233,7 @@ const settlements = reactive<PageResult<CleaningSettlement>>({
const cleaners = reactive<PageResult<ManagedUser>>({ items: [], total: 0, page: 1, pageSize: 20 });
const taskFilters = reactive({ storeId: '', cleanerUserId: '' });
const settlementFilters = reactive({ storeId: '', cleanerUserId: '' });
const statisticsFilters = reactive({ from: '', to: '', storeId: '' });
const statisticsFilters = reactive({ from: '', to: '', storeId: '', cleanerUserId: '' });
const statistics = reactive<CleaningStatistics>({
summary: {
taskTotal: 0,
@@ -307,7 +308,8 @@ async function loadStatistics() {
const result = await getCleaningStatistics(session.value, {
from: statisticsFilters.from || undefined,
to: statisticsFilters.to || undefined,
storeId: statisticsFilters.storeId || undefined
storeId: statisticsFilters.storeId || undefined,
cleanerUserId: statisticsFilters.cleanerUserId || undefined
});
Object.assign(statistics.summary, result.summary);
statistics.byStatus = result.byStatus;
@@ -373,7 +375,7 @@ function changeSettlementPage(page: number) {
void loadSettlements();
}
function changeStatisticsFilters(input: { from: string; to: string; storeId: string }) {
function changeStatisticsFilters(input: { from: string; to: string; storeId: string; cleanerUserId: string }) {
Object.assign(statisticsFilters, input);
void loadStatistics();
}
+2 -1
View File
@@ -71,12 +71,13 @@ export function listCleaningTasks(
export function getCleaningStatistics(
session: ApiSession,
input: { from?: string; to?: string; storeId?: string } = {}
input: { from?: string; to?: string; storeId?: string; cleanerUserId?: string } = {}
) {
const params = new URLSearchParams();
if (input.from) params.set('from', input.from);
if (input.to) params.set('to', input.to);
if (input.storeId) params.set('storeId', input.storeId);
if (input.cleanerUserId) params.set('cleanerUserId', input.cleanerUserId);
const query = params.toString();
return request<CleaningStatistics>(session, `/cleaning/statistics${query ? `?${query}` : ''}`);
}
@@ -14,6 +14,27 @@
<el-form-item label="门店 ID">
<el-input v-model="filterDraft.storeId" inputmode="numeric" />
</el-form-item>
<el-form-item label="保洁员">
<el-select
v-model="filterDraft.cleanerUserId"
class="filter-select"
clearable
filterable
placeholder="保洁员"
>
<el-option
v-for="cleaner in cleaners"
:key="cleaner.id"
:label="cleanerLabel(cleaner)"
:value="cleaner.id"
>
<div class="option-row">
<strong>{{ cleaner.nickname || compactText(cleaner.id) }}</strong>
<span>{{ cleaner.maskedPhone || '未留手机' }}</span>
</div>
</el-option>
</el-select>
</el-form-item>
<el-button type="primary" :icon="Search" @click="emitFilter">查询</el-button>
</el-form>
<el-tooltip content="刷新统计">
@@ -143,17 +164,18 @@
import { computed, reactive, watch } from 'vue';
import { RefreshCw, Search } from '@lucide/vue';
import { compactText, money } from '../format';
import type { CleaningStatistics } from '../types';
import type { CleaningStatistics, ManagedUser } from '../types';
const props = defineProps<{
loading: boolean;
statistics: CleaningStatistics;
filters: { from: string; to: string; storeId: string };
filters: { from: string; to: string; storeId: string; cleanerUserId: string };
cleaners: ManagedUser[];
}>();
const emit = defineEmits<{
refresh: [];
filter: [{ from: string; to: string; storeId: string }];
filter: [{ from: string; to: string; storeId: string; cleanerUserId: string }];
}>();
const filterDraft = reactive({ ...props.filters });
@@ -174,10 +196,15 @@ function emitFilter() {
emit('filter', {
from: filterDraft.from.trim(),
to: filterDraft.to.trim(),
storeId: filterDraft.storeId.trim()
storeId: filterDraft.storeId.trim(),
cleanerUserId: filterDraft.cleanerUserId.trim()
});
}
function cleanerLabel(cleaner: ManagedUser) {
return `${cleaner.nickname || compactText(cleaner.id)} / ${cleaner.maskedPhone || '未留手机'}`;
}
function applyQuickRange(value: string | number | boolean) {
const now = new Date();
const end = new Date(now.getFullYear(), now.getMonth(), now.getDate() + 1);