add event record calendar to record list

This commit is contained in:
Timi
2026-08-12 19:57:41 +08:00
parent 44a6153413
commit 6463abd93b
8 changed files with 140 additions and 11 deletions
+32
View File
@@ -39,6 +39,7 @@
v-model:selected-event-id-list="selectedEventIdList"
:customer-id="selectedCustomer.id || ''"
:customer-name="selectedCustomer.name"
@list="toEventRecordList"
/>
<customer-record-trend-chart
v-if="selectedCustomer"
@@ -66,6 +67,7 @@ import { Time } from "timi-web";
import CustomerAPI from "@/api/CustomerAPI";
import CodeScanner from "@/components/CodeScanner.vue";
import CustomerSelector from "@/components/CustomerSelector.vue";
import type { EventRecordCalendarListPayload } from "@/components/EventRecordCalendar.vue";
import CustomerChartSummary from "@/pages/customer/component/CustomerChartSummary.vue";
import CustomerEventRecordCalendarSection from "@/pages/customer/component/CustomerEventRecordCalendarSection.vue";
import CustomerEventStructureChart from "@/pages/customer/component/CustomerEventStructureChart.vue";
@@ -79,6 +81,7 @@ defineOptions({
});
const route = useRoute();
const router = useRouter();
const settingStore = useSettingStore();
// ---------- 路由 ----------
@@ -160,6 +163,35 @@ function clearLoadedCustomer(): void {
selectedCustomerId.value = "";
}
async function toEventRecordList(payload: EventRecordCalendarListPayload): Promise<void> {
if (!selectedCustomer.value?.id) {
return;
}
await router.push({
name: "EventRecordList",
query: buildEventRecordListQuery(payload.monthCursor, payload.selectedEventIdList, selectedCustomer.value)
});
}
function buildEventRecordListQuery(monthCursor: Date, eventIdList: string[], customer: Customer): Record<string, string> {
const monthStart = getMonthStart(monthCursor);
const monthEnd = getDateEnd(addDays(addMonths(monthStart, 1), -1));
return {
customerId: customer.id || "",
customerName: customer.name || "",
dateType: "custom",
beginAt: `${Time.formatDate(monthStart)} 00:00`,
endAt: `${Time.formatDate(monthEnd)} 23:59`,
transitionDepth: String(getCurrentRouteDepth() + 1),
eventIds: eventIdList.join(",")
};
}
function getCurrentRouteDepth(): number {
return Number(route.meta.depth ?? 0);
}
// ---------- 扫码 ----------
const scannerVisible = ref(false);
@@ -7,6 +7,7 @@
:customer-name="customerName"
:loading="isCalendarLoading"
:records="records"
@list="value => emit('list', value)"
/>
</template>
@@ -14,7 +15,7 @@
import { Time } from "timi-web";
import CustomerChartAPI from "@/api/CustomerChartAPI";
import EventAPI from "@/api/EventAPI";
import EventRecordCalendar from "@/components/EventRecordCalendar.vue";
import EventRecordCalendar, { type EventRecordCalendarListPayload } from "@/components/EventRecordCalendar.vue";
import type { EventItem } from "@/types/EventItem";
import type { EventRecord } from "@/types/EventRecord";
import type { StoreEventRecordCalendarView } from "@/types/Store";
@@ -29,6 +30,7 @@ const props = defineProps<{
const emit = defineEmits<{
"update:modelValue": [value: Date];
"update:selectedEventIdList": [value: string[]];
list: [value: EventRecordCalendarListPayload];
}>();
const monthCursorProxy = computed({
+39 -5
View File
@@ -163,7 +163,8 @@ const dateOptions: Array<{ label: string; value: DateFilterType }> = [
// ---------- 筛选 ----------
const keyword = ref(getQueryText("keyword"));
const keyword = ref(getInitialKeyword());
const customerId = ref(getQueryText("customerId"));
const dateFilterType = ref<DateFilterType>(parseDateFilterType(route.query.dateType));
const dateRange = ref(parseDateRange(dateFilterType.value));
const actionFilter = ref<string[]>([]);
@@ -350,12 +351,17 @@ async function toDetail(id: string): Promise<void> {
}
await router.push({
path: `/management/registration-event-records/${id}`,
query: buildFilterQuery()
query: buildFilterQuery(String(getCurrentRouteDepth() + 1))
});
}
async function toCreate(): Promise<void> {
await router.push("/management/registration-event-records/create");
await router.push({
path: "/management/registration-event-records/create",
query: {
transitionDepth: String(getCurrentRouteDepth() + 1)
}
});
}
async function confirmRemoveRecord(record: EventRecordListItemView): Promise<void> {
@@ -428,6 +434,7 @@ function buildRangeReq(): Omit<EventRecordPage, "index" | "size"> {
return {
beginAt,
endAt,
customerId: customerId.value || undefined,
keyword: keyword.value.trim() || undefined,
eventIdList: selectedAllEvent ? undefined : actionFilter.value
};
@@ -458,14 +465,41 @@ function parseEventIdList(value: unknown): string[] {
return text.split(",").map(item => item.trim()).filter(Boolean);
}
function buildFilterQuery(): Record<string, string> {
return {
function buildFilterQuery(transitionDepth = getQueryText("transitionDepth")): Record<string, string> {
const query = {
keyword: keyword.value.trim(),
dateType: dateFilterType.value,
beginAt: dateRange.value[0] || "",
endAt: dateRange.value[1] || "",
customerId: customerId.value,
customerName: getQueryText("customerName"),
eventIds: actionFilter.value.join(",")
};
if (isValidTransitionDepth(transitionDepth)) {
return {
...query,
transitionDepth
};
}
return query;
}
function getInitialKeyword(): string {
return getQueryText("keyword") || getQueryText("customerName");
}
function getCurrentRouteDepth(): number {
const transitionDepth = getQueryText("transitionDepth").trim();
if (isValidTransitionDepth(transitionDepth)) {
return Number(transitionDepth);
}
return Number(route.meta.depth ?? 0);
}
function isValidTransitionDepth(value: string): boolean {
const depth = Number(value);
return value !== "" && Number.isInteger(depth) && 0 <= depth && depth <= 20;
}
async function replaceFilterQuery(): Promise<void> {
+31 -1
View File
@@ -2,7 +2,7 @@
<div v-can="permissionCodes.stat.read" class="data-charts-page">
<store-chart-summary :date-text-list="dateTextList" />
<store-event-record-calendar-section />
<store-event-record-calendar-section @list="toEventRecordList" />
<store-customer-growth-chart :date-text-list="dateTextList" />
<store-event-record-trend-chart :date-text-list="dateTextList" />
<store-event-structure-chart :date-text-list="dateTextList" />
@@ -19,6 +19,7 @@ import StoreEventRecordCalendarSection from "@/pages/store/component/StoreEventR
import StoreEventRecordTrendChart from "@/pages/store/component/StoreEventRecordTrendChart.vue";
import StoreEventStructureChart from "@/pages/store/component/StoreEventStructureChart.vue";
import { permissionCodes } from "@/utils/permission";
import type { EventRecordCalendarListPayload } from "@/components/EventRecordCalendar.vue";
defineOptions({
name: "StoreDataCharts"
@@ -29,9 +30,38 @@ defineOptions({
const beginDate = getDateStart(addMonths(new Date(), -1));
const endDate = getDateEnd(new Date());
const dateTextList = buildDateTextList(beginDate, endDate);
const route = useRoute();
const router = useRouter();
async function toEventRecordList(payload: EventRecordCalendarListPayload): Promise<void> {
await router.push({
name: "EventRecordList",
query: buildEventRecordListQuery(payload.monthCursor, payload.selectedEventIdList)
});
}
function buildEventRecordListQuery(monthCursor: Date, eventIdList: string[]): Record<string, string> {
const monthStart = getMonthStart(monthCursor);
const monthEnd = getDateEnd(addDays(addMonths(monthStart, 1), -1));
return {
dateType: "custom",
beginAt: `${Time.formatDate(monthStart)} 00:00`,
endAt: `${Time.formatDate(monthEnd)} 23:59`,
transitionDepth: String(getCurrentRouteDepth() + 1),
eventIds: eventIdList.join(",")
};
}
function getCurrentRouteDepth(): number {
return Number(route.meta.depth ?? 0);
}
// ---------- 日期工具 ----------
function getMonthStart(date: Date): Date {
return new Date(date.getFullYear(), date.getMonth(), 1, 0, 0, 0, 0);
}
function getDateStart(date: Date): Date {
return new Date(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0, 0);
}
@@ -6,18 +6,23 @@
empty-text="当前月份暂无登记事件记录"
:loading="isCalendarLoading"
:records="monthRecords"
@list="value => emit('list', value)"
/>
</template>
<script setup lang="ts">
import EventAPI from "@/api/EventAPI";
import StoreChartAPI from "@/api/StoreChartAPI";
import EventRecordCalendar from "@/components/EventRecordCalendar.vue";
import EventRecordCalendar, { type EventRecordCalendarListPayload } from "@/components/EventRecordCalendar.vue";
import type { EventItem } from "@/types/EventItem";
import type { EventRecord } from "@/types/EventRecord";
import type { StoreEventRecordCalendarView } from "@/types/Store";
import { Time } from "timi-web";
const emit = defineEmits<{
list: [value: EventRecordCalendarListPayload];
}>();
const eventList = ref<EventItem[]>([]);
const selectedEventIdList = ref<string[]>([]);
const monthRecords = ref<EventRecord[]>([]);