浏览代码

feat(日程视图): 重构日程视图页面布局并添加日历功能

重构日程视图页面为左右布局,左侧添加日历导航和任务授权状态筛选功能。右侧显示日程内容区域,支持日/周/月视图切换。新增日历功能包括:
- 月份导航
- 日期选择
- 高亮显示当前日期
- 区分当月/非当月日期
weieryang 1 月之前
父节点
当前提交
3470e99d97
共有 1 个文件被更改,包括 228 次插入64 次删除
  1. 228 64
      apps/web-ele/src/views/schedule/view/index.vue

+ 228 - 64
apps/web-ele/src/views/schedule/view/index.vue

@@ -4,7 +4,7 @@ import { computed, ref, watch } from 'vue';
4 4
 import { Page, useVbenDrawer } from '@vben/common-ui';
5 5
 
6 6
 import dayjs from 'dayjs';
7
-import { ElRadioButton, ElRadioGroup } from 'element-plus';
7
+import { ElCheckbox, ElRadioButton, ElRadioGroup } from 'element-plus';
8 8
 
9 9
 import CreateTasK from './components/create/index.vue';
10 10
 import Day from './components/day/index.vue';
@@ -32,11 +32,22 @@ const searchParams = ref({
32 32
   date: getDefaultDate('day'),
33 33
 });
34 34
 
35
-// 监听timeType变化,更新默认日期
35
+// 当前显示的日期
36
+const currentDate = ref(dayjs());
37
+
38
+// 任务授权状态
39
+const taskStatuses = ref({
40
+  canAuthorize: true,
41
+  authorized: true,
42
+  beAuthorized: true,
43
+});
44
+
45
+// 监听timeType变化,更新默认日期和当前显示日期
36 46
 watch(
37 47
   () => searchParams.value.timeType,
38 48
   (newType) => {
39 49
     searchParams.value.date = getDefaultDate(newType);
50
+    currentDate.value = dayjs(searchParams.value.date);
40 51
   },
41 52
 );
42 53
 
@@ -49,6 +60,109 @@ const weekNumber = computed(() => {
49 60
   return dayjs(searchParams.value.date).week();
50 61
 });
51 62
 
63
+// 计算当前选中日期所在周的开始和结束日期
64
+const currentWeekRange = computed(() => {
65
+  const date = dayjs(searchParams.value.date);
66
+  // 计算周开始(周一)
67
+  const startOfWeek = date.startOf('week');
68
+  // 调整为周一(dayjs默认周日为一周开始)
69
+  const monday =
70
+    startOfWeek.day() === 0 ? startOfWeek.subtract(1, 'day') : startOfWeek;
71
+  // 计算周日
72
+  const sunday = monday.add(6, 'day');
73
+  return {
74
+    start: monday,
75
+    end: sunday,
76
+  };
77
+});
78
+
79
+// 生成日历天数
80
+const calendarDays = computed(() => {
81
+  const days = [];
82
+  const year = currentDate.value.year();
83
+  const month = currentDate.value.month();
84
+
85
+  // 获取当月第一天
86
+  const firstDay = dayjs(new Date(year, month, 1));
87
+  // 获取当月第一天是星期几(0-6,0是周日)
88
+  const firstDayOfWeek = firstDay.day();
89
+  // 计算需要显示的上个月天数
90
+  const prevMonthDays = firstDayOfWeek === 0 ? 6 : firstDayOfWeek - 1;
91
+
92
+  // 获取当月最后一天
93
+  const lastDay = dayjs(new Date(year, month + 1, 0));
94
+  const lastDate = lastDay.date();
95
+
96
+  // 添加上个月的日期
97
+  for (let i = prevMonthDays; i > 0; i--) {
98
+    const date = firstDay.subtract(i, 'day');
99
+    const isInCurrentWeek =
100
+      searchParams.value.timeType === 'week' &&
101
+      date.isAfter(currentWeekRange.value.start.subtract(1, 'day')) &&
102
+      date.isBefore(currentWeekRange.value.end.add(1, 'day'));
103
+    days.push({
104
+      date: date.format('YYYY-MM-DD'),
105
+      day: date.date(),
106
+      isToday: date.isSame(dayjs(), 'day'),
107
+      isOtherMonth: true,
108
+      isInCurrentWeek,
109
+    });
110
+  }
111
+
112
+  // 添加当月的日期
113
+  for (let i = 1; i <= lastDate; i++) {
114
+    const date = dayjs(new Date(year, month, i));
115
+    const isInCurrentWeek =
116
+      searchParams.value.timeType === 'week' &&
117
+      date.isAfter(currentWeekRange.value.start.subtract(1, 'day')) &&
118
+      date.isBefore(currentWeekRange.value.end.add(1, 'day'));
119
+    days.push({
120
+      date: date.format('YYYY-MM-DD'),
121
+      day: i,
122
+      isToday: date.isSame(dayjs(), 'day'),
123
+      isOtherMonth: false,
124
+      isInCurrentWeek,
125
+    });
126
+  }
127
+
128
+  // 计算需要显示的下个月天数
129
+  const totalDays = days.length;
130
+  const nextMonthDays = 42 - totalDays; // 6行7列=42个格子
131
+
132
+  // 添加下个月的日期
133
+  for (let i = 1; i <= nextMonthDays; i++) {
134
+    const date = lastDay.add(i, 'day');
135
+    const isInCurrentWeek =
136
+      searchParams.value.timeType === 'week' &&
137
+      date.isAfter(currentWeekRange.value.start.subtract(1, 'day')) &&
138
+      date.isBefore(currentWeekRange.value.end.add(1, 'day'));
139
+    days.push({
140
+      date: date.format('YYYY-MM-DD'),
141
+      day: date.date(),
142
+      isToday: date.isSame(dayjs(), 'day'),
143
+      isOtherMonth: true,
144
+      isInCurrentWeek,
145
+    });
146
+  }
147
+
148
+  return days;
149
+});
150
+
151
+// 切换到上个月
152
+const prevMonth = () => {
153
+  currentDate.value = currentDate.value.subtract(1, 'month');
154
+};
155
+
156
+// 切换到下个月
157
+const nextMonth = () => {
158
+  currentDate.value = currentDate.value.add(1, 'month');
159
+};
160
+
161
+// 选择日期
162
+const selectDate = (date: string) => {
163
+  searchParams.value.date = date;
164
+};
165
+
52 166
 const [CreateTaskDrawer, createTaskDrawerApi] = useVbenDrawer({
53 167
   // 连接抽离的组件
54 168
   connectedComponent: CreateTasK,
@@ -61,78 +175,128 @@ const createTaskDrawerEvent = () => {
61 175
 </script>
62 176
 
63 177
 <template>
64
-  <Page title="日程视图">
65
-    <template #description>
66
-      <!--筛选区域-->
67
-      <div class="flex items-center justify-between space-x-4">
68
-        <div class="flex items-center space-x-4">
178
+  <Page title="" class="h-screen">
179
+    <div class="flex h-full flex-row space-x-4">
180
+      <!--左侧筛选区域-->
181
+      <div
182
+        class="relative h-full w-80 flex-shrink-0 overflow-y-auto rounded-lg bg-white p-4 pb-20 shadow"
183
+      >
184
+        <!--油站选择-->
185
+        <div class="mb-4">
69 186
           <ElSelect
70 187
             v-model="searchParams.station"
71 188
             placeholder="请选择油站"
72
-            class="w-48 min-w-48 max-w-48"
73
-            style="width: 12rem"
189
+            class="w-full"
74 190
           >
75
-            <ElOption label="第一站-龙-龙血站" value="1" />
191
+            <ElOption label="张三站-龙飞加油站" value="1" />
76 192
           </ElSelect>
193
+        </div>
77 194
 
78
-          <ElRadioGroup v-model="searchParams.timeType">
79
-            <ElRadioButton label="day">日</ElRadioButton>
80
-            <ElRadioButton label="week">周</ElRadioButton>
81
-            <ElRadioButton label="month">月</ElRadioButton>
82
-          </ElRadioGroup>
83
-          <ElDatePicker
84
-            v-model="searchParams.date"
85
-            :type="
86
-              searchParams.timeType === 'month'
87
-                ? 'month'
88
-                : searchParams.timeType === 'week'
89
-                  ? 'week'
90
-                  : 'date'
91
-            "
92
-            :placeholder="
93
-              searchParams.timeType === 'month'
94
-                ? '选择月份'
95
-                : searchParams.timeType === 'week'
96
-                  ? '选择周'
97
-                  : '选择日期'
98
-            "
99
-            :format="
100
-              searchParams.timeType === 'month'
101
-                ? 'YYYY-MM'
102
-                : searchParams.timeType === 'week'
103
-                  ? 'YYYY [年] ww [周]'
104
-                  : 'YYYY-MM-DD'
105
-            "
106
-            :value-format="
107
-              searchParams.timeType === 'month'
108
-                ? 'YYYY-MM'
109
-                : searchParams.timeType === 'week'
110
-                  ? 'YYYY-MM-DD'
111
-                  : 'YYYY-MM-DD'
112
-            "
113
-            class="w-48 min-w-48 max-w-48"
114
-            style="width: 12rem"
115
-          />
195
+        <!--日期导航和视图切换-->
196
+        <div class="mb-4">
197
+          <div class="flex items-center justify-between">
198
+            <!--时间筛选靠左-->
199
+            <div class="flex items-center space-x-2">
200
+              <ElButton type="text" @click="prevMonth">&lt;</ElButton>
201
+              <span class="font-medium">{{
202
+                currentDate.format('YYYY年 M月')
203
+              }}</span>
204
+              <ElButton type="text" @click="nextMonth">&gt;</ElButton>
205
+            </div>
206
+
207
+            <!--视图切换靠右-->
208
+            <ElRadioGroup v-model="searchParams.timeType" size="small">
209
+              <ElRadioButton label="day">日</ElRadioButton>
210
+              <ElRadioButton label="week">周</ElRadioButton>
211
+              <ElRadioButton label="month">月</ElRadioButton>
212
+            </ElRadioGroup>
213
+          </div>
214
+
215
+          <!--日历显示-->
216
+          <div class="calendar-container mt-1">
217
+            <!--星期标题-->
218
+            <div class="mb-1 flex justify-between text-xs text-gray-500">
219
+              <div class="w-7 text-center">一</div>
220
+              <div class="w-7 text-center">二</div>
221
+              <div class="w-7 text-center">三</div>
222
+              <div class="w-7 text-center">四</div>
223
+              <div class="w-7 text-center">五</div>
224
+              <div class="w-7 text-center">六</div>
225
+              <div class="w-7 text-center">日</div>
226
+            </div>
227
+
228
+            <!--日期网格-->
229
+            <div class="grid grid-cols-7 gap-1">
230
+              <div
231
+                v-for="day in calendarDays"
232
+                :key="day.date"
233
+                class="flex h-7 w-7 cursor-pointer items-center justify-center rounded text-xs"
234
+                :class="{
235
+                  'bg-blue-100 text-blue-600': day.isToday,
236
+                  'bg-blue-50 text-blue-700':
237
+                    day.isInCurrentWeek && !day.isToday,
238
+                  'bg-gray-100 text-gray-400': day.isOtherMonth,
239
+                  'hover:bg-gray-100': !day.isOtherMonth,
240
+                }"
241
+                @click="selectDate(day.date)"
242
+              >
243
+                {{ day.day }}
244
+              </div>
245
+            </div>
246
+          </div>
116 247
         </div>
117 248
 
118
-        <div class="flex items-center space-x-4">
119
-          <ElButton type="primary" @click="createTaskDrawerEvent">
120
-            油站新增任务
121
-          </ElButton>
122
-          <ElButton type="primary"> 访客新增任务 </ElButton>
123
-          <ElButton type="primary"> 任务转接 </ElButton>
249
+        <!--任务授权状态-->
250
+        <div class="mb-4">
251
+          <div class="mb-2 font-medium">任务授权状态:</div>
252
+          <div class="space-y-1">
253
+            <ElCheckbox v-model="taskStatuses.canAuthorize">
254
+              任务可授权
255
+            </ElCheckbox>
256
+            <ElCheckbox v-model="taskStatuses.authorized">
257
+              任务已授权
258
+            </ElCheckbox>
259
+            <ElCheckbox v-model="taskStatuses.beAuthorized">
260
+              任务被授权
261
+            </ElCheckbox>
262
+          </div>
124 263
         </div>
264
+
265
+        <!--新增任务按钮固定在底部-->
266
+        <div class="absolute bottom-0 left-0 w-full bg-white p-4">
267
+          <div class="space-y-2">
268
+            <ElButton
269
+              type="primary"
270
+              class="w-full"
271
+              @click="createTaskDrawerEvent"
272
+            >
273
+              + 油站新增任务
274
+            </ElButton>
275
+          </div>
276
+          <div class="mt-1 space-y-2">
277
+            <ElButton type="default" class="w-full"> + 访客新增任务 </ElButton>
278
+          </div>
279
+        </div>
280
+      </div>
281
+
282
+      <!--右侧内容区域-->
283
+      <div class="h-full flex-1 overflow-y-auto">
284
+        <ElCard class="h-full w-full">
285
+          <div class="h-full">
286
+            <Day v-if="searchParams.timeType === 'day'" />
287
+            <Week
288
+              v-if="searchParams.timeType === 'week'"
289
+              :year="year"
290
+              :week-number="weekNumber"
291
+            />
292
+            <Month
293
+              v-if="searchParams.timeType === 'month'"
294
+              :month="currentDate.month() + 1"
295
+            />
296
+          </div>
297
+        </ElCard>
125 298
       </div>
126
-    </template>
127
-    <ElCard class="mb-5 w-full">
128
-      <Day v-if="searchParams.timeType === 'day'" />
129
-      <Week
130
-        v-if="searchParams.timeType === 'week'"
131
-        :year="year"
132
-        :week-number="weekNumber"
133
-      />
134
-      <Month v-if="searchParams.timeType === 'month'" :year="year" />
135
-    </ElCard>
299
+    </div>
136 300
     <CreateTaskDrawer />
137 301
   </Page>
138 302
 </template>