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

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 (149) 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 +578 -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 +623 -0
  12. package/dist/components/activity/types.d.ts +76 -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 +43544 -2307
  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 +465 -0
  74. package/src/components/activity/OMyActivityCalendar.vue +1342 -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 +83 -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 +1501 -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 +189 -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/OMyCalendarWrapper.vue +160 -0
  96. package/src/components/meeting/components/OSigMeetingAside.vue +197 -0
  97. package/src/components/meeting/config.ts +110 -0
  98. package/src/components/meeting/index.ts +45 -0
  99. package/src/components/meeting/types.ts +167 -0
  100. package/src/components/meeting/utils.ts +106 -0
  101. package/src/draft/Footer.vue +4 -4
  102. package/src/env.d.ts +15 -0
  103. package/src/i18n/en.ts +140 -0
  104. package/src/i18n/index.ts +18 -4
  105. package/src/i18n/zh.ts +140 -0
  106. package/src/index.ts +2 -0
  107. package/tsconfig.json +6 -2
  108. package/vite.config.ts +25 -9
  109. package/npmcachae/_cacache/content-v2/sha512/05/f7/dd881de8b21208ea65cfce17c65f29964c3897505819f81151b9798a3a6ab1a1114324192354ead15cd2c8d93f76cc9929af168066ec9cc7878d0fd87578 +0 -1
  110. package/npmcachae/_cacache/content-v2/sha512/08/b7/879230f8c2f3765920a6fd6113f4687141f1f645f96af7d95a0dee9113d1095d000fb78a5dd55c1860bbfb9b698ef6281b3874b03b2384222f61fe055fc4 +0 -1
  111. package/npmcachae/_cacache/content-v2/sha512/10/a0/a6626613c03ee052925a762e8675878efdf83dac64fafea43beb2a875f7d7c3907bb0ee30761253cd16021fd58911449594e1d3358675cbb7c48e62f220a +0 -1
  112. package/npmcachae/_cacache/content-v2/sha512/2e/a6/7cbcf55a98bbe2ca881d10e982ebf59211a0ec051eaf46eb1914df66cc35ae502ed6888850e51d8f45cd92695bac16961a642bc41508f8d5160a9ab617ab +0 -1
  113. package/npmcachae/_cacache/content-v2/sha512/92/8d/e5259c5d5cc2a625247f3c4d809192ca9482467e23683d74924a11e91a7997ad890b3d26adaf34df66d5329cc7a5fbde6713110cad05107a0b504e4fd4e8 +0 -1
  114. package/npmcachae/_cacache/content-v2/sha512/e9/45/9597d870127c35681155cec5fe52fde4e1aa0f778b996ee371e856aca850ee4c13aba74b0c3d3a89ff0ea4c9e1d33e64e53c31dc9cede0b31012695ee659 +0 -1
  115. package/npmcachae/_cacache/index-v5/16/4a/7195fcc6857299c4ab7e26014a8ae6e3c396507a2c8db3da1b74b005d574 +0 -3
  116. package/npmcachae/_cacache/index-v5/58/f0/4fe556f104b09be642895a82afa463fe560d9a0dc8f507efeef825a6905e +0 -3
  117. package/npmcachae/_cacache/index-v5/67/7d/0b50dc4c09555fc922ccf43c46994f1a0a5ff47dc0a5d5cf41437ac2d3e6 +0 -3
  118. package/npmcachae/_cacache/index-v5/8f/28/353f8839e030ab11aab3e7d9f1b8c053403e9f593cf6d4aa6ec8fdd7610d +0 -3
  119. package/npmcachae/_cacache/index-v5/97/10/0fcf20eb29d0726bd820822f6729718464b591b0e6901217c956740e943c +0 -3
  120. package/npmcachae/_cacache/index-v5/db/89/a0a4f35f593105624ab39339962d9e9b5cc65ed0c346b0732fb8dd73721d +0 -3
  121. package/npmcachae/_logs/2026-03-26T14_10_35_885Z-debug-0.log +0 -171
  122. package/npmcachae/_logs/2026-03-26T14_10_38_617Z-debug-0.log +0 -4227
  123. package/npmcachae/_logs/2026-03-26T14_10_45_316Z-debug-0.log +0 -4228
  124. package/npmcachae/_logs/2026-03-26T14_10_48_169Z-debug-0.log +0 -4228
  125. package/npmcachae/_logs/2026-03-26T14_10_51_306Z-debug-0.log +0 -464
  126. package/npmcachae/_logs/2026-03-26T14_10_53_911Z-debug-0.log +0 -464
  127. package/npmcachae/_logs/2026-03-26T14_10_56_398Z-debug-0.log +0 -464
  128. package/npmcachae/_logs/2026-03-26T14_10_58_861Z-debug-0.log +0 -464
  129. package/npmcachae/_logs/2026-03-26T14_11_01_337Z-debug-0.log +0 -464
  130. package/npmcachae/_logs/2026-03-26T14_11_03_851Z-debug-0.log +0 -464
  131. package/npmcachae/_logs/2026-03-26T14_11_08_024Z-debug-0.log +0 -464
  132. package/npmcachae/_update-notifier-last-checked +0 -0
  133. package/src/components/meeting/npmcachae/_cacache/content-v2/sha512/3e/17/1865217b9acb9f4921c53a09b5c76587cd2ab748beb2699ff6cfb1341d73b1aa56ed91ffc5ab2c9c9b3fbe626103b35d9a79ff29ff6b8cbb8d89755fe1a2 +0 -1
  134. package/src/components/meeting/npmcachae/_cacache/content-v2/sha512/a6/15/47bb7552ec9248079e839a5feecc1742d4de19524fdf041cf581701cf4760a5025106036145e279ba193b07c8fa5b07ae3d75f1b6032f0cb2219115b6167 +0 -1
  135. package/src/components/meeting/npmcachae/_cacache/content-v2/sha512/d1/4c/133b32e09c97101a27a07cc4432f94e470cff02d120d21babcea77c3f5cd436793516dc1a8e282ee1a568f923c148b1a48f4a43233462a530d35e8b41c67 +0 -1
  136. package/src/components/meeting/npmcachae/_cacache/index-v5/54/0d/a4909047714a0a7198bb9bd37020992464e47c79a791889919b84d90aab0 +0 -3
  137. package/src/components/meeting/npmcachae/_cacache/index-v5/8e/2b/21a79778e2ac08cf5663baf83cb35f951995a496007eb2e2f7fba54021a4 +0 -3
  138. package/src/components/meeting/npmcachae/_cacache/index-v5/eb/a0/b70c8132e5b57a0f1e129b8cc941796420a9c147c0baa680710083740898 +0 -2
  139. package/src/components/meeting/npmcachae/_logs/2026-03-20T07_03_54_955Z-debug-0.log +0 -277
  140. package/src/components/meeting/npmcachae/_logs/2026-03-20T07_03_57_842Z-debug-0.log +0 -277
  141. package/src/components/meeting/npmcachae/_logs/2026-03-20T07_04_00_016Z-debug-0.log +0 -277
  142. package/src/components/meeting/npmcachae/_logs/2026-03-20T07_04_02_191Z-debug-0.log +0 -277
  143. package/src/components/meeting/npmcachae/_logs/2026-03-20T07_04_04_425Z-debug-0.log +0 -277
  144. package/src/components/meeting/npmcachae/_logs/2026-03-20T07_04_06_642Z-debug-0.log +0 -277
  145. package/src/components/meeting/npmcachae/_logs/2026-03-20T07_04_08_826Z-debug-0.log +0 -277
  146. package/src/components/meeting/npmcachae/_logs/2026-03-20T07_25_36_140Z-debug-0.log +0 -433
  147. package/src/components/meeting/npmcachae/_logs/2026-03-20T07_25_39_573Z-debug-0.log +0 -433
  148. package/src/components/meeting/npmcachae/_logs/2026-03-20T07_25_42_134Z-debug-0.log +0 -212
  149. package/src/components/meeting/npmcachae/_update-notifier-last-checked +0 -0
@@ -0,0 +1,1501 @@
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
+ .header {
754
+ display: flex;
755
+ align-items: center;
756
+ justify-content: space-between;
757
+
758
+ .title {
759
+ font-weight: 500;
760
+ color: var(--o-color-info1);
761
+ @include h2;
762
+ }
763
+
764
+ .desc {
765
+ margin-top: 12px;
766
+ color: var(--o-color-info2);
767
+ @include tip1;
768
+ }
769
+ }
770
+
771
+ .meeting-list {
772
+ display: flex;
773
+ flex-wrap: nowrap;
774
+ gap: var(--o-gap-4);
775
+ height: 100%;
776
+ --phone-padding-top: 0;
777
+ @include respond-to('pad_v') {
778
+ flex-direction: column;
779
+ gap: var(--o-gap-4);
780
+ }
781
+ @include respond-to('phone') {
782
+ flex-direction: column;
783
+ gap: var(--o-gap-3);
784
+ --phone-padding-top: calc(var(--o-gap-5) + var(--o-gap-3) + var(--o-gap-3));
785
+ }
786
+
787
+ .o-loading {
788
+ .o-layer-mask {
789
+ background-color: transparent;
790
+ }
791
+
792
+ .o-loading-icon {
793
+ color: var(--layer-mask);
794
+ }
795
+ }
796
+
797
+ .list-calendar-mb {
798
+ display: none;
799
+ align-items: center;
800
+ justify-content: space-between;
801
+ padding: 0 var(--grid--layout-padding);
802
+
803
+ span:first-child {
804
+ @include display2;
805
+ }
806
+
807
+ span:last-child {
808
+ display: flex;
809
+ align-items: center;
810
+ }
811
+
812
+ .o-icon {
813
+ font-size: 24px;
814
+ cursor: pointer;
815
+
816
+ &:last-child {
817
+ margin-left: 24px;
818
+ }
819
+ }
820
+
821
+ @include respond-to('phone') {
822
+ padding-top: var(--o-gap-7);
823
+ background-color: var(--o-color-fill1);
824
+ padding-bottom: var(--o-gap-4);
825
+ display: flex;
826
+ position: fixed;
827
+ height: var(--phone-padding-top);
828
+ z-index: 1;
829
+ top: var(--layout-header-height);
830
+ left: 0;
831
+ right: 0;
832
+ }
833
+ }
834
+
835
+ .list-calendar {
836
+ width: 334px;
837
+ flex-shrink: 0;
838
+ --table-bg: var(--o-color-control2-light);
839
+
840
+ .el-calendar {
841
+ min-height: 460px;
842
+ height: calc(100% - 54px);
843
+ background-color: var(--table-bg);
844
+ border-radius: var(--o-radius-xs);
845
+
846
+ .el-calendar__header {
847
+ border-bottom: 1px solid var(--o-color-control4);
848
+
849
+ & > span {
850
+ font-weight: 500;
851
+ color: var(--o-color-info1);
852
+ @include h1;
853
+ }
854
+
855
+ & > div {
856
+ display: flex;
857
+ align-items: center;
858
+ gap: var(--o-gap-5);
859
+
860
+ .o-icon {
861
+ font-size: 24px;
862
+ cursor: pointer;
863
+
864
+ &:hover {
865
+ color: var(--o-color-primary1);
866
+ }
867
+ }
868
+ }
869
+ }
870
+
871
+ .el-calendar__body {
872
+ .el-calendar-table {
873
+ tr {
874
+ background: var(--table-bg) !important;
875
+ }
876
+
877
+ th {
878
+ text-align: center;
879
+ background: var(--table-bg) !important;
880
+ border: none;
881
+ }
882
+
883
+ td {
884
+ background: var(--table-bg) !important;
885
+ border: none;
886
+ text-align: center;
887
+ transition: none;
888
+ padding: 0;
889
+
890
+ .el-calendar-day {
891
+ padding: 0;
892
+ height: fit-content;
893
+ }
894
+
895
+ div {
896
+ cursor: default !important;
897
+ }
898
+
899
+ &:hover {
900
+ .el-calendar-day {
901
+ background-color: transparent;
902
+ }
903
+ }
904
+ }
905
+
906
+ .date-cell {
907
+ height: 56px;
908
+ width: 42px;
909
+ padding: var(--o-gap-1);
910
+ position: relative;
911
+ cursor: default !important;
912
+
913
+ .date-cell-text {
914
+ font-size: 14px;
915
+ line-height: 36px;
916
+ border-radius: var(--o-radius-xs);
917
+ background-color: var(--o-color-control2-light);
918
+ }
919
+
920
+ .date-cell-text {
921
+ cursor: not-allowed !important;
922
+ }
923
+
924
+ &.clickable {
925
+ .date-cell-text {
926
+ cursor: pointer !important;
927
+ }
928
+
929
+ &:not(.is-selected) {
930
+ .date-cell-text:hover {
931
+ background-color: var(--o-color-control3-light);
932
+ }
933
+ }
934
+ }
935
+
936
+ &::after {
937
+ content: '';
938
+ position: absolute;
939
+ bottom: 2px;
940
+ left: 50%;
941
+ transform: translateX(-50%);
942
+ width: 8px;
943
+ height: 8px;
944
+ border-radius: 50%;
945
+ }
946
+
947
+ &.is-today {
948
+ .date-cell-text {
949
+ color: #000;
950
+ background-color: var(--o-color-control3-light);
951
+ }
952
+ }
953
+
954
+ &.is-selected {
955
+ .date-cell-text {
956
+ color: #fff;
957
+ background-color: var(--o-color-primary1);
958
+ }
959
+ }
960
+
961
+ &.clickable {
962
+ &::after {
963
+ background-color: var(--o-color-primary1);
964
+ }
965
+
966
+ &.expired::after {
967
+ background-color: rgb(var(--o-mixedgray-6));
968
+ }
969
+
970
+ &.all-deleted::after {
971
+ background-color: rgb(var(--o-mixedgray-6));
972
+ }
973
+ }
974
+ }
975
+
976
+ .is-today {
977
+ color: inherit;
978
+ }
979
+ }
980
+ }
981
+ }
982
+
983
+ @include respond-to('pad_h') {
984
+ width: 240px;
985
+ .el-calendar {
986
+ .el-calendar__body {
987
+ padding-left: 12px;
988
+ padding-right: 12px;
989
+
990
+ .el-calendar-table .date-cell {
991
+ height: 40px;
992
+ width: 28px;
993
+
994
+ .date-cell-text {
995
+ line-height: 24px;
996
+ @include tip2;
997
+ }
998
+ }
999
+ }
1000
+ }
1001
+ }
1002
+ @include respond-to('pad_v') {
1003
+ width: 100%;
1004
+ }
1005
+ @include respond-to('phone') {
1006
+ display: none;
1007
+ }
1008
+ }
1009
+
1010
+ .list-wrapper {
1011
+ flex-grow: 1;
1012
+ background-color: var(--o-color-fill2);
1013
+
1014
+ &.is-empty {
1015
+ display: flex;
1016
+ align-items: center;
1017
+ justify-content: center;
1018
+ }
1019
+
1020
+ @include respond-to('phone') {
1021
+ margin-top: calc(var(--phone-padding-top) - var(--o-gap-4));
1022
+ }
1023
+
1024
+ .o-scroller {
1025
+ .o-scrollbar-rail {
1026
+ right: -16px;
1027
+ }
1028
+ }
1029
+
1030
+ .scroller-container {
1031
+ height: 100%;
1032
+ max-height: calc(var(--layout-left-height) - 4 * var(--o-gap-5) - var(--header-height) * 1px);
1033
+
1034
+ @include respond-to('phone') {
1035
+ max-height: fit-content;
1036
+ }
1037
+
1038
+ .group-item {
1039
+ padding-left: 24px;
1040
+ position: relative;
1041
+
1042
+ &.last-item {
1043
+ flex-grow: 1;
1044
+ }
1045
+
1046
+ @include respond-to('phone') {
1047
+ padding-left: var(--o-gap-2);
1048
+ }
1049
+
1050
+ .group-bar {
1051
+ position: absolute;
1052
+ left: 0;
1053
+ width: 16px;
1054
+ top: 0;
1055
+ bottom: 0;
1056
+ overflow: hidden;
1057
+
1058
+ --active-color: var(--o-color-primary1);
1059
+
1060
+ &::before {
1061
+ content: '';
1062
+ width: 2px;
1063
+ position: absolute;
1064
+ top: 0;
1065
+ bottom: 0;
1066
+ left: 50%;
1067
+ transform: translateX(-50%);
1068
+ background-color: var(--o-color-control4);
1069
+ }
1070
+
1071
+ .group-bar-dot {
1072
+ width: 16px;
1073
+ height: 26px;
1074
+ position: relative;
1075
+ @include respond-to('laptop') {
1076
+ height: 24px;
1077
+ }
1078
+ @include respond-to('pad_h') {
1079
+ height: 22px;
1080
+ }
1081
+ @include respond-to('<=pad_v') {
1082
+ height: 22px;
1083
+ }
1084
+
1085
+ &::before,
1086
+ &::after {
1087
+ content: '';
1088
+ border-radius: 50%;
1089
+ position: absolute;
1090
+ top: 50%;
1091
+ left: 50%;
1092
+ transform: translateY(-50%) translateX(-50%);
1093
+ }
1094
+
1095
+ &::before {
1096
+ width: 16px;
1097
+ height: 16px;
1098
+ background-color: transparent;
1099
+ }
1100
+
1101
+ &::after {
1102
+ width: 8px;
1103
+ height: 8px;
1104
+ background-color: var(--active-color);
1105
+ }
1106
+ }
1107
+
1108
+ &.is-active {
1109
+ .group-bar-dot {
1110
+ &::before {
1111
+ background-color: var(--active-color);
1112
+ }
1113
+
1114
+ &::after {
1115
+ background-color: var(--o-color-fill2);
1116
+ }
1117
+ }
1118
+ }
1119
+
1120
+ &.is-end {
1121
+ --active-color: rgb(222, 222, 227);
1122
+ }
1123
+ }
1124
+
1125
+ .group-title {
1126
+ font-weight: 500;
1127
+ margin-bottom: var(--o-gap-2);
1128
+ color: var(--o-color-info1);
1129
+ @include text2;
1130
+ @include respond-to('phone') {
1131
+ padding-left: var(--o-gap-5);
1132
+ }
1133
+
1134
+ &.is-end {
1135
+ color: var(--o-color-info3);
1136
+ }
1137
+ }
1138
+ }
1139
+ }
1140
+ }
1141
+
1142
+ .list-body {
1143
+ height: 100%;
1144
+
1145
+ @include respond-to('phone') {
1146
+ height: fit-content;
1147
+ padding: var(--o-gap-4) !important;
1148
+ }
1149
+
1150
+ .list-month-change {
1151
+ flex-shrink: 0;
1152
+ display: flex;
1153
+ align-items: center;
1154
+ gap: var(--o-gap-5);
1155
+ cursor: pointer;
1156
+ --btn-color: var(--o-color-primary1);
1157
+ @include hover {
1158
+ --btn-color: var(--o-color-primary2);
1159
+ }
1160
+
1161
+ @include respond-to('phone') {
1162
+ display: none;
1163
+ }
1164
+
1165
+ &.prev-month {
1166
+ margin-bottom: var(--o-gap-6);
1167
+ }
1168
+
1169
+ &.next-month {
1170
+ margin-top: var(--o-gap-6);
1171
+ padding-bottom: 32px;
1172
+ }
1173
+
1174
+ .o-icon {
1175
+ font-size: 24px;
1176
+ color: var(--btn-color);
1177
+ }
1178
+
1179
+ span {
1180
+ color: var(--btn-color);
1181
+ @include text1;
1182
+ }
1183
+ }
1184
+
1185
+ .o-collapse {
1186
+ padding: 0;
1187
+ border-radius: 0;
1188
+ height: 100%;
1189
+ display: flex;
1190
+ flex-direction: column;
1191
+
1192
+ .o-collapse-item {
1193
+ &.last-item {
1194
+ .o-collapse-item-header {
1195
+ border-bottom: none;
1196
+ }
1197
+ }
1198
+ }
1199
+
1200
+ .o-collapse-item-expanded + .o-collapse-item-expanded {
1201
+ margin-top: var(--o-gap-4);
1202
+ }
1203
+
1204
+ .height-placeholder {
1205
+ height: 0;
1206
+ transition: margin var(--o-easing-standard) var(--o-duration-s);
1207
+ }
1208
+
1209
+ .o-collapse-item-expanded + .height-placeholder {
1210
+ height: var(--o-gap-4);
1211
+ }
1212
+
1213
+ .o-collapse-item {
1214
+ padding: var(--o-gap-4) var(--o-gap-5);
1215
+ border-top: none;
1216
+ border-radius: var(--o-radius-xs);
1217
+ transition: margin var(--o-easing-standard) var(--o-duration-s);
1218
+ --copy-display: none;
1219
+ --icon-size: 24px;
1220
+ @include respond-to('<=pad_v') {
1221
+ padding: var(--o-gap-3) var(--o-gap-4);
1222
+ }
1223
+
1224
+ &:hover {
1225
+ @include respond-to('>pad_v') {
1226
+ --copy-display: inline-flex;
1227
+ }
1228
+ }
1229
+
1230
+ &.o-collapse-item-expanded {
1231
+ @include respond-to('<=pad_v') {
1232
+ --copy-display: inline-flex;
1233
+ }
1234
+ }
1235
+
1236
+ @include respond-to('phone') {
1237
+ --icon-size: 20px;
1238
+ }
1239
+
1240
+ &.o-collapse-item-expanded {
1241
+ background-color: var(--o-color-control2-light);
1242
+ }
1243
+ }
1244
+
1245
+ .o-collapse-item-header {
1246
+ border-bottom: 1px solid var(--o-color-control4);
1247
+ padding-top: 0;
1248
+ padding-bottom: var(--o-gap-2);
1249
+ display: flex;
1250
+ align-items: center;
1251
+ gap: var(--o-gap-4);
1252
+ position: relative;
1253
+
1254
+ .o-collapse-item-icon {
1255
+ position: relative;
1256
+ top: 4px;
1257
+ flex-shrink: 0;
1258
+ @include respond-to('phone') {
1259
+ position: absolute;
1260
+ right: 0;
1261
+ width: 20px;
1262
+ height: 20px;
1263
+ font-size: 20px;
1264
+ bottom: var(--o-gap-2);
1265
+ top: revert;
1266
+ }
1267
+ }
1268
+
1269
+ .o-collapse-item-title {
1270
+ flex: 1;
1271
+ width: 0;
1272
+ display: flex;
1273
+ flex-direction: column;
1274
+ align-items: flex-start;
1275
+ justify-content: space-between;
1276
+ .item-header-left {
1277
+ display: flex;
1278
+ align-items: flex-start;
1279
+ gap: var(--o-gap-3);
1280
+ width: 100%;
1281
+ margin-bottom: var(--o-gap-2);
1282
+ @include respond-to('phone') {
1283
+ flex-grow: 1;
1284
+ width: 100%;
1285
+ align-self: stretch;
1286
+ flex-shrink: 0;
1287
+ }
1288
+ .meeting-icon {
1289
+ width: var(--icon-size);
1290
+ height: var(--icon-size);
1291
+ border-radius: 50%;
1292
+ background-color: var(--o-color-primary1);
1293
+ color: #fff;
1294
+ display: flex;
1295
+ align-items: center;
1296
+ justify-content: center;
1297
+ flex-shrink: 0;
1298
+
1299
+ .o-icon {
1300
+ svg path {
1301
+ fill: currentColor;
1302
+ }
1303
+ }
1304
+
1305
+ }
1306
+
1307
+ .header-info {
1308
+ width: calc(100% - var(--o-gap-3) - var(--icon-size));
1309
+
1310
+ .meeting-title {
1311
+ font-weight: 500;
1312
+ display: flex;
1313
+ align-items: center;
1314
+ margin-bottom: var(--o-gap-2);
1315
+ @include text2;
1316
+
1317
+ &.is-delete,
1318
+ &.is-end {
1319
+ color: var(--o-color-info3);
1320
+ }
1321
+
1322
+ .tag-wrapper {
1323
+ flex: 10;
1324
+ margin-left: var(--o-gap-2);
1325
+
1326
+ .o-tag {
1327
+ background-color: var(--o-color-control2-light);
1328
+ border: none;
1329
+ }
1330
+ }
1331
+
1332
+ .title-wrapper {
1333
+ flex: 0 1 auto;
1334
+ min-width: 0;
1335
+ max-width: 100%;
1336
+ }
1337
+
1338
+ .title-text {
1339
+ @include text-truncate(1);
1340
+ }
1341
+ }
1342
+
1343
+ .meeting-info {
1344
+ color: var(--o-color-info3);
1345
+ display: flex;
1346
+ align-items: center;
1347
+ @include tip1;
1348
+
1349
+ span:last-child {
1350
+ width: 0;
1351
+ flex: 1;
1352
+ @include text-truncate(1);
1353
+ }
1354
+ }
1355
+ }
1356
+ }
1357
+
1358
+ .item-header-right {
1359
+ display: flex;
1360
+ align-items: center;
1361
+ padding-left: calc(var(--o-gap-3) + var(--icon-size));
1362
+ gap: var(--o-gap-5);
1363
+ width: 100%;
1364
+
1365
+ .o-link {
1366
+ font-size: 14px;
1367
+ line-height: 21px;
1368
+ }
1369
+
1370
+ .o-link + .o-link {
1371
+ margin-left: var(--o-gap-section-6);
1372
+ }
1373
+
1374
+ .o-icon {
1375
+ font-size: 16px;
1376
+ }
1377
+ }
1378
+
1379
+ .copy-icon {
1380
+ position: absolute;
1381
+ top: 50%;
1382
+ transform: translateY(-50%);
1383
+ right: calc(var(--collapse-item-icon-size) + var(--o-gap-4));
1384
+ font-size: 18px;
1385
+ height: 18px;
1386
+ width: 18px;
1387
+ //display: var(--copy-display);
1388
+ @include respond-to('phone') {
1389
+ bottom: var(--o-gap-2);
1390
+ transform: revert;
1391
+ top: revert;
1392
+ right: calc(20px + var(--o-gap-2))
1393
+ }
1394
+
1395
+ &:hover {
1396
+ color: var(--o-color-primary1);
1397
+ }
1398
+
1399
+
1400
+ svg path {
1401
+ fill: currentColor;
1402
+ }
1403
+ }
1404
+ }
1405
+ }
1406
+
1407
+ .o-collapse-item-body {
1408
+ margin-bottom: 0;
1409
+ padding: var(--o-gap-4) 0 0;
1410
+
1411
+ .meeting-detail {
1412
+ padding-left: calc(var(--o-gap-3) + var(--icon-size));
1413
+
1414
+ @include respond-to('phone') {
1415
+ padding-left: 0;
1416
+ }
1417
+
1418
+ .meeting-btn {
1419
+ border-top: 1px solid var(--o-color-control4);
1420
+ margin-top: var(--o-gap-5);
1421
+ padding-top: var(--o-gap-4);
1422
+ display: flex;
1423
+ align-items: center;
1424
+ justify-content: flex-end;
1425
+ gap: var(--o-gap-5);
1426
+ }
1427
+ }
1428
+ }
1429
+
1430
+ .o-btn.o-btn-text {
1431
+ padding-left: 0 !important;
1432
+ padding-right: 0 !important;
1433
+ min-width: auto;
1434
+ }
1435
+ }
1436
+
1437
+ .load-text {
1438
+ text-align: center;
1439
+ color: var(--o-color-info3);
1440
+ @include tip1;
1441
+ }
1442
+ }
1443
+ }
1444
+
1445
+ @include in-dark {
1446
+ .group-bar.is-end {
1447
+ --active-color: rgb(65, 65, 68) !important;
1448
+ }
1449
+ .meeting-list {
1450
+
1451
+ .is-today {
1452
+ .date-cell-text {
1453
+ color: #fff !important;
1454
+ }
1455
+ }
1456
+ }
1457
+ }
1458
+ }
1459
+ </style>
1460
+
1461
+ <style lang="scss">
1462
+ .handle-dialog {
1463
+ width: 450px;
1464
+
1465
+ .o-dlg-header {
1466
+ margin-bottom: var(--o-gap-5);
1467
+ }
1468
+
1469
+ .o-dlg-body-content {
1470
+ display: flex;
1471
+ justify-content: center;
1472
+ }
1473
+
1474
+ .dialog-footer {
1475
+ display: flex;
1476
+ justify-content: center;
1477
+ margin-top: var(--o-gap-4);
1478
+ column-gap: var(--o-gap-4);
1479
+ }
1480
+ }
1481
+
1482
+ .cancel-dialog {
1483
+ .dialog-content {
1484
+ width: 384px;
1485
+ text-align: center;
1486
+ }
1487
+
1488
+ .dialog-footer {
1489
+ display: flex;
1490
+ justify-content: center;
1491
+ margin-top: var(--o-gap-4);
1492
+ column-gap: var(--o-gap-4);
1493
+ }
1494
+ }
1495
+
1496
+ [data-o-theme='dark'] .meeting-list {
1497
+ .o-collapse-item-body {
1498
+ background-color: rgb(43, 43, 47) !important;
1499
+ }
1500
+ }
1501
+ </style>