mdm-client 1.0.3 → 1.0.4

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 (34) hide show
  1. package/package.json +1 -1
  2. package/src/App.vue +72 -67
  3. package/src/assets/image/common/layout-active16.png +0 -0
  4. package/src/assets/image/common/layout-active25.png +0 -0
  5. package/src/assets/image/common/layout-active3.png +0 -0
  6. package/src/assets/image/common/layout-active9.png +0 -0
  7. package/src/assets/image/common/layout16.png +0 -0
  8. package/src/assets/image/common/layout25.png +0 -0
  9. package/src/assets/image/common/layout3.png +0 -0
  10. package/src/assets/image/common/layout9.png +0 -0
  11. package/src/assets/image/common/mirror.png +0 -0
  12. package/src/assets/image/common/rotate_icon1.png +0 -0
  13. package/src/assets/image/common/rotate_icon2.png +0 -0
  14. package/src/assets/image/common/rotate_icon3.png +0 -0
  15. package/src/assets/image/common/rotate_icon4.png +0 -0
  16. package/src/assets/style/base.scss +5 -0
  17. package/src/components/LiveMulti/LiveMulti.vue +27 -6
  18. package/src/components/LiveMultipleMeeting/LiveMultipleMeeting.vue +1063 -98
  19. package/src/components/LiveMultipleMeeting/style/index.scss +145 -14
  20. package/src/components/LivePoint/LivePoint.vue +49 -211
  21. package/src/components/LivePointMeeting/LivePointMeeting.vue +159 -10
  22. package/src/components/LivePointMeeting/style/index.scss +35 -0
  23. package/src/components/MeetingReadyDialog/MeetingReadyDialog.vue +96 -14
  24. package/src/components/other/addressBook.vue +137 -20
  25. package/src/components/other/appointDialog.vue +1 -1
  26. package/src/components/other/customLayout.vue +368 -202
  27. package/src/components/other/layoutSwitch.vue +253 -37
  28. package/src/components/other/leadershipFocus.vue +422 -0
  29. package/src/components/other/leaveOptionDialog.vue +1 -1
  30. package/src/components/other/moreOptionDialog.vue +17 -1
  31. package/src/components/other/selectDialog.vue +1 -1
  32. package/src/components/other/selectSpecialDialog.vue +1 -1
  33. package/src/utils/api.js +19 -0
  34. package/src/utils/livekit/live-client-esm.js +1 -1
@@ -1,3 +1,11 @@
1
+ @keyframes rotate {
2
+ from {
3
+ transform: rotate(0deg);
4
+ }
5
+ to {
6
+ transform: rotate(360deg);
7
+ }
8
+ }
1
9
  // 会议室样式
2
10
  // 通用样式
3
11
  .meeting {
@@ -7,6 +15,7 @@
7
15
  // border: 1px solid #798BA4;
8
16
  border-radius: 5px;
9
17
  margin: 5px;
18
+ overflow: hidden; // 旋转后裁剪溢出内容,避免页面出现“怪异”形态
10
19
  .p-video {
11
20
  position: absolute;
12
21
  width: 100%;
@@ -16,6 +25,33 @@
16
25
  z-index: 10;
17
26
  object-fit: contain;
18
27
  border-radius: 5px;
28
+ backface-visibility: hidden; // 避免3D旋转引发的锯齿闪烁
29
+ will-change: transform; // 提示浏览器优化旋转
30
+ }
31
+ .loadingIndicator {
32
+ position: absolute;
33
+ z-index: 20;
34
+ width: 100%;
35
+ height: 100%;
36
+ left: 0;
37
+ top: 0;
38
+ display: flex;
39
+ flex-direction: column;
40
+ align-items: center;
41
+ justify-content: center;
42
+ .loading-icon {
43
+ height: 20%;
44
+ width: auto;
45
+ border-radius: 50%;
46
+ aspect-ratio: 1/1;
47
+ background: var(--meeting-loading-icon) no-repeat center / 100% 100%;
48
+ animation: rotate 2s linear infinite;
49
+ }
50
+ .loading-text {
51
+ font-size: 14px;
52
+ line-height: 22px;
53
+ color: var(--theme-font-color);
54
+ }
19
55
  }
20
56
  .board {
21
57
  position: absolute;
@@ -120,6 +156,43 @@
120
156
  min-height: 30px;
121
157
  background: var(--more-icon) no-repeat center / 100% 100%;
122
158
  }
159
+ .rotate-icon {
160
+ visibility: hidden;
161
+ cursor: pointer;
162
+ position: absolute;
163
+ bottom: 10px;
164
+ right: 14px;
165
+ z-index: 50;
166
+ aspect-ratio: 1/1;
167
+ width: auto;
168
+ height: 5%;
169
+ min-height: 30px;
170
+ &1 {
171
+ background: var(--rotate-icon1) no-repeat center / 100% 100%;
172
+ }
173
+ &2 {
174
+ background: var(--rotate-icon2) no-repeat center / 100% 100%;
175
+ }
176
+ &3 {
177
+ background: var(--rotate-icon3) no-repeat center / 100% 100%;
178
+ }
179
+ &4 {
180
+ background: var(--rotate-icon4) no-repeat center / 100% 100%;
181
+ }
182
+ }
183
+ .bitrate-indicator {
184
+ display: none;
185
+ position: absolute;
186
+ top: 10px;
187
+ left: 50px; /* Position next to the signal icon */
188
+ z-index: 60;
189
+ padding: 4px 8px;
190
+ background-color: rgba(0, 0, 0, 0.6);
191
+ color: var(--theme-font-color, #ffffff);
192
+ font-size: 12px;
193
+ border-radius: 4px;
194
+ white-space: nowrap;
195
+ }
123
196
  }
124
197
  }
125
198
  // 宫格布局
@@ -130,11 +203,11 @@
130
203
  .participant {
131
204
  width: 100%;
132
205
  height: 98%;
133
- .p-video {
134
- object-fit: cover !important;
135
- }
206
+ // .p-video {
207
+ // object-fit: contain !important;
208
+ // }
136
209
  }
137
- .describe{
210
+ .describe {
138
211
  transform: scale(1.3);
139
212
  }
140
213
  }
@@ -148,7 +221,7 @@
148
221
  height: auto;
149
222
  aspect-ratio: 16/9;
150
223
  }
151
- .describe{
224
+ .describe {
152
225
  transform: scale(1.1);
153
226
  }
154
227
  }
@@ -163,7 +236,7 @@
163
236
  max-height: calc(50% - 10px);
164
237
  aspect-ratio: 16/9;
165
238
  }
166
- .describe{
239
+ .describe {
167
240
  transform: scale(1.1);
168
241
  }
169
242
  }
@@ -177,7 +250,7 @@
177
250
  height: auto;
178
251
  aspect-ratio: 16/9;
179
252
  }
180
- .describe{
253
+ .describe {
181
254
  transform: scale(0.9);
182
255
  }
183
256
  }
@@ -199,11 +272,10 @@
199
272
  max-height: calc(33.33% - 10px);
200
273
  aspect-ratio: 16/9;
201
274
  }
202
- .describe{
275
+ .describe {
203
276
  transform: scale(0.9);
204
277
  }
205
278
  }
206
-
207
279
  }
208
280
  .grid6 {
209
281
  display: flex;
@@ -213,10 +285,10 @@
213
285
  .participant {
214
286
  width: calc(25% - 10px);
215
287
  height: auto;
216
- max-height: calc(33.33% - 10px);
288
+ max-height: calc(25% - 10px);
217
289
  aspect-ratio: 16/9;
218
290
  }
219
- .describe{
291
+ .describe {
220
292
  transform: scale(0.75);
221
293
  }
222
294
  }
@@ -226,12 +298,12 @@
226
298
  justify-content: center;
227
299
  align-content: center;
228
300
  .participant {
229
- width: calc(25% - 10px);
301
+ width: calc(20% - 10px);
230
302
  height: auto;
231
- max-height: calc(25% - 10px);
303
+ max-height: calc(20% - 10px);
232
304
  aspect-ratio: 16/9;
233
305
  }
234
- .describe{
306
+ .describe {
235
307
  transform: scale(0.75);
236
308
  }
237
309
  }
@@ -334,4 +406,63 @@
334
406
  &-other {
335
407
  display: none;
336
408
  }
409
+ }
410
+ // 环形布局(非 scoped,适配动态创建的 DOM)
411
+ .layout-ring {
412
+ width: 100%;
413
+ height: 100%;
414
+ display: flex;
415
+ flex-direction: column;
416
+ gap: 8px;
417
+ box-sizing: border-box;
418
+
419
+ &-top {
420
+ display: grid;
421
+ grid-template-columns: repeat(4, 1fr);
422
+ grid-template-rows: repeat(4, 1fr);
423
+ gap: 5px;
424
+ align-items: center;
425
+ justify-items: center;
426
+ box-sizing: border-box;
427
+ position: relative;
428
+
429
+ .ring-slot {
430
+ width: 100%;
431
+ height: 100%;
432
+ display: flex;
433
+ align-items: center;
434
+ justify-content: center;
435
+ box-sizing: border-box;
436
+ .participant {
437
+ width: 100%;
438
+ height: 100%;
439
+ }
440
+ }
441
+
442
+ .ring-center {
443
+ grid-column: 2 / span 2;
444
+ grid-row: 2 / span 2;
445
+ width: 100%;
446
+ height: 100%;
447
+ display: flex;
448
+ align-items: center;
449
+ justify-content: center;
450
+ box-sizing: border-box;
451
+ .participant {
452
+ width: 100%;
453
+ height: 100%;
454
+ }
455
+ }
456
+ }
457
+
458
+ &-bottom {
459
+ display: grid;
460
+ grid-template-columns: repeat(4, 1fr);
461
+ grid-auto-rows: 1fr;
462
+ gap: 5px;
463
+ box-sizing: border-box;
464
+ .participant {
465
+ aspect-ratio: 16/9;
466
+ }
467
+ }
337
468
  }
@@ -1,6 +1,44 @@
1
1
  <template>
2
2
  <div class="live-point">
3
- <!-- Components will be mounted to body using custom mounting -->
3
+ <teleport to="body">
4
+ <LiveCallBoard
5
+ v-if="model"
6
+ :default-call-num="defaultCallNum"
7
+ @voiceCall="makeVoiceCall"
8
+ @videoCall="makeVideoCall"
9
+ @miniCall="makeMiniCall"
10
+ @callBoardClose="model = false"
11
+ ></LiveCallBoard>
12
+ </teleport>
13
+ <teleport to="body">
14
+ <LiveInviteReceive
15
+ v-if="isInviteReceiveShow"
16
+ :inviteData="inviteData"
17
+ @receiveBoardClose="inviteReceiveClose"
18
+ @acceptInviteCall="acceptInviteCall"
19
+ @refuseInviteCall="refuseInviteCall"
20
+ >
21
+ </LiveInviteReceive>
22
+ </teleport>
23
+ <teleport to="body">
24
+ <LivePointMeeting
25
+ v-if="isMeetingDialogShow"
26
+ :joinType="pointMeetingData.joinType"
27
+ :meetingNum="pointMeetingData.meetingNum"
28
+ :meetingType="pointMeetingData.meetingType"
29
+ :inviteName="pointMeetingData.inviteName"
30
+ :inviteType="pointMeetingData.inviteType"
31
+ :invitePhone="pointMeetingData.invitePhone"
32
+ :inviteWays="inviteWays"
33
+ :inviteUserData="inviteUserData"
34
+ :isInMeeting="isInMeeting"
35
+ @meetingDialogClose="meetingDialogClose"
36
+ @miniLinkSend="miniLinkSend"
37
+ @meetingStarted="isInMeeting = true"
38
+ @meetingEnded="isInMeeting = false"
39
+ >
40
+ </LivePointMeeting>
41
+ </teleport>
4
42
  </div>
5
43
  </template>
6
44
 
@@ -10,6 +48,7 @@ import { mittBus, ShowMessage } from "../../utils/index.js";
10
48
  import LiveCallBoard from "../LiveCallBoard/LiveCallBoard.vue";
11
49
  import LivePointMeeting from "../LivePointMeeting/LivePointMeeting.vue";
12
50
  import LiveInviteReceive from "../LiveInviteReceive/LiveInviteReceive.vue";
51
+ import Teleport from 'vue2-teleport'
13
52
 
14
53
  export default {
15
54
  name: "LivePoint",
@@ -17,6 +56,7 @@ export default {
17
56
  LiveCallBoard,
18
57
  LivePointMeeting,
19
58
  LiveInviteReceive,
59
+ Teleport
20
60
  },
21
61
  props: {
22
62
  defaultCallNum: {
@@ -52,13 +92,6 @@ export default {
52
92
  isInMeeting: false,
53
93
  liveClient: null,
54
94
  showMessage: null,
55
- // DOM mounting references
56
- callBoardInstance: null,
57
- inviteReceiveInstance: null,
58
- pointMeetingInstance: null,
59
- callBoardContainer: null,
60
- inviteReceiveContainer: null,
61
- pointMeetingContainer: null,
62
95
  };
63
96
  },
64
97
  computed: {
@@ -75,15 +108,10 @@ export default {
75
108
  this.showMessage = new ShowMessage();
76
109
  this.handleLiveClientInitSuccess();
77
110
  mittBus.on("liveClientInitSuccess", this.handleLiveClientInitSuccess);
78
-
79
- // Initialize DOM containers for body mounting
80
- this.createMountContainers();
111
+
81
112
  },
82
113
  beforeDestroy() {
83
114
  mittBus.off("liveClientInitSuccess", this.handleLiveClientInitSuccess);
84
-
85
- // Clean up mounted components
86
- this.destroyMountedComponents();
87
115
  },
88
116
  methods: {
89
117
  // 对外暴露方法, 发起PC会议
@@ -96,7 +124,7 @@ export default {
96
124
  this.isMeetingDialogShow = true;
97
125
  },
98
126
  // volte语音外呼
99
- makeVoiceCall({ inviteName, invitePhone, inviteType = 0 } = {}) {
127
+ makeVoiceCall({ inviteName, invitePhone, inviteType = 0 } = e) {
100
128
  this.pointMeetingData.joinType = "launch";
101
129
  this.pointMeetingData.meetingType = "voice";
102
130
  this.pointMeetingData.invitePhone = invitePhone;
@@ -106,7 +134,7 @@ export default {
106
134
  this.isMeetingDialogShow = true;
107
135
  },
108
136
  // volte视频外呼
109
- makeVideoCall({ inviteName, invitePhone, inviteType = 0 } = {}) {
137
+ makeVideoCall({ inviteName, invitePhone, inviteType = 0 } = e) {
110
138
  this.pointMeetingData.joinType = "launch";
111
139
  this.pointMeetingData.meetingType = "video";
112
140
  this.pointMeetingData.invitePhone = invitePhone;
@@ -116,7 +144,7 @@ export default {
116
144
  this.isMeetingDialogShow = true;
117
145
  },
118
146
  // 通过小程序邀请
119
- makeMiniCall({ inviteName, invitePhone, inviteType = 0 } = {}) {
147
+ makeMiniCall({ inviteName, invitePhone, inviteType = 0 } = e) {
120
148
  this.pointMeetingData.joinType = "launch";
121
149
  this.pointMeetingData.meetingType = "miniLink";
122
150
  this.pointMeetingData.invitePhone = invitePhone;
@@ -126,7 +154,7 @@ export default {
126
154
  this.isMeetingDialogShow = true;
127
155
  },
128
156
  inviteReceiveClose() {
129
- this.$emit("inviteReceiveClose");
157
+ this.$emit("inviteReceiveClose")
130
158
  },
131
159
  // 点击接收按钮
132
160
  acceptInviteCall(e) {
@@ -137,7 +165,7 @@ export default {
137
165
  this.pointMeetingData.joinType = "join";
138
166
  this.pointMeetingData.meetingType = e.isVoice == 1 ? "voice" : "video";
139
167
  this.pointMeetingData.meetingNum = e.roomNum;
140
- this.isMeetingDialogShow = true;
168
+ this.isMeetingDialogShow.value = true;
141
169
  this.inviteReceiveClose();
142
170
  } else {
143
171
  this.showMessage.message("error", res?.msg || "接受会议邀请失败,请重试");
@@ -170,203 +198,13 @@ export default {
170
198
  meetingDialogClose() {
171
199
  this.isMeetingDialogShow = false;
172
200
  },
173
- handleCallBoardClose() {
174
- this.model = false;
175
- },
176
- handleMeetingStarted() {
177
- this.isInMeeting = true;
178
- },
179
- handleMeetingEnded() {
180
- this.isInMeeting = false;
181
- },
182
201
  handleLiveClientInitSuccess() {
183
202
  this.liveClient = window["liveClient"];
184
- },
185
-
186
- // Create mount containers for body mounting (replacing Teleport)
187
- createMountContainers() {
188
- // CallBoard container
189
- this.callBoardContainer = document.createElement('div');
190
- this.callBoardContainer.id = 'live-call-board-container';
191
-
192
- // InviteReceive container
193
- this.inviteReceiveContainer = document.createElement('div');
194
- this.inviteReceiveContainer.id = 'live-invite-receive-container';
195
-
196
- // PointMeeting container
197
- this.pointMeetingContainer = document.createElement('div');
198
- this.pointMeetingContainer.id = 'live-point-meeting-container';
199
- },
200
-
201
- // Mount CallBoard component to body
202
- mountCallBoard() {
203
- if (!this.callBoardContainer || document.getElementById('live-call-board-container')) return;
204
-
205
- document.body.appendChild(this.callBoardContainer);
206
-
207
- const CallBoardConstructor = Vue.extend(LiveCallBoard);
208
- this.callBoardInstance = new CallBoardConstructor({
209
- propsData: {
210
- defaultCallNum: this.defaultCallNum
211
- }
212
- });
213
-
214
- this.callBoardInstance.$on('voiceCall', this.makeVoiceCall);
215
- this.callBoardInstance.$on('videoCall', this.makeVideoCall);
216
- this.callBoardInstance.$on('miniCall', this.makeMiniCall);
217
- this.callBoardInstance.$on('callBoardClose', this.handleCallBoardClose);
218
-
219
- this.callBoardInstance.$mount(this.callBoardContainer);
220
- },
221
-
222
- // Mount InviteReceive component to body
223
- mountInviteReceive() {
224
- if (!this.inviteReceiveContainer || document.getElementById('live-invite-receive-container')) return;
225
-
226
- if (!this.isInviteReceiveShow) return;
227
-
228
- document.body.appendChild(this.inviteReceiveContainer);
229
-
230
- const InviteReceiveConstructor = Vue.extend(LiveInviteReceive);
231
- this.inviteReceiveInstance = new InviteReceiveConstructor({
232
- propsData: {
233
- inviteData: this.inviteData
234
- }
235
- });
236
-
237
- this.inviteReceiveInstance.$on('receiveBoardClose', this.inviteReceiveClose);
238
- this.inviteReceiveInstance.$on('acceptInviteCall', this.acceptInviteCall);
239
- this.inviteReceiveInstance.$on('refuseInviteCall', this.refuseInviteCall);
240
-
241
- this.inviteReceiveInstance.$mount(this.inviteReceiveContainer);
242
- },
243
-
244
- // Mount PointMeeting component to body
245
- mountPointMeeting() {
246
- if (!this.pointMeetingContainer || document.getElementById('live-point-meeting-container')) return;
247
-
248
- if (!this.isMeetingDialogShow) return;
249
-
250
- document.body.appendChild(this.pointMeetingContainer);
251
-
252
- const PointMeetingConstructor = Vue.extend(LivePointMeeting);
253
- this.pointMeetingInstance = new PointMeetingConstructor({
254
- propsData: {
255
- joinType: this.pointMeetingData.joinType,
256
- meetingNum: this.pointMeetingData.meetingNum,
257
- meetingType: this.pointMeetingData.meetingType,
258
- inviteName: this.pointMeetingData.inviteName,
259
- inviteType: this.pointMeetingData.inviteType,
260
- invitePhone: this.pointMeetingData.invitePhone,
261
- inviteWays: this.inviteWays,
262
- inviteUserData: this.inviteUserData
263
- }
264
- });
265
-
266
- this.pointMeetingInstance.$on('meetingDialogClose', this.meetingDialogClose);
267
- this.pointMeetingInstance.$on('miniLinkSend', this.miniLinkSend);
268
- this.pointMeetingInstance.$on('meetingStarted', this.handleMeetingStarted);
269
- this.pointMeetingInstance.$on('meetingEnded', this.handleMeetingEnded);
270
-
271
- this.pointMeetingInstance.$mount(this.pointMeetingContainer);
272
- },
273
-
274
- // Unmount CallBoard component
275
- unmountCallBoard() {
276
- if (this.callBoardInstance) {
277
- this.callBoardInstance.$destroy();
278
- this.callBoardInstance.$el.remove();
279
- this.callBoardInstance = null;
280
- }
281
- if (this.callBoardContainer && this.callBoardContainer.parentNode) {
282
- this.callBoardContainer.parentNode.removeChild(this.callBoardContainer);
283
- }
284
- },
285
-
286
- // Unmount InviteReceive component
287
- unmountInviteReceive() {
288
- if (this.inviteReceiveInstance) {
289
- this.inviteReceiveInstance.$destroy();
290
- this.inviteReceiveInstance.$el.remove();
291
- this.inviteReceiveInstance = null;
292
- }
293
- if (this.inviteReceiveContainer && this.inviteReceiveContainer.parentNode) {
294
- this.inviteReceiveContainer.parentNode.removeChild(this.inviteReceiveContainer);
295
- }
296
- },
297
-
298
- // Unmount PointMeeting component
299
- unmountPointMeeting() {
300
- if (this.pointMeetingInstance) {
301
- this.pointMeetingInstance.$destroy();
302
- this.pointMeetingInstance.$el.remove();
303
- this.pointMeetingInstance = null;
304
- }
305
- if (this.pointMeetingContainer && this.pointMeetingContainer.parentNode) {
306
- this.pointMeetingContainer.parentNode.removeChild(this.pointMeetingContainer);
307
- }
308
- },
309
-
310
- // Clean up all mounted components
311
- destroyMountedComponents() {
312
- this.unmountCallBoard();
313
- this.unmountInviteReceive();
314
- this.unmountPointMeeting();
315
- },
203
+ }
316
204
  },
317
-
318
205
  watch: {
319
- model(newVal) {
320
- if (newVal) {
321
- this.$nextTick(() => {
322
- this.mountCallBoard();
323
- });
324
- } else {
325
- this.unmountCallBoard();
326
- }
327
- },
328
-
329
- isInviteReceiveShow(newVal) {
330
- if (newVal) {
331
- this.$nextTick(() => {
332
- this.mountInviteReceive();
333
- });
334
- } else {
335
- this.unmountInviteReceive();
336
- }
337
- },
338
-
339
- isMeetingDialogShow(newVal) {
340
- if (newVal) {
341
- this.$nextTick(() => {
342
- this.mountPointMeeting();
343
- });
344
- } else {
345
- this.unmountPointMeeting();
346
- }
347
- },
348
-
349
- inviteData: {
350
- handler(newVal) {
351
- if (this.inviteReceiveInstance) {
352
- this.inviteReceiveInstance.inviteData = newVal;
353
- }
354
- },
355
- deep: true
356
- },
357
-
358
- pointMeetingData: {
359
- handler(newVal) {
360
- if (this.pointMeetingInstance) {
361
- Object.keys(newVal).forEach(key => {
362
- this.pointMeetingInstance[key] = newVal[key];
363
- });
364
- }
365
- },
366
- deep: true
367
- }
368
206
  }
369
207
  };
370
208
  </script>
371
209
 
372
- <style lang="scss" scoped></style>
210
+ <style lang="scss" scoped></style>