@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,1041 @@
1
+ <script setup lang="ts">
2
+ import { ElDatePicker, ElInputNumber, ElTimeSelect } from 'element-plus';
3
+ import { computed, onMounted, ref, watch } from 'vue';
4
+ import {
5
+ OButton,
6
+ OForm,
7
+ OFormItem,
8
+ OIcon,
9
+ OIconTime,
10
+ OInput,
11
+ OOption,
12
+ OPopover,
13
+ ORadio,
14
+ ORadioGroup,
15
+ OSelect,
16
+ OSwitch,
17
+ OTextarea,
18
+ useMessage,
19
+ } from '@opensig/opendesign';
20
+ import IconHelp from '~icons/meeting/icon-help.svg';
21
+ import IconTip from '~icons/meeting/icon-tip.svg';
22
+ import { MeetingFormPropsT, MeetingGroupType, MeetingPostT, OptionItemT } from './types';
23
+ import dayjs from 'dayjs';
24
+ import { findLabelFromOptions, formatDateNumber, getDateNumber, getPlatformLabel } from './utils';
25
+ import {
26
+ CYCLE_TYPE_OPTIONS0,
27
+ EMAIL_REGEX,
28
+ INTERVAL_DAY,
29
+ INTERVAL_MONTH,
30
+ INTERVAL_WEEK,
31
+ INTERVAL_WEEK_OPTIONS,
32
+ } from './config';
33
+ import OMeetingCalendarSelector from './components/OMeetingCalendarSelector.vue';
34
+ import { useScreen } from '@opendesign-plus/composables';
35
+ import { useI18n } from '@/i18n';
36
+
37
+ const { t, locale } = useI18n();
38
+
39
+ const props = withDefaults(defineProps<MeetingFormPropsT>(), {
40
+ isSub: false,
41
+ isEdit: false,
42
+ showBtns: true,
43
+ groupType: MeetingGroupType.SIG,
44
+ });
45
+ const message = useMessage(null);
46
+
47
+ const cycleTypeOptions = ref(CYCLE_TYPE_OPTIONS0);
48
+
49
+ const weekOptions = ref(INTERVAL_WEEK_OPTIONS);
50
+
51
+ const intervalTypeMax = computed(() => {
52
+ return findLabelFromOptions(form.value.cycle_type, cycleTypeOptions.value, 'max');
53
+ });
54
+ const initForm = {
55
+ is_record: false,
56
+ agenda: '',
57
+ email_list: '',
58
+ platform: '',
59
+ topic: '',
60
+ group_name: '',
61
+ etherpad: '',
62
+ date: '',
63
+ date_range: [],
64
+ start: '',
65
+ end: '',
66
+ time: '',
67
+ is_cycle: false,
68
+ cycle_interval: 1,
69
+ cycle_type: INTERVAL_DAY,
70
+ cycle_point: [],
71
+ };
72
+ const form = ref<MeetingPostT>(Object.assign({}, initForm) as unknown as MeetingPostT); // 表单数据
73
+ const formRef = ref(null); // 表单实例
74
+ const loading = ref(false); // 提交状态
75
+ // 表单校验规则
76
+ const rules = computed(() => {
77
+ return {
78
+ topic: [
79
+ { required: true, message: t('meeting.enterMeetingName') },
80
+ {
81
+ validator: (value: string) => {
82
+ if (value.length > 128) {
83
+ return {
84
+ type: 'danger',
85
+ message: t('meeting.meetingNameTooLong'),
86
+ };
87
+ }
88
+ },
89
+ },
90
+ ],
91
+ agenda: [
92
+ {
93
+ validator: (value: string) => {
94
+ if (value.length > 4096) {
95
+ return {
96
+ type: 'danger',
97
+ message: t('meeting.meetingAgendaTooLong'),
98
+ };
99
+ }
100
+ },
101
+ },
102
+ ],
103
+ group_name: [{
104
+ required: true,
105
+ message: props.groupType === MeetingGroupType.GROUP ? t('meeting.selectGroup') : t('meeting.selectSig'),
106
+ }],
107
+ etherpad: [{ required: true, message: t('meeting.enterEtherpad') }],
108
+ date: [{ required: true, message: t('meeting.selectDate') }],
109
+ time: [
110
+ {
111
+ validator: (value: string) => {
112
+ const { is_cycle, cycle_type, cycle_interval, cycle_point, date, date_range } = form.value;
113
+ if (is_cycle) {
114
+ const msg = {
115
+ type: 'danger',
116
+ message: t('meeting.finishMeetingConfig'),
117
+ };
118
+ if (cycle_type === INTERVAL_DAY) {
119
+ if (!cycle_interval) return msg;
120
+ }
121
+ if (cycle_type === INTERVAL_WEEK) {
122
+ if (!cycle_interval || !cycle_point?.length) return msg;
123
+ }
124
+ if (cycle_type === INTERVAL_MONTH) {
125
+ if (!cycle_interval || !cycle_point?.length) return msg;
126
+ }
127
+ if (!date_range?.length) {
128
+ return {
129
+ type: 'danger',
130
+ message: t('meeting.selectMeetingDate'),
131
+ };
132
+ }
133
+ const NONE_MSG = t('meeting.invalidMeetingDuration');
134
+ let start = date_range[0];
135
+ const end = date_range[1];
136
+ if (cycle_type === INTERVAL_WEEK) {
137
+ const weeks = new Set();
138
+ while (!dayjs(start).isAfter(dayjs(end))) {
139
+ weeks.add(dayjs(start).day());
140
+ start = dayjs(start).add(1, 'day');
141
+ }
142
+ if (cycle_point.every((point) => !weeks.has(point))) {
143
+ return {
144
+ type: 'danger',
145
+ message: NONE_MSG,
146
+ };
147
+ }
148
+ }
149
+ if (cycle_type === INTERVAL_MONTH) {
150
+ const days = new Set();
151
+ while (!dayjs(start).isAfter(dayjs(end))) {
152
+ days.add(dayjs(start).date());
153
+ start = dayjs(start).add(1, 'day');
154
+ }
155
+ if (cycle_point.every((point) => !days.has(point))) {
156
+ return {
157
+ type: 'danger',
158
+ message: NONE_MSG,
159
+ };
160
+ }
161
+ }
162
+ } else {
163
+ if (!date) {
164
+ return {
165
+ type: 'danger',
166
+ message: t('meeting.selectMeetingDate'),
167
+ };
168
+ }
169
+ }
170
+ if (!value?.trim()?.length) {
171
+ return {
172
+ type: 'danger',
173
+ message: t('meeting.selectMeetingTime'),
174
+ };
175
+ }
176
+ const arr = value.split('-').map((v) => v.split(':').map(Number));
177
+ if (arr[0][0] > arr[1][0] || (arr[0][0] === arr[1][0] && arr[0][1] >= arr[1][1])) {
178
+ return {
179
+ type: 'danger',
180
+ message: t('meeting.endTimeAfterStartTime'),
181
+ };
182
+ }
183
+ if (!form.value.is_cycle && form.value.date && form.value.start) {
184
+ const start = dayjs(`${ form.value.date } ${ form.value.start }`);
185
+ if (new Date(start).getTime() < new Date().getTime()) {
186
+ return {
187
+ type: 'danger',
188
+ message: t('meeting.startTimeBeforeEndTime'),
189
+ };
190
+ }
191
+ }
192
+ },
193
+ triggers: ['blur', 'change'],
194
+ },
195
+ ],
196
+ platform: [{ required: true, message: t('meeting.selectPlatform') }],
197
+ email_list: [
198
+ {
199
+ validator: (value: string) => {
200
+ if (props.isEdit) {
201
+ return {};
202
+ }
203
+ const str = value.replaceAll(' ', '').replaceAll(',', ';') || '';
204
+ if (str.length) {
205
+ if (str.length > 1020) {
206
+ return {
207
+ type: 'danger',
208
+ message: t('meeting.emailTooLong'),
209
+ };
210
+ }
211
+ const list = str.split(';') || [];
212
+ if (list.some((v) => !EMAIL_REGEX.test(v))) {
213
+ return {
214
+ type: 'danger',
215
+ message: t('meeting.emailInvalid'),
216
+ };
217
+ }
218
+ if (list.some((v) => v.length > 50)) {
219
+ return {
220
+ type: 'danger',
221
+ message: t('meeting.singleEmailTooLong'),
222
+ };
223
+ }
224
+ if (list.length > 20) {
225
+ return {
226
+ type: 'danger',
227
+ message: t('meeting.emailCountTooLong'),
228
+ };
229
+ }
230
+ }
231
+ },
232
+ triggers: ['blur', 'change'],
233
+ },
234
+ ],
235
+ };
236
+ });
237
+
238
+ const sigOptions = ref<OptionItemT[]>([]); // sig组选项列表
239
+ const getSigOptions = async () => {
240
+ if (!props.getGroupsRequest) {
241
+ return;
242
+ }
243
+ const res = await props.getGroupsRequest();
244
+ sigOptions.value = res.map((v) => ({ label: v.group_name, value: v.group_name, ...v }));
245
+ if (props.data) {
246
+ changeSig(form.value.group_name);
247
+ }
248
+ };
249
+ // 会议平台选项列表
250
+ const typeOptions = ref<OptionItemT[]>([]);
251
+ const getPlatformOptions = async () => {
252
+ if (!props.getPlatformsRequest) {
253
+ return;
254
+ }
255
+ const res = await props.getPlatformsRequest();
256
+ typeOptions.value = res.map((v) => ({ label: getPlatformLabel(v), value: v }));
257
+ if (!props.data) {
258
+ form.value.platform = typeOptions.value[0].value;
259
+ }
260
+ };
261
+
262
+ const emits = defineEmits(['confirm', 'cancel']);
263
+ watch(
264
+ () => props.data,
265
+ (data) => {
266
+ if (data) {
267
+ const sub = data?.cycle_sub?.find((v) => v.sub_id === props.subId) || {};
268
+ const { mid, date, start, end, sub_id } = sub;
269
+ Object.assign(
270
+ form.value,
271
+ data,
272
+ props.isSub
273
+ ? {
274
+ is_cycle: false,
275
+ mid,
276
+ date,
277
+ start,
278
+ end,
279
+ sub_id,
280
+ }
281
+ : {},
282
+ );
283
+ } else {
284
+ const today = dayjs().format('YYYY-MM-DD');
285
+ const now = dayjs().format('HH:mm');
286
+
287
+ let start = '';
288
+ let end = '';
289
+ const nowNum = getDateNumber(now);
290
+ if (nowNum <= getDateNumber('08:00')) {
291
+ start = '08:00';
292
+ end = '09:00';
293
+ } else if (getDateNumber('22:15') <= nowNum) {
294
+ start = '08:00';
295
+ end = '09:00';
296
+ } else {
297
+ let [h, m] = now.split(':').map(Number);
298
+ if (m >= 45) {
299
+ h++;
300
+ m = 0;
301
+ } else {
302
+ m = (Math.floor(m / 15) + 1) * 15;
303
+ }
304
+ start = formatDateNumber(h * 60 + m).slice(3);
305
+ end = formatDateNumber(h * 60 + m + 60).slice(3);
306
+ }
307
+ const date_range = [dayjs().format('YYYY-MM-DD'), dayjs().add(1, 'month').format('YYYY-MM-DD')];
308
+
309
+ Object.assign(form.value, {
310
+ date: today,
311
+ start,
312
+ end,
313
+ time: `${ start }-${ end }`,
314
+ date_range,
315
+ });
316
+ }
317
+ },
318
+ { immediate: true, deep: true },
319
+ );
320
+ const cancel = () => {
321
+ form.value = Object.assign({}, initForm);
322
+ formRef.value.clearValidate();
323
+ formRef.value.resetFields();
324
+ emits('cancel');
325
+ };
326
+
327
+ const changeIntervalType = () => {
328
+ form.value.cycle_point = [];
329
+ form.value.cycle_interval = 1;
330
+ };
331
+
332
+ const changeIsCycle = () => {
333
+ form.value.platform = 'WELINK';
334
+ };
335
+
336
+ const { lePadV } = useScreen();
337
+ const confirm = async () => {
338
+ let type = props.isEdit ? t('meeting.editSuccess') : t('meeting.booSuccess');
339
+ try {
340
+ loading.value = true;
341
+ const valid = await formRef.value.validate();
342
+ if (valid.some((v) => !!v)) {
343
+ return;
344
+ }
345
+ const {
346
+ topic,
347
+ etherpad,
348
+ group_name,
349
+ platform,
350
+ date,
351
+ start,
352
+ end,
353
+ agenda,
354
+ is_record,
355
+ is_cycle,
356
+ date_range,
357
+ cycle_type,
358
+ cycle_interval,
359
+ cycle_point,
360
+ } =
361
+ form.value;
362
+ let params = {
363
+ topic,
364
+ etherpad,
365
+ agenda,
366
+ is_record,
367
+ group_name,
368
+ platform,
369
+ is_cycle,
370
+ } as MeetingPostT;
371
+ if (is_cycle) {
372
+ params = {
373
+ ...params,
374
+ cycle_interval,
375
+ cycle_type,
376
+ cycle_start_date: date_range?.[0] || '',
377
+ cycle_end_date: date_range?.[1] || '',
378
+ cycle_start: start,
379
+ cycle_end: end,
380
+ };
381
+ if (cycle_type !== INTERVAL_DAY) {
382
+ params = {
383
+ ...params,
384
+ cycle_point: cycle_point.join(','),
385
+ };
386
+ }
387
+ } else {
388
+ params = {
389
+ ...params,
390
+ date: date?.split(' ')[0] || '',
391
+ start,
392
+ end,
393
+ };
394
+ }
395
+ if (props.isEdit) {
396
+ if (props.isSub) {
397
+ const { mid, sub_id } = form.value;
398
+ const { date, start, end } = params;
399
+ await props?.editSubMeetingRequest(sub_id, {
400
+ mid,
401
+ date,
402
+ start,
403
+ end,
404
+ is_notify: true,
405
+ });
406
+ } else {
407
+ const { email_list, platform, group_name, etherpad, ...data } = params;
408
+ await props?.editMeetingRequest(props.data.id, {
409
+ ...data,
410
+ is_notify: true,
411
+ });
412
+ }
413
+ } else {
414
+ await props?.createMeetingRequest({
415
+ ...params,
416
+ email_list: form.value.email_list.replaceAll(' ', ''),
417
+ });
418
+ }
419
+ const msg = t('meeting.meetingHandleSuccess', [form.value.topic, type]);
420
+ message.success({
421
+ content: msg,
422
+ });
423
+
424
+ emits('confirm');
425
+ } finally {
426
+ loading.value = false;
427
+ }
428
+ };
429
+ onMounted(() => {
430
+ getSigOptions();
431
+ getPlatformOptions();
432
+ });
433
+
434
+ const changeSig = (sig) => {
435
+ const find = sigOptions.value.find((v) => v.value === sig);
436
+ if (!props.isEdit) {
437
+ form.value.etherpad = find?.etherpad || '';
438
+ form.value.email_list = find?.email_list || '';
439
+ }
440
+ };
441
+ const disabledDate = (date) => {
442
+ return date.getTime() < Date.now() - 24 * 60 * 60 * 1000;
443
+ };
444
+ const changeTime = () => {
445
+ if (form.value.start && form.value.end) {
446
+ form.value.time = `${ form.value.start }-${ form.value.end }`;
447
+ } else {
448
+ form.value.time = '';
449
+ }
450
+ };
451
+
452
+ defineExpose({
453
+ confirm,
454
+ });
455
+ </script>
456
+
457
+ <template>
458
+ <div class="o-meeting-form">
459
+ <OForm :model="form" ref="formRef" has-required :layout="lePadV ? 'v' : 'h'" class="form-wrapper">
460
+ <OFormItem :rules="rules.topic" :label="t('meeting.meetingName')" field="topic">
461
+ <OInput
462
+ :disabled="isSub"
463
+ size="large"
464
+ :placeholder="t('meeting.enterMeetingName')"
465
+ style="width: 100%"
466
+ v-model="form.topic" />
467
+ </OFormItem>
468
+ <OFormItem
469
+ :rules="rules.group_name"
470
+ :label="groupType === MeetingGroupType.GROUP ? t('meeting.meetingGroup'):t('meeting.meetingSig')"
471
+ field="group_name">
472
+ <OSelect
473
+ :disabled="isEdit"
474
+ :placeholder="groupType === MeetingGroupType.GROUP ? t('meeting.selectGroup') : t('meeting.selectSig')"
475
+ size="large"
476
+ style="width: 100%"
477
+ v-model="form.group_name"
478
+ @change="changeSig"
479
+ >
480
+ <OOption v-for="t in sigOptions" :key="t.value" :value="t.value">{{ t.label }}</OOption>
481
+ </OSelect>
482
+ </OFormItem>
483
+ <OFormItem :rules="rules.etherpad" label="Etherpad" field="etherpad" v-if="form.group_name">
484
+ <template #label>
485
+ <div class="label-wrapper">
486
+ <span>{{ t('meeting.etherpad') }}&nbsp;</span>
487
+ <OPopover>
488
+ <div class="o-meeting-form-popover-content etherpad">{{ t('meeting.etherpadDesc') }}</div>
489
+ <template #target>
490
+ <OIcon>
491
+ <IconHelp />
492
+ </OIcon>
493
+ </template>
494
+ </OPopover>
495
+ </div>
496
+ </template>
497
+ <OInput
498
+ :disabled="isEdit"
499
+ size="large"
500
+ :placeholder="t('meeting.enterEtherpad')"
501
+ style="width: 100%"
502
+ v-model="form.etherpad"
503
+ />
504
+ </OFormItem>
505
+
506
+ <OFormItem :label="t('meeting.meetingTime')" field="time" :rules="rules.time" class="repeat-row" required>
507
+ <div class="repeat-config-wrapper">
508
+ <OFormItem field="repeat" class="repeat-item" v-if="!isSub">
509
+ <ORadioGroup v-model="form.is_cycle" @change="changeIsCycle" :disabled="isEdit">
510
+ <ORadio :value="false">{{ t('meeting.nonRepeat') }}</ORadio>
511
+ <ORadio :value="true">{{ t('meeting.isRepeat') }}</ORadio>
512
+ </ORadioGroup>
513
+ </OFormItem>
514
+ <div class="repeat-config">
515
+ <template v-if="form.is_cycle">
516
+ <OFormItem :label="t('meeting.every')" class="full-width-item">
517
+ <div class="repeat-config-item">
518
+ <OFormItem v-if="form.cycle_type !== INTERVAL_MONTH">
519
+ <ElInputNumber size="large" v-model="form.cycle_interval" :min="1" :max="intervalTypeMax" />
520
+ </OFormItem>
521
+ <OFormItem>
522
+ <OSelect
523
+ size="large"
524
+ v-model="form.cycle_type"
525
+ class="interval-select"
526
+ optionWrapClass="o-meeting-form-interval-select-options"
527
+ @change="changeIntervalType"
528
+ >
529
+ <OOption v-for="o in cycleTypeOptions" :key="o.value" :value="o.value" :label="o.label" />
530
+ </OSelect>
531
+ </OFormItem>
532
+ </div>
533
+ </OFormItem>
534
+ <OFormItem
535
+ :label="t('meeting.in')"
536
+ field="cycle_point"
537
+ class="point-item"
538
+ v-if="form.cycle_type !== INTERVAL_DAY"
539
+ >
540
+ <OSelect
541
+ v-if="form.cycle_type === INTERVAL_WEEK"
542
+ size="large"
543
+ multiple
544
+ v-model="form.cycle_point"
545
+ :placeholder="t('meeting.selectRepeatDate')"
546
+ :max-tag-count="1"
547
+ >
548
+ <OOption v-for="o in weekOptions" :key="o.value" :value="o.value" :label="o.label" />
549
+ </OSelect>
550
+ <OMeetingCalendarSelector v-if="form.cycle_type === INTERVAL_MONTH" v-model="form.cycle_point" />
551
+ </OFormItem>
552
+ <OFormItem :label="t('meeting.meetingDuration')" field="date_range">
553
+ <ElDatePicker
554
+ size="large"
555
+ v-model="form.date_range"
556
+ :start-placeholder="t('meeting.startDate')"
557
+ :end-placeholder="t('meeting.endDate')"
558
+ style="width: 100%"
559
+ value-format="YYYY-MM-DD"
560
+ :disabled-date="disabledDate"
561
+ :clearable="false"
562
+ type="daterange"
563
+ popper-class="o-meeting-form-date-picker-popper"
564
+ />
565
+ </OFormItem>
566
+ </template>
567
+ <template v-else>
568
+ <OFormItem :label="t('meeting.meetingDate')" field="date">
569
+ <ElDatePicker
570
+ popper-class="o-meeting-form-date-picker-popper"
571
+ size="large"
572
+ v-model="form.date"
573
+ :placeholder="t('meeting.selectDate')"
574
+ style="width: 100%"
575
+ value-format="YYYY-MM-DD"
576
+ :disabled-date="disabledDate"
577
+ :clearable="false"
578
+ />
579
+ </OFormItem>
580
+ </template>
581
+
582
+ <OFormItem :label="t('meeting.meetingTime')">
583
+ <div class="time-select-wrapper">
584
+ <OFormItem field="start">
585
+ <ElTimeSelect
586
+ popper-class="meeting-form-time-popover"
587
+ step="00:15"
588
+ start="08:00"
589
+ end="22:45"
590
+ :placeholder="t('meeting.startTime')"
591
+ v-model="form.start"
592
+ size="large"
593
+ :clearable="false"
594
+ @change="changeTime"
595
+ />
596
+ </OFormItem>
597
+ <span>-</span>
598
+ <OFormItem field="end">
599
+ <ElTimeSelect
600
+ popper-class="meeting-form-time-popover"
601
+ step="00:15"
602
+ start="08:00"
603
+ end="22:45"
604
+ :placeholder="t('meeting.endTime')"
605
+ v-model="form.end"
606
+ size="large"
607
+ :clearable="false"
608
+ @change="changeTime"
609
+ />
610
+ </OFormItem>
611
+ <OIconTime />
612
+ </div>
613
+ </OFormItem>
614
+ </div>
615
+ </div>
616
+ </OFormItem>
617
+ <OFormItem :label="t('meeting.meetingPlatform')" field="platform" :rules="rules.platform">
618
+ <ORadioGroup v-model="form.platform" v-if="!data" :disabled="form.is_cycle">
619
+ <ORadio v-for="item in typeOptions" :key="item.value" :value="item.value">{{ item.label }}</ORadio>
620
+ </ORadioGroup>
621
+ <span v-else>{{ form.platform }}</span>
622
+ </OFormItem>
623
+ <OFormItem field="agenda" :label="t('meeting.meetingAgenda')" :rules="rules.genda">
624
+ <OTextarea
625
+ :disabled="isSub"
626
+ size="large"
627
+ :placeholder="t('meeting.enterMeetingAgenda')"
628
+ style="width: 100%"
629
+ :rows="4" v-model="form.agenda" />
630
+ </OFormItem>
631
+ <OFormItem :label="t('meeting.meetingRecord')" field="is_record" class="record-item full-width-item">
632
+ <template v-if="lePadV">
633
+ <OSwitch v-model="form.is_record" :disabled="isSub" />
634
+ </template>
635
+ <template v-else>
636
+ <div class="switch-wrapper">
637
+ <OSwitch v-model="form.is_record" :disabled="isSub" />
638
+ <div class="switch-text">
639
+ <OIcon>
640
+ <IconTip />
641
+ </OIcon>
642
+ <span>{{ t('meeting.meetingRecordDesc', [form.platform]) }}</span>
643
+ </div>
644
+ </div>
645
+ </template>
646
+
647
+ </OFormItem>
648
+ <template v-if="lePadV">
649
+ <div class="switch-wrapper">
650
+ <div class="switch-text">
651
+ <OIcon>
652
+ <IconTip />
653
+ </OIcon>
654
+ <span>{{ t('meeting.meetingRecordDesc', [form.platform]) }}</span>
655
+ </div>
656
+ </div>
657
+ </template>
658
+ <OFormItem field="email_list" :rules="rules.email_list">
659
+ <template #label>
660
+ <div class="label-wrapper">
661
+ <span>{{ t('meeting.meetingEmail') }}&nbsp;</span>
662
+ <OPopover>
663
+ <div class="o-meeting-form-popover-content">
664
+ {{ t('meeting.meetingEmailDesc') }}
665
+ <a class="link-text" :href="`/${locale}/sig`">{{ t('meeting.sigGroupEmail') }}</a>
666
+ </div>
667
+ <template #target>
668
+ <OIcon>
669
+ <IconHelp />
670
+ </OIcon>
671
+ </template>
672
+ </OPopover>
673
+ </div>
674
+ </template>
675
+ <OTextarea
676
+ :disabled="isEdit"
677
+ size="large"
678
+ :placeholder="t('meeting.enterEmail')"
679
+ style="width: 100%"
680
+ :rows="4"
681
+ v-model="form.email_list" />
682
+ </OFormItem>
683
+ </OForm>
684
+ <div class="form-btns" v-if="showBtns">
685
+ <OButton color="primary" variant="solid" size="large" @click="confirm" :loading="loading">
686
+ {{ isEdit ? t('common.save') : (bookText || t('meeting.book')) }}
687
+ </OButton>
688
+ <OButton color="primary" variant="outline" size="large" @click="cancel">{{ t('common.cancel') }}</OButton>
689
+ </div>
690
+ </div>
691
+ </template>
692
+
693
+ <style lang="scss">
694
+ .o-meeting-form {
695
+ .form-wrapper {
696
+ & > .o-form-item {
697
+ max-width: 592px;
698
+ }
699
+
700
+ .repeat-row,
701
+ .full-width-item {
702
+ width: 100%;
703
+ }
704
+ }
705
+
706
+ .o-form {
707
+ --o-input-color: var(--o-color-info2);
708
+ --o-placeholder-color: var(--o-color-info4);
709
+
710
+
711
+ &.o-form-layout-v {
712
+ --form-item-gap: var(--o-gap-3);
713
+
714
+ .o-form-item-label {
715
+ margin-bottom: var(--o-gap-2);
716
+ }
717
+
718
+ .o-form-item-main {
719
+ margin-left: 0;
720
+ }
721
+ }
722
+
723
+ .o-textarea {
724
+ --_box-radius: var(--o-radius-xs);
725
+ }
726
+
727
+ input,
728
+ textarea {
729
+ color: var(--o-input-color);
730
+ @include text1;
731
+
732
+ &::placeholder {
733
+ color: var(--o-placeholder-color);
734
+ }
735
+ }
736
+
737
+ .o-select {
738
+ --select-bd-color: var(--o-color-control1);
739
+ --select-bd-color-hover: var(--o-color-primary2);
740
+ --select-bd-color-focus: var(--o-color-primary3);
741
+ --select-bd-color-disabled: var(--o-color-control4);
742
+ }
743
+
744
+ .o-form-item-label {
745
+ flex: 0 0 100px;
746
+ height: var(--o-control_size-l);
747
+ display: flex;
748
+ align-items: center;
749
+ --form-label-gap-top: 0;
750
+ @include respond-to('<=pad_v') {
751
+ height: fit-content;
752
+ }
753
+ }
754
+
755
+ .o-form-item-main {
756
+ margin-left: var(--o-gap-3);
757
+ }
758
+
759
+ .record-item {
760
+ @include respond-to('<=pad_v') {
761
+ display: flex;
762
+ align-items: center;
763
+ justify-content: space-between;
764
+ --form-item-gap: var(--o-gap-2);
765
+ }
766
+
767
+ .o-form-item-label {
768
+ margin: 0;
769
+ align-items: flex-start;
770
+ }
771
+
772
+ .o-form-item-main {
773
+ @include respond-to('<=pad_v') {
774
+ flex-grow: 0;
775
+ }
776
+ }
777
+ }
778
+
779
+ .switch-wrapper {
780
+ display: flex;
781
+ align-items: flex-start;
782
+ column-gap: var(--o-gap-4);
783
+ row-gap: var(--o-gap-2);
784
+
785
+ @include respond-to('<=pad_v') {
786
+ margin-bottom: var(--o-gap-3);
787
+ flex-direction: column;
788
+ align-items: flex-start;
789
+ }
790
+
791
+ .switch-text {
792
+ display: flex;
793
+ align-items: flex-start;
794
+ column-gap: var(--o-gap-1);
795
+ color: var(--o-color-info3);
796
+ @include tip1;
797
+
798
+ .o-icon {
799
+ font-size: 16px;
800
+ position: relative;
801
+ top: 2px;
802
+ }
803
+ }
804
+ }
805
+
806
+ input::placeholder {
807
+ @include text1;
808
+ }
809
+
810
+ .label-wrapper {
811
+ display: flex;
812
+ align-items: center;
813
+
814
+ .o-svg-icon {
815
+ font-size: 1.5em;
816
+ }
817
+ }
818
+ }
819
+
820
+ .form-btns {
821
+ margin-top: var(--o-gap-5);
822
+ display: flex;
823
+ align-items: center;
824
+
825
+ .o-btn {
826
+ height: 40px !important;
827
+ font-size: 16px !important;
828
+ line-height: 24px !important;
829
+ border-radius: 20px !important;
830
+ --btn-min-width: 90px;
831
+ }
832
+ }
833
+
834
+ .time-select-wrapper {
835
+ width: 100%;
836
+ display: flex;
837
+ align-items: center;
838
+ border: 1px solid var(--o-color-control1);
839
+ border-radius: var(--o-radius-xs);
840
+ padding: 0 15px;
841
+ background-color: var(--o-color-fill2);
842
+
843
+ & > span {
844
+ padding: 0 var(--o-gap-2);
845
+ }
846
+
847
+ &:hover {
848
+ border-color: var(--o-color-primary2);
849
+ }
850
+
851
+ @include respond-to('phone') {
852
+ background-color: var(--o-color-fill2);
853
+ }
854
+
855
+ .o-form-item {
856
+ margin-bottom: 0;
857
+ flex-grow: 1;
858
+ --o-input-color: var(--o-color-info1);
859
+
860
+ .o-form-item-label {
861
+ display: none;
862
+ }
863
+
864
+ .el-select__wrapper {
865
+ box-shadow: none;
866
+ padding: calc((var(--o-control_size-l) - 24px) / 2) 0;
867
+ min-height: var(--o-control_size-l);
868
+ gap: 0;
869
+ }
870
+
871
+ .el-select__placeholder {
872
+ @include text1;
873
+ }
874
+
875
+ .el-select__caret,
876
+ .el-input__prefix-icon {
877
+ display: none;
878
+ }
879
+
880
+ div.o-form-item-main {
881
+ margin-left: 0;
882
+ @include respond-to('phone') {
883
+ margin-top: 0;
884
+ }
885
+ }
886
+ }
887
+
888
+ .o-svg-icon {
889
+ flex-shrink: 0;
890
+ font-size: 24px;
891
+ color: var(--o-color-info2);
892
+ }
893
+ }
894
+
895
+ @include respond-to('phone') {
896
+ width: auto;
897
+ .o-form {
898
+ .o-form-item-main {
899
+ margin-left: 0;
900
+ }
901
+ }
902
+ }
903
+
904
+ .repeat-config-wrapper {
905
+ width: 100%;
906
+
907
+ .repeat-item {
908
+ .o-form-item-label {
909
+ display: none;
910
+ }
911
+
912
+ .o-form-item-main {
913
+ margin-left: 0;
914
+ }
915
+
916
+ @include respond-to('pad_v') {
917
+ margin-bottom: var(--o-gap-4);
918
+ }
919
+ @include respond-to('phone') {
920
+ margin-bottom: var(--o-gap-3);
921
+ }
922
+ }
923
+
924
+ .repeat-config {
925
+ background-color: color-mix(in srgb, var(--o-color-control2-light), transparent 60%);
926
+ padding: var(--o-gap-5);
927
+ border-radius: var(--o-radius-xs);
928
+ @include respond-to('<=pad_v') {
929
+ padding: var(--o-gap-4);
930
+ }
931
+
932
+ .o-form-item {
933
+ align-items: center;
934
+ }
935
+
936
+ .o-form-item-label {
937
+ .o-form-require-symbol {
938
+ display: none;
939
+ }
940
+
941
+ flex: 0 0 4em;
942
+ }
943
+
944
+ .o-form-item-main {
945
+ margin-left: var(--o-gap-6);
946
+ @include respond-to('pad_v') {
947
+ margin-left: 0;
948
+ }
949
+ @include respond-to('phone') {
950
+ margin-left: 0;
951
+ max-width: 100%;
952
+ }
953
+ }
954
+
955
+ .full-width-item {
956
+ .o-form-item-main {
957
+ max-width: 100%;
958
+ }
959
+ }
960
+
961
+ .repeat-config-item {
962
+ width: 100%;
963
+ display: flex;
964
+ flex-wrap: nowrap;
965
+ align-items: center;
966
+ gap: var(--o-gap-4);
967
+
968
+ .o-form-item {
969
+ margin-bottom: 0;
970
+ width: calc(50% - var(--o-gap-4) / 2);
971
+
972
+ .o-form-item-label {
973
+ display: none;
974
+ }
975
+
976
+ .o-form-item-main {
977
+ margin-left: 0;
978
+ }
979
+ }
980
+ }
981
+
982
+ .point-item {
983
+ .o-select {
984
+ width: 100%;
985
+ }
986
+ }
987
+ }
988
+ }
989
+ }
990
+ </style>
991
+
992
+ <style lang="scss">
993
+ .meeting-form-time-popover, .o-meeting-form-date-picker-popper {
994
+ --el-color-primary: var(--o-color-primary1);
995
+ --el-datepicker-active-color: var(--o-color-primary1);
996
+ --el-fill-color-light: var(--o-color-control2-light);
997
+ --el-input-bg-color: var(--o-color-control-light);
998
+ --el-fill-color-blank: var(--o-color-control-light);
999
+ }
1000
+
1001
+ .o-meeting-form-popover-content {
1002
+ max-width: 256px;
1003
+ text-align: left;
1004
+ @include tip1;
1005
+
1006
+ &.etherpad {
1007
+ width: 191px;
1008
+ }
1009
+
1010
+ .link-text {
1011
+ color: var(--o-color-primary1);
1012
+ cursor: pointer;
1013
+ }
1014
+ }
1015
+
1016
+ .o-meeting-form-interval-select-options {
1017
+ .o-option-item {
1018
+ justify-content: center;
1019
+ }
1020
+ }
1021
+
1022
+ .o-meeting-form-date-picker-popper {
1023
+ @include respond-to('phone') {
1024
+ .el-picker-panel {
1025
+ width: min(var(--grid-content-width), 400px);
1026
+
1027
+ .el-picker-panel__body {
1028
+ display: flex;
1029
+ flex-direction: column;
1030
+ min-width: auto;
1031
+
1032
+ .el-picker-panel__content {
1033
+ border-right: none;
1034
+ width: 100%;
1035
+ padding: 12px 16px;
1036
+ }
1037
+ }
1038
+ }
1039
+ }
1040
+ }
1041
+ </style>