add totalNumberValue for rank

This commit is contained in:
Timi
2026-08-14 18:58:16 +08:00
parent 020d187860
commit aa5ab33b77
2 changed files with 64 additions and 10 deletions
+62 -9
View File
@@ -85,20 +85,29 @@
<template #description> <template #description>
<div class="description"> <div class="description">
<t-tag <t-tag
v-if="rankType === 'TOTAL_DAYS'"
size="small" size="small"
variant="outline" variant="outline"
:content="`累计天数 ${item.totalEventDays || 0}`" :content="`累计天数 ${item.totalEventDays || 0}`"
/> />
<t-tag <t-tag
v-else-if="rankType === 'TOTAL_COUNT'"
size="small" size="small"
variant="outline" variant="outline"
:content="`累计次数 ${item.totalEventCount || 0}`" :content="`累计次数 ${item.totalEventCount || 0}`"
/> />
<t-tag <t-tag
v-else-if="rankType === 'CONTINUOUS_DAYS'"
size="small" size="small"
variant="outline" variant="outline"
:content="`连续天数 ${item.recentContinuousEventDays || 0}`" :content="`连续天数 ${item.recentContinuousEventDays || 0}`"
/> />
<t-tag
v-else
size="small"
variant="outline"
:content="`登记数值 ${getTotalNumberValueText(item)}`"
/>
</div> </div>
</template> </template>
</t-cell> </t-cell>
@@ -138,6 +147,7 @@ import type { CustomerEventRankView, EventRecordRankPage, EventRecordRankType }
import type { EventItem } from "@/types/EventItem"; import type { EventItem } from "@/types/EventItem";
import { getCustomerPhotoURL } from "@/utils/customer"; import { getCustomerPhotoURL } from "@/utils/customer";
import { getErrorMessage } from "@/utils/error"; import { getErrorMessage } from "@/utils/error";
import { formatEventNumberValue } from "@/utils/eventValue";
import { permissionCodes } from "@/utils/permission"; import { permissionCodes } from "@/utils/permission";
type DateFilterType = "all" | "today" | "yesterday" | "lastWeek" | "thisMonth" | "custom"; type DateFilterType = "all" | "today" | "yesterday" | "lastWeek" | "thisMonth" | "custom";
@@ -152,7 +162,8 @@ const router = useRouter();
const rankTypeOptions: Array<{ label: string; value: EventRecordRankType }> = [ const rankTypeOptions: Array<{ label: string; value: EventRecordRankType }> = [
{ label: "按登记天数", value: "TOTAL_DAYS" }, { label: "按登记天数", value: "TOTAL_DAYS" },
{ label: "按登记次数", value: "TOTAL_COUNT" }, { label: "按登记次数", value: "TOTAL_COUNT" },
{ label: "按连续天数", value: "CONTINUOUS_DAYS" } { label: "按连续天数", value: "CONTINUOUS_DAYS" },
{ label: "按登记数值", value: "TOTAL_NUMBER_VALUE" }
]; ];
const dateOptions: Array<{ label: string; value: DateFilterType }> = [ const dateOptions: Array<{ label: string; value: DateFilterType }> = [
{ label: "全部时间", value: "all" }, { label: "全部时间", value: "all" },
@@ -177,25 +188,45 @@ let initialized = false;
const isCustomRange = computed(() => dateFilterType.value === "custom"); const isCustomRange = computed(() => dateFilterType.value === "custom");
const rankTypeLabel = computed(() => rankTypeOptions.find(item => item.value === rankType.value)?.label || "按登记天数"); const rankTypeLabel = computed(() => rankTypeOptions.find(item => item.value === rankType.value)?.label || "按登记天数");
const dateFilterLabel = computed(() => dateOptions.find(item => item.value === dateFilterType.value)?.label || "全部时间"); const dateFilterLabel = computed(() => dateOptions.find(item => item.value === dateFilterType.value)?.label || "全部时间");
const eventOptions = computed(() => eventList.value.map(item => ({ const selectableEventList = computed(() => rankType.value === "TOTAL_NUMBER_VALUE"
? eventList.value.filter(item => item.valueType === "NUMBER")
: eventList.value);
const eventOptions = computed(() => selectableEventList.value.map(item => ({
label: item.name || "未命名事件", label: item.name || "未命名事件",
value: item.id || "" value: item.id || ""
})).filter(item => item.value)); })).filter(item => item.value));
const eventFilterLabel = computed(() => { const eventFilterLabel = computed(() => {
if (!eventFilter.value.length || eventFilter.value.length === eventList.value.length) { if (!eventFilter.value.length || eventFilter.value.length === selectableEventList.value.length) {
return "全部事件"; return rankType.value === "TOTAL_NUMBER_VALUE" ? "全部有数值事件" : "全部事件";
} }
return eventList.value return selectableEventList.value
.filter(item => item.id && eventFilter.value.includes(item.id)) .filter(item => item.id && eventFilter.value.includes(item.id))
.map(item => item.name || "未命名事件") .map(item => item.name || "未命名事件")
.join("、"); .join("、");
}); });
const canLoadRank = computed(() => rankType.value !== "CONTINUOUS_DAYS" || eventFilter.value.length === 1); const selectedNumberEvent = computed(() => {
if (rankType.value !== "TOTAL_NUMBER_VALUE" || eventFilter.value.length !== 1) {
return undefined;
}
return selectableEventList.value.find(item => item.id === eventFilter.value[0]);
});
const canLoadRank = computed(() => {
if (rankType.value === "CONTINUOUS_DAYS") {
return eventFilter.value.length === 1;
}
if (rankType.value === "TOTAL_NUMBER_VALUE") {
return Boolean(selectedNumberEvent.value);
}
return true;
});
const emptyStateText = computed(() => { const emptyStateText = computed(() => {
if (isLoading.value) { if (isLoading.value) {
return "正在加载登记记录排行"; return "正在加载登记记录排行";
} }
if (rankType.value === "TOTAL_NUMBER_VALUE") {
return "数值排行需要选择单个有数值事件";
}
return canLoadRank.value ? "暂无登记记录排行" : "连续排行需要选择单个登记事件"; return canLoadRank.value ? "暂无登记记录排行" : "连续排行需要选择单个登记事件";
}); });
@@ -299,6 +330,7 @@ async function loadEvents(): Promise<void> {
eventFilter.value = eventIdList.length eventFilter.value = eventIdList.length
? eventIdList ? eventIdList
: eventList.value.map(item => item.id).filter((item): item is string => Boolean(item)); : eventList.value.map(item => item.id).filter((item): item is string => Boolean(item));
normalizeEventFilter();
} }
async function selectRankType(value: DropdownValue): Promise<void> { async function selectRankType(value: DropdownValue): Promise<void> {
@@ -307,11 +339,14 @@ async function selectRankType(value: DropdownValue): Promise<void> {
} }
rankType.value = parseRankType(value); rankType.value = parseRankType(value);
const filterChanged = normalizeEventFilter();
await replaceFilterQuery(); await replaceFilterQuery();
if (!canLoadRank.value) { if (!canLoadRank.value) {
Toast.warning("连续排行需要选择单个登记事件"); Toast.warning(rankType.value === "TOTAL_NUMBER_VALUE" ? "数值排行需要选择单个有数值事件" : "连续排行需要选择单个登记事件");
}
if (!filterChanged) {
await reloadRanks();
} }
await reloadRanks();
} }
async function selectDateFilter(value: DropdownValue): Promise<void> { async function selectDateFilter(value: DropdownValue): Promise<void> {
@@ -348,9 +383,14 @@ function getCustomerInitial(item: CustomerEventRankView): string {
return getCustomerName(item).slice(0, 1); return getCustomerName(item).slice(0, 1);
} }
function getTotalNumberValueText(item: CustomerEventRankView): string {
return formatEventNumberValue(selectedNumberEvent.value, item.totalNumberValue);
}
function buildRankReq(): Omit<EventRecordRankPage, "index" | "size"> { function buildRankReq(): Omit<EventRecordRankPage, "index" | "size"> {
const [beginAt, endAt] = buildUnixRange(); const [beginAt, endAt] = buildUnixRange();
const selectedAllEvent = rankType.value !== "CONTINUOUS_DAYS" && (!eventFilter.value.length || eventFilter.value.length === eventList.value.length); const selectedAllEvent = (rankType.value === "TOTAL_DAYS" || rankType.value === "TOTAL_COUNT")
&& (!eventFilter.value.length || eventFilter.value.length === eventList.value.length);
return { return {
beginAt, beginAt,
endAt, endAt,
@@ -387,6 +427,19 @@ function parseEventIdList(value: unknown): string[] {
return text.split(",").map(item => item.trim()).filter(Boolean); return text.split(",").map(item => item.trim()).filter(Boolean);
} }
function normalizeEventFilter(): boolean {
const eventIdSet = new Set(selectableEventList.value.map(item => item.id).filter((item): item is string => Boolean(item)));
let nextEventIdList = eventFilter.value.filter(item => eventIdSet.has(item));
if (!nextEventIdList.length) {
nextEventIdList = [...eventIdSet];
}
const changed = nextEventIdList.join(",") !== eventFilter.value.join(",");
if (changed) {
eventFilter.value = nextEventIdList;
}
return changed;
}
function buildFilterQuery(): Record<string, string> { function buildFilterQuery(): Record<string, string> {
return { return {
rankType: rankType.value, rankType: rankType.value,
+2 -1
View File
@@ -53,7 +53,7 @@ export type EventRecordRankPage = {
endAt?: number; endAt?: number;
} & BasePage; } & BasePage;
export type EventRecordRankType = "TOTAL_DAYS" | "TOTAL_COUNT" | "CONTINUOUS_DAYS"; export type EventRecordRankType = "TOTAL_DAYS" | "TOTAL_COUNT" | "CONTINUOUS_DAYS" | "TOTAL_NUMBER_VALUE";
export type CustomerEventRankView = { export type CustomerEventRankView = {
rank?: number; rank?: number;
@@ -62,6 +62,7 @@ export type CustomerEventRankView = {
totalEventDays?: number; totalEventDays?: number;
totalEventCount?: number; totalEventCount?: number;
recentContinuousEventDays?: number; recentContinuousEventDays?: number;
totalNumberValue?: number;
latestRegisteredAt?: number; latestRegisteredAt?: number;
}; };