@opendesign-plus-test/components 0.0.1-rc.21 → 0.0.1-rc.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (148) hide show
  1. package/dist/chunk-OElCookieNotice.cjs.js +1 -1
  2. package/dist/chunk-OElCookieNotice.es.js +428 -137
  3. package/dist/components/OBanner.vue.d.ts +10 -1
  4. package/dist/components/OFooter.vue.d.ts +1 -1
  5. package/dist/components/OHeaderSearch.vue.d.ts +4 -4
  6. package/dist/components/activity/OActivityApproval.vue.d.ts +277 -0
  7. package/dist/components/activity/OActivityForm.vue.d.ts +140 -0
  8. package/dist/components/activity/OMyActivityCalendar.vue.d.ts +2 -0
  9. package/dist/components/activity/config.d.ts +15 -0
  10. package/dist/components/activity/data.d.ts +51 -0
  11. package/dist/components/activity/index.d.ts +332 -0
  12. package/dist/components/activity/types.d.ts +72 -0
  13. package/dist/components/meeting/OMeetingCalendar.vue.d.ts +309 -0
  14. package/dist/components/meeting/OMeetingForm.vue.d.ts +156 -0
  15. package/dist/components/meeting/OMyMeetingCalendar.vue.d.ts +582 -0
  16. package/dist/components/meeting/OSigMeetingCalendar.vue.d.ts +24 -0
  17. package/dist/components/meeting/components/OMeetingCalendarList.vue.d.ts +27 -0
  18. package/dist/components/meeting/components/OMeetingCalendarSelector.vue.d.ts +664 -0
  19. package/dist/components/meeting/components/OMeetingDetail.vue.d.ts +12 -0
  20. package/dist/components/meeting/components/OMeetingPlaybackSubtitles.vue.d.ts +5 -0
  21. package/dist/components/meeting/components/OMeetingPlaybackVideo.vue.d.ts +17 -0
  22. package/dist/components/meeting/components/OSigMeetingAside.vue.d.ts +16 -0
  23. package/dist/components/meeting/config.d.ts +27 -0
  24. package/dist/components/meeting/types.d.ts +140 -0
  25. package/dist/components/meeting/utils.d.ts +21 -0
  26. package/dist/components.cjs.js +224 -3
  27. package/dist/components.css +1 -1
  28. package/dist/components.es.js +43019 -2293
  29. package/dist/index.d.ts +2 -0
  30. package/package.json +6 -3
  31. package/scripts/generate-components-index.js +4 -0
  32. package/src/assets/meeting/svg-icons/icon-all.svg +3 -0
  33. package/src/assets/meeting/svg-icons/icon-backward.svg +4 -0
  34. package/src/assets/meeting/svg-icons/icon-calendar.svg +3 -0
  35. package/src/assets/meeting/svg-icons/icon-cancel.svg +4 -0
  36. package/src/assets/meeting/svg-icons/icon-captions.svg +4 -0
  37. package/src/assets/meeting/svg-icons/icon-close-captions.svg +6 -0
  38. package/src/assets/meeting/svg-icons/icon-close-fullscreen.svg +6 -0
  39. package/src/assets/meeting/svg-icons/icon-copy.svg +3 -0
  40. package/src/assets/meeting/svg-icons/icon-create.svg +5 -0
  41. package/src/assets/meeting/svg-icons/icon-delete.svg +7 -0
  42. package/src/assets/meeting/svg-icons/icon-empty.svg +31 -0
  43. package/src/assets/meeting/svg-icons/icon-empty_dark.svg +49 -0
  44. package/src/assets/meeting/svg-icons/icon-event.svg +3 -0
  45. package/src/assets/meeting/svg-icons/icon-export.svg +3 -0
  46. package/src/assets/meeting/svg-icons/icon-forward.svg +4 -0
  47. package/src/assets/meeting/svg-icons/icon-fullscreen.svg +6 -0
  48. package/src/assets/meeting/svg-icons/icon-help.svg +3 -0
  49. package/src/assets/meeting/svg-icons/icon-important.svg +4 -0
  50. package/src/assets/meeting/svg-icons/icon-info.svg +3 -0
  51. package/src/assets/meeting/svg-icons/icon-meet.svg +3 -0
  52. package/src/assets/meeting/svg-icons/icon-meeting-message.svg +5 -0
  53. package/src/assets/meeting/svg-icons/icon-meeting.svg +4 -0
  54. package/src/assets/meeting/svg-icons/icon-play.svg +5 -0
  55. package/src/assets/meeting/svg-icons/icon-playing-tip.svg +7 -0
  56. package/src/assets/meeting/svg-icons/icon-playing.svg +5 -0
  57. package/src/assets/meeting/svg-icons/icon-question.svg +4 -0
  58. package/src/assets/meeting/svg-icons/icon-sound.svg +5 -0
  59. package/src/assets/meeting/svg-icons/icon-speaker.svg +3 -0
  60. package/src/assets/meeting/svg-icons/icon-summit.svg +3 -0
  61. package/src/assets/meeting/svg-icons/icon-telligent.svg +3 -0
  62. package/src/assets/meeting/svg-icons/icon-tip.svg +3 -0
  63. package/src/assets/meeting/svg-icons/icon-todo.svg +4 -0
  64. package/src/assets/meeting/transparent.png +0 -0
  65. package/src/assets/svg-icons/icon-chevron-up.svg +3 -0
  66. package/src/assets/svg-icons/icon-filter.svg +3 -0
  67. package/src/assets/svg-icons/icon-loading.svg +4 -0
  68. package/src/assets/svg-icons/icon-search.svg +3 -0
  69. package/src/assets/svg-icons/icon-tips.svg +3 -0
  70. package/src/components/OBanner.vue +11 -3
  71. package/src/components/OFooter.vue +1 -1
  72. package/src/components/activity/OActivityApproval.vue +775 -0
  73. package/src/components/activity/OActivityForm.vue +540 -0
  74. package/src/components/activity/OMyActivityCalendar.vue +13 -0
  75. package/src/components/activity/config.ts +130 -0
  76. package/src/components/activity/data.ts +365 -0
  77. package/src/components/activity/index.ts +24 -0
  78. package/src/components/activity/types.ts +78 -0
  79. package/src/components/common/MoreText.vue +119 -0
  80. package/src/components/common/ThFilter.vue +326 -0
  81. package/src/components/events/OEventsApply.vue +2 -86
  82. package/src/components/events/OEventsCalendar.vue +0 -25
  83. package/src/components/events/OEventsList.vue +0 -51
  84. package/src/components/events/index.ts +1 -0
  85. package/src/components/meeting/OMeetingCalendar.vue +865 -0
  86. package/src/components/meeting/OMeetingForm.vue +1035 -0
  87. package/src/components/meeting/OMeetingPlayback.vue +439 -0
  88. package/src/components/meeting/OMyMeetingCalendar.vue +1534 -0
  89. package/src/components/meeting/OSigMeetingCalendar.vue +411 -0
  90. package/src/components/meeting/components/OMeetingCalendarList.vue +462 -0
  91. package/src/components/meeting/components/OMeetingCalendarSelector.vue +206 -0
  92. package/src/components/meeting/components/OMeetingDetail.vue +176 -0
  93. package/src/components/meeting/components/OMeetingPlaybackSubtitles.vue +611 -0
  94. package/src/components/meeting/components/OMeetingPlaybackVideo.vue +741 -0
  95. package/src/components/meeting/components/OSigMeetingAside.vue +197 -0
  96. package/src/components/meeting/config.ts +110 -0
  97. package/src/components/meeting/index.ts +45 -0
  98. package/src/components/meeting/types.ts +167 -0
  99. package/src/components/meeting/utils.ts +106 -0
  100. package/src/draft/Footer.vue +4 -4
  101. package/src/env.d.ts +15 -0
  102. package/src/i18n/en.ts +140 -0
  103. package/src/i18n/index.ts +18 -4
  104. package/src/i18n/zh.ts +140 -0
  105. package/src/index.ts +2 -0
  106. package/tsconfig.json +6 -2
  107. package/vite.config.ts +25 -9
  108. package/npmcachae/_cacache/content-v2/sha512/05/f7/dd881de8b21208ea65cfce17c65f29964c3897505819f81151b9798a3a6ab1a1114324192354ead15cd2c8d93f76cc9929af168066ec9cc7878d0fd87578 +0 -1
  109. package/npmcachae/_cacache/content-v2/sha512/08/b7/879230f8c2f3765920a6fd6113f4687141f1f645f96af7d95a0dee9113d1095d000fb78a5dd55c1860bbfb9b698ef6281b3874b03b2384222f61fe055fc4 +0 -1
  110. package/npmcachae/_cacache/content-v2/sha512/10/a0/a6626613c03ee052925a762e8675878efdf83dac64fafea43beb2a875f7d7c3907bb0ee30761253cd16021fd58911449594e1d3358675cbb7c48e62f220a +0 -1
  111. package/npmcachae/_cacache/content-v2/sha512/2e/a6/7cbcf55a98bbe2ca881d10e982ebf59211a0ec051eaf46eb1914df66cc35ae502ed6888850e51d8f45cd92695bac16961a642bc41508f8d5160a9ab617ab +0 -1
  112. package/npmcachae/_cacache/content-v2/sha512/92/8d/e5259c5d5cc2a625247f3c4d809192ca9482467e23683d74924a11e91a7997ad890b3d26adaf34df66d5329cc7a5fbde6713110cad05107a0b504e4fd4e8 +0 -1
  113. package/npmcachae/_cacache/content-v2/sha512/e9/45/9597d870127c35681155cec5fe52fde4e1aa0f778b996ee371e856aca850ee4c13aba74b0c3d3a89ff0ea4c9e1d33e64e53c31dc9cede0b31012695ee659 +0 -1
  114. package/npmcachae/_cacache/index-v5/16/4a/7195fcc6857299c4ab7e26014a8ae6e3c396507a2c8db3da1b74b005d574 +0 -3
  115. package/npmcachae/_cacache/index-v5/58/f0/4fe556f104b09be642895a82afa463fe560d9a0dc8f507efeef825a6905e +0 -3
  116. package/npmcachae/_cacache/index-v5/67/7d/0b50dc4c09555fc922ccf43c46994f1a0a5ff47dc0a5d5cf41437ac2d3e6 +0 -3
  117. package/npmcachae/_cacache/index-v5/8f/28/353f8839e030ab11aab3e7d9f1b8c053403e9f593cf6d4aa6ec8fdd7610d +0 -3
  118. package/npmcachae/_cacache/index-v5/97/10/0fcf20eb29d0726bd820822f6729718464b591b0e6901217c956740e943c +0 -3
  119. package/npmcachae/_cacache/index-v5/db/89/a0a4f35f593105624ab39339962d9e9b5cc65ed0c346b0732fb8dd73721d +0 -3
  120. package/npmcachae/_logs/2026-03-26T14_10_35_885Z-debug-0.log +0 -171
  121. package/npmcachae/_logs/2026-03-26T14_10_38_617Z-debug-0.log +0 -4227
  122. package/npmcachae/_logs/2026-03-26T14_10_45_316Z-debug-0.log +0 -4228
  123. package/npmcachae/_logs/2026-03-26T14_10_48_169Z-debug-0.log +0 -4228
  124. package/npmcachae/_logs/2026-03-26T14_10_51_306Z-debug-0.log +0 -464
  125. package/npmcachae/_logs/2026-03-26T14_10_53_911Z-debug-0.log +0 -464
  126. package/npmcachae/_logs/2026-03-26T14_10_56_398Z-debug-0.log +0 -464
  127. package/npmcachae/_logs/2026-03-26T14_10_58_861Z-debug-0.log +0 -464
  128. package/npmcachae/_logs/2026-03-26T14_11_01_337Z-debug-0.log +0 -464
  129. package/npmcachae/_logs/2026-03-26T14_11_03_851Z-debug-0.log +0 -464
  130. package/npmcachae/_logs/2026-03-26T14_11_08_024Z-debug-0.log +0 -464
  131. package/npmcachae/_update-notifier-last-checked +0 -0
  132. package/src/components/meeting/npmcachae/_cacache/content-v2/sha512/3e/17/1865217b9acb9f4921c53a09b5c76587cd2ab748beb2699ff6cfb1341d73b1aa56ed91ffc5ab2c9c9b3fbe626103b35d9a79ff29ff6b8cbb8d89755fe1a2 +0 -1
  133. package/src/components/meeting/npmcachae/_cacache/content-v2/sha512/a6/15/47bb7552ec9248079e839a5feecc1742d4de19524fdf041cf581701cf4760a5025106036145e279ba193b07c8fa5b07ae3d75f1b6032f0cb2219115b6167 +0 -1
  134. package/src/components/meeting/npmcachae/_cacache/content-v2/sha512/d1/4c/133b32e09c97101a27a07cc4432f94e470cff02d120d21babcea77c3f5cd436793516dc1a8e282ee1a568f923c148b1a48f4a43233462a530d35e8b41c67 +0 -1
  135. package/src/components/meeting/npmcachae/_cacache/index-v5/54/0d/a4909047714a0a7198bb9bd37020992464e47c79a791889919b84d90aab0 +0 -3
  136. package/src/components/meeting/npmcachae/_cacache/index-v5/8e/2b/21a79778e2ac08cf5663baf83cb35f951995a496007eb2e2f7fba54021a4 +0 -3
  137. package/src/components/meeting/npmcachae/_cacache/index-v5/eb/a0/b70c8132e5b57a0f1e129b8cc941796420a9c147c0baa680710083740898 +0 -2
  138. package/src/components/meeting/npmcachae/_logs/2026-03-20T07_03_54_955Z-debug-0.log +0 -277
  139. package/src/components/meeting/npmcachae/_logs/2026-03-20T07_03_57_842Z-debug-0.log +0 -277
  140. package/src/components/meeting/npmcachae/_logs/2026-03-20T07_04_00_016Z-debug-0.log +0 -277
  141. package/src/components/meeting/npmcachae/_logs/2026-03-20T07_04_02_191Z-debug-0.log +0 -277
  142. package/src/components/meeting/npmcachae/_logs/2026-03-20T07_04_04_425Z-debug-0.log +0 -277
  143. package/src/components/meeting/npmcachae/_logs/2026-03-20T07_04_06_642Z-debug-0.log +0 -277
  144. package/src/components/meeting/npmcachae/_logs/2026-03-20T07_04_08_826Z-debug-0.log +0 -277
  145. package/src/components/meeting/npmcachae/_logs/2026-03-20T07_25_36_140Z-debug-0.log +0 -433
  146. package/src/components/meeting/npmcachae/_logs/2026-03-20T07_25_39_573Z-debug-0.log +0 -433
  147. package/src/components/meeting/npmcachae/_logs/2026-03-20T07_25_42_134Z-debug-0.log +0 -212
  148. package/src/components/meeting/npmcachae/_update-notifier-last-checked +0 -0
@@ -0,0 +1,1534 @@
1
+ <script setup lang="ts">
2
+ import {
3
+ DialogActionT,
4
+ OCollapse,
5
+ OCollapseItem,
6
+ ODialog,
7
+ ODivider,
8
+ OIcon,
9
+ OIconArrowLeft,
10
+ OIconArrowRight,
11
+ OIconChevronLeft,
12
+ OIconChevronRight,
13
+ OLink,
14
+ ORadio,
15
+ ORadioGroup,
16
+ OScroller,
17
+ OTag,
18
+ useMessage,
19
+ } from '@opensig/opendesign';
20
+ import { ElCalendar } from 'element-plus';
21
+ import { computed, nextTick, onMounted, ref, onUnmounted, watch } from 'vue';
22
+ import OMeetingDetail from './components/OMeetingDetail.vue';
23
+ import type { MeetingItemT, PageParamsT } from './types.ts';
24
+ import dayjs from 'dayjs';
25
+ import IconMeeting from '~icons/meeting/icon-meet.svg';
26
+ import { INTERVAL_DAY, INTERVAL_MONTH, INTERVAL_WEEK, WEEKDAY } from './config.ts';
27
+ import { formatDate, getDateNumber } from './utils.ts';
28
+ import { getPointStr } from './utils.ts';
29
+ import { useDebounceFn } from '@vueuse/core';
30
+ import { useScreen } from '@opendesign-plus/composables';
31
+ import { Locales, useI18n } from '@/i18n';
32
+ import IconCopy from '~icons/meeting/icon-copy.svg';
33
+
34
+ const message = useMessage(null);
35
+ const tableLoading = ref(false); // 列表数据加载状态
36
+ const currentPage = ref(1); // 分页-当前页
37
+ const pageSize = ref(50); // 分页-每页数量
38
+ const total = ref<number | null>(null); // 分页-总数
39
+ const list = ref<MeetingItemT[]>([]); // 列表数据
40
+ const originList = ref([]); // 原始数据
41
+ const canLoadMore = computed(() => total.value === null || originList.value.length < total.value);
42
+ const reloadAll = ref(false); // 是否需要清空数据
43
+ const { t, locale } = useI18n();
44
+ const isEn = computed(() => locale.value === Locales.EN);
45
+
46
+ const props = defineProps<{
47
+ cancelSubMeetingRequest: any;
48
+ deleteMeetingRequest: any;
49
+ getMeetingListRequest: any
50
+ }>();
51
+
52
+ const dialogLoading = ref(false); // 弹窗按钮状态
53
+ const { isPhone } = useScreen();
54
+ const expanded = ref([]); // 展开的数据, sub_id 或 id
55
+ const emits = defineEmits(['edit']);
56
+ // -------------------- 自动加载下一页 --------------------
57
+ const nextLoading = ref(false);
58
+ const bottomReached = ref(false);
59
+ const headerRef = ref();
60
+ const headerHeight = ref(0);
61
+ const getHeaderHeight = () => {
62
+ headerHeight.value = headerRef.value?.clientHeight || 0;
63
+ };
64
+
65
+ const getList = async () => {
66
+ if (!props.getMeetingListRequest) {
67
+ return;
68
+ }
69
+ if (nextLoading.value) {
70
+ return;
71
+ }
72
+ try {
73
+ if (total.value > 0 && (currentPage.value - 1) * pageSize.value > total.value) {
74
+ return;
75
+ }
76
+ // 当月数据已加载完,手动切换下一月
77
+ if (!canLoadMore.value && isPhone.value) {
78
+ changeMonth('next-month');
79
+ return;
80
+ }
81
+ tableLoading.value = true;
82
+ nextLoading.value = true;
83
+ const res = await props.getMeetingListRequest({
84
+ page: currentPage.value,
85
+ size: pageSize.value,
86
+ order_by: 'date',
87
+ order_type: 'asc',
88
+ month: dayjs(selectedDate.value).format('YYYY-MM'),
89
+ } as unknown as PageParamsT);
90
+ const tempList = (res.data || [])
91
+ .map((item: MeetingItemT) => {
92
+ const {
93
+ is_cycle,
94
+ date,
95
+ start,
96
+ end,
97
+ cycle_sub,
98
+ cycle_start_date,
99
+ cycle_end_date,
100
+ cycle_start,
101
+ cycle_end,
102
+ cycle_type,
103
+ cycle_interval,
104
+ cycle_point,
105
+ } =
106
+ item;
107
+ if (is_cycle) {
108
+ let timeRange = '';
109
+ let cycleType = '';
110
+ if (cycle_type === INTERVAL_DAY) {
111
+ cycleType = t('meeting.cycleDay');
112
+ }
113
+ if (cycle_type === INTERVAL_WEEK) {
114
+ if (cycle_interval > 1) {
115
+ cycleType = t('meeting.cycleWeek.other', [getPointStr(cycle_type, cycle_point), cycle_interval]);
116
+ } else {
117
+ cycleType = t('meeting.cycleWeek.one', [getPointStr(cycle_type, cycle_point)]);
118
+ }
119
+ }
120
+ if (cycle_type === INTERVAL_MONTH) {
121
+ cycleType = t('meeting.cycleMonth', [getPointStr(cycle_type, cycle_point)]);
122
+ }
123
+ timeRange = t('meeting.cycleMeetingText2', {
124
+ startDate: cycle_start_date,
125
+ endDate: cycle_end_date,
126
+ startTime: cycle_start,
127
+ endTime: cycle_end,
128
+ cycleType,
129
+ });
130
+ const obsData = item.obs_data?.filter((v) => v.text_video_url);
131
+ return cycle_sub
132
+ .filter((v) => {
133
+ return (
134
+ dayjs(v.date).isBefore(dayjs(selectedDate.value).add(1, 'month').format('YYYY-MM-01')) &&
135
+ !dayjs(v.date).isBefore(dayjs(selectedDate.value).format('YYYY-MM-01'))
136
+ );
137
+ })
138
+ .map(({ id: _id, ...sub }) => {
139
+ return {
140
+ ...item,
141
+ ...sub,
142
+ timeRange: timeRange,
143
+ dateRange: `${ sub.start }-${ sub.end }`,
144
+ hasObsData: obsData.find((v) => v.sub_id === sub.sub_id),
145
+ time: `${ sub.start }-${ sub.end }`,
146
+ isExpired: dayjs(`${ sub.date } ${ sub.start }`).isBefore(dayjs()),
147
+ };
148
+ });
149
+ }
150
+ return [
151
+ {
152
+ ...item,
153
+ dateRange: `${ start } - ${ end }`,
154
+ timeRange: `${ start } - ${ end }`,
155
+ hasObsData: item.obs_data?.filter((v) => v.text_video_url)?.length > 0,
156
+ time: `${ start }-${ end }`,
157
+ isExpired: dayjs(`${ date } ${ start }`).isBefore(dayjs()),
158
+ },
159
+ ];
160
+ })
161
+ .flat()
162
+ .filter((v) => v.date.slice(0, 7) === formatDate(selectedDate.value, 'YYYY-MM-DD').slice(0, 7));
163
+ // 如果需要清空,则完全替换
164
+ // 如果页码为1,表示第一次加载
165
+ // 如果是移动端,则一直往里填充数据
166
+ if (reloadAll.value) {
167
+ originList.value = res.data || [];
168
+ list.value = tempList;
169
+ } else {
170
+ if (currentPage.value === 1 && !isPhone.value) {
171
+ originList.value = res.data || [];
172
+ list.value = tempList;
173
+ } else {
174
+ originList.value = [...originList.value, ...(res.data || [])];
175
+ list.value = [...list.value, ...tempList];
176
+ }
177
+ }
178
+ list.value.sort((a, b) => {
179
+ if (a.date === b.date) {
180
+ return getDateNumber(a.start) > getDateNumber(b.start) ? 1 : -1;
181
+ } else {
182
+ return dayjs(a.date).isAfter(dayjs(b.date)) ? 1 : -1;
183
+ }
184
+ });
185
+ total.value = res?.total || 0;
186
+ nextTick(() => {
187
+ getSelectedDate();
188
+ // 监听滚动事件以自动加载下一页
189
+ if (scrollerRef.value && !isPhone.value) {
190
+ updateScroller();
191
+ }
192
+ });
193
+ } finally {
194
+ tableLoading.value = false;
195
+ nextLoading.value = false;
196
+ bottomReached.value = false;
197
+ reloadAll.value = false;
198
+ }
199
+ };
200
+
201
+ const load = useDebounceFn(() => {
202
+ if (!canLoadMore.value) return;
203
+ if (isPhone.value) return;
204
+ bottomReached.value = true;
205
+ currentPage.value++;
206
+ getList();
207
+ }, 200);
208
+ const handleScroll = useDebounceFn(() => {
209
+ if (!canLoadMore.value) return;
210
+ if (!isPhone.value) return;
211
+ const scrollPosition = window.scrollY || window.pageYOffset;
212
+ // 检测是否接近底部
213
+ const windowHeight = window.innerHeight;
214
+ const docHeight = document.documentElement.scrollHeight;
215
+ const distanceToBottom = docHeight - (scrollPosition + windowHeight);
216
+ // 当距离底部300px时开始加载
217
+ if (distanceToBottom <= 300 && !nextLoading.value) {
218
+ bottomReached.value = true;
219
+ // 加载下一页
220
+ currentPage.value++;
221
+ getList();
222
+ }
223
+ }, 200);
224
+ const calcIfAllDeleted = (date) => {
225
+ const meetingsOfDate = list.value.filter((v) => v.date === date);
226
+ return meetingsOfDate.length && meetingsOfDate.every((v) => v.is_delete);
227
+ };
228
+
229
+ const scrollerScroll = (el) => {
230
+ const container = el.target;
231
+ if (!container) return;
232
+ const scrollTop = container.scrollTop; // 已经滚动的距离
233
+ const scrollHeight = container.scrollHeight; // 内容总高度
234
+ const clientHeight = container.clientHeight; // 容器可视高度
235
+ if (scrollTop + clientHeight >= scrollHeight) {
236
+ load();
237
+ }
238
+ };
239
+ const updateScroller = () => {
240
+ const scrollerContainerEl = scrollerRef.value.getContainerEl();
241
+ scrollerContainerEl.addEventListener('scroll', scrollerScroll);
242
+ };
243
+
244
+ const detailRefs = ref({}); // 会议详情组件实例
245
+ const getDetailRefs = (insRef, id) => {
246
+ if (insRef && id) {
247
+ detailRefs.value[id] = insRef;
248
+ }
249
+ };
250
+ const copyInfo = async (idx) => {
251
+ const instance = detailRefs.value[idx];
252
+ await instance.copyInfo();
253
+ message.success({
254
+ content: t('common.copySuccess'),
255
+ });
256
+ };
257
+ // -------------------- 取消 --------------------
258
+ const cancelVisible = ref(false); // 取消弹窗
259
+ const currentRow = ref<MeetingItemT | null>(null); // 当前激活行,用于取消事件
260
+ // 打开编辑会议弹窗
261
+ const editMeeting = (row: MeetingItemT) => {
262
+ emits('edit', row, 'whole');
263
+ };
264
+ // 打开取消会议弹窗
265
+ const cancelMeeting = (row: MeetingItemT) => {
266
+ currentRow.value = row;
267
+ cancelVisible.value = true;
268
+ };
269
+ // 确定取消会议
270
+ const confirmCancel = async () => {
271
+ if (!props.deleteMeetingRequest) {
272
+ return;
273
+ }
274
+ try {
275
+ dialogLoading.value = true;
276
+ await props.deleteMeetingRequest(currentRow.value.id);
277
+ cancelVisible.value = false;
278
+ message.success({
279
+ content: `${ t('meeting.meetingCancel', [currentRow.value.topic]) }`,
280
+ });
281
+ reloadAll.value = true;
282
+ getList();
283
+ } finally {
284
+ dialogLoading.value = false;
285
+ }
286
+ };
287
+ const handleDialogVisible = ref(false);
288
+ const handleDialogType = ref('');
289
+ const handleDialogRow = ref(null);
290
+ const handleOptions = [
291
+ {
292
+ label: t('meeting.meetingSingle'),
293
+ value: 'single',
294
+ },
295
+ {
296
+ label: t('meeting.meetingCycle'),
297
+ value: 'whole',
298
+ },
299
+ ];
300
+
301
+ const handleType = ref('single');
302
+ const handleItem = (row: MeetingItemT, type: 'edit' | 'cancel') => {
303
+ if (row.is_cycle) {
304
+ handleDialogRow.value = row;
305
+ handleDialogType.value = type;
306
+ handleDialogVisible.value = true;
307
+ } else {
308
+ if (type === 'cancel') {
309
+ cancelMeeting(row);
310
+ } else {
311
+ editMeeting(row);
312
+ }
313
+ }
314
+ };
315
+ const cancelHandleItem = () => {
316
+ handleDialogVisible.value = false;
317
+ handleDialogRow.value = null;
318
+ handleDialogType.value = '';
319
+ handleType.value = 'single';
320
+ };
321
+ const confirmHandleItem = async () => {
322
+ const row = handleDialogRow.value;
323
+ if (handleDialogType.value === 'cancel') {
324
+ try {
325
+ dialogLoading.value = true;
326
+ if (handleType.value === 'single' && row.is_cycle) {
327
+ if (!props.cancelSubMeetingRequest) {
328
+ return;
329
+ }
330
+ await props.cancelSubMeetingRequest(row.sub_id);
331
+ message.success({
332
+ content: `${ t('meeting.meetingCancel', [row.topic]) }`,
333
+ });
334
+ } else {
335
+ if (!props.deleteMeetingRequest) {
336
+ return;
337
+ }
338
+ await props.deleteMeetingRequest(row.id);
339
+ message.success({
340
+ content: `${ t('meeting.meetingCancel', [row.topic]) }`,
341
+ });
342
+ }
343
+ cancelHandleItem();
344
+ reloadAll.value = true;
345
+ getList();
346
+ } finally {
347
+ dialogLoading.value = false;
348
+ }
349
+ } else {
350
+ emits('edit', row, handleType.value);
351
+ cancelHandleItem();
352
+ }
353
+ };
354
+
355
+ // -------------------- 日历 --------------------
356
+ const calendarRef = ref();
357
+ const allDateList = computed<string[]>(() => [...new Set(list.value.map((v) => v.date))].sort((a, b) => (dayjs(a).isBefore(dayjs(b)) ? -1 : 1)));
358
+ const dateList = computed<string[]>(() =>
359
+ [...new Set(list.value.filter((v) => !v.isExpired && !v.is_delete).map((v) => v.date))].sort((a, b) => (dayjs(a).isBefore(dayjs(b)) ? -1 : 1)),
360
+ );
361
+ const selectedDate = ref();
362
+
363
+ const getSelectedDate = () => {
364
+ const latest = dateList.value.find((v) => !dayjs(v).isBefore(dayjs(new Date()).format('YYYY-MM-DD')));
365
+ if (latest) {
366
+ selectedDate.value = latest;
367
+ } else if (!selectedDate.value) {
368
+ selectedDate.value = dayjs().format('YYYY-MM-DD');
369
+ }
370
+ calendarRef.value?.pickDay(dayjs(selectedDate.value));
371
+ selectedDate.value = dayjs(selectedDate.value).format('YYYY-MM-DD');
372
+ // 根据天再计算出需要展开的最近的会议
373
+ const needExpand = list.value.find((v) => v.date === selectedDate.value && !v.isExpired && !v.is_delete);
374
+ if (needExpand) {
375
+ expanded.value = [needExpand.sub_id || needExpand.id];
376
+ }
377
+ };
378
+
379
+ const cellClick = (e: PointerEvent & any, clickable: boolean) => {
380
+ if (!clickable || !e.target?.className.includes('date-cell-text')) {
381
+ e.stopPropagation();
382
+ e.preventDefault();
383
+ }
384
+ };
385
+
386
+ const changeMonth = (val) => {
387
+ if (!calendarRef.value) return;
388
+ currentPage.value = 1;
389
+ total.value = null;
390
+ window.scrollTo({
391
+ top: 0,
392
+ behavior: 'smooth',
393
+ });
394
+ calendarRef.value.selectDate(val);
395
+ reloadAll.value = true;
396
+ nextTick(() => {
397
+ selectedDate.value = dayjs(calendarRef.value.selectedDay).format('YYYY-MM-DD');
398
+ getList();
399
+ });
400
+ };
401
+ // -------------------- 列表 --------------------
402
+ const groupList = computed(() => {
403
+ return list.value.reduce((prev, cur) => {
404
+ if (!prev.length) {
405
+ return [
406
+ {
407
+ date: cur.date,
408
+ list: [cur],
409
+ },
410
+ ];
411
+ } else {
412
+ const last = prev.at(-1);
413
+ if (last.date === cur.date) {
414
+ last.list.push(cur);
415
+ } else {
416
+ prev.push({
417
+ date: cur.date,
418
+ list: [cur],
419
+ });
420
+ }
421
+ return prev;
422
+ }
423
+ }, []);
424
+ });
425
+
426
+ const getWeekFromDate = (date) => {
427
+ return WEEKDAY[dayjs(date).day()];
428
+ };
429
+
430
+ // -------------------- 处理滚动事件 --------------------
431
+ const scrollerRef = ref();
432
+ watch(
433
+ () => selectedDate.value,
434
+ () => {
435
+ scrollToSelectedDate(selectedDate.value);
436
+ },
437
+ );
438
+ const scrollToSelectedDate = (date: string) => {
439
+ const key = dayjs(date).format('YYYY-MM-DD');
440
+ const targetEle = document.querySelector(`#group-title-${ key }`);
441
+ if (targetEle) {
442
+ if (isPhone.value) {
443
+ window.scrollTo({
444
+ top: (targetEle.parentElement?.offsetTop || 0) - 52,
445
+ behavior: 'smooth',
446
+ });
447
+ } else {
448
+ scrollerRef.value?.scrollTo({
449
+ top: targetEle.parentElement?.offsetTop || 0,
450
+ behavior: 'smooth',
451
+ });
452
+ }
453
+ }
454
+ };
455
+ onMounted(() => {
456
+ getList();
457
+ // 添加滚动事件监听
458
+ window.addEventListener('scroll', handleScroll);
459
+ // 添加resize监听器
460
+ window.addEventListener('resize', handleScroll);
461
+ getHeaderHeight();
462
+ window.addEventListener('resize', getHeaderHeight);
463
+ });
464
+
465
+ onUnmounted(() => {
466
+ window.removeEventListener('scroll', handleScroll);
467
+ window.removeEventListener('resize', handleScroll);
468
+ window.removeEventListener('resize', getHeaderHeight);
469
+ const scrollerContainerEl = scrollerRef.value?.getContainerEl();
470
+ scrollerContainerEl?.removeEventListener('scroll', scrollerScroll);
471
+ });
472
+
473
+ const formatYearMonth = (date) => {
474
+ date = dayjs(date ? date : undefined);
475
+ if (isEn.value) {
476
+ return date.format('MMMM YYYY');
477
+ } else {
478
+ return date.format('YYYY MM月');
479
+ }
480
+ };
481
+ const handleActions = computed<DialogActionT[]>(() => {
482
+ return [
483
+ {
484
+ id: 'confirm',
485
+ color: 'primary',
486
+ label: t('common.confirm'),
487
+ variant: 'solid',
488
+ size: 'large',
489
+ round: 'pill',
490
+ loading: dialogLoading.value,
491
+ onClick: () => {
492
+ confirmHandleItem();
493
+ },
494
+ },
495
+ {
496
+ id: 'cancel',
497
+ color: 'primary',
498
+ label: t('common.cancel'),
499
+ variant: 'outline',
500
+ size: 'large',
501
+ round: 'pill',
502
+ onClick: () => {
503
+ cancelHandleItem();
504
+ },
505
+ },
506
+ ];
507
+ });
508
+ const cancelActions = computed<DialogActionT[]>(() => {
509
+ return [
510
+ {
511
+ id: 'confirm',
512
+ color: 'primary',
513
+ label: t('common.confirm'),
514
+ variant: 'solid',
515
+ size: 'large',
516
+ round: 'pill',
517
+ loading: dialogLoading.value,
518
+ onClick: () => {
519
+ confirmCancel();
520
+ },
521
+ },
522
+ {
523
+ id: 'cancel',
524
+ color: 'primary',
525
+ label: t('common.cancel'),
526
+ variant: 'outline',
527
+ size: 'large',
528
+ round: 'pill',
529
+ onClick: () => {
530
+ cancelVisible.value = false;
531
+ },
532
+ },
533
+ ];
534
+ });
535
+ </script>
536
+
537
+ <template>
538
+ <div class="o-my-meeting-calendar">
539
+ <div class="meeting-list">
540
+ <div class="list-calendar-mb">
541
+ <span>{{ formatYearMonth(selectedDate) }}</span>
542
+ <span>
543
+ <OIcon @click="changeMonth('prev-month')"><OIconChevronLeft /></OIcon>
544
+ <OIcon @click="changeMonth('next-month')"><OIconChevronRight /></OIcon>
545
+ </span>
546
+ </div>
547
+ <div class="list-calendar">
548
+ <ElCalendar ref="calendarRef" v-model="selectedDate">
549
+ <template #header>
550
+ <span>{{ formatYearMonth(selectedDate) }}</span>
551
+ <div>
552
+ <OIcon @click="changeMonth('prev-month')">
553
+ <OIconChevronLeft />
554
+ </OIcon>
555
+ <OIcon @click="changeMonth('next-month')">
556
+ <OIconChevronRight />
557
+ </OIcon>
558
+ </div>
559
+ </template>
560
+ <template #date-cell="{ data }">
561
+ <div
562
+ @click="(e) => cellClick(e, allDateList.includes(data.day))"
563
+ :class="{
564
+ 'date-cell': true,
565
+ 'is-selected': data.isSelected,
566
+ 'is-today': formatDate(data.day) === formatDate(),
567
+ clickable: allDateList.includes(data.day),
568
+ expired: dayjs(formatDate()).isAfter(dayjs(data.day)),
569
+ 'all-deleted': calcIfAllDeleted(data.day),
570
+ }"
571
+ >
572
+ <div class="date-cell-text">
573
+ {{ Number(data.day.split('-')[2]) }}
574
+ </div>
575
+ </div>
576
+ </template>
577
+ </ElCalendar>
578
+ </div>
579
+ <div class="list-wrapper" :class="!list.length ? 'is-empty' : ''">
580
+ <OScroller
581
+ ref="scrollerRef"
582
+ @scrollend="load"
583
+ v-if="list.length"
584
+ :style="{ '--header-height': headerHeight }"
585
+ class="scroller-container"
586
+ show-type="hover"
587
+ >
588
+ <div class="list-body">
589
+ <OCollapse v-model="expanded" :accordion="isPhone">
590
+ <template v-for="(group, idx) in groupList" :key="group.date">
591
+ <div class="list-month-change prev-month" v-if="idx === 0" @click="changeMonth('prev-month')">
592
+ <OIcon>
593
+ <OIconArrowLeft />
594
+ </OIcon>
595
+ <span>{{ t('meeting.preMonth') }}</span>
596
+ </div>
597
+ <div class="group-item" :class="idx === groupList.length - 1 && 'last-item'">
598
+ <div
599
+ :class="{
600
+ 'group-bar': true,
601
+ 'is-active': dayjs(selectedDate).format('YYYY-MM-DD') === group.date,
602
+ 'is-end': group.list.every((row) => row.isExpired),
603
+ }"
604
+ >
605
+ <div class="group-bar-line"></div>
606
+ <div class="group-bar-dot"></div>
607
+ </div>
608
+ <div
609
+ :class="{
610
+ 'group-title': true,
611
+ 'is-end': group.list.every((row) => row.isExpired),
612
+ }"
613
+ :id="`group-title-${dayjs(new Date(group.date)).format('YYYY-MM-DD')}`"
614
+ >
615
+ {{ dayjs(group.date).format('MM/DD') }} {{ getWeekFromDate(group.date) }}
616
+ </div>
617
+ <OCollapseItem
618
+ v-for="(row, rowIdx) in group.list"
619
+ :key="row.sub_id || row.id"
620
+ :value="row.sub_id || row.id"
621
+ :class="{
622
+ 'last-item': idx === groupList.length - 1 && rowIdx === group.list.length - 1,
623
+ }"
624
+ >
625
+ <template #title>
626
+ <div class="item-header-left">
627
+ <div class="meeting-icon">
628
+ <OIcon>
629
+ <IconMeeting />
630
+ </OIcon>
631
+ </div>
632
+ <div class="header-info">
633
+ <div
634
+ :class="{
635
+ 'meeting-title': true,
636
+ 'is-delete': row.is_delete,
637
+ 'is-end': row.isExpired,
638
+ }"
639
+ >
640
+ <div v-if="row.is_delete">{{ t('meeting.meetingCancelled') }}</div>
641
+ <div class="title-wrapper">
642
+ <div class="title-text">{{ row.topic }}</div>
643
+ </div>
644
+ <div class="tag-wrapper" v-if="row.is_cycle">
645
+ <OTag color="primary" variant="outline">{{ t('meeting.cycle') }}</OTag>
646
+ </div>
647
+ </div>
648
+ <div class="meeting-info">
649
+ <span>{{ row.dateRange }}</span>
650
+ <ODivider direction="v" />
651
+ <span>{{ t('meeting.sigs') }}: {{ row.group_name }}</span>
652
+ </div>
653
+ </div>
654
+ </div>
655
+ <div class="item-header-right" v-if="!row.is_delete">
656
+ <OLink
657
+ v-if="!row.isExpired"
658
+ target="_blank"
659
+ :href="row.join_url"
660
+ rel="noopener noreferrer"
661
+ >
662
+ {{ t('meeting.joinMeeting') }}
663
+ <template #suffix>
664
+ <OIcon>
665
+ <OIconChevronRight></OIconChevronRight>
666
+ </OIcon>
667
+ </template>
668
+ </OLink>
669
+ <template v-else>
670
+ <OLink target="_blank" v-if="row.etherpad" :href="row.etherpad">
671
+ {{ t('meeting.meetingSummary') }}
672
+ <template #suffix>
673
+ <OIcon>
674
+ <OIconChevronRight></OIconChevronRight>
675
+ </OIcon>
676
+ </template>
677
+ </OLink>
678
+ <OLink
679
+ target="_blank"
680
+ :href="`/${locale}/video/${row.group_name}/${row.mid}/${row.date}`"
681
+ v-if="row.hasObsData">
682
+ {{ t('meeting.viewRecord') }}
683
+ <template #suffix>
684
+ <OIcon>
685
+ <OIconChevronRight></OIconChevronRight>
686
+ </OIcon>
687
+ </template>
688
+ </OLink>
689
+ </template>
690
+ </div>
691
+ <OIcon @click.stop="() => copyInfo(rowIdx)" class="copy-icon">
692
+ <IconCopy />
693
+ </OIcon>
694
+ </template>
695
+ <div class="meeting-detail">
696
+ <OMeetingDetail
697
+ :show="expanded.includes(row.sub_id || row.id)"
698
+ :data="row"
699
+ :ref="(insRef) => getDetailRefs(insRef, row.id)"
700
+ from="my"
701
+ />
702
+ <div class="meeting-btn" v-if="!row.isExpired && !row.is_delete">
703
+ <OLink @click="handleItem(row, 'edit')">{{ t('meeting.editMeeting') }}
704
+ </OLink>
705
+ <OLink @click="handleItem(row, 'cancel')">{{ t('meeting.cancelMeeting') }}
706
+ </OLink>
707
+ </div>
708
+ </div>
709
+ </OCollapseItem>
710
+ <div class="height-placeholder"></div>
711
+ </div>
712
+ <template v-if="idx === groupList.length - 1">
713
+ <div class="load-text" v-if="bottomReached">{{ t('common.loading') }}</div>
714
+ <div class="list-month-change next-month" @click="changeMonth('next-month')">
715
+ <OIcon>
716
+ <OIconArrowRight />
717
+ </OIcon>
718
+ <span>{{ t('meeting.nextMonth') }}</span>
719
+ </div>
720
+ </template>
721
+ </template>
722
+ </OCollapse>
723
+ </div>
724
+ </OScroller>
725
+ <slot name="empty" v-else-if="!tableLoading"></slot>
726
+ </div>
727
+ <ODialog
728
+ v-model:visible="handleDialogVisible"
729
+ main-class="handle-dialog"
730
+ @close="cancelHandleItem"
731
+ :actions="handleActions"
732
+ >
733
+ <template #header>
734
+ {{
735
+ t('meeting.meetingHandleText', [handleDialogType === 'edit' ? t('meeting.edit') : t('meeting.cancel2')])
736
+ }}
737
+ </template>
738
+ <ORadioGroup v-model="handleType">
739
+ <ORadio v-for="t in handleOptions" :value="t.value" :key="t.value">{{ t.label }}</ORadio>
740
+ </ORadioGroup>
741
+ </ODialog>
742
+ <ODialog v-model:visible="cancelVisible" main-class="cancel-dialog" :actions="cancelActions">
743
+ <template #header>{{ t('meeting.confirmCancel') }}</template>
744
+ <div class="dialog-content">{{ t('meeting.confirmCancelDesc', [currentRow?.topic]) }}</div>
745
+ </ODialog>
746
+ </div>
747
+ </div>
748
+ </template>
749
+
750
+ <style lang="scss">
751
+ .o-my-meeting-calendar {
752
+
753
+ .card-content-wrapper {
754
+ height: 100%;
755
+ @include respond-to('phone') {
756
+ padding-top: 0;
757
+ padding-left: 0;
758
+ padding-right: 0;
759
+ }
760
+
761
+ &::before {
762
+ content: '';
763
+ position: absolute;
764
+ left: 0;
765
+ right: 0;
766
+ bottom: 0;
767
+ height: 32px;
768
+ z-index: 11;
769
+ background: linear-gradient(180deg, rgba(var(--o-gray-1), 0), rgba(var(--o-gray-1), 0.3) 25%, rgba(var(--o-gray-1), 1) 100%,);
770
+ @include respond-to('phone') {
771
+ display: none;
772
+ }
773
+ }
774
+
775
+ @include respond-to('phone') {
776
+ background-color: transparent;
777
+ }
778
+
779
+ .content-wrapper {
780
+ @include respond-to('<=pad_v') {
781
+ padding-top: 0;
782
+ }
783
+ }
784
+ }
785
+
786
+ .header {
787
+ display: flex;
788
+ align-items: center;
789
+ justify-content: space-between;
790
+
791
+ .title {
792
+ font-weight: 500;
793
+ color: var(--o-color-info1);
794
+ @include h2;
795
+ }
796
+
797
+ .desc {
798
+ margin-top: 12px;
799
+ color: var(--o-color-info2);
800
+ @include tip1;
801
+ }
802
+ }
803
+
804
+ .meeting-list {
805
+ display: flex;
806
+ flex-wrap: nowrap;
807
+ gap: var(--o-gap-4);
808
+ height: 100%;
809
+ --phone-padding-top: 0;
810
+ @include respond-to('pad_v') {
811
+ flex-direction: column;
812
+ gap: var(--o-gap-4);
813
+ }
814
+ @include respond-to('phone') {
815
+ flex-direction: column;
816
+ gap: var(--o-gap-3);
817
+ --phone-padding-top: calc(var(--o-gap-5) + var(--o-gap-3) + var(--o-gap-3));
818
+ }
819
+
820
+ .o-loading {
821
+ .o-layer-mask {
822
+ background-color: transparent;
823
+ }
824
+
825
+ .o-loading-icon {
826
+ color: var(--layer-mask);
827
+ }
828
+ }
829
+
830
+ .list-calendar-mb {
831
+ display: none;
832
+ align-items: center;
833
+ justify-content: space-between;
834
+ padding: 0 var(--grid--layout-padding);
835
+
836
+ span:first-child {
837
+ @include display2;
838
+ }
839
+
840
+ span:last-child {
841
+ display: flex;
842
+ align-items: center;
843
+ }
844
+
845
+ .o-icon {
846
+ font-size: 24px;
847
+ cursor: pointer;
848
+
849
+ &:last-child {
850
+ margin-left: 24px;
851
+ }
852
+ }
853
+
854
+ @include respond-to('phone') {
855
+ padding-top: var(--o-gap-7);
856
+ background-color: var(--o-color-fill1);
857
+ padding-bottom: var(--o-gap-4);
858
+ display: flex;
859
+ position: fixed;
860
+ height: var(--phone-padding-top);
861
+ z-index: 1;
862
+ top: var(--layout-header-height);
863
+ left: 0;
864
+ right: 0;
865
+ }
866
+ }
867
+
868
+ .list-calendar {
869
+ width: 334px;
870
+ flex-shrink: 0;
871
+ --table-bg: var(--o-color-control2-light);
872
+
873
+ .el-calendar {
874
+ min-height: 460px;
875
+ height: calc(100% - 54px);
876
+ background-color: var(--table-bg);
877
+ border-radius: var(--o-radius-xs);
878
+
879
+ .el-calendar__header {
880
+ border-bottom: 1px solid var(--o-color-control4);
881
+
882
+ & > span {
883
+ font-weight: 500;
884
+ color: var(--o-color-info1);
885
+ @include h1;
886
+ }
887
+
888
+ & > div {
889
+ display: flex;
890
+ align-items: center;
891
+ gap: var(--o-gap-5);
892
+
893
+ .o-icon {
894
+ font-size: 24px;
895
+ cursor: pointer;
896
+
897
+ &:hover {
898
+ color: var(--o-color-primary1);
899
+ }
900
+ }
901
+ }
902
+ }
903
+
904
+ .el-calendar__body {
905
+ .el-calendar-table {
906
+ tr {
907
+ background: var(--table-bg) !important;
908
+ }
909
+
910
+ th {
911
+ text-align: center;
912
+ background: var(--table-bg) !important;
913
+ border: none;
914
+ }
915
+
916
+ td {
917
+ background: var(--table-bg) !important;
918
+ border: none;
919
+ text-align: center;
920
+ transition: none;
921
+ padding: 0;
922
+
923
+ .el-calendar-day {
924
+ padding: 0;
925
+ height: fit-content;
926
+ }
927
+
928
+ div {
929
+ cursor: default !important;
930
+ }
931
+
932
+ &:hover {
933
+ .el-calendar-day {
934
+ background-color: transparent;
935
+ }
936
+ }
937
+ }
938
+
939
+ .date-cell {
940
+ height: 56px;
941
+ width: 42px;
942
+ padding: var(--o-gap-1);
943
+ position: relative;
944
+ cursor: default !important;
945
+
946
+ .date-cell-text {
947
+ font-size: 14px;
948
+ line-height: 36px;
949
+ border-radius: var(--o-radius-xs);
950
+ background-color: var(--o-color-control2-light);
951
+ }
952
+
953
+ .date-cell-text {
954
+ cursor: not-allowed !important;
955
+ }
956
+
957
+ &.clickable {
958
+ .date-cell-text {
959
+ cursor: pointer !important;
960
+ }
961
+
962
+ &:not(.is-selected) {
963
+ .date-cell-text:hover {
964
+ background-color: var(--o-color-control3-light);
965
+ }
966
+ }
967
+ }
968
+
969
+ &::after {
970
+ content: '';
971
+ position: absolute;
972
+ bottom: 2px;
973
+ left: 50%;
974
+ transform: translateX(-50%);
975
+ width: 8px;
976
+ height: 8px;
977
+ border-radius: 50%;
978
+ }
979
+
980
+ &.is-today {
981
+ .date-cell-text {
982
+ color: #000;
983
+ background-color: var(--o-color-control3-light);
984
+ }
985
+ }
986
+
987
+ &.is-selected {
988
+ .date-cell-text {
989
+ color: #fff;
990
+ background-color: var(--o-color-primary1);
991
+ }
992
+ }
993
+
994
+ &.clickable {
995
+ &::after {
996
+ background-color: var(--o-color-primary1);
997
+ }
998
+
999
+ &.expired::after {
1000
+ background-color: rgb(var(--o-mixedgray-6));
1001
+ }
1002
+
1003
+ &.all-deleted::after {
1004
+ background-color: rgb(var(--o-mixedgray-6));
1005
+ }
1006
+ }
1007
+ }
1008
+
1009
+ .is-today {
1010
+ color: inherit;
1011
+ }
1012
+ }
1013
+ }
1014
+ }
1015
+
1016
+ @include respond-to('pad_h') {
1017
+ width: 240px;
1018
+ .el-calendar {
1019
+ .el-calendar__body {
1020
+ padding-left: 12px;
1021
+ padding-right: 12px;
1022
+
1023
+ .el-calendar-table .date-cell {
1024
+ height: 40px;
1025
+ width: 28px;
1026
+
1027
+ .date-cell-text {
1028
+ line-height: 24px;
1029
+ @include tip2;
1030
+ }
1031
+ }
1032
+ }
1033
+ }
1034
+ }
1035
+ @include respond-to('pad_v') {
1036
+ width: 100%;
1037
+ }
1038
+ @include respond-to('phone') {
1039
+ display: none;
1040
+ }
1041
+ }
1042
+
1043
+ .list-wrapper {
1044
+ flex-grow: 1;
1045
+ background-color: var(--o-color-fill2);
1046
+
1047
+ &.is-empty {
1048
+ display: flex;
1049
+ align-items: center;
1050
+ justify-content: center;
1051
+ }
1052
+
1053
+ @include respond-to('phone') {
1054
+ margin-top: calc(var(--phone-padding-top) - var(--o-gap-4));
1055
+ }
1056
+
1057
+ .o-scroller {
1058
+ .o-scrollbar-rail {
1059
+ right: -16px;
1060
+ }
1061
+ }
1062
+
1063
+ .scroller-container {
1064
+ height: 100%;
1065
+ max-height: calc(var(--layout-left-height) - 4 * var(--o-gap-5) - var(--header-height) * 1px);
1066
+
1067
+ @include respond-to('phone') {
1068
+ max-height: fit-content;
1069
+ }
1070
+
1071
+ .group-item {
1072
+ padding-left: 24px;
1073
+ position: relative;
1074
+
1075
+ &.last-item {
1076
+ flex-grow: 1;
1077
+ }
1078
+
1079
+ @include respond-to('phone') {
1080
+ padding-left: var(--o-gap-2);
1081
+ }
1082
+
1083
+ .group-bar {
1084
+ position: absolute;
1085
+ left: 0;
1086
+ width: 16px;
1087
+ top: 0;
1088
+ bottom: 0;
1089
+ overflow: hidden;
1090
+
1091
+ --active-color: var(--o-color-primary1);
1092
+
1093
+ &::before {
1094
+ content: '';
1095
+ width: 2px;
1096
+ position: absolute;
1097
+ top: 0;
1098
+ bottom: 0;
1099
+ left: 50%;
1100
+ transform: translateX(-50%);
1101
+ background-color: var(--o-color-control4);
1102
+ }
1103
+
1104
+ .group-bar-dot {
1105
+ width: 16px;
1106
+ height: 26px;
1107
+ position: relative;
1108
+ @include respond-to('laptop') {
1109
+ height: 24px;
1110
+ }
1111
+ @include respond-to('pad_h') {
1112
+ height: 22px;
1113
+ }
1114
+ @include respond-to('<=pad_v') {
1115
+ height: 22px;
1116
+ }
1117
+
1118
+ &::before,
1119
+ &::after {
1120
+ content: '';
1121
+ border-radius: 50%;
1122
+ position: absolute;
1123
+ top: 50%;
1124
+ left: 50%;
1125
+ transform: translateY(-50%) translateX(-50%);
1126
+ }
1127
+
1128
+ &::before {
1129
+ width: 16px;
1130
+ height: 16px;
1131
+ background-color: transparent;
1132
+ }
1133
+
1134
+ &::after {
1135
+ width: 8px;
1136
+ height: 8px;
1137
+ background-color: var(--active-color);
1138
+ }
1139
+ }
1140
+
1141
+ &.is-active {
1142
+ .group-bar-dot {
1143
+ &::before {
1144
+ background-color: var(--active-color);
1145
+ }
1146
+
1147
+ &::after {
1148
+ background-color: var(--o-color-fill2);
1149
+ }
1150
+ }
1151
+ }
1152
+
1153
+ &.is-end {
1154
+ --active-color: rgb(222, 222, 227);
1155
+ }
1156
+ }
1157
+
1158
+ .group-title {
1159
+ font-weight: 500;
1160
+ margin-bottom: var(--o-gap-2);
1161
+ color: var(--o-color-info1);
1162
+ @include text2;
1163
+ @include respond-to('phone') {
1164
+ padding-left: var(--o-gap-5);
1165
+ }
1166
+
1167
+ &.is-end {
1168
+ color: var(--o-color-info3);
1169
+ }
1170
+ }
1171
+ }
1172
+ }
1173
+ }
1174
+
1175
+ .list-body {
1176
+ height: 100%;
1177
+
1178
+ @include respond-to('phone') {
1179
+ height: fit-content;
1180
+ padding: var(--o-gap-4) !important;
1181
+ }
1182
+
1183
+ .list-month-change {
1184
+ flex-shrink: 0;
1185
+ display: flex;
1186
+ align-items: center;
1187
+ gap: var(--o-gap-5);
1188
+ cursor: pointer;
1189
+ --btn-color: var(--o-color-primary1);
1190
+ @include hover {
1191
+ --btn-color: var(--o-color-primary2);
1192
+ }
1193
+
1194
+ @include respond-to('phone') {
1195
+ display: none;
1196
+ }
1197
+
1198
+ &.prev-month {
1199
+ margin-bottom: var(--o-gap-6);
1200
+ }
1201
+
1202
+ &.next-month {
1203
+ margin-top: var(--o-gap-6);
1204
+ padding-bottom: 32px;
1205
+ }
1206
+
1207
+ .o-icon {
1208
+ font-size: 24px;
1209
+ color: var(--btn-color);
1210
+ }
1211
+
1212
+ span {
1213
+ color: var(--btn-color);
1214
+ @include text1;
1215
+ }
1216
+ }
1217
+
1218
+ .o-collapse {
1219
+ padding: 0;
1220
+ border-radius: 0;
1221
+ height: 100%;
1222
+ display: flex;
1223
+ flex-direction: column;
1224
+
1225
+ .o-collapse-item {
1226
+ &.last-item {
1227
+ .o-collapse-item-header {
1228
+ border-bottom: none;
1229
+ }
1230
+ }
1231
+ }
1232
+
1233
+ .o-collapse-item-expanded + .o-collapse-item-expanded {
1234
+ margin-top: var(--o-gap-4);
1235
+ }
1236
+
1237
+ .height-placeholder {
1238
+ height: 0;
1239
+ transition: margin var(--o-easing-standard) var(--o-duration-s);
1240
+ }
1241
+
1242
+ .o-collapse-item-expanded + .height-placeholder {
1243
+ height: var(--o-gap-4);
1244
+ }
1245
+
1246
+ .o-collapse-item {
1247
+ padding: var(--o-gap-4) var(--o-gap-5);
1248
+ border-top: none;
1249
+ border-radius: var(--o-radius-xs);
1250
+ transition: margin var(--o-easing-standard) var(--o-duration-s);
1251
+ --copy-display: none;
1252
+ --icon-size: 24px;
1253
+ @include respond-to('<=pad_v') {
1254
+ padding: var(--o-gap-3) var(--o-gap-4);
1255
+ }
1256
+
1257
+ &:hover {
1258
+ @include respond-to('>pad_v') {
1259
+ --copy-display: inline-flex;
1260
+ }
1261
+ }
1262
+
1263
+ &.o-collapse-item-expanded {
1264
+ @include respond-to('<=pad_v') {
1265
+ --copy-display: inline-flex;
1266
+ }
1267
+ }
1268
+
1269
+ @include respond-to('phone') {
1270
+ --icon-size: 20px;
1271
+ }
1272
+
1273
+ &.o-collapse-item-expanded {
1274
+ background-color: var(--o-color-control2-light);
1275
+ }
1276
+ }
1277
+
1278
+ .o-collapse-item-header {
1279
+ border-bottom: 1px solid var(--o-color-control4);
1280
+ padding-top: 0;
1281
+ padding-bottom: var(--o-gap-2);
1282
+ display: flex;
1283
+ align-items: center;
1284
+ gap: var(--o-gap-4);
1285
+ position: relative;
1286
+
1287
+ .o-collapse-item-icon {
1288
+ position: relative;
1289
+ top: 4px;
1290
+ flex-shrink: 0;
1291
+ @include respond-to('phone') {
1292
+ position: absolute;
1293
+ right: 0;
1294
+ width: 20px;
1295
+ height: 20px;
1296
+ font-size: 20px;
1297
+ bottom: var(--o-gap-2);
1298
+ top: revert;
1299
+ }
1300
+ }
1301
+
1302
+ .o-collapse-item-title {
1303
+ flex: 1;
1304
+ width: 0;
1305
+ display: flex;
1306
+ flex-direction: column;
1307
+ align-items: flex-start;
1308
+ justify-content: space-between;
1309
+ .item-header-left {
1310
+ display: flex;
1311
+ align-items: flex-start;
1312
+ gap: var(--o-gap-3);
1313
+ width: 100%;
1314
+ margin-bottom: var(--o-gap-2);
1315
+ @include respond-to('phone') {
1316
+ flex-grow: 1;
1317
+ width: 100%;
1318
+ align-self: stretch;
1319
+ flex-shrink: 0;
1320
+ }
1321
+ .meeting-icon {
1322
+ width: var(--icon-size);
1323
+ height: var(--icon-size);
1324
+ border-radius: 50%;
1325
+ background-color: var(--o-color-primary1);
1326
+ color: #fff;
1327
+ display: flex;
1328
+ align-items: center;
1329
+ justify-content: center;
1330
+ flex-shrink: 0;
1331
+
1332
+ .o-icon {
1333
+ svg path {
1334
+ fill: currentColor;
1335
+ }
1336
+ }
1337
+
1338
+ }
1339
+
1340
+ .header-info {
1341
+ width: calc(100% - var(--o-gap-3) - var(--icon-size));
1342
+
1343
+ .meeting-title {
1344
+ font-weight: 500;
1345
+ display: flex;
1346
+ align-items: center;
1347
+ margin-bottom: var(--o-gap-2);
1348
+ @include text2;
1349
+
1350
+ &.is-delete,
1351
+ &.is-end {
1352
+ color: var(--o-color-info3);
1353
+ }
1354
+
1355
+ .tag-wrapper {
1356
+ flex: 10;
1357
+ margin-left: var(--o-gap-2);
1358
+
1359
+ .o-tag {
1360
+ background-color: var(--o-color-control2-light);
1361
+ border: none;
1362
+ }
1363
+ }
1364
+
1365
+ .title-wrapper {
1366
+ flex: 0 1 auto;
1367
+ min-width: 0;
1368
+ max-width: 100%;
1369
+ }
1370
+
1371
+ .title-text {
1372
+ @include text-truncate(1);
1373
+ }
1374
+ }
1375
+
1376
+ .meeting-info {
1377
+ color: var(--o-color-info3);
1378
+ display: flex;
1379
+ align-items: center;
1380
+ @include tip1;
1381
+
1382
+ span:last-child {
1383
+ width: 0;
1384
+ flex: 1;
1385
+ @include text-truncate(1);
1386
+ }
1387
+ }
1388
+ }
1389
+ }
1390
+
1391
+ .item-header-right {
1392
+ display: flex;
1393
+ align-items: center;
1394
+ padding-left: calc(var(--o-gap-3) + var(--icon-size));
1395
+ gap: var(--o-gap-5);
1396
+ width: 100%;
1397
+
1398
+ .o-link {
1399
+ font-size: 14px;
1400
+ line-height: 21px;
1401
+ }
1402
+
1403
+ .o-link + .o-link {
1404
+ margin-left: var(--o-gap-section-6);
1405
+ }
1406
+
1407
+ .o-icon {
1408
+ font-size: 16px;
1409
+ }
1410
+ }
1411
+
1412
+ .copy-icon {
1413
+ position: absolute;
1414
+ top: 50%;
1415
+ transform: translateY(-50%);
1416
+ right: calc(var(--collapse-item-icon-size) + var(--o-gap-4));
1417
+ font-size: 18px;
1418
+ height: 18px;
1419
+ width: 18px;
1420
+ //display: var(--copy-display);
1421
+ @include respond-to('phone') {
1422
+ bottom: var(--o-gap-2);
1423
+ transform: revert;
1424
+ top: revert;
1425
+ right: calc(20px + var(--o-gap-2))
1426
+ }
1427
+
1428
+ &:hover {
1429
+ color: var(--o-color-primary1);
1430
+ }
1431
+
1432
+
1433
+ svg path {
1434
+ fill: currentColor;
1435
+ }
1436
+ }
1437
+ }
1438
+ }
1439
+
1440
+ .o-collapse-item-body {
1441
+ margin-bottom: 0;
1442
+ padding: var(--o-gap-4) 0 0;
1443
+
1444
+ .meeting-detail {
1445
+ padding-left: calc(var(--o-gap-3) + var(--icon-size));
1446
+
1447
+ @include respond-to('phone') {
1448
+ padding-left: 0;
1449
+ }
1450
+
1451
+ .meeting-btn {
1452
+ border-top: 1px solid var(--o-color-control4);
1453
+ margin-top: var(--o-gap-5);
1454
+ padding-top: var(--o-gap-4);
1455
+ display: flex;
1456
+ align-items: center;
1457
+ justify-content: flex-end;
1458
+ gap: var(--o-gap-5);
1459
+ }
1460
+ }
1461
+ }
1462
+
1463
+ .o-btn.o-btn-text {
1464
+ padding-left: 0 !important;
1465
+ padding-right: 0 !important;
1466
+ min-width: auto;
1467
+ }
1468
+ }
1469
+
1470
+ .load-text {
1471
+ text-align: center;
1472
+ color: var(--o-color-info3);
1473
+ @include tip1;
1474
+ }
1475
+ }
1476
+ }
1477
+
1478
+ @include in-dark {
1479
+ .group-bar.is-end {
1480
+ --active-color: rgb(65, 65, 68) !important;
1481
+ }
1482
+ .meeting-list {
1483
+
1484
+ .is-today {
1485
+ .date-cell-text {
1486
+ color: #fff !important;
1487
+ }
1488
+ }
1489
+ }
1490
+ }
1491
+ }
1492
+ </style>
1493
+
1494
+ <style lang="scss">
1495
+ .handle-dialog {
1496
+ width: 450px;
1497
+
1498
+ .o-dlg-header {
1499
+ margin-bottom: var(--o-gap-5);
1500
+ }
1501
+
1502
+ .o-dlg-body-content {
1503
+ display: flex;
1504
+ justify-content: center;
1505
+ }
1506
+
1507
+ .dialog-footer {
1508
+ display: flex;
1509
+ justify-content: center;
1510
+ margin-top: var(--o-gap-4);
1511
+ column-gap: var(--o-gap-4);
1512
+ }
1513
+ }
1514
+
1515
+ .cancel-dialog {
1516
+ .dialog-content {
1517
+ width: 384px;
1518
+ text-align: center;
1519
+ }
1520
+
1521
+ .dialog-footer {
1522
+ display: flex;
1523
+ justify-content: center;
1524
+ margin-top: var(--o-gap-4);
1525
+ column-gap: var(--o-gap-4);
1526
+ }
1527
+ }
1528
+
1529
+ [data-o-theme='dark'] .meeting-list {
1530
+ .o-collapse-item-body {
1531
+ background-color: rgb(43, 43, 47) !important;
1532
+ }
1533
+ }
1534
+ </style>