169 lines
4.7 KiB
Vue
169 lines
4.7 KiB
Vue
<script lang="ts" setup>
|
|
import type { ThingType } from './type';
|
|
import dayjs from 'dayjs';
|
|
import isoWeek from 'dayjs/plugin/isoWeek';
|
|
import weekday from 'dayjs/plugin/weekday';
|
|
import { getWeekDates } from './helper';
|
|
|
|
const props = withDefaults(defineProps<Props>(), {
|
|
groupedEvents: () => new Map(),
|
|
timeLineWidth: 80,
|
|
});
|
|
dayjs.extend(isoWeek);
|
|
dayjs.extend(weekday);
|
|
|
|
defineComponent({ name: 'GantDate' });
|
|
|
|
interface Props {
|
|
groupedEvents?: Map<number, ThingType[]>
|
|
timeLineWidth?: number
|
|
}
|
|
|
|
const value = defineModel('value', {
|
|
type: Number,
|
|
|
|
default: dayjs().valueOf(),
|
|
});
|
|
|
|
/** ** 正确的格式一定为某一天的起始 */
|
|
const selectedDate = computed({
|
|
get: () => dayjs(value.value).startOf('day').valueOf(),
|
|
set: (val) => {
|
|
value.value = val;
|
|
},
|
|
});
|
|
|
|
const weekDates = defineModel('weekDates', {
|
|
type: Object as () => { date: number, day: string, weekDay: string }[],
|
|
default: () => [],
|
|
});
|
|
|
|
// 选择日期
|
|
function selectDate(date: number) {
|
|
selectedDate.value = date;
|
|
}
|
|
|
|
// 日历选择器事件
|
|
// function datePickerChange(time: number) {
|
|
// selectDate(time);
|
|
// weekDates.value = getWeekDates(time);
|
|
// }
|
|
|
|
// 回到今天
|
|
function backToToday() {
|
|
selectDate(dayjs().startOf('day').valueOf());
|
|
weekDates.value = getWeekDates(dayjs().startOf('day').valueOf());
|
|
}
|
|
|
|
// 上一周
|
|
function prevWeek() {
|
|
const prevWeekDate = dayjs(selectedDate.value).subtract(7, 'day').valueOf();
|
|
selectDate(prevWeekDate);
|
|
weekDates.value = getWeekDates(prevWeekDate);
|
|
}
|
|
|
|
// 下一周
|
|
function nextWeek() {
|
|
const nextWeekDate = dayjs(selectedDate.value).add(7, 'day').valueOf();
|
|
selectDate(nextWeekDate);
|
|
weekDates.value = getWeekDates(nextWeekDate);
|
|
}
|
|
|
|
const weekDatesForMarks = computed(() => {
|
|
return weekDates.value.map((item) => {
|
|
return {
|
|
...item,
|
|
isMark: props.groupedEvents.get(item.date)?.length,
|
|
};
|
|
});
|
|
});
|
|
</script>
|
|
|
|
<template>
|
|
<div class="gantDateShadow flex flex-col pb-2 pt-2">
|
|
<div class="relative flex flex-1 flex-row items-center justify-center flex-self-stretch">
|
|
<div class="relative flex flex-row items-center gap-2">
|
|
<!-- <n-date-picker
|
|
class="absolute left-0 top-0 z-2 wh-full overflow-hidden opacity-0 !cursor-pointer"
|
|
:value="selectedDate"
|
|
:default-value="selectedDate"
|
|
type="date"
|
|
@update:value="datePickerChange"
|
|
/> -->
|
|
<span class="font-bold">
|
|
{{ dayjs(selectedDate).format('YYYY年M月') }}
|
|
</span>
|
|
<SvgIcon class="rotate-0 font-bold" icon="i-ic-round-keyboard-arrow-down" />
|
|
</div>
|
|
<div class="absolute b h-full flex-col flex items-center justify-center right-0 flex-self-stretch">
|
|
<div
|
|
class="text-onPrimary text-20 bg-primary py-1 pr-1 pl-2 rounded-l-full flex items-center justify-center line-height-none"
|
|
@click="backToToday"
|
|
>
|
|
回到今日
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div
|
|
class="relative mt-8rpx flex flex-row items-center flex-self-stretch"
|
|
:style="{
|
|
paddingLeft: `${props.timeLineWidth}rpx`,
|
|
}"
|
|
>
|
|
<div
|
|
class="absolute h-32 w-32 flex items-center justify-center rounded-full bg-primary left-8rpx" @click="prevWeek"
|
|
>
|
|
<SvgIcon class="text-28 text-white font-bold" icon="i-material-symbols-chevron-left-rounded" />
|
|
</div>
|
|
|
|
<!-- 周历表 -->
|
|
<div class="flex w-[calc((100%/7.5)*7)] flex-row items-center justify-between flex-self-stretch">
|
|
<div
|
|
v-for="(item, index) in weekDatesForMarks"
|
|
:key="index"
|
|
class="flex flex-col cursor-pointer flex-1 items-center justify-center"
|
|
@click="selectDate(item.date)"
|
|
>
|
|
<span
|
|
class="text-20"
|
|
:class="{
|
|
'text-primary': item.date === selectedDate,
|
|
}"
|
|
>
|
|
{{ item.weekDay }}
|
|
</span>
|
|
|
|
<span
|
|
class="text-20 font-bold"
|
|
:class="{
|
|
'text-primary': item.date === selectedDate,
|
|
}"
|
|
>
|
|
{{ item.day }}
|
|
</span>
|
|
|
|
<!-- 标记点 -->
|
|
<div
|
|
class="mt-0 h-1 w-1 rounded-full"
|
|
:class="{
|
|
'bg-primary': item.isMark,
|
|
'!bg-[#CCCCCC]': item.isMark && item.date < dayjs().startOf('day').valueOf(),
|
|
}"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="absolute right-8rpx h-32 w-32 flex items-center justify-center rounded-full bg-primary" @click="nextWeek">
|
|
<SvgIcon class="text-5 text-white font-bold" icon="i-material-symbols-chevron-right-rounded" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<style lang="scss" scoped>
|
|
.gantDateShadow {
|
|
box-shadow: 0rpx 16rpx 40rpx 20rpx rgba(0, 0, 0, 0.02);
|
|
}
|
|
</style>
|