Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions packages/tuikit-atomicx-vue3/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "tuikit-atomicx-vue3",
"version": "5.8.1",
"version": "5.8.2",
"type": "module",
"main": "./dist/index.js",
"module": "./dist/index.js",
Expand Down Expand Up @@ -37,11 +37,11 @@
},
"scripts": {},
"peerDependencies": {
"@tencentcloud/lite-chat": "^1.6.4",
"@tencentcloud/lite-chat": "^1.6.11",
"@tencentcloud/chat-uikit-engine-lite": "~1.0.5",
"@tencentcloud/tui-core-lite": "~1.0.0",
"@tencentcloud/tuiroom-engine-js": "~4.0.3",
"@tencentcloud/uikit-base-component-vue3": "~1.4.0",
"@tencentcloud/tui-core-lite": "~1.0.1",
"@tencentcloud/tuiroom-engine-js": "~4.0.4",
"@tencentcloud/uikit-base-component-vue3": "~1.4.1",
"vue": "^3.4.0"
},
"dependencies": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ export const resource = {
'FreeBeauty.Cancel': 'Cancel',
'FreeBeauty.Reset': 'Reset',
'FreeBeauty.Confirm': 'Confirm',
'FreeBeauty.Degree': 'Degree',
'FreeBeauty.Degree': 'Intensity',
'FreeBeauty.Compare': 'Compare',
'FreeBeauty.Beauty Effects': 'Beauty Effects',
'FreeBeauty.Close': 'Close',
'FreeBeauty.Smoother': 'Smoother',
'FreeBeauty.Beauty Effects': 'Beauty Filter',
'FreeBeauty.Close': 'Off',
'FreeBeauty.Smoother': 'Smooth',
'FreeBeauty.Whitening': 'Whitening',
'FreeBeauty.Ruddy': 'Ruddy',
'FreeBeauty.Ruddy': 'Rosy',
'FreeBeauty.Sure you want to reset the beauty effect?': 'Sure you want to reset the beauty effect?',
'FreeBeauty.All beauty parameters will revert to default after reset': 'All beauty parameters will revert to default after reset',
};
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
<div
v-if="needPlayStreamViewInfo.length > 0 && !isPictureInPicture"
class="live-core-ui"
:style="{ pointerEvents: isAnchor ? 'none' : 'auto' }"
>
<div
v-for="(item, index) in needPlayStreamViewInfo"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
<template>
<View>
<div
:class="[
styles['quick-conference-picker__button'],
(props.disabled || isLoading) && styles['disabled'],
]"
@click="handleQuickConferenceClick"
>
<slot>
<IconLoading
v-if="isLoading"
:size="props.iconSize"
:class="[styles['quick-conference-picker__icon'], styles['is-loading']]"
/>
<IconConference
v-else
:size="props.iconSize"
:class="styles['quick-conference-picker__icon']"
/>
</slot>
</div>
</View>
</template>

<script setup lang="ts">
import { ref, useCssModule } from 'vue';
import { TUICore, TUIConstants } from '@tencentcloud/tui-core-lite';
import { IconLoading, IconConference, useUIKit, TUIToast, TOAST_TYPE } from '@tencentcloud/uikit-base-component-vue3';
import { View } from '../../../baseComp/View';
import { useLoginState } from '../../../states/LoginState';
import { useMessageInputState } from '../../../states/MessageInputState';
import { useRoomParticipantState } from '../../../states/RoomParticipantState';
import { useRoomState } from '../../../states/RoomState';
import type { MessageModel } from '../../../types';

interface QuickConferencePickerProps {
label?: string;
iconSize?: number;
disabled?: boolean;
}

const props = withDefaults(defineProps<QuickConferencePickerProps>(), {
label: '',
iconSize: 20,
disabled: false,
});

const styles = useCssModule();
const { t } = useUIKit();
const { loginUserInfo } = useLoginState();
const isLoading = ref(false);

const { sendCustomMessage } = useMessageInputState();
const { currentRoom } = useRoomState();
const { localParticipant } = useRoomParticipantState();
const generateRoomId = () => String(Date.now()) + String(Math.floor(Math.random() * 1000)).padStart(3, '0');

const getQuickConferenceRoomName = () => t('ConferencePicker.Quick_Conference', {
name: loginUserInfo.value?.userName || loginUserInfo.value?.userId,
});

const getConferenceOwnerProfile = () => {
const roomOwner = currentRoom.value?.roomOwner;
const participant = localParticipant.value;
return {
faceUrl: participant?.avatarUrl || roomOwner?.avatarUrl || loginUserInfo.value?.avatarUrl || '',
nickName: participant?.userName || roomOwner?.userName || loginUserInfo.value?.userName || '',
userId: participant?.userId || roomOwner?.userId || loginUserInfo.value?.userId || '',
};
};

const createCurrentUserPayload = () => {
const ownerProfile = getConferenceOwnerProfile();
return ownerProfile.userId ? [ownerProfile] : [];
};

const startRoom = (params: { roomId: string; options: { roomName: string } }) => new Promise<void>((resolve, reject) => {
TUICore.callService({
serviceName: TUIConstants.TUIRoom.SERVICE.NAME,
method: TUIConstants.TUIRoom.SERVICE.METHOD.START_ROOM,
params,
callback: (result?: unknown) => {
if (result instanceof Error) {
reject(result);
return;
}
if ((result as any)?.code || (result as any)?.message) {
reject(result);
return;
}
resolve();
},
});
});

const handleQuickConferenceClick = async () => {
if (props.disabled || isLoading.value) {
return;
}
if (currentRoom.value?.roomId) {
TUIToast({
type: TOAST_TYPE.WARNING,
message: t('ConferencePicker.Cannot_Start_While_In_Meeting'),
});
return;
}

isLoading.value = true;
try {
const roomId = generateRoomId();
const roomName = getQuickConferenceRoomName();
await startRoom({
roomId,
options: {
roomName,
},
});

const sentMessage = await sendCustomMessage({
payload: {
data: JSON.stringify({
businessID: 'group_room_message',
owner: loginUserInfo.value?.userId,
roomId,
roomState: 'created',
roomName,
userList: createCurrentUserPayload(),
ownerName: getConferenceOwnerProfile().nickName,
}),
},
});

TUICore.notifyEvent(
TUIConstants.TUIRoom.SERVICE.NAME,
TUIConstants.TUIRoom.SERVICE.EVENT.QUICK_CONFERENCE_MESSAGE_CREATED,
{
roomId,
message: sentMessage as MessageModel | undefined,
},
);
} catch (error: unknown) {
console.error('[QuickConferencePicker] Failed to create conference:', error);
TUIToast({
type: TOAST_TYPE.ERROR,
message: t('ConferencePicker.Create_Conference_Failed'),
});
} finally {
isLoading.value = false;
}
};

</script>

<style lang="scss" module>
.quick-conference-picker {
&__button {
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
padding: 4px 6px;
transition: background-color 0.5s ease;
border-radius: 4px;

&:hover {
background-color: var(--button-color-secondary-hover);
}

&:active {
background-color: var(--button-color-secondary-active);
}
}

&__icon {
color: var(--icon-color-primary);
}
}

.is-loading {
animation: quick-conference-rotate 0.8s linear infinite;
}

.disabled {
opacity: 0.5;
cursor: not-allowed;
user-select: none;
pointer-events: none;
}

@keyframes quick-conference-rotate {
from {
transform: rotate(0deg);
}

to {
transform: rotate(360deg);
}
}
</style>
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import QuickConferencePicker from './QuickConferencePicker.vue';

export { QuickConferencePicker };
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,14 @@ const OfflinePush = {
custom: '[Custom Message]',
};

const ConferencePicker = {
Quick_Conference: '{{name}} \'s Quick Room',
Create_Conference_Failed: 'Failed to create room, please try again',
Cannot_Start_While_In_Meeting: 'You are already in a room and cannot start another one',
};

export default {
OfflinePush,
MessageInput,
ConferencePicker,
};
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,14 @@ const OfflinePush = {
custom: '[自定义消息]',
};

const ConferencePicker = {
Quick_Conference: '{{name}}的快速房间',
Create_Conference_Failed: '创建房间失败,请重试',
Cannot_Start_While_In_Meeting: '您当前已经在房间中,不可再次发起房间',
};

export default {
MessageInput,
OfflinePush,
ConferencePicker,
};
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,19 @@ import { EmojiPicker as EmojiPickerComponent } from './EmojiPicker';
import { resources } from './i18n';
import MessageInputComponent from './MessageInput.vue';
import MessageInputH5Component from './MessageInputH5.vue';
import { QuickConferencePicker as QuickConferencePickerComponent } from './QuickConferencePicker';
import { TextEditor as TextEditorComponent } from './TextEditor';
import { VideoCallPicker as VideoCallPickerComponent } from './VideoCallPicker';

addI18n('en-US', { translation: {
MessageInput: resources['en-US'].MessageInput,
OfflinePush: resources['en-US'].OfflinePush,
ConferencePicker: resources['en-US'].ConferencePicker,
} });
addI18n('zh-CN', { translation: {
MessageInput: resources['zh-CN'].MessageInput,
OfflinePush: resources['zh-CN'].OfflinePush,
ConferencePicker: resources['zh-CN'].ConferencePicker,
} });

const MessageInput = MessageInputComponent;
Expand All @@ -32,6 +35,7 @@ const TextEditor = TextEditorComponent;
const AttachmentPicker = AttachmentPickerComponent;
const AudioCallPicker = AudioCallPickerComponent;
const VideoCallPicker = VideoCallPickerComponent;
const QuickConferencePicker = QuickConferencePickerComponent;

export {
AttachmentPicker,
Expand All @@ -44,4 +48,5 @@ export {
MessageInputH5,
AudioCallPicker,
VideoCallPicker,
QuickConferencePicker,
};
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,30 @@
import { computed, useCssModule } from 'vue';
import { View } from '../../../../baseComp/View';
import { isCallMessage as _isCallMessage } from '../../../../utils/call';
import { isRoomMessage } from '../../../../utils/room';
import { CallMessage } from './CallMessage';
import { QuickConferenceMessage } from './QuickConferenceMessage';
import type { MessageModel } from '../../../../types';

interface Props {
message: MessageModel;
}
const props = defineProps<Props>();

const classes = useCssModule();

interface CustomMessageData {
businessID: string;
[key: string]: any;
}

interface CustomMessagePayload {
data: string;
description: string;
extension: string;
}

const props = defineProps<Props>();

const classes = useCssModule();

const isCallMessage = computed(() => _isCallMessage(props.message));

const textLinkData = computed<{ text?: string; link?: string } | null>(() => {
Expand All @@ -37,6 +41,7 @@ const textLinkData = computed<{ text?: string; link?: string } | null>(() => {
return null;
}
});

</script>

<template>
Expand All @@ -46,6 +51,11 @@ const textLinkData = computed<{ text?: string; link?: string } | null>(() => {
:class="classes['custom-message']"
/>

<QuickConferenceMessage
v-else-if="isRoomMessage(props.message)"
:message="props.message"
/>

<!-- text_link -->
<View v-else-if="textLinkData" :class="classes['custom-message']">
<div>{{ textLinkData.text }}</div>
Expand Down
Loading