@opendesign-plus/components 0.0.1-rc.10

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