@opendesign-plus/components 0.0.1-rc.3 → 0.0.1-rc.30

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