add store closed day in event record calendar
This commit is contained in:
@@ -36,12 +36,15 @@
|
||||
v-for="item in calendarDayList"
|
||||
:key="item.key"
|
||||
class="day-cell"
|
||||
:class="{muted: !item.inMonth, today: item.isToday, marked: 0 < item.records.length}"
|
||||
:class="{muted: !item.inMonth, today: item.isToday, marked: 0 < item.records.length, 'rest-day': item.isRestDay}"
|
||||
type="button"
|
||||
:disabled="!item.records.length"
|
||||
@click="openDayRecords(item)"
|
||||
>
|
||||
<span class="date" v-text="item.day" />
|
||||
<span class="date">
|
||||
<span v-text="item.day" />
|
||||
<span v-if="item.isRestDay" class="rest">休</span>
|
||||
</span>
|
||||
<span v-if="item.records.length" class="count" v-text="`${item.records.length} 条`" />
|
||||
</button>
|
||||
</div>
|
||||
@@ -104,8 +107,11 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import StoreAPI from "@/api/StoreAPI";
|
||||
import type {EventItem} from "@/types/EventItem";
|
||||
import type {EventRecord} from "@/types/EventRecord";
|
||||
import type {StoreBusinessDay} from "@/types/Store";
|
||||
import {getCurrentStoreId} from "@/utils/store";
|
||||
import {Time} from "timi-web";
|
||||
|
||||
interface CalendarDay {
|
||||
@@ -114,6 +120,7 @@ interface CalendarDay {
|
||||
dateText: string;
|
||||
inMonth: boolean;
|
||||
isToday: boolean;
|
||||
isRestDay: boolean;
|
||||
records: EventRecord[];
|
||||
}
|
||||
|
||||
@@ -131,11 +138,13 @@ const props = withDefaults(defineProps<{
|
||||
records: EventRecord[];
|
||||
selectedEventIdList: string[];
|
||||
showEventFilter?: boolean;
|
||||
storeId?: string;
|
||||
}>(), {
|
||||
customerName: "",
|
||||
emptyText: "当前月份暂无匹配登记",
|
||||
loading: false,
|
||||
showEventFilter: true
|
||||
showEventFilter: true,
|
||||
storeId: ""
|
||||
});
|
||||
|
||||
const emit = defineEmits<{
|
||||
@@ -151,6 +160,8 @@ const dayRecordVisible = ref(false);
|
||||
const eventFilterVisible = ref(false);
|
||||
const selectedDayTitle = ref("");
|
||||
const selectedDayRecords = ref<EventRecord[]>([]);
|
||||
const businessDayList = ref<StoreBusinessDay[]>([]);
|
||||
let businessDayRequestId = 0;
|
||||
|
||||
const selectedEventIdListProxy = computed({
|
||||
get: () => props.selectedEventIdList,
|
||||
@@ -166,6 +177,12 @@ const eventNameMap = computed(() => {
|
||||
return map;
|
||||
});
|
||||
const selectedEventIdSet = computed(() => new Set(props.selectedEventIdList));
|
||||
const resolvedStoreId = computed(() => props.storeId || getCurrentStoreId());
|
||||
const restDaySet = computed(() => new Set(
|
||||
businessDayList.value
|
||||
.filter(item => item.status === "CLOSED" && item.dateValue)
|
||||
.map(item => item.dateValue as number)
|
||||
));
|
||||
const filteredRecords = computed(() => {
|
||||
if (!props.showEventFilter || !props.selectedEventIdList.length) {
|
||||
return props.records;
|
||||
@@ -188,12 +205,42 @@ const calendarDayList = computed<CalendarDay[]>(() => {
|
||||
dateText,
|
||||
inMonth: date.getMonth() === props.modelValue.getMonth(),
|
||||
isToday: dateText === todayText,
|
||||
isRestDay: restDaySet.value.has(toDateValue(date)),
|
||||
records: filteredRecords.value.filter(item => getRecordDateText(item) === dateText)
|
||||
});
|
||||
}
|
||||
return list;
|
||||
});
|
||||
|
||||
watch([() => props.modelValue, resolvedStoreId], async () => {
|
||||
await loadBusinessDays();
|
||||
}, {
|
||||
deep: true,
|
||||
immediate: true
|
||||
});
|
||||
|
||||
async function loadBusinessDays(): Promise<void> {
|
||||
const storeId = resolvedStoreId.value;
|
||||
if (!storeId) {
|
||||
businessDayList.value = [];
|
||||
return;
|
||||
}
|
||||
|
||||
const requestId = ++businessDayRequestId;
|
||||
const beginDate = getCalendarBeginDate(props.modelValue);
|
||||
const endDate = addDays(beginDate, 41);
|
||||
try {
|
||||
const result = await StoreAPI.businessDayCalendar(storeId, toDateValue(beginDate), toDateValue(endDate));
|
||||
if (requestId === businessDayRequestId) {
|
||||
businessDayList.value = result || [];
|
||||
}
|
||||
} catch {
|
||||
if (requestId === businessDayRequestId) {
|
||||
businessDayList.value = [];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function shiftMonth(offset: number): void {
|
||||
emit("update:modelValue", addMonths(props.modelValue, offset));
|
||||
}
|
||||
@@ -286,6 +333,10 @@ function addMonths(date: Date, months: number): Date {
|
||||
return new Date(date.getFullYear(), date.getMonth() + months, 1, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
function toDateValue(date: Date): number {
|
||||
return Number(Time.formatDate(date).replaceAll("-", ""));
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
@@ -353,13 +404,22 @@ function addMonths(date: Date, months: number): Date {
|
||||
flex-direction: column;
|
||||
|
||||
.date {
|
||||
display: flex;
|
||||
font-size: .875rem;
|
||||
align-items: center;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.rest {
|
||||
color: #dc2626;
|
||||
margin-left: .125rem;
|
||||
font-size: .625rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.count {
|
||||
width: 100%;
|
||||
color: #2563eb;
|
||||
color: var(--td-brand-color);
|
||||
overflow: hidden;
|
||||
font-size: .625rem;
|
||||
font-weight: 700;
|
||||
@@ -373,11 +433,15 @@ function addMonths(date: Date, months: number): Date {
|
||||
}
|
||||
|
||||
&.today {
|
||||
border-color: #2563eb;
|
||||
color: var(--td-brand-color);
|
||||
}
|
||||
|
||||
&.marked {
|
||||
background: #eff6ff;
|
||||
background: var(--td-brand-color-1);
|
||||
}
|
||||
|
||||
&.rest-day {
|
||||
background: #fef2f2;
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
@@ -479,6 +543,10 @@ function addMonths(date: Date, months: number): Date {
|
||||
&.marked {
|
||||
background: rgba(37, 99, 235, .2);
|
||||
}
|
||||
|
||||
&.rest-day {
|
||||
background: rgba(220, 38, 38, .12);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
v-model:selected-event-id-list="selectedEventIdList"
|
||||
:customer-id="selectedCustomer.id || ''"
|
||||
:customer-name="selectedCustomer.name"
|
||||
:store-id="selectedCustomer.storeId"
|
||||
@list="toEventRecordList"
|
||||
/>
|
||||
<customer-record-trend-chart
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
class="calendar-section"
|
||||
:event-list="eventList"
|
||||
:customer-name="customerName"
|
||||
:store-id="storeId"
|
||||
:loading="isCalendarLoading"
|
||||
:records="records"
|
||||
@list="value => emit('list', value)"
|
||||
@@ -23,6 +24,7 @@ import type { StoreEventRecordCalendarView } from "@/types/Store";
|
||||
const props = defineProps<{
|
||||
customerId: string;
|
||||
customerName?: string;
|
||||
storeId?: string;
|
||||
modelValue: Date;
|
||||
selectedEventIdList: string[];
|
||||
}>();
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
empty-text="当前月份暂无登记事件记录"
|
||||
:loading="isCalendarLoading"
|
||||
:records="monthRecords"
|
||||
:store-id="storeId"
|
||||
@list="value => emit('list', value)"
|
||||
/>
|
||||
</template>
|
||||
@@ -17,6 +18,7 @@ import EventRecordCalendar, { type EventRecordCalendarListPayload } from "@/comp
|
||||
import type { EventItem } from "@/types/EventItem";
|
||||
import type { EventRecord } from "@/types/EventRecord";
|
||||
import type { StoreEventRecordCalendarView } from "@/types/Store";
|
||||
import { useCurrentStoreStore } from "@/store/currentStoreStore";
|
||||
import { Time } from "timi-web";
|
||||
|
||||
const emit = defineEmits<{
|
||||
@@ -28,6 +30,8 @@ const selectedEventIdList = ref<string[]>([]);
|
||||
const monthRecords = ref<EventRecord[]>([]);
|
||||
const isCalendarLoading = ref(false);
|
||||
const monthCursor = ref(getMonthStart(new Date()));
|
||||
const currentStoreStore = useCurrentStoreStore();
|
||||
const storeId = computed(() => currentStoreStore.currentStoreId);
|
||||
let calendarRequestId = 0;
|
||||
|
||||
watch(monthCursor, async () => {
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
* @param backgroundColor 头像背景色
|
||||
*/
|
||||
export function buildFallbackAvatar(name?: string, backgroundColor = "#2563eb"): string {
|
||||
const text = encodeURIComponent((name?.trim() || "用户").slice(0, 2));
|
||||
const text = encodeURIComponent((name?.trim() || "用户").slice(0, 1));
|
||||
const fill = encodeURIComponent(backgroundColor);
|
||||
return [
|
||||
"data:image/svg+xml;charset=UTF-8,",
|
||||
|
||||
Reference in New Issue
Block a user