gaoluyang
昨天 b64a0deae5b5d33f9e20671a68936b27f0b9b00b
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
<script lang="ts" setup>
import type { MesCalCalendarApi } from '#/api/mes/cal/calendar';
 
import { computed } from 'vue';
 
import { MesCalShiftTypeEnum } from '@vben/constants';
 
import { Tag } from 'ant-design-vue';
import dayjs from 'dayjs';
import { SolarDay } from 'tyme4ts';
 
const props = defineProps<{
  calendarDayMap: Map<string, MesCalCalendarApi.CalendarDay>; // 排班数据
  day: string; // 日期,格式 yyyy-MM-dd
  holidaySet: Set<string>; // 节假日集合
}>();
 
const dayNumber = computed(() => props.day.split('-')[2] || ''); // 取日期中的"日"部分展示
const isHoliday = computed(() => props.holidaySet.has(props.day));
const isWeekend = computed(() => {
  const weekday = dayjs(props.day).day();
  return weekday === 0 || weekday === 6; // 0=周日,6=周六
});
 
const calDay = computed(() => props.calendarDayMap.get(props.day));
const teamShifts = computed(() => calDay.value?.teamShifts || []);
const shiftType = computed(() => calDay.value?.shiftType);
 
/**
 * 班次标签展示数据:根据 sort 与 shiftType 推导背景色
 *
 * 配色规则(sort 对应轮班方式中的班次顺序):
 *   sort=1 白班 → 绿色(#95d475)
 *   sort=2 中班 → 三班倒用橙色(#f0a020),两班倒用灰色(#909399)
 *   sort=3 夜班 → 灰色(#909399)
 */
const displayShifts = computed(() => {
  const isThreeShift = shiftType.value === MesCalShiftTypeEnum.THREE;
  const colorMap: Record<number, string> = {
    1: 'bg-[#95d475]',
    2: isThreeShift ? 'bg-[#f0a020]' : 'bg-[#909399]',
    3: 'bg-[#909399]',
  };
  return teamShifts.value
    .map((item) => {
      const bgClass = colorMap[item.sort ?? -1];
      if (!bgClass) {
        return null;
      }
      return {
        bgClass,
        key: `${item.teamId}-${item.shiftId}`,
        label: `${item.shiftName} · ${item.teamName}`,
      };
    })
    .filter((v): v is { bgClass: string; key: string; label: string } => !!v);
});
 
/** 解析当天的农历、节气、节日信息 */
const lunarInfo = computed(() => {
  const [year, month, date] = props.day.split('-').map(Number);
  try {
    const solarDay = SolarDay.fromYmd(year!, month!, date!);
    const lunarDay = solarDay.getLunarDay();
    const solarFestival = solarDay.getFestival(); // 公历节日,如 元旦
    const lunarFestival = lunarDay.getFestival(); // 农历节日,如 春节
    const termDay = solarDay.getTermDay();
    const termName =
      termDay.getDayIndex() === 0 ? termDay.getSolarTerm().getName() : '';
    const lunarMonthName = lunarDay.getLunarMonth().getName();
    const lunarDayName = lunarDay.getName();
    return {
      lunarFestival: lunarFestival ? lunarFestival.getName() : '',
      lunarText: lunarMonthName + lunarDayName,
      solarFestival: solarFestival ? solarFestival.getName() : '',
      termName,
    };
  } catch {
    return {
      lunarFestival: '',
      lunarText: '',
      solarFestival: '',
      termName: '',
    };
  }
});
 
/** 优先级:公历节日 > 农历节日 > 节气 > 农历月日 */
const lunarDisplay = computed(() => {
  const info = lunarInfo.value;
  return (
    info.solarFestival || info.lunarFestival || info.termName || info.lunarText
  );
});
 
/** 当天是否有节日或节气(用于高亮显示农历文字) */
const hasFestivalDay = computed(() => {
  const info = lunarInfo.value;
  return Boolean(info.solarFestival || info.lunarFestival || info.termName);
});
</script>
 
<template>
  <div class="flex h-full flex-col overflow-hidden p-1">
    <!-- 顶部:日期数字 + 上班/休息标签 -->
    <div class="flex shrink-0 items-center justify-between">
      <span
        class="text-base font-medium"
        :class="{ 'text-red-500': isWeekend }"
      >
        {{ dayNumber }}
      </span>
      <Tag v-if="isHoliday" color="green" class="!m-0"> 休 </Tag>
      <Tag v-else color="blue" class="!m-0"> 班 </Tag>
    </div>
    <!-- 农历 / 节气 / 节日显示 -->
    <div
      class="mt-0.5 shrink-0 truncate text-[11px]"
      :class="hasFestivalDay ? 'text-green-600' : 'text-muted-foreground'"
    >
      {{ lunarDisplay }}
    </div>
    <!--
      班次列表:节假日不显示排班
      配色规则与背景类由 displayShifts 计算
    -->
    <div v-if="!isHoliday" class="mt-0.5 flex flex-col gap-px overflow-hidden">
      <div
        v-for="shift in displayShifts"
        :key="shift.key"
        class="block w-full truncate rounded-sm px-1 py-px text-[11px] leading-normal text-white"
        :class="shift.bgClass"
      >
        {{ shift.label }}
      </div>
    </div>
  </div>
</template>