UNPKG

@tencentcloud/roomkit-electron-vue3

Version:

<h1 align="center"> TUIRoomKit</h1> Conference (TUIRoomKit) is a product suitable for multi-person audio and video conversation scenarios such as business meetings, webinars, and online education. By integrating this product, you can add room management,

702 lines (701 loc) 29.7 kB
import { defineComponent, ref, computed, watch, nextTick, createElementBlock, openBlock, createVNode, unref, withCtx, createElementVNode, createCommentVNode, toDisplayString, Fragment, renderList, normalizeClass, createBlock, createTextVNode } from "vue"; import { useI18n } from "../../../locales/index.mjs"; import TuiInput from "../../common/base/Input/index.vue.mjs"; import TuiSelect from "../../common/base/Select/index.vue.mjs"; import TuiOption from "../../common/base/Option/index.vue.mjs"; import TuiCheckbox from "../../common/base/Checkbox/index.vue.mjs"; import TuiButton from "../../common/base/Button.vue.mjs"; import TuiAvatar from "../../common/Avatar.vue.mjs"; import TuiDatepicker from "../../common/base/Datepicker/index.vue.mjs"; import _sfc_main$1 from "../../common/base/Timepicker/index.vue.mjs"; import _sfc_main$2 from "../DurationTimePicker.vue.mjs"; import _sfc_main$3 from "../TimezonePicker.vue.mjs"; import TuiShareLink from "../ShareLink.vue.mjs"; import Contacts from "../Contacts.vue.mjs"; import ScheduleAttendees from "../../common/icons/ScheduleAttendees.vue.mjs"; import PanelContainer from "../PanelContainer.vue.mjs"; import CloseIcon from "../../common/icons/CloseIcon.vue.mjs"; import HideContentIcon from "../../common/icons/HideContentIcon.vue.mjs"; import ShowContentIcon from "../../common/icons/ShowContentIcon.vue.mjs"; import "../../../services/main.mjs"; import { roomService } from "../../../services/roomService.mjs"; import { EventType } from "../../../services/types.mjs"; import { TUISeatMode, TUIConferenceStatus } from "@tencentcloud/tuiroom-engine-electron"; import "../../../utils/environment.mjs"; import { deepClone, calculateByteLength } from "../../../utils/utils.mjs"; import "mitt"; import "../../../services/manager/roomActionManager.mjs"; import "@tencentcloud/tui-core"; import { PASSWORD_MAX_LENGTH_LIMIT } from "../../../constants/room.mjs"; import { invalidDigitalPasswordRegex } from "../../../utils/common.mjs"; import { getDateAndTime, convertToTimestamp, calculateEndTime } from "../scheduleUtils.mjs"; import SvgIcon from "../../common/base/SvgIcon.vue.mjs"; const _hoisted_1 = { class: "schedule-conference-form" }; const _hoisted_2 = { class: "form-item" }; const _hoisted_3 = { class: "form-label" }; const _hoisted_4 = { key: 0, class: "form-item" }; const _hoisted_5 = { class: "form-label" }; const _hoisted_6 = { class: "form-value" }; const _hoisted_7 = { class: "form-item" }; const _hoisted_8 = { class: "form-label" }; const _hoisted_9 = { class: "form-value" }; const _hoisted_10 = { class: "form-item" }; const _hoisted_11 = { class: "form-label" }; const _hoisted_12 = { class: "form-value" }; const _hoisted_13 = { class: "form-item" }; const _hoisted_14 = { class: "form-label" }; const _hoisted_15 = { class: "form-value" }; const _hoisted_16 = { class: "form-item column" }; const _hoisted_17 = { class: "form-label" }; const _hoisted_18 = { class: "form-value" }; const _hoisted_19 = ["title"]; const _hoisted_20 = { class: "form-attendees" }; const _hoisted_21 = ["title"]; const _hoisted_22 = { key: 0, class: "form-attendees-item", style: { "flex-basis": "content" } }; const _hoisted_23 = { key: 1, class: "form-item column", style: { "align-items": "baseline" } }; const _hoisted_24 = { class: "form-label" }; const _hoisted_25 = { class: "password-container" }; const _hoisted_26 = { class: "form-title" }; const _hoisted_27 = { key: 2, class: "form-item column" }; const _hoisted_28 = { class: "form-label" }; const _hoisted_29 = { class: "form-value" }; const _hoisted_30 = { class: "checkbox-group" }; const _hoisted_31 = { class: "schedule-conference-footer" }; const _sfc_main = /* @__PURE__ */ defineComponent({ __name: "index", props: { userName: {}, visible: { type: Boolean }, conferenceInfo: {} }, emits: ["input"], setup(__props, { emit: __emit }) { const { t } = useI18n(); const shareLinkData = ref({}); const props = __props; const emit = __emit; const isDialogVisible = ref(false); const contactsVisible = ref(false); const showRoomInvite = ref(false); const isShowPassword = ref(false); const passwordChecked = ref(false); const isEditMode = computed(() => !!props.conferenceInfo); const roomId = ref(""); const contacts = ref([]); const { date: startDate, laterTime: startTime } = getDateAndTime(/* @__PURE__ */ new Date()); const defaultFormData = ref({ roomName: t("sb temporary room", { name: props.userName || roomService.basicStore.userId }), roomMode: "FreeToSpeak", startDate, startTime, duration: 1800, timezone: Intl.DateTimeFormat().resolvedOptions().timeZone, searchUser: "", scheduleAttendees: [], isMicrophoneDisableForAllUser: false, isScreenShareDisableForAllUser: false, isCameraDisableForAllUser: false, password: "" }); const form = ref(deepClone(defaultFormData.value)); const inputType = computed(() => isShowPassword.value ? "text" : "password"); const toggleShowPassword = () => { isShowPassword.value = !isShowPassword.value; }; const resetData = () => { defaultFormData.value.startDate = form.value.startDate; defaultFormData.value.startTime = form.value.startTime; form.value = Object.assign({}, deepClone(defaultFormData.value)); }; watch( () => props.visible, async (val) => { isDialogVisible.value = val; if (val) { const { date, laterTime } = getDateAndTime(/* @__PURE__ */ new Date()); form.value.roomName = t("sb temporary room", { name: props.userName || roomService.basicStore.userId }); form.value.startDate = date; form.value.startTime = laterTime; contacts.value = await roomService.scheduleConferenceManager.fetchFriendList(); isEditMode.value && (form.value = Object.assign({}, deepClone(editParams.value))); } }, { immediate: true } ); const updateDialogVisible = (val) => { emit("input", val); if (!val) { passwordChecked.value = false; isShowPassword.value = false; resetData(); } }; watch( isDialogVisible, (val) => { updateDialogVisible(val); }, { immediate: true } ); const editParams = computed(() => { if (!props.conferenceInfo) return {}; const { basicRoomInfo, scheduleAttendees, scheduleStartTime, scheduleEndTime } = props.conferenceInfo; const { date, time } = getDateAndTime(new Date(scheduleStartTime * 1e3)); const { roomName, isSeatEnabled, isMicrophoneDisableForAllUser, isScreenShareDisableForAllUser, isCameraDisableForAllUser, password } = basicRoomInfo; return { roomName, roomMode: isSeatEnabled ? "SpeakAfterTakingSeat" : "FreeToSpeak", startDate: date, startTime: time, duration: scheduleEndTime - scheduleStartTime, timezone: Intl.DateTimeFormat().resolvedOptions().timeZone, searchUser: "", scheduleAttendees, isMicrophoneDisableForAllUser, isScreenShareDisableForAllUser, isCameraDisableForAllUser, password }; }); const scheduleParams = computed(() => { const { startDate: startDate2, startTime: startTime2, timezone, duration, scheduleAttendees } = form.value; const scheduleStartTime = convertToTimestamp(startDate2, startTime2, timezone); const scheduleEndTime = calculateEndTime(scheduleStartTime, duration); return { roomId: roomId.value, scheduleStartTime: scheduleStartTime / 1e3, scheduleEndTime: scheduleEndTime / 1e3, scheduleAttendees, roomName: form.value.roomName, isSeatEnabled: form.value.roomMode !== "FreeToSpeak", seatMode: form.value.roomMode === "SpeakAfterTakingSeat" ? TUISeatMode.kApplyToTake : void 0, isMicrophoneDisableForAllUser: form.value.isMicrophoneDisableForAllUser, isScreenShareDisableForAllUser: form.value.isScreenShareDisableForAllUser, isCameraDisableForAllUser: form.value.isCameraDisableForAllUser, password: form.value.password }; }); const roomPasswordCheck = () => { if (!passwordChecked.value) { form.value.password = ""; return true; } const { password } = form.value; if (calculateByteLength(password) !== PASSWORD_MAX_LENGTH_LIMIT) { roomService.emit(EventType.ROOM_NOTICE_MESSAGE, { type: "warning", message: t("Your room password format is incorrect, please check it") }); return false; } return true; }; const timeCheck = () => { if (!props.visible) return true; const { timezone, startDate: startDate2, startTime: startTime2 } = form.value; const scheduleStartTime = convertToTimestamp(startDate2, startTime2, timezone); const currentDate = /* @__PURE__ */ new Date(); currentDate.setMilliseconds(0); currentDate.setSeconds(0); const currentTime = currentDate.getTime(); const result = scheduleStartTime >= currentTime; !result && roomService.emit(EventType.ROOM_NOTICE_MESSAGE, { type: "warning", message: t("The start time cannot be earlier than the current time") }); return result; }; const roomNameCheck = () => { if (!props.visible) return true; if (form.value.roomName === "") { roomService.emit(EventType.ROOM_NOTICE_MESSAGE, { type: "warning", message: t("The room name cannot be empty") }); return false; } const result = calculateByteLength(form.value.roomName) <= 100; !result && roomService.emit(EventType.ROOM_NOTICE_MESSAGE, { type: "warning", message: t("The room name cannot exceed 100 characters") }); return result; }; const roomStatusCheck = () => { var _a; if (!props.visible) return true; const isNotStarted = ((_a = props.conferenceInfo) == null ? void 0 : _a.status) === TUIConferenceStatus.kConferenceStatusNotStarted; !isNotStarted && roomService.emit(EventType.ROOM_NOTICE_MESSAGE, { type: "warning", message: t( "The meeting is in progress and any meeting information cannot be modified" ) }); return isNotStarted; }; watch( () => form.value.startTime, async (newValue, oldValue) => { if (!timeCheck()) { await nextTick(); form.value.startTime = oldValue; } } ); watch( () => form.value.startDate, async (newValue, oldValue) => { if (!timeCheck()) { await nextTick(); form.value.startDate = oldValue; } } ); watch( () => form.value.password, async (val) => { if (val && invalidDigitalPasswordRegex.test(val)) { await nextTick(); form.value.password = val.replace(invalidDigitalPasswordRegex, ""); } } ); watch( () => passwordChecked.value, (val) => { if (val) { form.value.password = `${Math.floor(Math.random() * 9e5) + 1e5}`; } } ); watch( () => form.value.timezone, async (newValue, oldValue) => { const { startDate: startDate2, startTime: startTime2 } = form.value; const currentDate = new Date( convertToTimestamp(startDate2, startTime2, newValue, -1, oldValue) ); const { date, laterTime } = getDateAndTime(currentDate); form.value.startDate = date; form.value.startTime = laterTime; } ); const roomTypeList = [ { label: "Free Speech Room", value: "FreeToSpeak" }, { label: "On-stage Speaking Room", value: "SpeakAfterTakingSeat" } ]; const selectScheduleAttends = () => { contactsVisible.value = true; }; const searchScheduleAttend = (v) => { if (!v) return []; return contacts.value.filter( (user) => (user == null ? void 0 : user.profile.nick.includes(v)) || (user == null ? void 0 : user.userID.includes(v)) ); }; const addSelectUser = (user) => { var _a, _b; form.value.searchUser = ""; if (form.value.scheduleAttendees.findIndex( (item) => item.userId === user.userID ) !== -1) return; form.value.scheduleAttendees.push({ userId: user.userID, userName: (_a = user.profile) == null ? void 0 : _a.nick, avatarUrl: (_b = user.profile) == null ? void 0 : _b.avatar }); }; const removeSelectUser = (user) => { form.value.scheduleAttendees = form.value.scheduleAttendees.filter( (item) => item.userId !== user.userId ); }; const contactsConfirm = (contacts2) => { form.value.scheduleAttendees = contacts2; }; let scheduleConferenceInProgress = false; const scheduleConference = async () => { if (scheduleConferenceInProgress) return; if (!timeCheck()) return; if (!roomNameCheck()) return; if (!roomPasswordCheck()) return; scheduleConferenceInProgress = true; try { roomId.value = await roomService.scheduleConferenceManager.generateRoomId(); await roomService.scheduleConferenceManager.scheduleConference({ ...scheduleParams.value, roomId: roomId.value }); const userIdList = scheduleParams.value.scheduleAttendees.map( (item) => item.userId ); if (userIdList && userIdList.length > 0) { await roomService.scheduleConferenceManager.addAttendeesByAdmin({ roomId: roomId.value, userIdList }); } shareLinkData.value = deepClone(scheduleParams.value); updateDialogVisible(false); showRoomInvite.value = true; } catch (err) { roomService.emit(EventType.ROOM_NOTICE_MESSAGE, { type: "error", message: err.message }); } scheduleConferenceInProgress = false; }; const compareArrays = (oldArray, newArray, key) => { const added = []; const removed = []; const newKeySet = new Set(newArray.map((item) => item[key])); const oldKeySet = new Set(oldArray.map((item) => item[key])); newArray.forEach((item) => { if (!oldKeySet.has(item[key])) { added.push(item); } }); oldArray.forEach((item) => { if (!newKeySet.has(item[key])) { removed.push(item); } }); return { added, removed }; }; const updateConferenceInfo = async () => { var _a; if (!roomStatusCheck()) return; if (!timeCheck()) return; if (!roomNameCheck()) return; try { const roomId2 = (_a = props.conferenceInfo) == null ? void 0 : _a.basicRoomInfo.roomId; if (!roomId2) return; const { roomName, scheduleStartTime, scheduleEndTime, scheduleAttendees } = scheduleParams.value; await roomService.scheduleConferenceManager.updateConferenceInfo({ roomId: roomId2, roomName, scheduleStartTime, scheduleEndTime }); const compareResult = compareArrays( props.conferenceInfo.scheduleAttendees, scheduleAttendees, "userId" ); await Promise.all([ compareResult.added.length > 0 && roomService.scheduleConferenceManager.addAttendeesByAdmin({ roomId: roomId2, userIdList: compareResult.added.map((item) => item.userId) }), compareResult.removed.length > 0 && roomService.scheduleConferenceManager.removeAttendeesByAdmin({ roomId: roomId2, userIdList: compareResult.removed.map((item) => item.userId) }) ]); updateDialogVisible(false); } catch (err) { roomService.emit(EventType.ROOM_NOTICE_MESSAGE, { type: "error", message: err.message }); } }; const cancel = () => { updateDialogVisible(false); }; return (_ctx, _cache) => { return openBlock(), createElementBlock("div", null, [ createVNode(PanelContainer, { visible: isDialogVisible.value, title: unref(t)(!isEditMode.value ? unref(t)("Schedule") : unref(t)("Modify Room")), onInput: _cache[11] || (_cache[11] = ($event) => isDialogVisible.value = $event) }, { footer: withCtx(() => [ createElementVNode("div", _hoisted_31, [ createVNode(TuiButton, { class: "footer-button", type: "primary", onClick: cancel }, { default: withCtx(() => [ createTextVNode(toDisplayString(unref(t)("Cancel")), 1) ]), _: 1 }), !isEditMode.value ? (openBlock(), createBlock(TuiButton, { key: 0, class: "footer-button", onClick: scheduleConference }, { default: withCtx(() => [ createTextVNode(toDisplayString(unref(t)("Schedule")), 1) ]), _: 1 })) : (openBlock(), createBlock(TuiButton, { key: 1, class: "footer-button", onClick: updateConferenceInfo }, { default: withCtx(() => [ createTextVNode(toDisplayString(unref(t)("Save")), 1) ]), _: 1 })) ]) ]), default: withCtx(() => { var _a; return [ createElementVNode("div", _hoisted_1, [ createElementVNode("div", _hoisted_2, [ createElementVNode("span", _hoisted_3, toDisplayString(unref(t)("Room Name")), 1), createVNode(TuiInput, { "model-value": form.value.roomName, onInput: _cache[0] || (_cache[0] = ($event) => form.value.roomName = $event), class: "form-value", placeholder: unref(t)("please enter the room name"), maxlength: "" }, null, 8, ["model-value", "placeholder"]) ]), !isEditMode.value ? (openBlock(), createElementBlock("div", _hoisted_4, [ createElementVNode("span", _hoisted_5, toDisplayString(unref(t)("Room type")), 1), createElementVNode("div", _hoisted_6, [ createVNode(TuiSelect, { modelValue: form.value.roomMode, "onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => form.value.roomMode = $event), class: "select", teleported: false, "popper-append-to-body": false, "custom-select-content-style": { "font-weight": 400 } }, { default: withCtx(() => [ (openBlock(), createElementBlock(Fragment, null, renderList(roomTypeList, (item) => { return createVNode(TuiOption, { key: item.value, value: item.value, label: unref(t)(item.label), "custom-option-content-style": { "font-weight": 400 } }, null, 8, ["value", "label"]); }), 64)) ]), _: 1 }, 8, ["modelValue"]) ]) ])) : createCommentVNode("", true), createElementVNode("div", _hoisted_7, [ createElementVNode("span", _hoisted_8, toDisplayString(unref(t)("Starting time")), 1), createElementVNode("div", _hoisted_9, [ createVNode(TuiDatepicker, { "model-value": form.value.startDate, class: "date-picker", onInput: _cache[2] || (_cache[2] = ($event) => form.value.startDate = $event) }, null, 8, ["model-value"]), createVNode(_sfc_main$1, { "model-value": form.value.startTime, class: "time-picker", onInput: _cache[3] || (_cache[3] = ($event) => form.value.startTime = $event) }, null, 8, ["model-value"]) ]) ]), createElementVNode("div", _hoisted_10, [ createElementVNode("span", _hoisted_11, toDisplayString(unref(t)("Room duration")), 1), createElementVNode("div", _hoisted_12, [ createVNode(_sfc_main$2, { "model-value": form.value.duration, class: "select", onInput: _cache[4] || (_cache[4] = ($event) => form.value.duration = $event) }, null, 8, ["model-value"]) ]) ]), createElementVNode("div", _hoisted_13, [ createElementVNode("span", _hoisted_14, toDisplayString(unref(t)("Time zone")), 1), createElementVNode("div", _hoisted_15, [ createVNode(_sfc_main$3, { "model-value": form.value.timezone, class: "select", onInput: _cache[5] || (_cache[5] = ($event) => form.value.timezone = $event) }, null, 8, ["model-value"]) ]) ]), createElementVNode("div", _hoisted_16, [ createElementVNode("span", _hoisted_17, toDisplayString(unref(t)("Attendees")), 1), createElementVNode("div", _hoisted_18, [ createVNode(TuiInput, { "model-value": form.value.searchUser, onInput: _cache[6] || (_cache[6] = ($event) => form.value.searchUser = $event), class: "form-input search-user", search: searchScheduleAttend, select: addSelectUser, placeholder: unref(t)("Please enter the member name") }, { suffixIcon: withCtx(() => [ createVNode(SvgIcon, { onClick: selectScheduleAttends, icon: ScheduleAttendees, class: normalizeClass(["select-attendees"]) }) ]), searchResultItem: withCtx(({ data }) => [ createVNode(TuiAvatar, { class: "form-attendees-item-avatar", "img-src": data.profile.avatar }, null, 8, ["img-src"]), createElementVNode("p", { class: "form-attendees-item-name", title: data.profile.nick }, toDisplayString(data.profile.nick), 9, _hoisted_19) ]), _: 1 }, 8, ["model-value", "placeholder"]), createElementVNode("div", _hoisted_20, [ (openBlock(true), createElementBlock(Fragment, null, renderList(form.value.scheduleAttendees, (user) => { return openBlock(), createElementBlock("span", { key: user.userId, class: "form-attendees-item" }, [ createVNode(TuiAvatar, { class: "form-attendees-item-avatar", "img-src": user.avatarUrl }, null, 8, ["img-src"]), createElementVNode("p", { class: "form-attendees-item-name", title: user.userName }, toDisplayString(user.userName), 9, _hoisted_21), createVNode(CloseIcon, { class: "form-attendees-item-remove", onClick: ($event) => removeSelectUser(user) }, null, 8, ["onClick"]) ]); }), 128)), ((_a = form.value.scheduleAttendees) == null ? void 0 : _a.length) > 0 ? (openBlock(), createElementBlock("span", _hoisted_22, toDisplayString(`${form.value.scheduleAttendees.length} ${unref(t)("people")}`), 1)) : createCommentVNode("", true) ]) ]) ]), !isEditMode.value ? (openBlock(), createElementBlock("div", _hoisted_23, [ createElementVNode("span", _hoisted_24, toDisplayString(unref(t)("Security")), 1), createElementVNode("div", _hoisted_25, [ createVNode(TuiCheckbox, { "model-value": form.value.passwordChecked, class: "checkbox-group-item", onInput: _cache[7] || (_cache[7] = ($event) => passwordChecked.value = $event) }, { default: withCtx(() => [ createElementVNode("span", _hoisted_26, toDisplayString(unref(t)("Room Password")), 1) ]), _: 1 }, 8, ["model-value"]), passwordChecked.value ? (openBlock(), createBlock(TuiInput, { key: 0, "model-value": form.value.password, onInput: _cache[8] || (_cache[8] = ($event) => form.value.password = $event), class: "form-value", style: { "margin-top": "8px" }, placeholder: unref(t)("Enter 6-digit password"), maxlength: "6", type: inputType.value }, { suffixIcon: withCtx(() => [ isShowPassword.value ? (openBlock(), createBlock(SvgIcon, { key: 0, class: "icon", onClick: toggleShowPassword, icon: ShowContentIcon })) : (openBlock(), createBlock(SvgIcon, { key: 1, class: "icon", onClick: toggleShowPassword, icon: HideContentIcon })) ]), _: 1 }, 8, ["model-value", "placeholder", "type"])) : createCommentVNode("", true) ]) ])) : createCommentVNode("", true), !isEditMode.value ? (openBlock(), createElementBlock("div", _hoisted_27, [ createElementVNode("span", _hoisted_28, toDisplayString(unref(t)("Member management")), 1), createElementVNode("div", _hoisted_29, [ createElementVNode("div", _hoisted_30, [ createVNode(TuiCheckbox, { "model-value": form.value.isMicrophoneDisableForAllUser, class: "checkbox-group-item", onInput: _cache[9] || (_cache[9] = ($event) => form.value.isMicrophoneDisableForAllUser = $event) }, { default: withCtx(() => [ createElementVNode("span", null, toDisplayString(unref(t)("Disable all audios")), 1) ]), _: 1 }, 8, ["model-value"]), createVNode(TuiCheckbox, { "model-value": form.value.isCameraDisableForAllUser, class: "checkbox-group-item", onInput: _cache[10] || (_cache[10] = ($event) => form.value.isCameraDisableForAllUser = $event) }, { default: withCtx(() => [ createTextVNode(toDisplayString(unref(t)("Disable all videos")), 1) ]), _: 1 }, 8, ["model-value"]) ]) ]) ])) : createCommentVNode("", true) ]) ]; }), _: 1 }, 8, ["visible", "title"]), createVNode(Contacts, { visible: contactsVisible.value, contacts: contacts.value, "selected-list": scheduleParams.value.scheduleAttendees, onInput: _cache[12] || (_cache[12] = ($event) => contactsVisible.value = $event), onConfirm: contactsConfirm }, null, 8, ["visible", "contacts", "selected-list"]), createVNode(TuiShareLink, { visible: showRoomInvite.value, "schedule-params": shareLinkData.value, onInput: _cache[13] || (_cache[13] = ($event) => showRoomInvite.value = $event) }, null, 8, ["visible", "schedule-params"]) ]); }; } }); export { _sfc_main as default };