@opendesign-plus/components 0.0.1-rc.25 → 0.0.1-rc.26

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 (78) hide show
  1. package/dist/chunk-OElCookieNotice.cjs.js +1 -1
  2. package/dist/chunk-OElCookieNotice.es.js +111 -88
  3. package/dist/components/OHeaderSearch.vue.d.ts +814 -534
  4. package/dist/components/OHeaderUser.vue.d.ts +1 -1
  5. package/dist/components/OLanguageSwitcher.vue.d.ts +49 -0
  6. package/dist/components/OThemeSwitcher.vue.d.ts +1 -1
  7. package/dist/components/activity/OActivityMyCalendar.vue.d.ts +4 -4
  8. package/dist/components/activity/index.d.ts +2 -2
  9. package/dist/components/banner/OBanner.vue.d.ts +13 -0
  10. package/dist/components/banner/OBannerContent.vue.d.ts +7 -0
  11. package/dist/components/banner/index.d.ts +68 -0
  12. package/dist/components/banner/types.d.ts +31 -0
  13. package/dist/components/meeting/OMeetingCalendar.vue.d.ts +5 -3
  14. package/dist/components/meeting/OMeetingMyCalendar.vue.d.ts +4 -4
  15. package/dist/components/meeting/OMeetingPlayback.vue.d.ts +50 -1
  16. package/dist/components/meeting/components/OMeetingCalendarSelector.vue.d.ts +1 -1
  17. package/dist/components/meeting/components/OMeetingPlaybackSubtitles.vue.d.ts +16 -1
  18. package/dist/components/meeting/composables/useMeetingConfig.d.ts +1 -1
  19. package/dist/components/meeting/index.d.ts +17 -7
  20. package/dist/components/meeting/types.d.ts +1 -1
  21. package/dist/components/search/OSearchInput.vue.d.ts +1005 -0
  22. package/dist/components/search/composables/useImageSearch.d.ts +48 -0
  23. package/dist/components/search/composables/useKeywordHighlight.d.ts +2 -0
  24. package/dist/components/search/composables/useSearchHistory.d.ts +14 -0
  25. package/dist/components/search/index.d.ts +590 -0
  26. package/dist/components/search/internal/HighlightText.vue.d.ts +9 -0
  27. package/dist/components/search/internal/SearchImageInput.vue.d.ts +716 -0
  28. package/dist/components/search/internal/SearchPanel.vue.d.ts +100 -0
  29. package/dist/components/search/types.d.ts +20 -0
  30. package/dist/components.cjs.js +41 -41
  31. package/dist/components.css +1 -1
  32. package/dist/components.es.js +11383 -10083
  33. package/dist/index.d.ts +4 -2
  34. package/package.json +2 -2
  35. package/scripts/generate-components-index.js +1 -1
  36. package/src/assets/styles/element-plus.scss +16 -9
  37. package/src/assets/svg-icons/icon-delete-hover.svg +4 -0
  38. package/src/assets/svg-icons/icon-delete.svg +5 -1
  39. package/src/assets/svg-icons/icon-image-close.svg +4 -0
  40. package/src/assets/svg-icons/icon-image-upload.svg +3 -0
  41. package/src/assets/svg-icons/icon-image-zoomin.svg +3 -0
  42. package/src/assets/svg-icons/icon-refresh.svg +3 -0
  43. package/src/components/OHeaderSearch.vue +445 -418
  44. package/src/components/OLanguageSwitcher.vue +211 -0
  45. package/src/components/OPlusConfigProvider.vue +2 -2
  46. package/src/components/activity/OActivityForm.vue +7 -3
  47. package/src/components/activity/OActivityMyCalendar.vue +16 -7
  48. package/src/components/banner/OBanner.vue +288 -0
  49. package/src/components/banner/OBannerContent.vue +175 -0
  50. package/src/components/banner/index.ts +18 -0
  51. package/src/components/banner/types.ts +39 -0
  52. package/src/components/header/OHeader.vue +1 -1
  53. package/src/components/meeting/OMeetingCalendar.vue +11 -6
  54. package/src/components/meeting/OMeetingForm.vue +55 -9
  55. package/src/components/meeting/OMeetingMyCalendar.vue +17 -14
  56. package/src/components/meeting/OMeetingPlayback.vue +10 -4
  57. package/src/components/meeting/OMeetingSigCalendar.vue +1 -1
  58. package/src/components/meeting/components/OMeetingCalendarList.vue +57 -21
  59. package/src/components/meeting/components/OMeetingCalendarSelector.vue +11 -8
  60. package/src/components/meeting/components/OMeetingDetail.vue +1 -1
  61. package/src/components/meeting/components/OMeetingPlaybackSubtitles.vue +7 -4
  62. package/src/components/meeting/composables/useMeetingConfig.ts +5 -5
  63. package/src/components/meeting/types.ts +1 -1
  64. package/src/components/search/OSearchInput.vue +526 -0
  65. package/src/components/search/composables/useImageSearch.ts +157 -0
  66. package/src/components/search/composables/useKeywordHighlight.ts +30 -0
  67. package/src/components/search/composables/useSearchHistory.ts +75 -0
  68. package/src/components/search/index.ts +23 -0
  69. package/src/components/search/internal/HighlightText.vue +37 -0
  70. package/src/components/search/internal/SearchImageInput.vue +498 -0
  71. package/src/components/search/internal/SearchPanel.vue +431 -0
  72. package/src/components/search/types.ts +25 -0
  73. package/src/i18n/en.ts +13 -1
  74. package/src/i18n/zh.ts +14 -3
  75. package/src/index.ts +5 -3
  76. package/vite.config.ts +4 -0
  77. package/dist/components/OBanner.vue.d.ts +0 -11
  78. package/src/components/OBanner.vue +0 -398
@@ -0,0 +1,175 @@
1
+ <script setup lang="ts">
2
+ import { OButton, OFigure } from '@opensig/opendesign';
3
+ import ContentWrapper from '../common/ContentWrapper.vue';
4
+ import type { BannerContentProps } from './types';
5
+
6
+ defineProps<BannerContentProps>();
7
+
8
+ // 内联定义 emits 类型
9
+ const emit = defineEmits<{
10
+ (e: 'click', href: string | undefined): void;
11
+ }>();
12
+
13
+ const onClick = (href: string | undefined, hasBtn: string | undefined) => {
14
+ if (href && !hasBtn) {
15
+ window.open(href);
16
+ emit('click', href);
17
+ }
18
+ };
19
+ </script>
20
+
21
+ <template>
22
+ <OFigure
23
+ class="banner-bg"
24
+ :src="info.bg"
25
+ :class="{
26
+ 'with-sticky-bg': info.withStickyBg,
27
+ 'cursor-pointer': info.href && !info.btn,
28
+ }"
29
+ :style="{
30
+ '--pad-offset': info.pad_offset,
31
+ }"
32
+ @click="onClick(info.href, info.btn)"
33
+ >
34
+ <ContentWrapper class="banner-wrapper" :class="['banner-wrapper', contentJustifyCenter ? 'content-center' : '']">
35
+ <div class="banner-content">
36
+ <img v-if="!isPhone && info.attach" :src="info.attach" class="banner-attach" />
37
+
38
+ <!-- 标题 -->
39
+ <div
40
+ :class="{
41
+ 'banner-title': true,
42
+ 'text-dark': info.text_theme === 'dark'
43
+ }"
44
+ v-if="info.title"
45
+ >
46
+ {{ info.title }}
47
+ </div>
48
+ <!-- 副标题 -->
49
+ <div
50
+ :class="{
51
+ 'banner-subtitle': true,
52
+ 'text-dark': info.text_theme === 'dark'
53
+ }"
54
+ v-if="info.subtitle"
55
+ >
56
+ {{ info.subtitle }}
57
+ </div>
58
+ <div
59
+ class="banner-text"
60
+ v-if="info.bg_text"
61
+ :style="{
62
+ backgroundImage: `url(${info.bg_text})`,
63
+ '--pc-width': info.pc_text_width,
64
+ '--pc-height': info.pc_text_height,
65
+ '--pad-width': info.pad_text_width,
66
+ '--pad-height': info.pad_text_height,
67
+ }"
68
+ ></div>
69
+ <!-- 操作按钮 -->
70
+ <div v-if="info.btn" class="banner-opts">
71
+ <OButton
72
+ :href="info.href"
73
+ target="_blank"
74
+ variant="solid"
75
+ color="primary"
76
+ :size="size === 'tiny' ? undefined : size"
77
+ >
78
+ {{ info.btn }}
79
+ </OButton>
80
+ </div>
81
+ </div>
82
+ </ContentWrapper>
83
+ </OFigure>
84
+ </template>
85
+
86
+ <style lang="scss" scoped>
87
+ .banner-bg {
88
+ width: 100%;
89
+ height: 100%;
90
+
91
+ :deep(.o-figure-img) {
92
+ width: 100%;
93
+ height: 100%;
94
+ }
95
+
96
+ @include respond-to('pad') {
97
+ :deep(.o-figure-img) {
98
+ transition: object-position 0.3s ease;
99
+ object-position: var(--pad-offset);
100
+ }
101
+ }
102
+
103
+ @include respond-to('phone') {
104
+ --figure-radius: 4px;
105
+ }
106
+ }
107
+
108
+ .banner-wrapper {
109
+ height: 100%;
110
+
111
+ &.content-center {
112
+ display: flex;
113
+ justify-content: center;
114
+
115
+ & .banner-content {
116
+ align-items: center;
117
+ }
118
+ }
119
+ }
120
+
121
+ .banner-content {
122
+ height: 100%;
123
+ display: inline-flex;
124
+ flex-direction: column;
125
+ justify-content: center;
126
+ position: relative;
127
+ }
128
+
129
+ .banner-title {
130
+ @include display1;
131
+ color: var(--o-color-info1);
132
+ font-weight: 500;
133
+ margin-bottom: 8px;
134
+
135
+ &.text-dark {
136
+ color: var(--o-color-info1-inverse);
137
+ }
138
+
139
+ @include respond-to('<=pad_v') {
140
+ font-size: 22px;
141
+ line-height: 30px;
142
+ }
143
+ }
144
+
145
+ .banner-subtitle {
146
+ color: var(--o-color-info1);
147
+ margin-top: 8px;
148
+ font-size: 16px;
149
+
150
+ &.text-dark {
151
+ color: var(--o-color-info1-inverse);
152
+ }
153
+ }
154
+
155
+ .banner-text {
156
+ height: var(--pc-height);
157
+ width: var(--pc-width);
158
+ background-size: contain;
159
+ background-repeat: no-repeat;
160
+
161
+ @include respond-to('pad') {
162
+ height: var(--pad-height);
163
+ width: var(--pad-width);
164
+ }
165
+ }
166
+
167
+ .banner-opts {
168
+ margin-top: 24px;
169
+ --d: 20px;
170
+ }
171
+
172
+ .cursor-pointer {
173
+ cursor: pointer;
174
+ }
175
+ </style>
@@ -0,0 +1,18 @@
1
+ import _OBanner from './OBanner.vue';
2
+ import _OBannerContent from './OBannerContent.vue';
3
+ import type { App } from 'vue';
4
+
5
+
6
+ const OBanner = Object.assign(_OBanner, {
7
+ install(app: App) {
8
+ app.component('OBanner', _OBanner);
9
+ },
10
+ });
11
+ const OBannerContent = Object.assign(_OBannerContent, {
12
+ install(app: App) {
13
+ app.component('OBannerContent', _OBannerContent);
14
+ },
15
+ });
16
+
17
+ export { OBanner, OBannerContent };
18
+ export * from './types';
@@ -0,0 +1,39 @@
1
+ // Banner 项的类型定义
2
+ export interface BannerItem {
3
+ title?: string;
4
+ subtitle?: string;
5
+ bg: string;
6
+ text_theme?: 'light' | 'dark';
7
+ bg_text?: string;
8
+ pc_text_width?: string;
9
+ pc_text_height?: string;
10
+ pad_text_width?: string;
11
+ pad_text_height?: string;
12
+ attach?: string;
13
+ href?: string;
14
+ btn?: string;
15
+ withStickyBg?: boolean;
16
+ pad_offset?: string;
17
+ }
18
+
19
+ // BannerContent 组件的 Props 类型
20
+ export interface BannerContentProps {
21
+ info: BannerItem;
22
+ size?: 'large' | 'medium' | 'small' | 'tiny';
23
+ contentJustifyCenter?: boolean;
24
+ isPhone?: boolean;
25
+ isLight?: boolean;
26
+ }
27
+
28
+ // Emits 事件类型
29
+ export interface HomeBannerEmits {
30
+ (e: 'before-change', index: number): void;
31
+ (e: 'click', href: string | undefined): void;
32
+ }
33
+
34
+ export interface BannerContentEmits {
35
+ (e: 'click', href: string | undefined): void;
36
+ }
37
+
38
+ // 组件尺寸类型
39
+ export type ComponentSize = 'large' | 'medium' | 'small' | 'tiny';
@@ -35,7 +35,7 @@ const handleMouseenter = (val: any) => {
35
35
  itemVisible.value = true;
36
36
  }
37
37
  };
38
- const handleMouseleave = (val: any) => {
38
+ const handleMouseleave = () => {
39
39
  itemVisible.value = false;
40
40
  };
41
41
  const handleClick = (val: any) => {
@@ -286,6 +286,10 @@ const checkSelectedDay = (type: CalendarDataType, date: string) => {
286
286
  }
287
287
  return false;
288
288
  };
289
+
290
+ defineExpose({
291
+ refresh: getDateData,
292
+ });
289
293
  </script>
290
294
  <template>
291
295
  <div class="o-meeting-calendar">
@@ -372,7 +376,7 @@ const checkSelectedDay = (type: CalendarDataType, date: string) => {
372
376
  >
373
377
  <OOption v-for="t in groups" :value="t" :key="t">{{ t }}</OOption>
374
378
  </OSelect>
375
- <OTab v-model="tabType" :line="false">
379
+ <OTab v-model="tabType" :line="false" :max-show="9999">
376
380
  <OTabPane v-for="item in tabs" :key="item.value" :value="item.value">
377
381
  <template #nav>
378
382
  <OIcon>
@@ -822,6 +826,7 @@ const checkSelectedDay = (type: CalendarDataType, date: string) => {
822
826
 
823
827
  .o-select {
824
828
  display: none;
829
+ margin-bottom: var(--o-gap-2);
825
830
  @include respond('<=pad_v') {
826
831
  display: inline-flex;
827
832
  }
@@ -829,6 +834,7 @@ const checkSelectedDay = (type: CalendarDataType, date: string) => {
829
834
  display: flex;
830
835
  width: 100%;
831
836
  max-width: 100%;
837
+ margin-bottom: 0;
832
838
  }
833
839
  }
834
840
 
@@ -857,17 +863,16 @@ const checkSelectedDay = (type: CalendarDataType, date: string) => {
857
863
  .o-icon {
858
864
  display: none;
859
865
  }
860
- .o-tab-navs-wrap {
861
- height: 40px;
866
+ .o-tab-navs-container {
862
867
 
863
868
  .o-tab-nav {
864
- line-height: 2;
869
+ line-height: 32px;
865
870
  }
866
871
  }
867
872
  }
868
873
  @include respond('phone') {
869
- .o-tab-navs-wrap {
870
- height: auto;
874
+ .o-tab-nav {
875
+ line-height: 2;
871
876
  }
872
877
  }
873
878
 
@@ -45,7 +45,7 @@ const intervalTypeMax = computed(() => {
45
45
  return findLabelFromOptions(form.value.cycle_type, cycleTypeOptions.value, 'max');
46
46
  });
47
47
  const initForm: MeetingPostT = {
48
- is_record: false,
48
+ is_record: true,
49
49
  agenda: '',
50
50
  email_list: '',
51
51
  platform: 'WELINK',
@@ -265,15 +265,48 @@ const getPlatformOptions = async () => {
265
265
  };
266
266
 
267
267
  const emits = defineEmits(['confirm', 'cancel']);
268
+
269
+ const getPropData = () => {
270
+ if (!props.data) {
271
+ return {};
272
+ }
273
+ const {
274
+ start,
275
+ end,
276
+ is_cycle,
277
+ cycle_start_date,
278
+ cycle_end_date,
279
+ cycle_point,
280
+ cycle_interval,
281
+ cycle_start,
282
+ cycle_end,
283
+ } = props.data;
284
+ return {
285
+ ...props.data,
286
+ time: `${ start }-${ end }`,
287
+ ...(is_cycle
288
+ ? {
289
+ date_range: [cycle_start_date, cycle_end_date],
290
+ cycle_point: cycle_point?.map((v) => parseInt(v)) || [],
291
+ cycle_interval: cycle_interval || 1,
292
+ time: `${ cycle_start }-${ cycle_end }`,
293
+ start: cycle_start,
294
+ end: cycle_end,
295
+ }
296
+ : {}),
297
+ };
298
+ };
299
+
268
300
  watch(
269
301
  () => props.data,
270
302
  (data) => {
271
303
  if (data) {
272
- const sub = data?.cycle_sub?.find((v) => v.sub_id === props.subId) || {} as unknown as CycleSubItemT;
304
+ const propData = getPropData() as unknown as CycleSubItemT;
305
+ const sub = propData?.cycle_sub?.find((v) => v.sub_id === (props.subId || propData.sub_id)) || {} as unknown as CycleSubItemT;
273
306
  const { mid, date, start, end, sub_id } = sub;
274
307
  Object.assign(
275
308
  form.value,
276
- data,
309
+ propData,
277
310
  props.isSub
278
311
  ? {
279
312
  is_cycle: false,
@@ -373,6 +406,7 @@ const confirm = async () => {
373
406
  platform,
374
407
  is_cycle,
375
408
  } as MeetingPostT as unknown as any;
409
+ let flag = undefined;
376
410
  if (is_cycle) {
377
411
  params = {
378
412
  ...params,
@@ -401,7 +435,7 @@ const confirm = async () => {
401
435
  if (props.isSub) {
402
436
  const { mid, sub_id } = form.value;
403
437
  const { date, start, end } = params;
404
- await props?.editSubMeetingRequest(sub_id, {
438
+ flag = await props?.editSubMeetingRequest(sub_id, {
405
439
  mid,
406
440
  date,
407
441
  start,
@@ -416,17 +450,21 @@ const confirm = async () => {
416
450
  etherpad: _etherpad,
417
451
  ...data
418
452
  } = params;
419
- await props?.editMeetingRequest(props.data?.id as unknown as number, {
453
+ flag = await props?.editMeetingRequest(props.data?.id as unknown as number, {
420
454
  ...data,
421
455
  is_notify: true,
422
456
  });
423
457
  }
424
458
  } else {
425
- await props?.createMeetingRequest({
459
+ flag = await props?.createMeetingRequest({
426
460
  ...params,
427
461
  email_list: form.value.email_list.replaceAll(' ', ''),
428
462
  });
429
463
  }
464
+ // 如果返回的是boolean,只有true表示回调成功
465
+ if (typeof flag === 'boolean' && !flag) {
466
+ return;
467
+ }
430
468
  const msg = t('meeting.meetingHandleSuccess', [form.value.topic, type]);
431
469
  message.success({
432
470
  content: msg,
@@ -651,7 +689,11 @@ defineExpose({
651
689
  <OIcon>
652
690
  <IconTip />
653
691
  </OIcon>
654
- <span>{{ t('meeting.meetingRecordDesc', [getPlatformLabel(form.platform)]) }}</span>
692
+ <div>
693
+ <span>{{ t('meeting.meetingRecordDesc1') }}</span>
694
+ <br>
695
+ <span>{{ t('meeting.meetingRecordDesc2') }}</span>
696
+ </div>
655
697
  </div>
656
698
  </div>
657
699
  </template>
@@ -663,7 +705,11 @@ defineExpose({
663
705
  <OIcon>
664
706
  <IconTip />
665
707
  </OIcon>
666
- <span>{{ t('meeting.meetingRecordDesc', [getPlatformLabel(form.platform)]) }}</span>
708
+ <div>
709
+ <span>{{ t('meeting.meetingRecordDesc1') }}</span>
710
+ <br>
711
+ <span>{{ t('meeting.meetingRecordDesc2') }}</span>
712
+ </div>
667
713
  </div>
668
714
  </div>
669
715
  </template>
@@ -695,7 +741,7 @@ defineExpose({
695
741
  </OForm>
696
742
  <div class="form-btns" v-if="showBtns">
697
743
  <OButton color="primary" variant="solid" size="large" @click="confirm" :loading="loading">
698
- {{ isEdit ? t('common.save') : (bookText || t('meeting.book')) }}
744
+ {{ isEdit ? t('common.save') : (confirmText || t('meeting.book')) }}
699
745
  </OButton>
700
746
  <OButton color="primary" variant="outline" size="large" @click="cancel">{{ t('common.cancel') }}</OButton>
701
747
  </div>
@@ -22,7 +22,6 @@ import { computed, nextTick, onMounted, ref, onUnmounted, watch } from 'vue';
22
22
  import OMeetingDetail from './components/OMeetingDetail.vue';
23
23
  import { CalendarDataType, MeetingGroupType, MeetingItemT, PageParamsT } from './types.ts';
24
24
  import dayjs from 'dayjs';
25
- import IconMeeting from '~icons/meeting/icon-meet.svg';
26
25
  import { INTERVAL_DAY, INTERVAL_MONTH, INTERVAL_WEEK } from './config.ts';
27
26
  import { formatDate, getDateNumber } from './utils.ts';
28
27
  import { useMeetingConfig } from './composables/useMeetingConfig';
@@ -279,7 +278,10 @@ const confirmCancel = async () => {
279
278
  }
280
279
  try {
281
280
  dialogLoading.value = true;
282
- await props.deleteMeetingRequest(currentRow.value.id);
281
+ const flag = await props.deleteMeetingRequest(currentRow.value.id);
282
+ if (typeof flag === 'boolean' && !flag) {
283
+ return;
284
+ }
283
285
  cancelVisible.value = false;
284
286
  message.success({
285
287
  content: `${ t('meeting.meetingCancel', [currentRow.value.topic]) }`,
@@ -331,24 +333,25 @@ const confirmHandleItem = async () => {
331
333
  }
332
334
  if (handleDialogType.value === 'cancel') {
333
335
  try {
336
+ let flag = undefined;
334
337
  dialogLoading.value = true;
335
338
  if (handleType.value === 'single' && row.is_cycle) {
336
339
  if (!props.cancelSubMeetingRequest) {
337
340
  return;
338
341
  }
339
- await props.cancelSubMeetingRequest(row.sub_id);
340
- message.success({
341
- content: `${ t('meeting.meetingCancel', [row.topic]) }`,
342
- });
342
+ flag = await props.cancelSubMeetingRequest(row.sub_id);
343
343
  } else {
344
344
  if (!props.deleteMeetingRequest) {
345
345
  return;
346
346
  }
347
- await props.deleteMeetingRequest(row.id);
348
- message.success({
349
- content: `${ t('meeting.meetingCancel', [row.topic]) }`,
350
- });
347
+ flag = await props.deleteMeetingRequest(row.id);
348
+ }
349
+ if (typeof flag === 'boolean' && !flag) {
350
+ return;
351
351
  }
352
+ message.success({
353
+ content: `${ t('meeting.meetingCancel', [row.topic]) }`,
354
+ });
352
355
  cancelHandleItem();
353
356
  reloadAll.value = true;
354
357
  getList();
@@ -968,14 +971,13 @@ const cancelActions = computed<DialogActionT[]>(() => {
968
971
 
969
972
  .date-cell {
970
973
  height: 56px;
971
- width: 42px;
972
- padding: var(--o-gap-1);
974
+ width: 34px;
973
975
  position: relative;
974
976
  cursor: default !important;
975
977
 
976
978
  .date-cell-text {
977
979
  font-size: 14px;
978
- line-height: 36px;
980
+ line-height: 34px;
979
981
  border-radius: var(--meeting-cell-radius);
980
982
  background-color: var(--o-color-control2-light);
981
983
  border: 1px solid transparent;
@@ -1000,7 +1002,7 @@ const cancelActions = computed<DialogActionT[]>(() => {
1000
1002
  &::after {
1001
1003
  content: '';
1002
1004
  position: absolute;
1003
- bottom: 2px;
1005
+ bottom: 5px;
1004
1006
  left: 50%;
1005
1007
  transform: translateX(-50%);
1006
1008
  width: 8px;
@@ -1057,6 +1059,7 @@ const cancelActions = computed<DialogActionT[]>(() => {
1057
1059
  display: flex;
1058
1060
  align-items: center;
1059
1061
  justify-content: center;
1062
+ min-height: 600px;
1060
1063
  }
1061
1064
 
1062
1065
 
@@ -200,7 +200,7 @@ onUnmounted(() => {
200
200
  />
201
201
  </div>
202
202
  <div class="info-wrapper">
203
- <OTab v-model="tab">
203
+ <OTab v-model="tab" :max-show="9999">
204
204
  <OTabPane v-for="t in tabOptions" :key="t.value" :value="t.value" :label="t.label" />
205
205
  </OTab>
206
206
  <OScroller :class="['tab-content', `tab-content-${tab}`]" show-type="hover">
@@ -261,7 +261,12 @@ onUnmounted(() => {
261
261
  <OMeetingPlaybackSubtitles
262
262
  :captions="captionsList"
263
263
  :trackIdx="trackIdx"
264
- :instance="playbackInstance" />
264
+ :instance="playbackInstance"
265
+ >
266
+ <template #empty>
267
+ <slot name="empty"></slot>
268
+ </template>
269
+ </OMeetingPlaybackSubtitles>
265
270
  </div>
266
271
  </div>
267
272
  </template>
@@ -319,8 +324,9 @@ onUnmounted(() => {
319
324
 
320
325
  .o-tab {
321
326
  --tab-nav-justify: flex-start;
322
- .o-tab-navs {
323
- justify-content: flex-start;
327
+
328
+ .o-tab-nav-list {
329
+ width: 100%;
324
330
  }
325
331
 
326
332
  .o-tab-nav {
@@ -254,7 +254,7 @@ onMounted(() => {
254
254
  </div>
255
255
  </OPopover>
256
256
  </div>
257
- <OTab v-model="tabType" @change="selectTab" :line="false">
257
+ <OTab v-model="tabType" @change="selectTab" :line="false" :max-show="9999">
258
258
  <OTabPane v-for="item in meetingTabs.slice(0, -1)" :key="item.value" :value="item.value">
259
259
  <template #nav>
260
260
  <OIcon>