IM相关模块本地测试
@ -22,6 +22,8 @@
|
||||
"dependencies": {
|
||||
"@element-plus/icons-vue": "2.3.1",
|
||||
"@highlightjs/vue-plugin": "2.1.0",
|
||||
"@tencentcloud/chat": "^3.5.5",
|
||||
"@tencentcloud/chat-uikit-vue": "^2.4.3",
|
||||
"@vueup/vue-quill": "1.2.0",
|
||||
"@vueuse/core": "13.1.0",
|
||||
"animate.css": "4.1.1",
|
||||
|
33
src/main.ts
@ -8,7 +8,9 @@ import 'element-plus/theme-chalk/dark/css-vars.css';
|
||||
import App from './App.vue';
|
||||
import store from './store';
|
||||
import router from './router';
|
||||
|
||||
import { TUIComponents, TUIChatKit } from './TUIKit';
|
||||
import { TUIStore, StoreName, TUITranslateService } from '@tencentcloud/chat-uikit-engine';
|
||||
import TUINotification from './TUIKit/components/TUINotification/index';
|
||||
// 自定义指令
|
||||
import directive from './directive';
|
||||
|
||||
@ -55,3 +57,32 @@ app.use(plugins);
|
||||
directive(app);
|
||||
|
||||
app.mount('#app');
|
||||
|
||||
const SDKAppID = 1600089570; // Your SDKAppID
|
||||
const secretKey = 'b84abcf1d5c41a702b1c63fe50adaa1bc77cc51233d0073f044e25c6f21fcb58';
|
||||
const userSig =
|
||||
'eJyrVgrxCdYrSy1SslIy0jNQ0gHzM1NS80oy0zLBwpX5pUCUk5mYl16ckZgPVVKckp1YUJCZomRlaGZgYGBhaWpuAJFJrSjILEoFipuamhoBpSCiJZm5IDFzEwtTSwsTY2OoKZnpQBtcPYq8XMvLkiKjTC1yDPLcM53zI7yS3POLLfyyDSNzK0ucjMOT-Q1Lgn09bZVqAf37Nfg_'; // Your secretKey
|
||||
TUIChatKit.components(TUIComponents, app);
|
||||
TUIChatKit.init();
|
||||
/**
|
||||
* Init TUINotification configuration.
|
||||
*/
|
||||
TUINotification.setNotificationConfiguration({
|
||||
showPreviews: true,
|
||||
allowNotifications: true,
|
||||
notificationTitle: 'Tencent Cloud Chat',
|
||||
notificationIcon: 'https://web.sdk.qcloud.com/im/demo/latest/faviconnew.png'
|
||||
});
|
||||
|
||||
/**
|
||||
* Listen for new messages and use notification components.
|
||||
* This capability is only available in the web environment.
|
||||
*/
|
||||
TUIStore.watch(StoreName.CHAT, {
|
||||
newMessageList: (newMessageList: unknown) => {
|
||||
if (Array.isArray(newMessageList)) {
|
||||
newMessageList.forEach((message) => TUINotification.notify(message));
|
||||
}
|
||||
}
|
||||
});
|
||||
export { SDKAppID, secretKey, userSig };
|
||||
|
@ -19,9 +19,10 @@ const isWhiteList = (path: string) => {
|
||||
|
||||
router.beforeEach(async (to, from, next) => {
|
||||
NProgress.start();
|
||||
if (getToken()) {
|
||||
next();
|
||||
/* if (getToken()) {
|
||||
to.meta.title && useSettingsStore().setTitle(to.meta.title as string);
|
||||
/* has token*/
|
||||
/!* has token*!/
|
||||
if (to.path === '/login') {
|
||||
next({ path: '/' });
|
||||
NProgress.done();
|
||||
@ -62,7 +63,7 @@ router.beforeEach(async (to, from, next) => {
|
||||
next(`/login?redirect=${redirect}`); // 否则全部重定向到登录页
|
||||
NProgress.done();
|
||||
}
|
||||
}
|
||||
}*/
|
||||
});
|
||||
|
||||
router.afterEach(() => {
|
||||
|
@ -37,6 +37,11 @@ export const constantRoutes: RouteRecordRaw[] = [
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/im-test',
|
||||
hidden: true,
|
||||
component: () => import('@/views/im/index.vue')
|
||||
},
|
||||
{
|
||||
path: '/social-callback',
|
||||
hidden: true,
|
||||
|
140
src/utils/link.ts
Normal file
@ -0,0 +1,140 @@
|
||||
const Link = {
|
||||
adv: {
|
||||
label: '首购低至1折, 复购7.5折起! 立即选购',
|
||||
url: 'https://cloud.tencent.com/act/pro/imnew?from=16262',
|
||||
},
|
||||
demo: {
|
||||
label: '体验更多Demo',
|
||||
url: 'https://cloud.tencent.com/document/product/269/36852',
|
||||
},
|
||||
im: {
|
||||
label: '访问官网',
|
||||
url: 'https://cloud.tencent.com/product/im',
|
||||
},
|
||||
privacy: {
|
||||
label: '隐私条例',
|
||||
url: 'https://web.sdk.qcloud.com/document/Tencent-IM-Privacy-Protection-Guidelines.html',
|
||||
},
|
||||
agreement: {
|
||||
label: '用户协议',
|
||||
url: 'https://web.sdk.qcloud.com/document/Tencent-IM-User-Agreement.html',
|
||||
},
|
||||
product: {
|
||||
label: '产品文档',
|
||||
url: 'https://cloud.tencent.com/document/product/269/1499#.E7.BE.A4.E7.BB.84.E5.8A.9F.E8.83.BD',
|
||||
},
|
||||
customMessage: {
|
||||
label: '自定义消息',
|
||||
url: 'https://web.sdk.qcloud.com/im/doc/zh-cn/SDK.html#createCustomMessage',
|
||||
},
|
||||
contact: {
|
||||
label: '联系我们',
|
||||
url: 'https://cloud.tencent.com/document/product/269/59590',
|
||||
},
|
||||
intl: {
|
||||
label: '国际站',
|
||||
url: 'https://web.sdk.qcloud.com/im/demo/en/index.html#/home',
|
||||
},
|
||||
stepList: [
|
||||
{
|
||||
label: '创建项目',
|
||||
url: 'https://cloud.tencent.com/document/product/269/68493#.E6.AD.A5.E9.AA.A41.EF.BC.9A.E5.88.9B.E5.BB.BA.E9.A1.B9.E7.9B.AE',
|
||||
},
|
||||
{
|
||||
label: '下载TUIKit组件',
|
||||
url: 'https://cloud.tencent.com/document/product/269/68493#.E6.AD.A5.E9.AA.A42.EF.BC.9A.E4.B8.8B.E8.BD.BD-tuikit-.E7.BB.84.E4.BB.B6',
|
||||
},
|
||||
{
|
||||
label: '引入TUIKit组件',
|
||||
url: 'https://cloud.tencent.com/document/product/269/68493#.E6.AD.A5.E9.AA.A43.EF.BC.9A.E5.BC.95.E5.85.A5-tuikit-.E7.BB.84.E4.BB.B6',
|
||||
},
|
||||
{
|
||||
label: '获取SDKAppID',
|
||||
url: 'https://cloud.tencent.com/document/product/269/68493#.E6.AD.A5.E9.AA.A44.EF.BC.9A-.E8.8E.B7.E5.8F.96-sdkappid-.E3.80.81.E5.AF.86.E9.92.A5.E4.B8.8E-userid',
|
||||
},
|
||||
{
|
||||
label: '调用TUIKit组件',
|
||||
url: 'https://cloud.tencent.com/document/product/269/68493#.E6.AD.A5.E9.AA.A45.EF.BC.9A.E8.B0.83.E7.94.A8-tuikit-.E7.BB.84.E4.BB.B6',
|
||||
},
|
||||
{
|
||||
label: '启动项目',
|
||||
url: 'https://cloud.tencent.com/document/product/269/68493#.E6.AD.A5.E9.AA.A46.EF.BC.9A.E5.90.AF.E5.8A.A8.E9.A1.B9.E7.9B.AE',
|
||||
},
|
||||
{
|
||||
label: '发送您的第一条消息',
|
||||
url: 'https://cloud.tencent.com/document/product/269/68493#.E6.AD.A5.E9.AA.A47.EF.BC.9A.E5.8F.91.E9.80.81.E6.82.A8.E7.9A.84.E7.AC.AC.E4.B8.80.E6.9D.A1.E6.B6.88.E6.81.AF',
|
||||
},
|
||||
],
|
||||
advList: [
|
||||
{
|
||||
label: 'IM首购低至1折',
|
||||
subLabel: '续费9折起',
|
||||
btnText: '立即选购',
|
||||
url: 'https://cloud.tencent.com/act/pro/imnew?from=16262',
|
||||
},
|
||||
],
|
||||
apkQRCodeList: [
|
||||
{
|
||||
type: 'android',
|
||||
label: '扫码体验 Chat (React Native)',
|
||||
url: 'https://web.sdk.qcloud.com/component/TUIKit/chat_react-native_demo_apk.png',
|
||||
},
|
||||
{
|
||||
type: 'android',
|
||||
label: '扫码体验 Chat&Push (uni-app)',
|
||||
url: 'https://qcloudimg.tencent-cloud.cn/raw/c1fed062d91cd95fdfb57059edcd5890.png',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const qrList = [
|
||||
{
|
||||
icon: 'https://web.sdk.qcloud.com/im/assets/images/react_native.svg',
|
||||
name: 'React Native',
|
||||
link: 'https://web.sdk.qcloud.com/component/TUIKit/chat_react-native_demo_apk.png',
|
||||
detail: '扫描二维码下载',
|
||||
},
|
||||
{
|
||||
icon: 'https://web.sdk.qcloud.com/im/assets/images/uniapp.svg',
|
||||
name: 'Uniapp',
|
||||
link: 'https://qcloudimg.tencent-cloud.cn/raw/c1fed062d91cd95fdfb57059edcd5890.png',
|
||||
detail: '扫描二维码下载',
|
||||
},
|
||||
{
|
||||
icon: 'https://web.sdk.qcloud.com/im/assets/images/Android.svg',
|
||||
name: 'Android',
|
||||
link: 'https://web.sdk.qcloud.com/im/assets/images/android.png',
|
||||
detail: '扫描二维码下载',
|
||||
},
|
||||
{
|
||||
icon: 'https://web.sdk.qcloud.com/im/assets/images/iOS.svg',
|
||||
name: 'iOS',
|
||||
link: 'https://web.sdk.qcloud.com/im/assets/images/ios.png',
|
||||
detail: '扫描二维码下载',
|
||||
},
|
||||
{
|
||||
icon: 'https://web.sdk.qcloud.com/im/assets/images/Miniprogram.svg',
|
||||
name: '小程序',
|
||||
link: 'https://web.sdk.qcloud.com/im/assets/images/mini.png',
|
||||
detail: '微信扫码进入',
|
||||
},
|
||||
];
|
||||
|
||||
const mobileList = [
|
||||
{
|
||||
type: 'android',
|
||||
link: 'https://web.sdk.qcloud.com/im/assets/images/android-mobile.svg',
|
||||
url: 'https://comm.qq.com/im_demo_download/index.html#/mobile-demo',
|
||||
},
|
||||
{
|
||||
type: 'iphone',
|
||||
link: 'https://web.sdk.qcloud.com/im/assets/images/iphone-mobile.svg',
|
||||
url: 'https://apps.apple.com/cn/app/%E8%85%BE%E8%AE%AF%E4%BA%91im/id1112479040',
|
||||
},
|
||||
{
|
||||
type: 'miniprogram',
|
||||
link: 'https://web.sdk.qcloud.com/im/assets/images/mini-mobile.svg',
|
||||
},
|
||||
];
|
||||
|
||||
export { Link, qrList, mobileList };
|
@ -124,7 +124,8 @@ service.interceptors.response.use(
|
||||
if (res.request.responseType === 'blob' || res.request.responseType === 'arraybuffer') {
|
||||
return res.data;
|
||||
}
|
||||
if (code === 401) {
|
||||
return Promise.resolve(res.data);
|
||||
/* if (code === 401) {
|
||||
// prettier-ignore
|
||||
if (!isRelogin.show) {
|
||||
isRelogin.show = true;
|
||||
@ -158,7 +159,7 @@ service.interceptors.response.use(
|
||||
return Promise.reject('error');
|
||||
} else {
|
||||
return Promise.resolve(res.data);
|
||||
}
|
||||
}*/
|
||||
},
|
||||
(error: any) => {
|
||||
let { message } = error;
|
||||
|
430
src/views/im/components/About.vue
Normal file
@ -0,0 +1,430 @@
|
||||
<template>
|
||||
<div
|
||||
:class="['about-container', 'container', isH5 && 'container-h5']"
|
||||
@click="closeAboutBox"
|
||||
@mousedown.stop
|
||||
>
|
||||
<div
|
||||
:class="['about-box', 'box', isH5 && 'box-h5']"
|
||||
@click.stop
|
||||
>
|
||||
<header
|
||||
v-if="isH5"
|
||||
class="title"
|
||||
>
|
||||
<div
|
||||
class="title-back"
|
||||
@click="closeAboutBox"
|
||||
>
|
||||
<Icon :file="backSVG" />
|
||||
</div>
|
||||
<div class="title-name">
|
||||
{{ TUITranslateService.t("Home.关于腾讯云·通信") }}
|
||||
</div>
|
||||
</header>
|
||||
<main class="main">
|
||||
<div class="main-name">
|
||||
<img
|
||||
class="logo"
|
||||
src="../assets/image/logo.svg"
|
||||
alt=""
|
||||
>
|
||||
<div class="name">
|
||||
{{ TUITranslateService.t("即时通信") }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="main-version">
|
||||
{{ TUITranslateService.t("Home.SDK版本") }}: {{ SDKVersion }}
|
||||
</div>
|
||||
</main>
|
||||
<footer class="footer">
|
||||
<ul class="list">
|
||||
<li class="line">
|
||||
<a
|
||||
class="link"
|
||||
:href="Link.privacy.url"
|
||||
target="_blank"
|
||||
>
|
||||
{{ TUITranslateService.t(`Login.${Link.privacy.label}`) }}
|
||||
</a>
|
||||
<a
|
||||
class="link"
|
||||
:href="Link.agreement.url"
|
||||
target="_blank"
|
||||
>
|
||||
{{ TUITranslateService.t(`Login.${Link.agreement.label}`) }}
|
||||
</a>
|
||||
<a
|
||||
class="link"
|
||||
@click="toggleDisclaimer"
|
||||
>
|
||||
{{ TUITranslateService.t("Home.免责声明") }}
|
||||
<div
|
||||
v-if="isDisclaimerBoxShow"
|
||||
:class="['disclaimer-container', 'container', isH5 && 'container-h5']"
|
||||
@click="toggleDisclaimer"
|
||||
>
|
||||
<div
|
||||
:class="['disclaimer-box', 'box', isH5 && 'box-h5']"
|
||||
@click.stop
|
||||
>
|
||||
<header
|
||||
v-if="isH5"
|
||||
class="title"
|
||||
>
|
||||
<div
|
||||
class="title-back"
|
||||
@click="toggleDisclaimer"
|
||||
>
|
||||
<Icon :file="backSVG" />
|
||||
</div>
|
||||
<div class="title-name">
|
||||
{{ TUITranslateService.t("Home.关于腾讯云·通信") }}
|
||||
</div>
|
||||
</header>
|
||||
<main class="main">
|
||||
<header class="main-title">
|
||||
{{ TUITranslateService.t(`Home.IM-免责声明`) }}
|
||||
</header>
|
||||
<p class="main-info">
|
||||
{{
|
||||
TUITranslateService.t(
|
||||
`Home.IM(“本产品”)是由腾讯云提供的一款测试产品,腾讯云享有本产品的著作权和所有权。本产品仅用于功能体验,不得用于任何商业用途。依据相关部门监管要求,严禁在使用中有任何色情、辱骂、暴恐、涉政等违法内容传播。`
|
||||
)
|
||||
}}
|
||||
</p>
|
||||
</main>
|
||||
<footer class="footer">
|
||||
<button
|
||||
class="btn btn-default"
|
||||
@click.stop="submitDisclaimer"
|
||||
>
|
||||
{{ TUITranslateService.t("Home.同意") }}
|
||||
</button>
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="line">
|
||||
<a
|
||||
class="link"
|
||||
:href="Link.contact.url"
|
||||
target="_blank"
|
||||
>
|
||||
{{ TUITranslateService.t(`Home.${Link.contact.label}`) }}
|
||||
</a>
|
||||
<a
|
||||
class="link"
|
||||
@click="toggleCancellation"
|
||||
>
|
||||
{{ TUITranslateService.t("Home.注销账户") }}
|
||||
<div
|
||||
v-if="isCancellationBoxShow"
|
||||
:class="['cancellation-container', 'container', isH5 && 'container-h5']"
|
||||
@click="toggleCancellation"
|
||||
>
|
||||
<div
|
||||
:class="['cancellation-box', 'box', isH5 && 'box-h5']"
|
||||
@click.stop
|
||||
>
|
||||
<header
|
||||
v-if="isH5"
|
||||
class="title"
|
||||
>
|
||||
<div
|
||||
class="title-back"
|
||||
@click="toggleCancellation"
|
||||
>
|
||||
<Icon :file="backSVG" />
|
||||
</div>
|
||||
<div class="title-name">
|
||||
{{ TUITranslateService.t("Home.关于腾讯云·通信") }}
|
||||
</div>
|
||||
</header>
|
||||
<main class="main">
|
||||
<img
|
||||
src="../assets/image/warn.svg"
|
||||
width="60"
|
||||
height="60"
|
||||
>
|
||||
<p class="main-text">
|
||||
{{
|
||||
TUITranslateService.t(
|
||||
"Home.注销后,您将无法使用当前账号,相关数据也将删除无法找回"
|
||||
)
|
||||
}}
|
||||
</p>
|
||||
<p>
|
||||
<span>{{ TUITranslateService.t("Home.当前账号") + ": " }}</span>
|
||||
<span class="main-id">{{ props.userProfile.userID }}</span>
|
||||
</p>
|
||||
</main>
|
||||
<footer class="footer">
|
||||
<button
|
||||
class="btn btn-error"
|
||||
@click.stop="submitCancellation"
|
||||
>
|
||||
{{ TUITranslateService.t("Home.注销") }}
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-default"
|
||||
@click.stop="toggleCancellation"
|
||||
>
|
||||
{{ TUITranslateService.t("Home.取消") }}
|
||||
</button>
|
||||
</footer>
|
||||
</div>
|
||||
</div></a>
|
||||
</li>
|
||||
<li class="line">
|
||||
<p class="copyright">
|
||||
Copyright © 2013-2023 Tencent Cloud. All Rights Reserved.
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ref, withDefaults, defineProps, defineEmits } from '@/TUIKit/adapter-vue';
|
||||
import { TUITranslateService, TUIStore, StoreName } from '@tencentcloud/chat-uikit-engine';
|
||||
import { TUILogin } from '@tencentcloud/tui-core';
|
||||
import Icon from '../TUIKit/components/common/Icon.vue';
|
||||
import backSVG from '../TUIKit/assets/icon/back.svg';
|
||||
import { isH5 } from '../TUIKit/utils/env';
|
||||
import { Link } from '../utils/link';
|
||||
import { cancellation } from '../api';
|
||||
import { IUserProfile } from '../TUIKit/interface';
|
||||
import router from '../router';
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
userProfile: IUserProfile;
|
||||
}>(),
|
||||
{
|
||||
userProfile: () => ({} as IUserProfile),
|
||||
},
|
||||
);
|
||||
|
||||
const emits = defineEmits(['closeAboutBox']);
|
||||
|
||||
const isAboutBoxShow = ref<boolean>(false);
|
||||
const isDisclaimerBoxShow = ref<boolean>(false);
|
||||
const isCancellationBoxShow = ref<boolean>(false);
|
||||
const SDKVersion = TUIStore.getData(StoreName.APP, 'SDKVersion');
|
||||
|
||||
function closeAboutBox() {
|
||||
isAboutBoxShow.value = false;
|
||||
emits('closeAboutBox');
|
||||
}
|
||||
// Disclaimer dialog
|
||||
function toggleDisclaimer() {
|
||||
isDisclaimerBoxShow.value = !isDisclaimerBoxShow.value;
|
||||
}
|
||||
function submitDisclaimer() {
|
||||
isDisclaimerBoxShow.value = false;
|
||||
}
|
||||
// Cancellation dialog
|
||||
function toggleCancellation() {
|
||||
isCancellationBoxShow.value = !isCancellationBoxShow.value;
|
||||
}
|
||||
function submitCancellation() {
|
||||
isCancellationBoxShow.value = false;
|
||||
const deleteInfo: any = localStorage.getItem('TUIKit-userInfo');
|
||||
const deleteInfoList = JSON.parse(deleteInfo);
|
||||
const options: any = {
|
||||
userId: deleteInfoList.userId,
|
||||
token: deleteInfoList.token,
|
||||
phone: deleteInfoList.phone,
|
||||
};
|
||||
TUILogin.logout().then(() => {
|
||||
localStorage.removeItem('TUIKit-userInfo');
|
||||
cancellation(options);
|
||||
router.push({ path: '/' });
|
||||
});
|
||||
}
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
@import "../styles/common";
|
||||
|
||||
.main {
|
||||
flex: 1;
|
||||
|
||||
@include flex;
|
||||
}
|
||||
|
||||
.btn {
|
||||
flex: 1;
|
||||
margin-top: 14px;
|
||||
margin-right: 10px;
|
||||
|
||||
&:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-default {
|
||||
@include btn-default;
|
||||
}
|
||||
|
||||
.btn-error {
|
||||
@include btn-error;
|
||||
}
|
||||
|
||||
.about-container {
|
||||
.about-box {
|
||||
padding: 100px 180px;
|
||||
padding-bottom: 0;
|
||||
|
||||
.main {
|
||||
padding-bottom: 126px;
|
||||
|
||||
.main-name {
|
||||
@include flex;
|
||||
|
||||
padding-bottom: 28px;
|
||||
|
||||
.logo {
|
||||
width: 110px;
|
||||
}
|
||||
|
||||
.name {
|
||||
font-size: 40px;
|
||||
font-family: PingFangSC-Medium;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
.main-version {
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
|
||||
.footer {
|
||||
.list {
|
||||
@include flex;
|
||||
|
||||
list-style: none;
|
||||
|
||||
.line {
|
||||
@include flex(row, center, center);
|
||||
|
||||
padding-top: 10px;
|
||||
|
||||
.link {
|
||||
font-size: 16px;
|
||||
padding: 0 10px;
|
||||
color: #006eff;
|
||||
border-right: 1px solid #eee;
|
||||
}
|
||||
|
||||
.link:last-child {
|
||||
border-right: 0 solid #000;
|
||||
}
|
||||
|
||||
.copyright {
|
||||
font-size: 14px;
|
||||
padding: 25px 0;
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.disclaimer-box {
|
||||
@include flex(column, center, stretch);
|
||||
|
||||
padding: 10px 10px 0;
|
||||
|
||||
.main {
|
||||
align-items: flex-start;
|
||||
width: 360px;
|
||||
font-size: 1rem;
|
||||
padding: 3.5rem 4rem;
|
||||
color: #000;
|
||||
|
||||
.main-title {
|
||||
font-size: 18px;
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
|
||||
.main-info {
|
||||
text-wrap: wrap;
|
||||
}
|
||||
}
|
||||
|
||||
.footer {
|
||||
display: flex;
|
||||
padding: 4rem;
|
||||
}
|
||||
}
|
||||
|
||||
.cancellation-box {
|
||||
@include flex;
|
||||
|
||||
padding: 55px 42px;
|
||||
max-width: 566px;
|
||||
|
||||
.main {
|
||||
@include flex;
|
||||
|
||||
padding-bottom: 30px;
|
||||
|
||||
.main-text {
|
||||
margin-top: 20px;
|
||||
text-wrap: wrap;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.main-info {
|
||||
text-wrap: wrap;
|
||||
}
|
||||
|
||||
.main-id {
|
||||
color: #006eff;
|
||||
}
|
||||
}
|
||||
|
||||
.footer {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
width: 100%;
|
||||
|
||||
.btn {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.about-box.box-h5 {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.disclaimer-box.box-h5,
|
||||
.cancellation-box.box-h5 {
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
justify-content: flex-start;
|
||||
|
||||
.main {
|
||||
flex: none;
|
||||
box-sizing: border-box;
|
||||
padding: 30px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.footer {
|
||||
box-sizing: border-box;
|
||||
padding: 10px 30px;
|
||||
|
||||
.btn {
|
||||
height: 50px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
31
src/views/im/components/AdvList.vue
Normal file
@ -0,0 +1,31 @@
|
||||
<template>
|
||||
<ul class="adv-list">
|
||||
<li v-for="(item, index) of list" :key="index" :item="item">
|
||||
<slot name="item" :data="item" />
|
||||
</li>
|
||||
</ul>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { defineProps } from "../TUIKit/adapter-vue";
|
||||
const props = defineProps({
|
||||
list: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.adv-list {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-around;
|
||||
align-items: center;
|
||||
|
||||
li {
|
||||
width: 150px;
|
||||
}
|
||||
}
|
||||
</style>
|
105
src/views/im/components/AdvListItem.vue
Normal file
@ -0,0 +1,105 @@
|
||||
<template>
|
||||
<li class="adv-list-item">
|
||||
<div class="show-box" @click="showEvent">
|
||||
<label class="img-box">
|
||||
<img :src="item?.icon" alt="" />
|
||||
</label>
|
||||
<span class="name">{{ item?.name && TUITranslateService.t(`Login.${item?.name}`) }}</span>
|
||||
</div>
|
||||
<div class="show-box hover-box" @click="hoverEvent">
|
||||
<label class="img-box">
|
||||
<img :src="item?.link" alt="" />
|
||||
</label>
|
||||
<span class="name">{{ item?.detail && TUITranslateService.t(`Login.${item?.name}`) }}</span>
|
||||
<span class="name">{{ item?.detail && TUITranslateService.t(`Login.${item?.detail}`) }}</span>
|
||||
</div>
|
||||
</li>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { defineProps, defineEmits, withDefaults } from "../TUIKit/adapter-vue";
|
||||
import { TUITranslateService } from "@tencentcloud/chat-uikit-engine";
|
||||
|
||||
type IAdvListItem = {
|
||||
name?: string;
|
||||
link?: string;
|
||||
detail?: string;
|
||||
};
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
item: IAdvListItem;
|
||||
}>(),
|
||||
{
|
||||
item: () => ({} as IAdvListItem),
|
||||
}
|
||||
);
|
||||
|
||||
const emits = defineEmits(["showEvent", "hoverEvent"]);
|
||||
|
||||
const showEvent = () => {
|
||||
emits("showEvent", props.item);
|
||||
};
|
||||
|
||||
const hoverEvent = () => {
|
||||
emits("hoverEvent", props.item);
|
||||
};
|
||||
</script>
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style scoped lang="scss">
|
||||
.adv-list-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
|
||||
&:hover {
|
||||
.show-box {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.hover-box {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
.show-box {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
|
||||
.img-box {
|
||||
width: 82px;
|
||||
height: 82px;
|
||||
border-radius: 8px;
|
||||
background: rgba(255, 255, 255, 1);
|
||||
box-shadow: 0 8px 12px 0 rgba(223, 235, 253, 0.5);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
img {
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.name {
|
||||
color: rgba(0, 0, 0, 1);
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
font-family: "PingFang SC";
|
||||
text-align: left;
|
||||
line-height: 16px;
|
||||
height: 16px;
|
||||
padding-top: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.hover-box {
|
||||
display: none;
|
||||
position: relative;
|
||||
top: -15px;
|
||||
}
|
||||
}
|
||||
</style>
|
59
src/views/im/components/ChatDefaultContent.vue
Normal file
@ -0,0 +1,59 @@
|
||||
<template>
|
||||
<div class="welcome">
|
||||
<div class="welcome-title">
|
||||
{{ TUITranslateService.t("Home.欢迎使用") }}
|
||||
<img class="logo" src="../assets/image/logo.svg" alt="" />
|
||||
{{ TUITranslateService.t("即时通信") }}
|
||||
</div>
|
||||
<div v-if="isOfficial" class="welcome-content">
|
||||
{{
|
||||
TUITranslateService.t(
|
||||
"Home.我们为您默认提供了一位“示例好友”和一个“示例客服群”您不用额外添加好友和群聊就可完整体验腾讯云 IM 单聊、群聊的所有功能。"
|
||||
)
|
||||
}}
|
||||
<br />
|
||||
{{ TUITranslateService.t("Home.随时随地") }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { TUITranslateService, TUIStore, StoreName } from "@tencentcloud/chat-uikit-engine";
|
||||
const isOfficial = TUIStore.getData(StoreName.APP, "isOfficial");
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.welcome {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
padding-left: 40px;
|
||||
padding-top: 100px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: url("../assets/image/login-background.png") no-repeat;
|
||||
background-size: cover;
|
||||
background-position-x: -17px;
|
||||
background-position-y: 173px;
|
||||
.welcome-title {
|
||||
font-size: 1.75rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-family: PingFangSC-Medium;
|
||||
font-weight: 500;
|
||||
color: #000;
|
||||
.logo {
|
||||
width: 40px;
|
||||
padding-left: 0.98rem;
|
||||
padding-right: 0.98rem;
|
||||
}
|
||||
}
|
||||
.welcome-content {
|
||||
padding-top: 1.88rem;
|
||||
max-width: 393px;
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
font-family: PingFangSC-Regular;
|
||||
font-weight: 400;
|
||||
color: #666;
|
||||
}
|
||||
}
|
||||
</style>
|
492
src/views/im/components/EditProfile.vue
Normal file
@ -0,0 +1,492 @@
|
||||
<template>
|
||||
<div
|
||||
class="edit-profile-container container dialog"
|
||||
:class="[isH5 ? 'edit-profile-container-h5' : 'edit-profile-container-pc']"
|
||||
@click="closeEditProfileBox"
|
||||
@mousedown.stop
|
||||
>
|
||||
<div :class="['edit-profile-box']" @click.stop>
|
||||
<header class="title">
|
||||
<div v-if="isH5" class="title-back" @click="closeEditProfileBox">
|
||||
<Icon :file="backSVG"></Icon>
|
||||
</div>
|
||||
<div class="title-name">{{ TUITranslateService.t("Profile.编辑资料") }}</div>
|
||||
</header>
|
||||
<div class="edit-form">
|
||||
<div v-if="isH5" class="edit-form-space"></div>
|
||||
<div class="edit-form-item">
|
||||
<div class="form-label">{{ TUITranslateService.t("Profile.头像") }}</div>
|
||||
<div v-if="isH5" class="form-info" @click="showBottomPopup('avatar')">
|
||||
<Avatar useSkeletonAnimation :url="userProfile.avatar" size="60px" />
|
||||
<Icon class="form-info-arrow" :file="rightArrowIcon" size="14px"></Icon>
|
||||
</div>
|
||||
<EditProfilePopup
|
||||
class="form-item"
|
||||
:show="isPC || currentBottomPopupShow === 'avatar'"
|
||||
:title="TUITranslateService.t('Profile.选择头像')"
|
||||
@onClose="closeBottomPopup"
|
||||
@onSubmit="submitEditProfileBox"
|
||||
>
|
||||
<ul class="avatar-list">
|
||||
<li
|
||||
:class="[
|
||||
'avatar-list-item',
|
||||
currentEditProfile.avatar === avatar && 'avatar-list-item-selected',
|
||||
]"
|
||||
v-for="avatar in avatarList"
|
||||
:key="avatar"
|
||||
@click="changeCurrentEditProfile('avatar', avatar)"
|
||||
>
|
||||
<Avatar useSkeletonAnimation :url="avatar" :size="isPC ? '36px' : '50px'" />
|
||||
</li>
|
||||
</ul>
|
||||
</EditProfilePopup>
|
||||
</div>
|
||||
<div v-if="isH5" class="edit-form-space"></div>
|
||||
<div class="edit-form-item">
|
||||
<div class="form-label">{{ TUITranslateService.t("Profile.昵称") }}</div>
|
||||
<div v-if="isH5" class="form-info" @click="showBottomPopup('nick')">
|
||||
<div class="form-info-content">{{ userProfile.nick }}</div>
|
||||
<Icon class="form-info-arrow" :file="rightArrowIcon" size="14px"></Icon>
|
||||
</div>
|
||||
<EditProfilePopup
|
||||
class="form-item"
|
||||
:show="isPC || currentBottomPopupShow === 'nick'"
|
||||
:title="TUITranslateService.t('Profile.设置昵称')"
|
||||
@onClose="closeBottomPopup"
|
||||
@onSubmit="submitEditProfileBox"
|
||||
>
|
||||
<input class="form-item-input" type="text" v-model="currentEditProfile.nick" />
|
||||
</EditProfilePopup>
|
||||
</div>
|
||||
<div class="edit-form-item">
|
||||
<div class="form-label">{{ TUITranslateService.t("Profile.账号") }}</div>
|
||||
<div class="form-info">{{ userProfile.userID }}</div>
|
||||
</div>
|
||||
<div v-if="isH5" class="edit-form-space"></div>
|
||||
<div class="edit-form-item">
|
||||
<div class="form-label">{{ TUITranslateService.t("Profile.个性签名") }}</div>
|
||||
<div v-if="isH5" class="form-info" @click="showBottomPopup('selfSignature')">
|
||||
<div class="form-info-content">{{ userProfile.selfSignature }}</div>
|
||||
<Icon class="form-info-arrow" :file="rightArrowIcon" size="14px"></Icon>
|
||||
</div>
|
||||
<EditProfilePopup
|
||||
class="form-item"
|
||||
:show="isPC || currentBottomPopupShow === 'selfSignature'"
|
||||
:title="TUITranslateService.t('Profile.个性签名')"
|
||||
@onClose="closeBottomPopup"
|
||||
@onSubmit="submitEditProfileBox"
|
||||
>
|
||||
<input class="form-item-input" type="text" v-model="currentEditProfile.selfSignature" />
|
||||
</EditProfilePopup>
|
||||
</div>
|
||||
<div class="edit-form-item">
|
||||
<div class="form-label">{{ TUITranslateService.t("Profile.性别") }}</div>
|
||||
<div v-if="isH5" class="form-info" @click="showBottomPopup('gender')">
|
||||
<div>
|
||||
{{
|
||||
(userProfile.gender &&
|
||||
TUITranslateService.t(`Profile.${genderLabelList[userProfile.gender]}`)) ||
|
||||
""
|
||||
}}
|
||||
</div>
|
||||
<Icon class="form-info-arrow" :file="rightArrowIcon" size="14px"></Icon>
|
||||
</div>
|
||||
<EditProfilePopup
|
||||
class="form-item"
|
||||
:show="isPC || currentBottomPopupShow === 'gender'"
|
||||
:title="TUITranslateService.t('Profile.性别选择')"
|
||||
@onClose="closeBottomPopup"
|
||||
@onSubmit="submitEditProfileBox"
|
||||
>
|
||||
<ul class="gender-list">
|
||||
<li
|
||||
class="gender-list-li"
|
||||
v-for="(value, key) in genderLabelList"
|
||||
:key="key"
|
||||
@click="changeCurrentEditProfile('gender', key)"
|
||||
>
|
||||
<div
|
||||
:class="[
|
||||
'gender-list-item',
|
||||
currentEditProfile.gender === key && 'gender-list-item-selected',
|
||||
]"
|
||||
@click="changeCurrentEditProfile('gender', key)"
|
||||
>
|
||||
<input
|
||||
v-if="isPC"
|
||||
class="gender-list-radio"
|
||||
type="radio"
|
||||
name="gender"
|
||||
:value="key"
|
||||
:checked="currentEditProfile.gender === key"
|
||||
/>
|
||||
{{ TUITranslateService.t(`Profile.${value}`) }}
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</EditProfilePopup>
|
||||
</div>
|
||||
<div class="edit-form-item">
|
||||
<div class="form-label">{{ TUITranslateService.t("Profile.出生年月") }}</div>
|
||||
<div v-if="isH5" class="form-info" @click="showBottomPopup('birthday')">
|
||||
<div class="form-info-content">{{ birthdayObj.format }}</div>
|
||||
<Icon class="form-info-arrow" :file="rightArrowIcon" size="14px"></Icon>
|
||||
</div>
|
||||
<EditProfilePopup
|
||||
class="form-item"
|
||||
:show="isPC || currentBottomPopupShow === 'birthday'"
|
||||
:title="TUITranslateService.t('Profile.请选择出生日期')"
|
||||
@onClose="closeBottomPopup"
|
||||
@onSubmit="submitEditProfileBox"
|
||||
>
|
||||
<div class="birthday-container">
|
||||
<DatePicker
|
||||
class="birthday-date-picker"
|
||||
type="single"
|
||||
rangeTableType="one"
|
||||
:startPlaceholder="TUITranslateService.t('Profile.请选择出生日期')"
|
||||
popupPosition="top"
|
||||
:defaultSingleDate="birthdayObj.obj"
|
||||
@pick="pickBirthday"
|
||||
>
|
||||
<template #end-icon>
|
||||
<Icon :file="calendarSVG" size="16px"></Icon>
|
||||
</template>
|
||||
</DatePicker>
|
||||
</div>
|
||||
</EditProfilePopup>
|
||||
</div>
|
||||
</div>
|
||||
<footer v-if="!isH5" class="edit-footer">
|
||||
<button class="btn-close" @click="closeEditProfileBox">
|
||||
{{ TUITranslateService.t("Profile.取消") }}
|
||||
</button>
|
||||
<button class="btn-save" @click="submitEditProfileBox">
|
||||
{{ TUITranslateService.t("Profile.保存") }}
|
||||
</button>
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ref, defineEmits } from "../TUIKit/adapter-vue";
|
||||
import TUIChatEngine, {
|
||||
TUITranslateService,
|
||||
TUIUserService,
|
||||
TUIStore,
|
||||
StoreName,
|
||||
} from "@tencentcloud/chat-uikit-engine";
|
||||
import dayjs, { Dayjs } from "dayjs";
|
||||
import { Toast, TOAST_TYPE } from "../TUIKit/components/common/Toast/index";
|
||||
import EditProfilePopup from "./EditProfilePopup.vue";
|
||||
import DatePicker from "../TUIKit/components/common/DatePicker";
|
||||
import Avatar from "../TUIKit/components/common/Avatar/index.vue";
|
||||
import Icon from "../TUIKit/components/common/Icon.vue";
|
||||
import backSVG from "../TUIKit/assets/icon/back.svg";
|
||||
import rightArrowIcon from "../TUIKit/assets/icon/right-icon.svg";
|
||||
import calendarSVG from "../assets/icon/calendar.svg";
|
||||
import { IUserProfile } from "../TUIKit/interface";
|
||||
import { isH5, isPC } from "../TUIKit/utils/env";
|
||||
import { enableSampleTaskStatus } from "../TUIKit/utils/enableSampleTaskStatus";
|
||||
|
||||
const emits = defineEmits(["closeEditProfileBox"]);
|
||||
// config
|
||||
const avatarListBaseUrl = "https://im.sdk.qcloud.com/download/tuikit-resource/avatar/avatar_";
|
||||
const avatarList = ["1.png", "2.png", "3.png", "4.png", "5.png", "6.png"].map(
|
||||
(url: string) => avatarListBaseUrl + url
|
||||
);
|
||||
const genderLabelList: {
|
||||
[propsName: string]: string;
|
||||
} = {
|
||||
[TUIChatEngine.TYPES.GENDER_MALE]: "男",
|
||||
[TUIChatEngine.TYPES.GENDER_FEMALE]: "女",
|
||||
[TUIChatEngine.TYPES.GENDER_UNKNOWN]: "不显示",
|
||||
};
|
||||
const userProfile = ref<IUserProfile>({});
|
||||
// current edit value
|
||||
const currentEditProfile = ref<IUserProfile>({
|
||||
avatar: userProfile.value?.avatar,
|
||||
nick: userProfile.value?.nick,
|
||||
selfSignature: userProfile.value?.selfSignature,
|
||||
gender: userProfile.value?.gender,
|
||||
birthday: userProfile.value?.birthday,
|
||||
});
|
||||
const birthdayObj = ref<{ obj: typeof Dayjs; format: string; value: number }>({});
|
||||
const currentBottomPopupShow = ref<string>("");
|
||||
|
||||
TUIStore.watch(StoreName.USER, {
|
||||
userProfile: (userProfileData: IUserProfile) => {
|
||||
userProfile.value = userProfileData;
|
||||
const { avatar, nick, selfSignature, gender, birthday } = userProfileData;
|
||||
currentEditProfile.value = { avatar, nick, selfSignature, gender, birthday };
|
||||
birthdayObj.value = generateBirthdayObj(userProfileData.birthday);
|
||||
},
|
||||
});
|
||||
|
||||
function generateBirthdayObj(YYYYMMDD: any) {
|
||||
let birthdayDayjsObj: typeof Dayjs = null;
|
||||
let birthdayFormat = "";
|
||||
if (YYYYMMDD && typeof YYYYMMDD === "number") {
|
||||
birthdayDayjsObj = dayjs(YYYYMMDD.toString(), "YYYYMMDD");
|
||||
birthdayFormat = birthdayDayjsObj.format("YYYY/MM/DD");
|
||||
}
|
||||
return {
|
||||
obj: birthdayDayjsObj,
|
||||
format: birthdayFormat,
|
||||
value: userProfile.value?.birthday || 0,
|
||||
};
|
||||
}
|
||||
|
||||
function showBottomPopup(key: string) {
|
||||
currentBottomPopupShow.value = key;
|
||||
}
|
||||
function closeBottomPopup() {
|
||||
currentBottomPopupShow.value = "";
|
||||
}
|
||||
|
||||
function pickBirthday(date: typeof Dayjs) {
|
||||
currentEditProfile.value.birthday = parseInt(date.format("YYYYMMDD"), 10);
|
||||
}
|
||||
|
||||
function changeCurrentEditProfile(key: keyof IUserProfile, value: any) {
|
||||
if (Object.prototype.hasOwnProperty.call(currentEditProfile.value, key)) {
|
||||
currentEditProfile.value[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
function closeEditProfileBox() {
|
||||
emits("closeEditProfileBox");
|
||||
}
|
||||
|
||||
function submitEditProfileBox() {
|
||||
let isNickModified = currentEditProfile.value.nick !== userProfile.value.nick;
|
||||
const profileOptions = Object.fromEntries(
|
||||
Object.entries(currentEditProfile.value).filter(([key, value]) => {
|
||||
return value !== null && value !== undefined && value !== "";
|
||||
})
|
||||
);
|
||||
TUIUserService.updateMyProfile(profileOptions)
|
||||
.then(() => {
|
||||
isNickModified && enableSampleTaskStatus("modifyNickName");
|
||||
Toast({
|
||||
message: TUITranslateService.t("Profile.修改个人资料成功"),
|
||||
type: TOAST_TYPE.SUCCESS,
|
||||
});
|
||||
isPC && closeEditProfileBox();
|
||||
})
|
||||
.catch((error: Error) => {
|
||||
Toast({
|
||||
message: TUITranslateService.t("Profile.修改个人资料失败") + error?.message,
|
||||
type: TOAST_TYPE.ERROR,
|
||||
});
|
||||
isPC && closeEditProfileBox();
|
||||
});
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
@import "../styles/common.scss";
|
||||
.edit-profile-container {
|
||||
@extend .container;
|
||||
font-size: 14px;
|
||||
.edit-profile-box {
|
||||
@extend .box;
|
||||
align-items: stretch;
|
||||
.edit-form {
|
||||
flex: 1;
|
||||
@include flex(column, flex-start, stretch);
|
||||
.edit-form-item {
|
||||
@include flex(row, flex-start, center);
|
||||
min-height: 54px;
|
||||
padding: 10px;
|
||||
.form-label {
|
||||
box-sizing: border-box;
|
||||
width: 70px;
|
||||
margin-right: 20px;
|
||||
color: #333;
|
||||
}
|
||||
.form-item {
|
||||
@include flex(row, flex-start, stretch);
|
||||
.avatar-list {
|
||||
@include flex(row, space-between, stretch);
|
||||
.avatar-list-item {
|
||||
margin: 10px;
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
.avatar-list-item:first-child {
|
||||
margin-left: 0px;
|
||||
}
|
||||
.avatar-list-item-selected {
|
||||
border: 1px solid #006eff;
|
||||
color: #006eff;
|
||||
border-radius: 5px;
|
||||
}
|
||||
}
|
||||
.form-item-input {
|
||||
flex: 1;
|
||||
padding: 6px 10px;
|
||||
border: 1px solid rgba(131, 137, 153, 0.4);
|
||||
border-radius: 2px;
|
||||
line-height: 20px;
|
||||
color: #596174;
|
||||
}
|
||||
.gender-list {
|
||||
@include flex(row, space-between, center);
|
||||
.gender-list-li {
|
||||
@include flex(row);
|
||||
margin-right: 20px;
|
||||
.gender-list-item {
|
||||
@include flex(row);
|
||||
flex: 1;
|
||||
font-size: 14px;
|
||||
.gender-list-item-radio {
|
||||
margin: 0px 2px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.birthday-container {
|
||||
@include flex(row, space-between, stretch);
|
||||
flex: 1;
|
||||
padding: 6px 10px;
|
||||
border: 1px solid rgba(131, 137, 153, 0.4);
|
||||
.birthday-date-picker {
|
||||
@include flex(row);
|
||||
flex: 1;
|
||||
height: 20px;
|
||||
:deep(.tui-date-picker-input) {
|
||||
@include flex(row, flex-start);
|
||||
flex: 1;
|
||||
}
|
||||
:deep(.tui-date-picker-input-start) {
|
||||
padding: 2px 0px;
|
||||
text-align: start;
|
||||
font-size: 14px;
|
||||
&::placeholder {
|
||||
text-align: start;
|
||||
}
|
||||
}
|
||||
:deep(.tui-date-picker-dialog-container-one) {
|
||||
left: -220px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.edit-footer {
|
||||
@include flex(row, flex-end);
|
||||
.btn-close {
|
||||
@include btn-normal;
|
||||
margin-right: 10px;
|
||||
}
|
||||
.btn-save {
|
||||
@include btn-default;
|
||||
}
|
||||
.btn-close,
|
||||
.btn-save {
|
||||
width: 90px;
|
||||
height: 30px;
|
||||
padding: 2px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.edit-profile-container-pc {
|
||||
.edit-profile-box {
|
||||
width: 495px;
|
||||
height: 472px;
|
||||
border-radius: 10px;
|
||||
padding: 20px;
|
||||
.edit-form {
|
||||
.edit-form-item {
|
||||
.form-item {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.title {
|
||||
justify-content: flex-start;
|
||||
padding: 0px;
|
||||
}
|
||||
}
|
||||
.edit-profile-container-h5 {
|
||||
@extend .edit-profile-container;
|
||||
.edit-profile-box {
|
||||
@extend .box-h5;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: #efefef;
|
||||
.title {
|
||||
background-color: #ffffff;
|
||||
}
|
||||
.edit-form {
|
||||
.edit-form-item {
|
||||
background-color: #ffffff;
|
||||
.form-label {
|
||||
font-size: 16px;
|
||||
color: #000000;
|
||||
width: 80px;
|
||||
}
|
||||
.form-info {
|
||||
@include flex(row, flex-end, stretch);
|
||||
.form-info-content {
|
||||
@include single-line-ellipsis(auto);
|
||||
}
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
font-size: 16px;
|
||||
color: rgba(151, 151, 151, 1);
|
||||
.form-info-arrow {
|
||||
margin-left: 2px;
|
||||
}
|
||||
}
|
||||
.form-item {
|
||||
flex: none;
|
||||
.avatar-list,
|
||||
.form-item-input,
|
||||
.gender-list,
|
||||
.birthday-container {
|
||||
margin: 0 20px;
|
||||
}
|
||||
.avatar-list {
|
||||
.avatar-list-item {
|
||||
margin: 10px 0px;
|
||||
}
|
||||
}
|
||||
.gender-list {
|
||||
.gender-list-li {
|
||||
margin: 0px;
|
||||
.gender-list-item {
|
||||
border: 1px solid rgba(221, 221, 221, 1);
|
||||
font-size: 16px;
|
||||
border-radius: 5px;
|
||||
width: 120px;
|
||||
height: 40px;
|
||||
&-selected {
|
||||
border: 1px solid #006eff;
|
||||
color: #006eff;
|
||||
border-radius: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.form-item-input {
|
||||
padding: 14px 10px;
|
||||
font-size: 16px;
|
||||
border: 0px;
|
||||
background-color: rgba(248, 248, 248, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
.edit-form-space {
|
||||
box-sizing: border-box;
|
||||
height: 10px;
|
||||
padding: 0px;
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
38
src/views/im/components/EditProfilePopup.vue
Normal file
@ -0,0 +1,38 @@
|
||||
<template>
|
||||
<BottomPopup
|
||||
class="form-item-bottom-popup"
|
||||
:show="props.show"
|
||||
:title="props.title"
|
||||
:showHeaderCloseButton="true"
|
||||
:showFooterSubmitButton="true"
|
||||
:submitButtonContent="TUITranslateService.t('确认')"
|
||||
borderRadius="20px"
|
||||
@onClose="onClose"
|
||||
@onSubmit="onSubmit"
|
||||
>
|
||||
<slot></slot>
|
||||
</BottomPopup>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { withDefaults, defineProps, defineEmits } from "../TUIKit/adapter-vue";
|
||||
import { TUITranslateService } from "@tencentcloud/chat-uikit-engine";
|
||||
import BottomPopup from "../TUIKit/components/common/BottomPopup";
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
show: boolean;
|
||||
title: string;
|
||||
}>(),
|
||||
{
|
||||
show: false,
|
||||
title: "",
|
||||
}
|
||||
);
|
||||
const emits = defineEmits(["onClose", "onSubmit"]);
|
||||
function onClose() {
|
||||
emits("onClose");
|
||||
}
|
||||
function onSubmit() {
|
||||
emits("onSubmit");
|
||||
}
|
||||
</script>
|
||||
<style scoped lang="scss"></style>
|
147
src/views/im/components/Header.vue
Normal file
@ -0,0 +1,147 @@
|
||||
<template>
|
||||
<div class="header">
|
||||
<div class="left">
|
||||
<div v-if="showType === 'menu'" class="menu" @click="toggleMenu">
|
||||
<Icon :file="menuPNG" />
|
||||
<div class="menu-guide">
|
||||
{{ TUITranslateService.t('使用指引') }}
|
||||
</div>
|
||||
</div>
|
||||
<div v-else-if="showType === 'logo'" class="logo">
|
||||
<a :href="Link.im.url" target="_blank" class="logo">
|
||||
<img class="logo-img" src="../assets/image/txc-logo.svg" alt="" />
|
||||
<div class="logo-name label-tencent">{{ TUITranslateService.t('腾讯云') }}</div>
|
||||
<div class="logo-name label-im">{{ TUITranslateService.t('即时通信IM') }}</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="right">
|
||||
<el-dropdown @command="changeLanguage">
|
||||
<div class="dropdown">
|
||||
<Icon :file="globalPNG" />
|
||||
<div class="dropdown-label">
|
||||
{{ localeLabelMap[locale] }}
|
||||
</div>
|
||||
<Icon :file="arrowDownPNG" width="10px" height="5px" />
|
||||
</div>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item command="zh" class="language-item"> 简体中文 </el-dropdown-item>
|
||||
<el-dropdown-item command="en" class="language-item"> English </el-dropdown-item>
|
||||
<el-dropdown-item command="zh_tw" class="language-item"> 繁體中文 </el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { withDefaults, defineProps, defineEmits, ref } from '@/TUIKit/adapter-vue';
|
||||
import { TUITranslateService } from '@tencentcloud/chat-uikit-engine';
|
||||
import { TUICore, TUIConstants } from '@tencentcloud/tui-core';
|
||||
import Icon from '@/TUIKit/components/common/Icon.vue';
|
||||
import menuPNG from '@/views/im/icon/menu.png';
|
||||
import globalPNG from '@/views/im/icon/global.png';
|
||||
import arrowDownPNG from '@/views/im/icon/arrow-down.png';
|
||||
import { Link } from '@/utils/link';
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
showType: 'menu' | 'logo';
|
||||
defaultLanguage: string;
|
||||
}>(),
|
||||
{
|
||||
showType: 'logo',
|
||||
defaultLanguage: 'zh'
|
||||
}
|
||||
);
|
||||
const localeLabelMap: { [propsName: string]: string } = {
|
||||
zh: '简体中文',
|
||||
en: 'English',
|
||||
zh_tw: '繁體中文'
|
||||
};
|
||||
const emits = defineEmits(['toggleMenu', 'closeMenu', 'changeLanguage']);
|
||||
const locale = ref<string>(props.defaultLanguage);
|
||||
function toggleMenu() {
|
||||
emits('toggleMenu');
|
||||
}
|
||||
|
||||
function changeLanguage(value: string) {
|
||||
TUITranslateService.changeLanguage(value).then(() => {
|
||||
locale.value = value;
|
||||
emits('changeLanguage', locale.value);
|
||||
TUICore.notifyEvent(TUIConstants.TUITranslate.EVENT.LANGUAGE_CHANGED, TUIConstants.TUITranslate.EVENT_SUB_KEY.CHANGE_SUCCESS, {
|
||||
language: locale.value
|
||||
});
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
background: #fff;
|
||||
box-sizing: border-box;
|
||||
padding: 20px 34px;
|
||||
user-select: none;
|
||||
|
||||
.left {
|
||||
.menu,
|
||||
.logo {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
.menu {
|
||||
.menu-guide {
|
||||
margin-left: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
.logo {
|
||||
.logo-img {
|
||||
width: 30px;
|
||||
margin-right: 7px;
|
||||
}
|
||||
|
||||
.logo-name {
|
||||
font-family: PingFangSC-Regular;
|
||||
font-size: 18px;
|
||||
font-weight: 500;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.label-tencent {
|
||||
padding-right: 15px;
|
||||
border-right: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.label-im {
|
||||
padding-left: 15px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.right {
|
||||
.dropdown {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
|
||||
.dropdown-label {
|
||||
padding: 0 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
427
src/views/im/components/Menu.vue
Normal file
@ -0,0 +1,427 @@
|
||||
<template>
|
||||
<div :class="['menu', isH5 && 'menu-h5']">
|
||||
<div
|
||||
v-if="isPC"
|
||||
class="header header-border"
|
||||
>
|
||||
<div class="header-tencent-cloud">
|
||||
<img
|
||||
class="header-icon"
|
||||
src="../assets/image/txc-logo.svg"
|
||||
alt=""
|
||||
>
|
||||
<span class="header-name">{{ TUITranslateService.t("腾讯云") }}</span>
|
||||
</div>
|
||||
<div class="header-im header-name">
|
||||
{{ TUITranslateService.t("即时通信IM") }}
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-if="isH5"
|
||||
class="header header-guide"
|
||||
>
|
||||
<div class="header-name">
|
||||
{{ TUITranslateService.t("使用指引") }}
|
||||
</div>
|
||||
<div
|
||||
class="header-close"
|
||||
@click="closeMenu"
|
||||
>
|
||||
{{ TUITranslateService.t("关闭") }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="main">
|
||||
<div
|
||||
v-for="item in apkQRCodeList"
|
||||
:key="item.url"
|
||||
class="task"
|
||||
>
|
||||
<div class="task-title">
|
||||
{{ TUITranslateService.t(`Home.${item.label}`) }}
|
||||
</div>
|
||||
<div class="task-list qr-box">
|
||||
<img
|
||||
class="qr-code"
|
||||
:src="item.url"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div class="task">
|
||||
<div class="task-title">
|
||||
{{ TUITranslateService.t("Home.建议体验功能") }}
|
||||
</div>
|
||||
<div class="task-list">
|
||||
<div
|
||||
v-for="(taskLabel, taskKey) in taskLabelMap"
|
||||
:key="taskKey"
|
||||
:class="['task-list-item', tasks[taskKey] && 'task-list-item-done']"
|
||||
>
|
||||
<div class="task-list-item-label">
|
||||
{{ TUITranslateService.t(`Home.${taskLabel}`) }}
|
||||
</div>
|
||||
<div class="task-list-item-status">
|
||||
{{ TUITranslateService.t(tasks[taskKey] ? "Home.已完成" : "Home.待体验") }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="step">
|
||||
<div class="step-title">
|
||||
{{ TUITranslateService.t("Home.用UI组件快速集成") }}
|
||||
</div>
|
||||
<div class="step-list">
|
||||
<div
|
||||
v-for="(step, index) in stepList"
|
||||
:key="step.label"
|
||||
class="step-list-item"
|
||||
>
|
||||
<div class="step-list-item-index">
|
||||
{{ index + 1 }}
|
||||
</div>
|
||||
<a
|
||||
class="step-list-item-label"
|
||||
:href="step.url"
|
||||
target="_blank"
|
||||
>{{
|
||||
TUITranslateService.t(`Home.${step.label}`)
|
||||
}}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer">
|
||||
<div class="footer-card-list">
|
||||
<div
|
||||
v-for="advItem in advList"
|
||||
:key="advItem.label"
|
||||
class="footer-card"
|
||||
@click="openLink(advItem.url)"
|
||||
>
|
||||
<div class="footer-card-content">
|
||||
<div>{{ TUITranslateService.t(`Home.${advItem.label}`) }}</div>
|
||||
<div>{{ TUITranslateService.t(`Home.${advItem.subLabel}`) }}</div>
|
||||
</div>
|
||||
<div class="footer-card-button">
|
||||
{{ TUITranslateService.t(`Home.${advItem.btnText}`) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { defineEmits, onMounted, ref, onUnmounted } from '@/TUIKit/adapter-vue';
|
||||
import { TUITranslateService, TUIStore, StoreName } from '@tencentcloud/chat-uikit-engine';
|
||||
import { Link } from '@/utils/link';
|
||||
import { isPC, isH5 } from '@/TUIKit/utils/env';
|
||||
import { deepCopy } from '@/TUIKit/components/TUIChat/utils/utils';
|
||||
|
||||
interface ITasks {
|
||||
[propsName: string]: boolean;
|
||||
}
|
||||
|
||||
const emits = defineEmits(['closeMenu']);
|
||||
const stepList = Link.stepList;
|
||||
const advList = Link.advList;
|
||||
const apkQRCodeList = Link.apkQRCodeList;
|
||||
const tasks = ref<ITasks>({
|
||||
sendMessage: false,
|
||||
revokeMessage: false,
|
||||
modifyNickName: false,
|
||||
groupChat: false,
|
||||
muteGroup: false,
|
||||
dismissGroup: false,
|
||||
call: false,
|
||||
searchCloudMessage: false,
|
||||
customerService: false,
|
||||
});
|
||||
|
||||
const taskLabelMap = {
|
||||
sendMessage: '发送一条消息',
|
||||
revokeMessage: '撤回一条消息',
|
||||
modifyNickName: '修改一次我的昵称',
|
||||
groupChat: '发起一个群聊',
|
||||
muteGroup: '开启一次群禁言',
|
||||
dismissGroup: '解散一个群聊',
|
||||
call: '发起一次通话',
|
||||
searchCloudMessage: '搜索一次消息',
|
||||
customerService: '进行一次客服会话',
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
TUIStore.watch(StoreName.APP, {
|
||||
tasks: setTasksValue,
|
||||
});
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
TUIStore.unwatch(StoreName.APP, {
|
||||
tasks: setTasksValue,
|
||||
});
|
||||
});
|
||||
|
||||
function setTasksValue(tasksValue: ITasks) {
|
||||
if (JSON.stringify(tasksValue) === '{}') {
|
||||
return;
|
||||
}
|
||||
tasks.value = deepCopy(tasksValue);
|
||||
}
|
||||
|
||||
function closeMenu() {
|
||||
emits('closeMenu');
|
||||
}
|
||||
|
||||
function openLink(url: string) {
|
||||
window.open(url);
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.menu,
|
||||
.header,
|
||||
.main,
|
||||
.footer {
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.menu {
|
||||
width: 300px;
|
||||
z-index: 100;
|
||||
background: rgb(255, 255, 255);
|
||||
box-shadow: 10px 20px 30px 0 rgba(56, 73, 90, 0.09);
|
||||
padding: 0 30px;
|
||||
user-select: none;
|
||||
overflow: auto;
|
||||
|
||||
.header {
|
||||
width: 100%;
|
||||
flex-direction: row;
|
||||
padding: 20px 0;
|
||||
|
||||
.header-tencent-cloud,
|
||||
.header-im {
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.header-tencent-cloud {
|
||||
padding-right: 20px;
|
||||
}
|
||||
|
||||
.header-im {
|
||||
padding-left: 20px;
|
||||
border-left: 1px solid rgb(221, 221, 221);
|
||||
}
|
||||
|
||||
.header-name {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
color: rgb(0, 0, 0);
|
||||
font-style: normal;
|
||||
font-family: PingFangSC-Regular;
|
||||
}
|
||||
|
||||
.header-icon {
|
||||
width: 30px;
|
||||
margin-right: 7px;
|
||||
}
|
||||
}
|
||||
|
||||
.header-border {
|
||||
border-bottom: 1px solid rgb(221, 221, 221);
|
||||
}
|
||||
|
||||
.header-guide {
|
||||
padding-bottom: 0;
|
||||
justify-content: space-between;
|
||||
|
||||
.header-name {
|
||||
font-family: PingFangSC-Medium;
|
||||
font-weight: 500;
|
||||
font-size: 20px;
|
||||
color: #000;
|
||||
line-height: 28px;
|
||||
}
|
||||
|
||||
.header-close {
|
||||
font-family: PingFangSC-Regular;
|
||||
font-weight: 400;
|
||||
color: #006eff;
|
||||
font-size: 18px;
|
||||
}
|
||||
}
|
||||
|
||||
.main {
|
||||
width: 100%;
|
||||
padding-bottom: 16px;
|
||||
font-size: 14px;
|
||||
font-family: PingFangSC-Regular;
|
||||
font-weight: 400;
|
||||
|
||||
.task,
|
||||
.step {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.task-title,
|
||||
.step-title {
|
||||
padding: 20px 0;
|
||||
font-size: 16px;
|
||||
font-family: PingFangSC-Medium;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.task-list-item,
|
||||
.step-list-item {
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
padding-bottom: 16px;
|
||||
}
|
||||
|
||||
.task {
|
||||
padding-bottom: 14px;
|
||||
border-bottom: 1px solid rgb(221, 221, 221);
|
||||
|
||||
.task-list-item {
|
||||
justify-content: space-between;
|
||||
|
||||
.task-list-item-label {
|
||||
color: rgb(181, 181, 181);
|
||||
}
|
||||
|
||||
.task-list-item-status {
|
||||
background-color: rgba(207, 215, 224);
|
||||
border-radius: 2px;
|
||||
padding: 0 5px;
|
||||
color: rgb(255, 255, 255);
|
||||
text-wrap: nowrap;
|
||||
height: fit-content;
|
||||
align-self: center;
|
||||
}
|
||||
}
|
||||
|
||||
.task-list-item-done {
|
||||
.task-list-item-label {
|
||||
color: rgb(51, 51, 51);
|
||||
}
|
||||
|
||||
.task-list-item-status {
|
||||
background-color: rgb(20, 122, 255);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.step-list-item {
|
||||
justify-content: flex-start;
|
||||
|
||||
.step-list-item-index {
|
||||
background: rgba(81, 94, 136, 0.04);
|
||||
border: 1px solid #d2d6dc;
|
||||
color: rgb(210, 214, 220);
|
||||
display: inline-flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border-radius: 50%;
|
||||
font-size: 11.67px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.step-list-item-label {
|
||||
line-height: 22px;
|
||||
color: #147aff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.footer {
|
||||
width: 100%;
|
||||
margin-top: auto;
|
||||
margin-bottom: 30px;
|
||||
|
||||
.footer-card-list {
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
|
||||
.footer-card {
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
border: 1px solid #96c3ff;
|
||||
border-radius: 4px;
|
||||
background-image: url("../assets/image/adv-background.svg");
|
||||
background-size: cover;
|
||||
|
||||
.footer-card-content {
|
||||
padding: 10px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
.footer-card-button {
|
||||
margin-right: 10px;
|
||||
padding: 1px 7px;
|
||||
background: #147aff;
|
||||
border-radius: 0.88rem;
|
||||
box-shadow: 0 0.19rem 0.25rem 0 rgba(255, 255, 255, 0.7),
|
||||
0 0.13rem 0.38rem 0 rgba(20, 122, 255, 0.55);
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.qr-box {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
.qr-code {
|
||||
max-width: 150px;
|
||||
max-height: 150px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.menu-h5 {
|
||||
flex: 1;
|
||||
border-radius: 12px 12px 0 0;
|
||||
margin-top: 200px;
|
||||
height: calc(100% - 200px);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
|
||||
.header-guide {
|
||||
position: sticky;
|
||||
padding: 15px 30px;
|
||||
}
|
||||
|
||||
.main {
|
||||
flex: 1;
|
||||
overflow: auto;
|
||||
padding: 0 30px;
|
||||
}
|
||||
|
||||
.footer {
|
||||
margin: 10px 0;
|
||||
padding: 0 30px;
|
||||
}
|
||||
}
|
||||
</style>
|
256
src/views/im/components/NavBar.vue
Normal file
@ -0,0 +1,256 @@
|
||||
<template>
|
||||
<div :class="['navbar', isH5 && 'navbar-h5']">
|
||||
<div v-if="isPC" class="header">
|
||||
<div class="user-info">
|
||||
<Avatar useSkeletonAnimation :url="avatar" />
|
||||
<div class="user-info-main">
|
||||
<slot name="profile"></slot>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="navbar-list">
|
||||
<div
|
||||
v-for="item in navBarListForShow"
|
||||
:key="item.name"
|
||||
:class="['navbar-list-item', currentSelectedNav === item.name && 'navbar-list-item-selected']"
|
||||
@click="switchNavBar(item.name)"
|
||||
>
|
||||
<Icon
|
||||
:file="(currentSelectedNav === item.name && item.selectedIcon) || (isPC && item.icon) || (!isPC && item.h5Icon)"
|
||||
:width="isH5 ? '20px' : '24px'"
|
||||
:height="isH5 ? '20px' : '24px'"
|
||||
></Icon>
|
||||
<div v-if="isH5" class="navbar-list-item-name">
|
||||
{{ TUITranslateService.t(`Home.${item.label}`) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="isPC" class="footer">
|
||||
<div class="setting">
|
||||
<Icon :file="settingPNG" @click="toggleSetting" @mousedown.stop></Icon>
|
||||
<div v-if="isSettingShow" class="setting-more">
|
||||
<slot name="setting"></slot>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, defineEmits, watch, withDefaults, defineProps } from '@/TUIKit/adapter-vue';
|
||||
import { TUIStore, StoreName, TUITranslateService } from '@tencentcloud/chat-uikit-engine';
|
||||
import Icon from '@/TUIKit/components/common/Icon.vue';
|
||||
import Avatar from '@/TUIKit/components/common/Avatar/index.vue';
|
||||
import messageWebSVG from '@/views/im/icon/message.svg';
|
||||
import messageH5SVG from '@/views/im/icon/message-real.svg';
|
||||
import messageSelectedSVG from '@/views/im/icon/message-selected.svg';
|
||||
import relationWebSVG from '@/views/im/icon/relation.svg';
|
||||
import relationH5SVG from '@/views/im/icon/relation-real.svg';
|
||||
import relationSelectedSVG from '@/views/im/icon/relation-selected.svg';
|
||||
import profileH5SVG from '@/views/im/icon/profile.svg';
|
||||
import profileSelectedSVG from '@/views/im/icon/profile-selected.svg';
|
||||
import settingPNG from '@/views/im/icon/setting.png';
|
||||
import { IUserProfile } from '@/TUIKit/interface';
|
||||
import { isPC, isH5 } from '@/TUIKit/utils/env';
|
||||
|
||||
export interface INavBarItem {
|
||||
icon: any;
|
||||
h5Icon: any;
|
||||
selectedIcon: any;
|
||||
name: string;
|
||||
label: string;
|
||||
}
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
currentNavBar: string;
|
||||
isSettingShow: boolean;
|
||||
}>(),
|
||||
{
|
||||
currentNavBar: () => 'message',
|
||||
isSettingShow: false
|
||||
}
|
||||
);
|
||||
|
||||
const emits = defineEmits(['update:currentNavBar', 'update:isSettingShow']);
|
||||
|
||||
const currentSettingStatus = ref<boolean>(false);
|
||||
const currentSelectedNav = ref(props.currentNavBar);
|
||||
const navBarListForShow = computed<Array<INavBarItem>>(() => {
|
||||
return isPC ? navBarList.filter((item: INavBarItem) => item.name !== 'profile') : navBarList;
|
||||
});
|
||||
const avatar = ref<string>('');
|
||||
|
||||
TUIStore.watch(StoreName.USER, {
|
||||
userProfile: (userProfileData: IUserProfile) => {
|
||||
avatar.value = userProfileData?.avatar || '';
|
||||
}
|
||||
});
|
||||
|
||||
const navBarList: Array<INavBarItem> = [
|
||||
{
|
||||
icon: messageWebSVG,
|
||||
h5Icon: messageH5SVG,
|
||||
selectedIcon: messageSelectedSVG,
|
||||
name: 'message',
|
||||
label: '消息'
|
||||
},
|
||||
{
|
||||
icon: relationWebSVG,
|
||||
h5Icon: relationH5SVG,
|
||||
selectedIcon: relationSelectedSVG,
|
||||
name: 'relation',
|
||||
label: '通讯录'
|
||||
},
|
||||
{
|
||||
icon: profileH5SVG,
|
||||
h5Icon: profileH5SVG,
|
||||
selectedIcon: profileSelectedSVG,
|
||||
name: 'profile',
|
||||
label: '个人中心'
|
||||
}
|
||||
];
|
||||
|
||||
function toggleSetting() {
|
||||
currentSettingStatus.value = !currentSettingStatus.value;
|
||||
emits('update:isSettingShow', currentSettingStatus.value);
|
||||
}
|
||||
|
||||
function switchNavBar(name: string) {
|
||||
currentSelectedNav.value = name;
|
||||
emits('update:currentNavBar', name);
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.currentNavBar,
|
||||
() => {
|
||||
currentSelectedNav.value = props.currentNavBar;
|
||||
},
|
||||
{
|
||||
immediate: true
|
||||
}
|
||||
);
|
||||
watch(
|
||||
() => props.isSettingShow,
|
||||
() => {
|
||||
currentSettingStatus.value = props.isSettingShow;
|
||||
},
|
||||
{
|
||||
immediate: true
|
||||
}
|
||||
);
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.navbar {
|
||||
box-sizing: border-box;
|
||||
width: 60px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 56px 0 17px;
|
||||
background: #e8e8e9;
|
||||
user-select: none;
|
||||
|
||||
.navbar-list {
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
|
||||
.navbar-list-item {
|
||||
padding: 13px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.navbar-list-item-selected {
|
||||
background: #ddd;
|
||||
}
|
||||
}
|
||||
.header,
|
||||
.footer {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
.header {
|
||||
.user-info {
|
||||
padding: 12px;
|
||||
position: relative;
|
||||
.avatar {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
&:hover {
|
||||
.user-info-main {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
.user-info-main {
|
||||
width: 100%;
|
||||
display: none;
|
||||
position: absolute;
|
||||
min-width: 165px;
|
||||
max-width: 200px;
|
||||
top: 0;
|
||||
left: 100%;
|
||||
z-index: 5;
|
||||
padding: 14px 20px;
|
||||
border-radius: 0 4px 4px 0;
|
||||
background: #fff;
|
||||
box-shadow: 0 1px 10px 0 rgba(2, 16, 43, 0.15);
|
||||
}
|
||||
}
|
||||
}
|
||||
.footer {
|
||||
.setting {
|
||||
cursor: pointer;
|
||||
padding: 12px;
|
||||
position: relative;
|
||||
flex: 1;
|
||||
.setting-more {
|
||||
background: #fff;
|
||||
box-shadow: 0 1px 10px 0 rgba(2, 16, 43, 0.15);
|
||||
min-width: 11.25rem;
|
||||
border-radius: 0 4px 4px 0;
|
||||
position: absolute;
|
||||
bottom: 10px;
|
||||
left: 100%;
|
||||
z-index: 9999;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.navbar-h5 {
|
||||
padding: 0px;
|
||||
flex-direction: row;
|
||||
flex: 1;
|
||||
box-shadow: 0 0 18px 0 #f0f6ff;
|
||||
border-radius: 9px;
|
||||
overflow: hidden;
|
||||
.navbar-list {
|
||||
flex-direction: row;
|
||||
background: #ebf0f6;
|
||||
justify-content: space-around;
|
||||
.navbar-list-item {
|
||||
flex: 1;
|
||||
padding: 10px;
|
||||
.navbar-list-item-name {
|
||||
text-align: center;
|
||||
padding-top: 4px;
|
||||
font-size: 12px;
|
||||
color: #a0a3a6;
|
||||
}
|
||||
}
|
||||
.navbar-list-item-selected {
|
||||
background-color: inherit;
|
||||
.navbar-list-item-name {
|
||||
color: #006eff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
423
src/views/im/components/Profile.vue
Normal file
@ -0,0 +1,423 @@
|
||||
<template>
|
||||
<div :class="['TUI-profile', !isPC && 'TUI-profile-h5']">
|
||||
<div v-if="displayType !== 'setting'" :class="['TUI-profile-basic', !isPC && 'TUI-profile-h5-basic']">
|
||||
<img
|
||||
:class="['TUI-profile-basic-avatar', !isPC && 'TUI-profile-h5-basic-avatar']"
|
||||
:src="userProfile.avatar || 'https://web.sdk.qcloud.com/component/TUIKit/assets/avatar_21.png'"
|
||||
/>
|
||||
<div :class="['TUI-profile-basic-info', !isPC && 'TUI-profile-h5-basic-info']">
|
||||
<div :class="['TUI-profile-basic-info-nick', !isPC && 'TUI-profile-h5-basic-info-nick']">
|
||||
{{ userProfile.nick || '-' }}
|
||||
</div>
|
||||
<div :class="['TUI-profile-basic-info-id', !isPC && 'TUI-profile-h5-basic-info-id']">
|
||||
<label :class="['TUI-profile-basic-info-id-label', !isPC && 'TUI-profile-h5-basic-info-id-label']"
|
||||
>{{ TUITranslateService.t('Profile.用户ID') }}:</label
|
||||
>
|
||||
<div :class="['TUI-profile-basic-info-id-value', !isPC && 'TUI-profile-h5-basic-info-id-value']">
|
||||
{{ userProfile.userID }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-if="displayType !== 'profile' && (!isPC || (showSetting && !hideSetting))"
|
||||
ref="settingDomRef"
|
||||
:class="['TUI-profile-setting', !isPC && 'TUI-profile-h5-setting']"
|
||||
@click.stop
|
||||
>
|
||||
<div
|
||||
v-for="item in settingList"
|
||||
:key="item.value"
|
||||
:class="['TUI-profile-setting-item', !isPC && 'TUI-profile-h5-setting-item', item.value === 'exit' && 'TUI-profile-h5-setting-item-exit']"
|
||||
>
|
||||
<div :class="['TUI-profile-setting-item-label', !isPC && 'TUI-profile-h5-setting-item-label']" @click="handleSettingListItemOnClick(item)">
|
||||
<div :class="['label-left']">
|
||||
<div :class="['label-title']">
|
||||
{{ TUITranslateService.t(`Profile.${item.label}`) }}
|
||||
</div>
|
||||
<div v-if="item.children && !isPC && item.childrenShowType === 'switch'" :class="['label-desc']">
|
||||
{{ item.value }}
|
||||
</div>
|
||||
</div>
|
||||
<div :class="['label-right']">
|
||||
<div
|
||||
v-if="!isPC && item.children && item.selectedChild && item.childrenShowType === 'bottomPopup'"
|
||||
:class="['TUI-profile-setting-item-label-value', !isPC && 'TUI-profile-h5-setting-item-label-value']"
|
||||
>
|
||||
{{ TUITranslateService.t(`Profile.${item?.children[item.selectedChild]?.label}`) }}
|
||||
</div>
|
||||
<Icon v-if="item.children" :file="rightArrowIcon" width="14px" height="14px" />
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="item.children && isPC" :class="['TUI-profile-setting-item-children', !isPC && 'TUI-profile-h5-setting-item-children']">
|
||||
<div
|
||||
v-for="child in item.children"
|
||||
:key="child.value"
|
||||
:class="['TUI-profile-setting-item-children-item', !isPC && 'TUI-profile-h5-setting-item-children-item']"
|
||||
@click="handleSettingListItemOnClick(child)"
|
||||
>
|
||||
<div :class="['TUI-profile-setting-item-children-item-label', !isPC && 'TUI-profile-h5-setting-item-children-item-label']">
|
||||
{{ TUITranslateService.t(`Profile.${child.label}`) }}
|
||||
</div>
|
||||
<Icon v-if="item.selectedChild === child.value" :file="selectedIcon" width="14px" height="14px" />
|
||||
</div>
|
||||
</div>
|
||||
<!-- <BottomPopup
|
||||
v-if="item.children && !isPC && item.childrenShowType === 'bottomPopup'"
|
||||
:show="item.showChildren"
|
||||
@onClose="item.showChildren = false"
|
||||
>
|
||||
<div
|
||||
v-for="child in item.children"
|
||||
:key="child.value"
|
||||
:class="['TUI-profile-setting-item-bottom-popup', !isPC && 'TUI-profile-h5-setting-item-bottom-popup']"
|
||||
@click="handleSettingListItemOnClick(child)"
|
||||
>
|
||||
{{ TUITranslateService.t(`Profile.${child.label}`) }}
|
||||
</div>
|
||||
</BottomPopup>-->
|
||||
</div>
|
||||
</div>
|
||||
<!-- <AboutDialog v-if="isAboutBoxShow" :userProfile="userProfile" @closeAboutBox="closeAboutBox" />
|
||||
<EditProfileDialog v-if="isEditProfileBoxShow" @closeEditProfileBox="closeEditProfileBox" />-->
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, watch, nextTick, onMounted } from '@/TUIKit/adapter-vue';
|
||||
import TUIChatEngine, { TUITranslateService, TUIUserService, TUIStore, StoreName, TUIChatService } from '@tencentcloud/chat-uikit-engine';
|
||||
import { TUILogin } from '@tencentcloud/tui-core';
|
||||
import { Toast, TOAST_TYPE } from '@/TUIKit/components/common/Toast/index';
|
||||
import BottomPopup from '@/TUIKit/components/common/BottomPopup/index.vue';
|
||||
import Icon from '@/TUIKit/components/common/Icon.vue';
|
||||
/*import AboutDialog from '../components/About.vue';
|
||||
import EditProfileDialog from '../components/EditProfile.vue';*/
|
||||
import rightArrowIcon from '@/TUIKit/assets/icon/right-icon.svg';
|
||||
import selectedIcon from '@/TUIKit/assets/icon/selected.svg';
|
||||
import { IUserProfile } from '@/TUIKit/interface';
|
||||
import { isPC } from '@/TUIKit/utils/env';
|
||||
import { deepCopy } from '@/TUIKit/components/TUIChat/utils/utils';
|
||||
import { translator } from '@/TUIKit/components/TUIChat/utils/translation';
|
||||
|
||||
const props = defineProps({
|
||||
displayType: {
|
||||
type: String,
|
||||
default: 'profile' // "profile"/"setting"/"all"
|
||||
},
|
||||
showSetting: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
});
|
||||
const router = useRouter();
|
||||
const emits = defineEmits(['update:showSetting']);
|
||||
const settingDomRef = ref();
|
||||
const userProfile = ref<IUserProfile>({});
|
||||
const isAboutBoxShow = ref<boolean>(false);
|
||||
const isEditProfileBoxShow = ref<boolean>(false);
|
||||
const hideSetting = ref<boolean>(false);
|
||||
const settingList = ref<{
|
||||
[propsName: string]: {
|
||||
value: string;
|
||||
label: string;
|
||||
onClick?: any;
|
||||
// children related
|
||||
selectedChild?: string;
|
||||
childrenShowType?: string; // "bottomPopup"/"switch"
|
||||
showChildren?: boolean;
|
||||
children?: {
|
||||
[propsName: string]: {
|
||||
value: string;
|
||||
label: string;
|
||||
onClick?: any;
|
||||
};
|
||||
};
|
||||
};
|
||||
}>({
|
||||
editProfile: {
|
||||
value: 'editProfile',
|
||||
label: '编辑资料',
|
||||
onClick: () => {
|
||||
hideSetting.value = true;
|
||||
isEditProfileBoxShow.value = true;
|
||||
}
|
||||
},
|
||||
allowType: {
|
||||
value: 'allowType',
|
||||
label: '加我为好友时',
|
||||
selectedChild: '',
|
||||
childrenShowType: 'bottomPopup',
|
||||
showChildren: false,
|
||||
onClick: (item: any) => {
|
||||
if (!isPC) {
|
||||
item.showChildren = true;
|
||||
}
|
||||
},
|
||||
children: {
|
||||
[TUIChatEngine.TYPES.ALLOW_TYPE_ALLOW_ANY]: {
|
||||
value: TUIChatEngine.TYPES.ALLOW_TYPE_ALLOW_ANY,
|
||||
label: '同意任何用户加好友',
|
||||
onClick: (item: any) => {
|
||||
switchAllowType(item.value);
|
||||
}
|
||||
},
|
||||
[TUIChatEngine.TYPES.ALLOW_TYPE_NEED_CONFIRM]: {
|
||||
value: TUIChatEngine.TYPES.ALLOW_TYPE_NEED_CONFIRM,
|
||||
label: '需要验证',
|
||||
onClick: (item: any) => {
|
||||
switchAllowType(item.value);
|
||||
}
|
||||
},
|
||||
[TUIChatEngine.TYPES.ALLOW_TYPE_DENY_ANY]: {
|
||||
value: TUIChatEngine.TYPES.ALLOW_TYPE_DENY_ANY,
|
||||
label: '拒绝任何人加好友',
|
||||
onClick: (item: any) => {
|
||||
switchAllowType(item.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
displayMessageReadReceipt: {
|
||||
value: 'displayMessageReadReceipt',
|
||||
label: '消息阅读状态',
|
||||
selectedChild: 'userLevelReadReceiptOpen',
|
||||
childrenShowType: 'bottomPopup',
|
||||
showChildren: false,
|
||||
onClick(item: any) {
|
||||
if (!isPC) {
|
||||
item.showChildren = true;
|
||||
}
|
||||
},
|
||||
children: {
|
||||
userLevelReadReceiptOpen: {
|
||||
value: 'userLevelReadReceiptOpen',
|
||||
label: '开启',
|
||||
onClick() {
|
||||
switchEnableUserLevelReadReceipt(true);
|
||||
}
|
||||
},
|
||||
userLevelReadReceiptClose: {
|
||||
value: 'userLevelReadReceiptClose',
|
||||
label: '关闭',
|
||||
onClick() {
|
||||
switchEnableUserLevelReadReceipt(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
displayOnlineStatus: {
|
||||
value: 'displayOnlineStatus',
|
||||
label: '显示在线状态',
|
||||
selectedChild: 'userLevelOnlineStatusOpen',
|
||||
childrenShowType: 'bottomPopup',
|
||||
showChildren: false,
|
||||
onClick(item: any) {
|
||||
if (!isPC) {
|
||||
item.showChildren = true;
|
||||
}
|
||||
},
|
||||
children: {
|
||||
userLevelOnlineStatusOpen: {
|
||||
value: 'userLevelOnlineStatusOpen',
|
||||
label: '开启',
|
||||
onClick() {
|
||||
switchUserLevelOnlineStatus(true);
|
||||
}
|
||||
},
|
||||
userLevelOnlineStatusClose: {
|
||||
value: 'userLevelOnlineStatusClose',
|
||||
label: '关闭',
|
||||
onClick() {
|
||||
switchUserLevelOnlineStatus(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
translateLanguage: {
|
||||
value: 'translateLanguage',
|
||||
label: '翻译语言',
|
||||
selectedChild: 'zh',
|
||||
childrenShowType: 'bottomPopup',
|
||||
showChildren: false,
|
||||
onClick(item: any) {
|
||||
if (!isPC) {
|
||||
item.showChildren = true;
|
||||
}
|
||||
},
|
||||
children: {
|
||||
zh: {
|
||||
value: 'zh',
|
||||
label: 'zh',
|
||||
onClick() {
|
||||
switchTranslationTargetLanguage('zh');
|
||||
}
|
||||
},
|
||||
en: {
|
||||
value: 'en',
|
||||
label: 'en',
|
||||
onClick() {
|
||||
switchTranslationTargetLanguage('en');
|
||||
}
|
||||
},
|
||||
jp: {
|
||||
value: 'jp',
|
||||
label: 'jp',
|
||||
onClick() {
|
||||
switchTranslationTargetLanguage('jp');
|
||||
}
|
||||
},
|
||||
kr: {
|
||||
value: 'kr',
|
||||
label: 'kr',
|
||||
onClick() {
|
||||
switchTranslationTargetLanguage('kr');
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
about: {
|
||||
value: 'about',
|
||||
label: '关于腾讯云IM',
|
||||
selectedChild: '',
|
||||
childrenShowType: 'bottomPopup',
|
||||
showChildren: false,
|
||||
children: {},
|
||||
onClick: () => {
|
||||
hideSetting.value = true;
|
||||
isAboutBoxShow.value = true;
|
||||
}
|
||||
},
|
||||
exit: {
|
||||
value: 'exit',
|
||||
label: '退出登录',
|
||||
onClick: () => {
|
||||
TUILogin.logout().then(() => {
|
||||
router.push({ path: '/' });
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const handleSettingListItemOnClick = (item: any) => {
|
||||
if (item?.onClick && typeof item?.onClick === 'function') {
|
||||
item.onClick(item);
|
||||
}
|
||||
};
|
||||
|
||||
const closeAboutBox = () => {
|
||||
isAboutBoxShow.value = false;
|
||||
emits('update:showSetting', false);
|
||||
};
|
||||
|
||||
const closeEditProfileBox = () => {
|
||||
isEditProfileBoxShow.value = false;
|
||||
emits('update:showSetting', false);
|
||||
};
|
||||
|
||||
const updateMyProfile = (props: object) => {
|
||||
TUIUserService.updateMyProfile(props)
|
||||
.then(() => {
|
||||
Toast({
|
||||
message: '更新用户资料成功',
|
||||
type: TOAST_TYPE.SUCCESS
|
||||
});
|
||||
})
|
||||
.catch((err: any) => {
|
||||
console.warn('更新用户资料失败', err);
|
||||
Toast({
|
||||
message: '更新用户资料失败',
|
||||
type: TOAST_TYPE.ERROR
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
TUIStore.watch(StoreName.USER, {
|
||||
userProfile: (userProfileData: IUserProfile) => {
|
||||
userProfile.value = deepCopy(userProfileData);
|
||||
if (userProfile?.value?.allowType) {
|
||||
settingList.value.allowType.selectedChild = userProfile?.value?.allowType;
|
||||
}
|
||||
},
|
||||
displayMessageReadReceipt(isDisplay: boolean) {
|
||||
settingList.value.displayMessageReadReceipt.selectedChild = isDisplay ? 'userLevelReadReceiptOpen' : 'userLevelReadReceiptClose';
|
||||
},
|
||||
displayOnlineStatus(isOnlineStatusDisplay: boolean) {
|
||||
settingList.value.displayOnlineStatus.selectedChild = isOnlineStatusDisplay ? 'userLevelOnlineStatusOpen' : 'userLevelOnlineStatusClose';
|
||||
}
|
||||
});
|
||||
|
||||
// pc click outside
|
||||
let clickOutside = false;
|
||||
let clickInner = false;
|
||||
const onClickOutside = (component: any) => {
|
||||
document.addEventListener('mousedown', onClickDocument);
|
||||
component?.addEventListener && component?.addEventListener('mousedown', onClickTarget);
|
||||
};
|
||||
const onClickDocument = () => {
|
||||
clickOutside = true;
|
||||
if (!clickInner && clickOutside) {
|
||||
emits('update:showSetting', false);
|
||||
removeClickListener(settingDomRef.value);
|
||||
}
|
||||
clickOutside = false;
|
||||
clickInner = false;
|
||||
};
|
||||
const onClickTarget = () => {
|
||||
clickInner = true;
|
||||
};
|
||||
const removeClickListener = (component: any) => {
|
||||
document.removeEventListener('mousedown', onClickDocument);
|
||||
component?.removeEventListener && component?.removeEventListener('mousedown', onClickTarget);
|
||||
};
|
||||
|
||||
watch(
|
||||
() => props.showSetting,
|
||||
(newVal: any, oldVal: any) => {
|
||||
if (isPC && newVal && !oldVal) {
|
||||
nextTick(() => {
|
||||
onClickOutside(settingDomRef.value);
|
||||
});
|
||||
}
|
||||
},
|
||||
{
|
||||
immediate: true
|
||||
}
|
||||
);
|
||||
|
||||
onMounted(() => {
|
||||
// get user profile
|
||||
TUIUserService.getUserProfile().then((res: any) => {
|
||||
userProfile.value = res.data;
|
||||
});
|
||||
// get current target language when component mounted
|
||||
const lang = TUIStore.getData(StoreName.USER, 'targetLanguage');
|
||||
if (lang) {
|
||||
settingList.value.translateLanguage.selectedChild = lang;
|
||||
}
|
||||
});
|
||||
|
||||
function switchAllowType(value: string) {
|
||||
updateMyProfile({ allowType: value });
|
||||
settingList.value.allowType.showChildren = false;
|
||||
}
|
||||
|
||||
function switchEnableUserLevelReadReceipt(status: boolean) {
|
||||
TUIStore.update(StoreName.USER, 'displayMessageReadReceipt', status);
|
||||
settingList.value.displayMessageReadReceipt.showChildren = false;
|
||||
}
|
||||
|
||||
function switchUserLevelOnlineStatus(status: boolean) {
|
||||
TUIUserService.switchUserStatus({ displayOnlineStatus: status });
|
||||
settingList.value.displayOnlineStatus.showChildren = false;
|
||||
}
|
||||
|
||||
function switchTranslationTargetLanguage(lang: string) {
|
||||
translator.clear();
|
||||
TUIChatService.setTranslationLanguage(lang);
|
||||
settingList.value.translateLanguage.selectedChild = lang;
|
||||
settingList.value.translateLanguage.showChildren = false;
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '../styles/profile';
|
||||
</style>
|
17
src/views/im/icon/adv-arrow.svg
Normal file
@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="21px" height="21px" viewBox="0 0 21 21" version="1.1">
|
||||
<title>编组 5</title>
|
||||
<g id="web" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="登录" transform="translate(-627.000000, -516.000000)" stroke="#FFFFFF" stroke-width="1.2">
|
||||
<g id="编组-3" transform="translate(266.400000, 332.400000)">
|
||||
<g id="编组-6" transform="translate(3.600000, 172.800000)">
|
||||
<g id="编组-5" transform="translate(357.600000, 10.800000)">
|
||||
<rect id="矩形" x="6.6" y="10.2" width="6" height="1" rx="0.5"></rect>
|
||||
<circle id="椭圆形" cx="10.2" cy="10.2" r="9.6"></circle>
|
||||
<polyline id="路径-2" stroke-linecap="round" stroke-linejoin="round" points="9.6 13.4662027 13.2 10.2 9.6 7.30762441"></polyline>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 969 B |
BIN
src/views/im/icon/arrow-down-line.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
src/views/im/icon/arrow-down.png
Normal file
After Width: | Height: | Size: 400 B |
8
src/views/im/icon/calendar.svg
Normal file
@ -0,0 +1,8 @@
|
||||
<svg width="16" height="14" viewBox="0 0 16 14" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path id="形状结合"
|
||||
fill-rule="evenodd" clip-rule="evenodd"
|
||||
d="M3.73333 0H5.86667V1.55556H10.1333V0H12.2667V1.55556H16V14H0V1.55556H3.73333V0ZM10.1333 3.11111V4.14815H12.2667V3.11111H14.4V12.4444H1.6V3.11111H3.73333V4.14815H5.86667V3.11111H10.1333ZM12.2667 7.25926H9.06667V10.3704H12.2667V7.25926Z"
|
||||
fill="#596174"
|
||||
style="fill:#596174;fill:color(display-p3 0.3490 0.3804 0.4549);fill-opacity:1;" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 605 B |
BIN
src/views/im/icon/global.png
Normal file
After Width: | Height: | Size: 2.0 KiB |
BIN
src/views/im/icon/menu.png
Normal file
After Width: | Height: | Size: 691 B |
16
src/views/im/icon/message-real.svg
Normal file
@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="48px" height="48px" viewBox="0 0 48 48" version="1.1">
|
||||
<title>编组 8</title>
|
||||
<g id="页面-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="通讯页" transform="translate(-123.000000, -1406.000000)">
|
||||
<g id="编组-15" transform="translate(0.000000, 1378.000000)">
|
||||
<g id="编组-12备份-5" transform="translate(32.000000, 12.000000)">
|
||||
<g id="编组-8" transform="translate(91.000000, 16.000000)">
|
||||
<rect id="矩形" x="0" y="0" width="48" height="48"></rect>
|
||||
<path d="M24,5 C34.4934102,5 43,13.5065898 43,24 C43,34.1653543 35.0169798,42.4661744 24.9781429,42.9752568 L25.004234,43 L7,43 C5.8954305,43 5,42.1045695 5,41 L5,23 L5.02459166,23.0248508 C5.53217539,12.9846073 13.8336352,5 24,5 Z M24,25 L14,25 C13.4477153,25 13,25.4477153 13,26 L13,26 L13,28 C13,28.5522847 13.4477153,29 14,29 L14,29 L24,29 C24.5522847,29 25,28.5522847 25,28 L25,28 L25,26 C25,25.4477153 24.5522847,25 24,25 L24,25 Z M34,17 L14,17 C13.4477153,17 13,17.4477153 13,18 L13,18 L13,20 C13,20.5522847 13.4477153,21 14,21 L14,21 L34,21 C34.5522847,21 35,20.5522847 35,20 L35,20 L35,18 C35,17.4477153 34.5522847,17 34,17 L34,17 Z" id="形状结合" fill="#A0A3A6"></path>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.4 KiB |
16
src/views/im/icon/message-selected.svg
Normal file
@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24px" height="24px" viewBox="0 0 24 24" version="1.1">
|
||||
<title>编组 8</title>
|
||||
<g id="页面-2备份" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="更多" transform="translate(-498.000000, -339.000000)">
|
||||
<g id="左侧边栏" transform="translate(480.000000, 220.000000)">
|
||||
<g id="编组-8" transform="translate(18.000000, 119.000000)">
|
||||
<rect id="矩形" x="0" y="0" width="24" height="24"></rect>
|
||||
<g id="编组-18" transform="translate(3.000000, 3.000000)" fill="#147AFF">
|
||||
<path d="M1.33333333,18 C0.596953667,18 -7.9799792e-16,17.4030463 0,16.6666667 L0,8.52631579 L0.0116474743,8.53811106 C0.252069935,3.78219505 4.18434547,0 9,0 C13.9705627,0 18,4.02943725 18,9 C18,13.815317 14.2183351,17.7473789 9.46288884,17.9883019 L9.47568977,18 L1.33333333,18 Z" id="形状结合"></path>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.0 KiB |
14
src/views/im/icon/message.svg
Normal file
@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24px" height="24px" viewBox="0 0 24 24" version="1.1">
|
||||
<title>编组 8</title>
|
||||
<g id="new" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="ICON" transform="translate(-58.000000, -20.000000)">
|
||||
<g id="编组-8" transform="translate(58.000000, 20.000000)">
|
||||
<g id="编组-18" transform="translate(3.000000, 3.000000)" stroke="#999999">
|
||||
<path d="M9,0.5 C11.3472102,0.5 13.4722102,1.45139491 15.0104076,2.98959236 C16.5486051,4.52778981 17.5,6.65278981 17.5,9 C17.5,11.2679988 16.6117526,13.3285462 15.1641141,14.8526931 C13.7116662,16.3819037 11.6961744,17.3713309 9.44969786,17.4883204 L9.44969786,17.4883204 L1.33333333,17.5 C1.10321469,17.5 0.894881354,17.406726 0.744077682,17.2559223 C0.59327401,17.1051186 0.5,16.8967853 0.5,16.6666667 L0.5,16.6666667 L0.5,8.53977783 C0.62256394,6.29760907 1.61581474,4.28394186 3.14775549,2.83262957 C4.67315258,1.38751653 6.73292542,0.5 9,0.5 Z" id="形状结合"></path>
|
||||
</g>
|
||||
<rect id="矩形" x="0" y="0" width="24" height="24"></rect>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.2 KiB |
32
src/views/im/icon/profile-selected.svg
Normal file
@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="48px" height="48px" viewBox="0 0 48 48" version="1.1">
|
||||
<title>编组 8</title>
|
||||
<defs>
|
||||
<path d="M16,0 L670,0 C678.836556,-1.623249e-15 686,7.163444 686,16 L686,94 C686,102.836556 678.836556,110 670,110 L16,110 C7.163444,110 1.082166e-15,102.836556 0,94 L0,16 C-1.082166e-15,7.163444 7.163444,1.623249e-15 16,0 Z" id="path-1"></path>
|
||||
<filter x="-7.0%" y="-43.6%" width="114.0%" height="187.3%" filterUnits="objectBoundingBox" id="filter-2">
|
||||
<feOffset dx="0" dy="0" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
|
||||
<feGaussianBlur stdDeviation="16" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
|
||||
<feColorMatrix values="0 0 0 0 0.941176471 0 0 0 0 0.964705882 0 0 0 0 1 0 0 0 1 0" type="matrix" in="shadowBlurOuter1"></feColorMatrix>
|
||||
</filter>
|
||||
</defs>
|
||||
<g id="页面-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="个人信息" transform="translate(-580.000000, -1405.000000)">
|
||||
<rect fill="#F7F8FA" x="0" y="0" width="750" height="1624"></rect>
|
||||
<g id="编组-17" transform="translate(0.000000, 1378.000000)">
|
||||
<polygon id="矩形" fill="#FFFFFF" points="0 -1.15130128e-13 750 -1.15130128e-13 750 122 0 122"></polygon>
|
||||
<g id="编组-12备份-5" transform="translate(32.000000, 12.000000)">
|
||||
<g id="矩形备份-22">
|
||||
<use fill="black" fill-opacity="1" filter="url(#filter-2)" xlink:href="#path-1"></use>
|
||||
<use fill="#EBF0F6" fill-rule="evenodd" xlink:href="#path-1"></use>
|
||||
</g>
|
||||
<g id="编组-6" transform="translate(457.000000, 0.000000)">
|
||||
<polygon id="矩形" points="0 3.55965257e-14 229 3.55965257e-14 229 110 0 110"></polygon>
|
||||
<g id="编组-8" transform="translate(91.000000, 15.000000)" fill="#006EFF">
|
||||
<path d="M31,26 C35.418278,26 39,29.581722 39,34 L39,40 C39,41.1045695 38.1045695,42 37,42 L11,42 C9.8954305,42 9,41.1045695 9,40 L9,34 C9,29.581722 12.581722,26 17,26 L31,26 Z M24.0020419,6 C28.9737572,6 33.0040839,10.0294125 33.0040839,15 C33.0040839,19.9705875 28.9737572,24 24.0020419,24 C19.0303267,24 15,19.9705875 15,15 C15,10.0294125 19.0303267,6 24.0020419,6 Z" id="形状结合"></path>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.4 KiB |
17
src/views/im/icon/profile.svg
Normal file
@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="48px" height="48px" viewBox="0 0 48 48" version="1.1">
|
||||
<title>编组 8</title>
|
||||
<g id="页面-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="消息页" transform="translate(-580.000000, -1405.000000)" fill="#B0B4B8">
|
||||
<g id="编组-15" transform="translate(0.000000, 1378.000000)">
|
||||
<g id="编组-12备份-5" transform="translate(32.000000, 12.000000)">
|
||||
<g id="编组-6" transform="translate(457.000000, 0.000000)">
|
||||
<g id="编组-8" transform="translate(91.000000, 15.000000)">
|
||||
<path d="M31,26 C35.418278,26 39,29.581722 39,34 L39,40 C39,41.1045695 38.1045695,42 37,42 L11,42 C9.8954305,42 9,41.1045695 9,40 L9,34 C9,29.581722 12.581722,26 17,26 L31,26 Z M24.0020419,6 C28.9737572,6 33.0040839,10.0294125 33.0040839,15 C33.0040839,19.9705875 28.9737572,24 24.0020419,24 C19.0303267,24 15,19.9705875 15,15 C15,10.0294125 19.0303267,6 24.0020419,6 Z" id="形状结合"></path>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.1 KiB |
19
src/views/im/icon/relation-real.svg
Normal file
@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="48px" height="48px" viewBox="0 0 48 48" version="1.1">
|
||||
<title>编组 8</title>
|
||||
<g id="页面-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="消息页" transform="translate(-351.000000, -1405.000000)" fill="#B0B4B8">
|
||||
<g id="编组-15" transform="translate(0.000000, 1378.000000)">
|
||||
<g id="编组-12备份-5" transform="translate(32.000000, 12.000000)">
|
||||
<g id="编组-6" transform="translate(229.000000, 0.000000)">
|
||||
<g id="编组-2" transform="translate(84.000000, 15.000000)">
|
||||
<g id="编组-8" transform="translate(6.000000, 0.000000)">
|
||||
<path d="M25,26 C29.418278,26 33,29.581722 33,34 L33,40 C33,41.1045695 32.1045695,42 31,42 L5,42 C3.8954305,42 3,41.1045695 3,40 L3,34 C3,29.581722 6.581722,26 11,26 L25,26 Z M43.9994591,26 C44.5517438,26 44.9994591,26.4477153 44.9994591,27 L44.9994591,29 C44.9994591,29.5522847 44.5517438,30 43.9994591,30 L36.9994591,30 C36.4471743,30 35.9994591,29.5522847 35.9994591,29 L35.9994591,27 C35.9994591,26.4477153 36.4471743,26 36.9994591,26 L43.9994591,26 Z M18.0020419,6 C22.9737572,6 27.0040839,10.0294125 27.0040839,15 C27.0040839,19.9705875 22.9737572,24 18.0020419,24 C13.0303267,24 9,19.9705875 9,15 C9,10.0294125 13.0303267,6 18.0020419,6 Z M43.9994591,18 C44.5517438,18 44.9994591,18.4477153 44.9994591,19 L44.9994591,21 C44.9994591,21.5522847 44.5517438,22 43.9994591,22 L31.9994591,22 C31.4471743,22 30.9994591,21.5522847 30.9994591,21 L30.9994591,19 C30.9994591,18.4477153 31.4471743,18 31.9994591,18 L43.9994591,18 Z" id="形状结合"></path>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.8 KiB |
16
src/views/im/icon/relation-selected.svg
Normal file
@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24px" height="24px" viewBox="0 0 24 24" version="1.1">
|
||||
<title>编组 8</title>
|
||||
<g id="new" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="ICON" transform="translate(-19.000000, -60.000000)">
|
||||
<g id="编组-8" transform="translate(19.000000, 60.000000)">
|
||||
<rect id="矩形" x="0" y="0" width="24" height="24"></rect>
|
||||
<rect id="矩形" stroke="#006EFF" transform="translate(19.000000, 8.500000) scale(1, -1) translate(-19.000000, -8.500000) " x="16.5" y="8.5" width="5" height="1" rx="0.5"></rect>
|
||||
<rect id="矩形备份-2" stroke="#006EFF" x="16.5" y="11.5" width="5" height="1" rx="0.5"></rect>
|
||||
<rect id="矩形备份-3" stroke="#006EFF" x="18.5" y="14.5" width="3" height="1" rx="0.5"></rect>
|
||||
<path d="M9,12 C11.209139,12 13,9.35025579 13,7.09090909 C13,4.83156239 11.209139,3 9,3 C6.790861,3 5,4.83156239 5,7.09090909 C5,9.35025579 6.790861,12 9,12 Z" id="椭圆形" fill="#006EFF"></path>
|
||||
<path d="M6,13 L12,13 C14.209139,13 16,14.790861 16,17 L16,20 C16,20.5522847 15.5522847,21 15,21 L3,21 C2.44771525,21 2,20.5522847 2,20 L2,17 C2,14.790861 3.790861,13 6,13 Z" id="矩形" fill="#006EFF"></path>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.3 KiB |
18
src/views/im/icon/relation.svg
Normal file
@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24px" height="24px" viewBox="0 0 24 24" version="1.1">
|
||||
<title>编组 8</title>
|
||||
<g id="页面-2备份" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="更多" transform="translate(-498.000000, -389.000000)">
|
||||
<g id="左侧边栏" transform="translate(480.000000, 220.000000)">
|
||||
<g id="编组-8" transform="translate(18.000000, 169.000000)">
|
||||
<rect id="矩形" x="0" y="0" width="24" height="24"></rect>
|
||||
<rect id="矩形" stroke="#999999" transform="translate(19.000000, 8.500000) scale(1, -1) translate(-19.000000, -8.500000) " x="16.5" y="8.5" width="5" height="1" rx="0.5"></rect>
|
||||
<rect id="矩形备份-2" stroke="#999999" x="16.5" y="11.5" width="5" height="1" rx="0.5"></rect>
|
||||
<rect id="矩形备份-3" stroke="#999999" x="18.5" y="14.5" width="3" height="1" rx="0.5"></rect>
|
||||
<path d="M9,3.5 C9.9652364,3.5 10.8385592,3.90102188 11.4709238,4.54775835 C12.1073095,5.19860738 12.5,6.09799921 12.5,7.09090909 C12.5,8.1638596 12.0512293,9.33155704 11.3410312,10.2031638 C10.7279048,10.9556371 9.91231344,11.5 9,11.5 C8.08768656,11.5 7.27209516,10.9556371 6.65896878,10.2031638 C5.94877068,9.33155704 5.5,8.1638596 5.5,7.09090909 C5.5,6.09799921 5.89269049,5.19860738 6.52907621,4.54775835 C7.16144075,3.90102188 8.0347636,3.5 9,3.5 L9,3.5 Z" id="椭圆形" stroke="#999999"></path>
|
||||
<path d="M12,13.5 C12.9664983,13.5 13.8414983,13.8917508 14.4748737,14.5251263 C15.1082492,15.1585017 15.5,16.0335017 15.5,17 L15.5,17 L15.5,20 L3,20.5 L2.5,17 C2.5,16.0335017 2.89175084,15.1585017 3.52512627,14.5251263 C4.15850169,13.8917508 5.03350169,13.5 6,13.5 L6,13.5 Z" id="矩形" stroke="#999999"></path>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.8 KiB |
BIN
src/views/im/icon/setting.png
Normal file
After Width: | Height: | Size: 457 B |
189
src/views/im/index.vue
Normal file
@ -0,0 +1,189 @@
|
||||
<!-- eslint-disable vue/multi-word-component-names -->
|
||||
<template>
|
||||
<div :id="isPC ? 'preloadedImages' : ''" :class="['home', isH5 && 'home-h5']">
|
||||
<!-- <div v-show="isMenuShow" class="home-menu">
|
||||
<Menu @closeMenu="toggleMenu(false)" />
|
||||
</div>-->
|
||||
<div :class="['home-container', isMenuShow && 'menu-expand']">
|
||||
<!-- <div v-if="isPC" class="home-header">
|
||||
<Header
|
||||
:class="[isMenuShow && 'header-menu-show']"
|
||||
showType="menu"
|
||||
:defaultLanguage="locale"
|
||||
@toggleMenu="toggleMenu(!isMenuShow)"
|
||||
@changeLanguage="changeLanguage"
|
||||
/>
|
||||
</div>-->
|
||||
<div class="home-main">
|
||||
<div class="home-TUIKit">
|
||||
<div v-if="isPC || !currentConversationID" class="home-TUIKit-navbar">
|
||||
<NavBar v-model:currentNavBar="currentNavBar" v-model:isSettingShow="isSettingShow">
|
||||
<template #profile>
|
||||
<Profile display-type="profile" />
|
||||
</template>
|
||||
<template #setting>
|
||||
<Profile v-model:showSetting="isSettingShow" display-type="setting" />
|
||||
</template>
|
||||
</NavBar>
|
||||
</div>
|
||||
<div v-if="isPC" class="home-TUIKit-main">
|
||||
<div v-show="currentNavBar === 'message'" class="home-TUIKit-main">
|
||||
<div class="home-conversation">
|
||||
<TUISearch searchType="global" />
|
||||
<TUIConversation />
|
||||
</div>
|
||||
<div class="home-chat">
|
||||
<TUIChat>
|
||||
<ChatDefaultContent />
|
||||
</TUIChat>
|
||||
<TUIGroup class="chat-aside" />
|
||||
<TUISearch class="chat-aside" searchType="conversation" />
|
||||
</div>
|
||||
<TUIContact display-type="selectFriend" />
|
||||
</div>
|
||||
<div v-show="currentNavBar === 'relation'" class="home-TUIKit-main">
|
||||
<TUIContact display-type="contactList" @switchConversation="currentNavBar = 'message'" />
|
||||
</div>
|
||||
</div>
|
||||
<div v-else-if="isH5" class="home-TUIKit-main">
|
||||
<div v-if="!currentConversationID" class="home-TUIKit-main">
|
||||
<div v-show="currentNavBar === 'message'" class="home-TUIKit-main">
|
||||
<TUISearch searchType="global" />
|
||||
<TUIConversation />
|
||||
<TUIContact display-type="selectFriend" />
|
||||
</div>
|
||||
<div v-show="currentNavBar === 'relation'" class="home-TUIKit-main">
|
||||
<TUIContact display-type="contactList" @switchConversation="currentNavBar = 'message'" />
|
||||
</div>
|
||||
<div v-show="currentNavBar === 'profile'" class="home-TUIKit-main">
|
||||
<Profile display-type="all" />
|
||||
</div>
|
||||
</div>
|
||||
<TUIChat v-else />
|
||||
<TUIGroup class="chat-popup" />
|
||||
<TUISearch class="chat-popup" searchType="conversation" />
|
||||
</div>
|
||||
<Drag ref="dragRef" :show="isCalling" domClassName="callkit-drag-container">
|
||||
<TUICallKit
|
||||
:class="['callkit-drag-container', `callkit-drag-container-${isMinimized ? 'mini' : isH5 ? 'h5' : 'pc'}`]"
|
||||
:allowedMinimized="true"
|
||||
:allowedFullScreen="false"
|
||||
:beforeCalling="beforeCalling"
|
||||
:afterCalling="afterCalling"
|
||||
:onMinimized="onMinimized"
|
||||
/>
|
||||
</Drag>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ref } from '@/TUIKit/adapter-vue';
|
||||
import { SDKAppID, secretKey, userSig } from '@/main';
|
||||
import { TUILogin } from '@tencentcloud/tui-core';
|
||||
import { TUIStore, StoreName, TUIUserService } from '@tencentcloud/chat-uikit-engine';
|
||||
import { TUICallKit } from '@tencentcloud/call-uikit-vue';
|
||||
import { TUIChat, TUIConversation, TUIContact, TUIGroup, TUISearch, genTestUserSig } from '@/TUIKit';
|
||||
import Header from '@/views/im/components/Header.vue';
|
||||
import Menu from '@/views/im/components/Menu.vue';
|
||||
import NavBar from '@/views/im/components/NavBar.vue';
|
||||
import Profile from '@/views/im/components/Profile.vue';
|
||||
import ChatDefaultContent from '@/views/im/components/ChatDefaultContent.vue';
|
||||
import Drag from '@/TUIKit/components/common/Drag';
|
||||
import { isPC, isH5 } from '@/TUIKit/utils/env';
|
||||
import { enableSampleTaskStatus } from '@/TUIKit/utils/enableSampleTaskStatus';
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
language: string;
|
||||
}>(),
|
||||
{
|
||||
language: 'zh'
|
||||
}
|
||||
);
|
||||
const emits = defineEmits(['changeLanguage']);
|
||||
|
||||
const locale = ref<string>(props.language);
|
||||
const isMenuShow = ref<boolean>(true);
|
||||
const currentNavBar = ref<string>('message');
|
||||
const currentConversationID = ref<string>('');
|
||||
const isCalling = ref<boolean>(false);
|
||||
const isMinimized = ref<boolean>(false);
|
||||
const dragRef = ref<typeof Drag>();
|
||||
const isSettingShow = ref<boolean>(false);
|
||||
|
||||
function changeLanguage(language: string) {
|
||||
emits('changeLanguage', language);
|
||||
}
|
||||
|
||||
TUIStore.watch(StoreName.CONV, {
|
||||
currentConversationID: (id: string) => {
|
||||
currentConversationID.value = id;
|
||||
}
|
||||
});
|
||||
function toggleMenu(value: boolean) {
|
||||
isMenuShow.value = value;
|
||||
}
|
||||
|
||||
function beforeCalling() {
|
||||
isCalling.value = true;
|
||||
isMinimized.value = false;
|
||||
enableSampleTaskStatus('call');
|
||||
}
|
||||
|
||||
function afterCalling() {
|
||||
isCalling.value = false;
|
||||
isMinimized.value = false;
|
||||
}
|
||||
|
||||
function onMinimized(oldMinimizedStatus: boolean, newMinimizedStatus: boolean) {
|
||||
isMinimized.value = newMinimizedStatus;
|
||||
dragRef?.value?.positionReset();
|
||||
}
|
||||
|
||||
function genUser() {
|
||||
const options = genTestUserSig({
|
||||
SDKAppID,
|
||||
secretKey,
|
||||
userID: 'youyouliangshao'
|
||||
});
|
||||
const loginInfo: any = {
|
||||
SDKAppID,
|
||||
// userID: ruleForm.value.userID,
|
||||
userID: 'youyouliangshao',
|
||||
|
||||
userSig: userSig,
|
||||
useUploadPlugin: true,
|
||||
framework: `vue3`
|
||||
};
|
||||
imLogin(loginInfo);
|
||||
}
|
||||
|
||||
function imLogin(loginInfo) {
|
||||
TUILogin.login(loginInfo)
|
||||
.then((res: any) => {
|
||||
// router.push({ path: 'home' });
|
||||
// TUIUserService.switchUserStatus({ displayOnlineStatus: true });
|
||||
})
|
||||
.catch((error: any) => {
|
||||
console.info('111111111111111111111111', error);
|
||||
ElMessage({
|
||||
message: '登录失败',
|
||||
grouping: true,
|
||||
type: 'error'
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
/* TUILogin.logout().then(() => {
|
||||
|
||||
});*/
|
||||
genUser();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import './styles/home';
|
||||
</style>
|
115
src/views/im/styles/common.scss
Normal file
@ -0,0 +1,115 @@
|
||||
@import "@/TUIKit/assets/styles/common.scss";
|
||||
// button
|
||||
@mixin btn {
|
||||
border-radius: 5px;
|
||||
padding: 13px 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
@mixin btn-default {
|
||||
@include btn;
|
||||
background: #006eff;
|
||||
border: 1px solid #006eff;
|
||||
color: #fff;
|
||||
}
|
||||
@mixin btn-error {
|
||||
@include btn;
|
||||
border: 1px solid #e54545;
|
||||
color: #e54545;
|
||||
background: #fff;
|
||||
}
|
||||
@mixin btn-normal {
|
||||
@include btn;
|
||||
background: #fff;
|
||||
border: 1px solid #ddd;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
// flex
|
||||
// flex布局 默认 纵向垂直居中水平居中
|
||||
@mixin flex($direction: column, $js: center, $al: center) {
|
||||
box-sizing: border-box;
|
||||
display: -webkit-box;
|
||||
display: -moz-box;
|
||||
display: -webkit-flex;
|
||||
display: -moz-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
flex-direction: $direction;
|
||||
justify-content: $js;
|
||||
align-items: $al;
|
||||
border: 0px solid black;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
// 文本超出隐藏 ...隐藏文本
|
||||
@mixin single-line-ellipsis($width: 100%) {
|
||||
width: $width;
|
||||
overflow: hidden;
|
||||
-ms-text-overflow: ellipsis;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
// 文本最多(n)行,超出部分用...表示
|
||||
@mixin line($num) {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: $num;
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
|
||||
// position居中
|
||||
@mixin positionCenter {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
-webkit-transform: translate(-50%, -50%);
|
||||
-moz-transform: translate(-50%, -50%);
|
||||
-ms-transform: translate(-50%, -50%);
|
||||
-o-transform: translate(-50%, -50%);
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
|
||||
.container {
|
||||
@include flex;
|
||||
position: fixed;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 3;
|
||||
background: rgba(0, 0, 0, 0.3);
|
||||
overflow: hidden;
|
||||
.box {
|
||||
@include flex;
|
||||
border-radius: 0.5rem;
|
||||
background: #fff;
|
||||
overflow: hidden;
|
||||
color: #000;
|
||||
}
|
||||
.box-h5 {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 0px;
|
||||
border-radius: 0px;
|
||||
.title {
|
||||
@include flex;
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
padding: 15px 18px;
|
||||
position: relative;
|
||||
.title-back {
|
||||
position: absolute;
|
||||
left: 18px;
|
||||
}
|
||||
.title-name {
|
||||
font-size: 18px;
|
||||
font-weight: 500;
|
||||
font-family: PingFangSC-Medium;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
63
src/views/im/styles/h5/home.scss
Normal file
@ -0,0 +1,63 @@
|
||||
/* stylelint-disable */
|
||||
.home-h5 {
|
||||
flex-direction: column;
|
||||
min-width: 100%;
|
||||
min-height: 100%;
|
||||
background: #fff;
|
||||
|
||||
.home-menu {
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
z-index: 10;
|
||||
align-items: flex-end;
|
||||
}
|
||||
|
||||
.home-container {
|
||||
.home-main {
|
||||
padding: 0;
|
||||
min-width: 0;
|
||||
|
||||
.home-TUIKit {
|
||||
flex-direction: column-reverse;
|
||||
border-radius: 0;
|
||||
max-width: 100%;
|
||||
|
||||
.home-TUIKit-navbar {
|
||||
width: 100%;
|
||||
padding: 12px 18px;
|
||||
}
|
||||
|
||||
.home-TUIKit-main {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.chat-popup {
|
||||
position: absolute;
|
||||
}
|
||||
}
|
||||
|
||||
.callkit-drag-container {
|
||||
&-h5 {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
left: 0;
|
||||
top: 0;
|
||||
border-radius: 0;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
&-mini {
|
||||
width: 72px;
|
||||
height: 72px;
|
||||
left: calc(100% - 100px);
|
||||
top: 20px;
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
154
src/views/im/styles/h5/login.scss
Normal file
@ -0,0 +1,154 @@
|
||||
@import "../common.scss";
|
||||
.login-h5 {
|
||||
min-width: 100%;
|
||||
max-width: 100%;
|
||||
padding: 17px 0;
|
||||
.login-header {
|
||||
padding: 0 23px;
|
||||
}
|
||||
.login-main {
|
||||
.login-main-content {
|
||||
padding: 0 23px;
|
||||
background: url("../assets/image/h5/login-bg.png") no-repeat;
|
||||
background-size: 65%;
|
||||
background-position-x: right;
|
||||
align-items: flex-start;
|
||||
.login-form {
|
||||
flex: 1;
|
||||
.login-title {
|
||||
flex-direction: column;
|
||||
padding: 60px 0 18px;
|
||||
p {
|
||||
padding-left: 0;
|
||||
font-size: 27px;
|
||||
line-height: 40px;
|
||||
}
|
||||
}
|
||||
.login-form-item {
|
||||
font-size: 18px;
|
||||
.el-checkbox {
|
||||
.checked-text {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
.login-form-item-disabled {
|
||||
font-size: 18px;
|
||||
padding: 20px;
|
||||
}
|
||||
}
|
||||
.login-btn {
|
||||
button {
|
||||
height: auto !important;
|
||||
font-size: 20px;
|
||||
line-height: 27px;
|
||||
padding: 13px 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.login-footer {
|
||||
background: none;
|
||||
padding: 10px 10px;
|
||||
|
||||
&-list {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
|
||||
&-item {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
background: url("../assets/image/h5/adv-more.svg") no-repeat;
|
||||
background-size: 100% 100%;
|
||||
border: solid #96c3ff 1px;
|
||||
|
||||
&:last-child {
|
||||
background: url("../assets/image/h5/adv-im.svg") no-repeat;
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
|
||||
a {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
align-items: center;
|
||||
box-sizing: border-box;
|
||||
padding: 20px;
|
||||
|
||||
span {
|
||||
padding: 5px 20px;
|
||||
background: #147aff;
|
||||
box-shadow: 0 4px 5px 0 rgba(255, 255, 255, 0.7), 0 3px 8px 0 rgba(20, 122, 255, 0.55);
|
||||
border-radius: 30.5px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-family: PingFangSC-Regular;
|
||||
font-weight: 400;
|
||||
font-size: 15px;
|
||||
color: #ffffff;
|
||||
letter-spacing: 0;
|
||||
}
|
||||
|
||||
aside {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
h1 {
|
||||
font-family: PingFangSC-Regular;
|
||||
font-size: 16px;
|
||||
color: #000000;
|
||||
letter-spacing: 0;
|
||||
}
|
||||
|
||||
.sub {
|
||||
align-self: flex-end;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-bottom {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
.text-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
span {
|
||||
padding: 20px 20px;
|
||||
width: 84px;
|
||||
font-family: "PingFang SC";
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
color: #bbbbbb;
|
||||
}
|
||||
}
|
||||
|
||||
i {
|
||||
width: 120px;
|
||||
height: 1px;
|
||||
background: #dbdbdb;
|
||||
}
|
||||
|
||||
&-image {
|
||||
display: flex;
|
||||
|
||||
.platform {
|
||||
width: 41px;
|
||||
height: 41px;
|
||||
padding: 0 20px;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
94
src/views/im/styles/h5/profile.scss
Normal file
@ -0,0 +1,94 @@
|
||||
.TUI-profile-h5 {
|
||||
background: #efefef;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
&-basic {
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
background: #ffffff;
|
||||
padding: 14px 18px;
|
||||
flex-direction: row;
|
||||
align-items: flex-start;
|
||||
margin-bottom: 10px;
|
||||
&-avatar {
|
||||
width: 78px;
|
||||
height: 78px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
&-info {
|
||||
&-nick {
|
||||
font-size: 14px;
|
||||
flex: 1;
|
||||
word-break: keep-all;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
padding: 6px 0;
|
||||
font-family: PingFangSC-Medium;
|
||||
font-weight: 500;
|
||||
color: #000;
|
||||
letter-spacing: 0;
|
||||
}
|
||||
&-id {
|
||||
font-family: PingFangSC-Regular;
|
||||
font-weight: 400;
|
||||
color: #999;
|
||||
letter-spacing: 0;
|
||||
font-size: 14px;
|
||||
word-break: keep-all;
|
||||
padding: 6px 0;
|
||||
&-label {
|
||||
}
|
||||
&-value {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
&-setting {
|
||||
width: 100%;
|
||||
flex-direction: column;
|
||||
|
||||
&-item {
|
||||
margin-bottom: 10px;
|
||||
background: #ffffff;
|
||||
padding: 10px;
|
||||
&-exit {
|
||||
.TUI-profile-h5-setting-item-label {
|
||||
justify-content: center;
|
||||
.label-left {
|
||||
.label-title {
|
||||
color: red;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
&-label {
|
||||
.label-left {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
.label-title {
|
||||
color: #444444;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
.label-right {
|
||||
color: #000000;
|
||||
font-size: 14px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
}
|
||||
&-bottom-popup {
|
||||
font-size: 16px;
|
||||
color: #147aff;
|
||||
padding: 10px;
|
||||
border-bottom: 1px solid #DBDBDB;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
3
src/views/im/styles/home.scss
Normal file
@ -0,0 +1,3 @@
|
||||
@import './web/home.scss';
|
||||
@import './h5/home.scss';
|
||||
@import "./common.scss";
|
3
src/views/im/styles/login.scss
Normal file
@ -0,0 +1,3 @@
|
||||
@import "./web/login.scss";
|
||||
@import "./h5/login.scss";
|
||||
@import "./common.scss";
|
3
src/views/im/styles/profile.scss
Normal file
@ -0,0 +1,3 @@
|
||||
@import "./web/profile.scss";
|
||||
@import "./h5/profile.scss";
|
||||
@import "./common.scss";
|
121
src/views/im/styles/web/home.scss
Normal file
@ -0,0 +1,121 @@
|
||||
#preloadedImages {
|
||||
background: linear-gradient(135deg, #f1f4f7 0%, #edf5ff 100%) no-repeat;
|
||||
background-size: cover;
|
||||
background-image: url("https://web.sdk.qcloud.com/im/assets/images/background-zip.png");
|
||||
}
|
||||
|
||||
.home {
|
||||
box-sizing: border-box;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
min-width: 1024px;
|
||||
background-size: contain;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
.home-menu {
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
}
|
||||
.home-container {
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
align-items: stretch;
|
||||
.home-header {
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
.header-menu-show {
|
||||
padding-left: 0px;
|
||||
}
|
||||
}
|
||||
.home-main {
|
||||
box-sizing: border-box;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
padding: 50px;
|
||||
min-width: 968px;
|
||||
.home-TUIKit {
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex: 1;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
max-width: 1400px;
|
||||
overflow: hidden;
|
||||
min-height: 640px;
|
||||
border-radius: 12px;
|
||||
background-color: #ffffff;
|
||||
box-shadow: 0 11px 20px 0 rgba(0, 0, 0, 0.3);
|
||||
.home-TUIKit-navbar {
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
}
|
||||
.home-TUIKit-main {
|
||||
box-sizing: border-box;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
flex-direction: row;
|
||||
border: 0 solid black;
|
||||
.home-conversation,
|
||||
.home-relation {
|
||||
min-width: 285px;
|
||||
box-sizing: border-box;
|
||||
flex: 0 0 24%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border-right: 1px solid #f4f5f9;
|
||||
}
|
||||
.home-chat {
|
||||
box-sizing: border-box;
|
||||
min-width: 0;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
}
|
||||
}
|
||||
.callkit-drag-container {
|
||||
position: fixed;
|
||||
z-index: 100;
|
||||
background-color: #ffffff;
|
||||
user-select: none;
|
||||
&-pc {
|
||||
left: calc(50% - 25rem);
|
||||
top: calc(50% - 18rem);
|
||||
width: 50rem;
|
||||
height: 36rem;
|
||||
border-radius: 16px;
|
||||
box-shadow: rgba(0, 0, 0, 0.16) 0px 3px 6px, rgba(0, 0, 0, 0.23) 0px 3px 6px;
|
||||
}
|
||||
&-mini {
|
||||
width: 168px;
|
||||
height: 56px;
|
||||
right: 10px;
|
||||
top: 70px;
|
||||
background-color: transparent;
|
||||
border-radius: 0px;
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.home-container.menu-expand {
|
||||
.dialog,
|
||||
.container {
|
||||
width: calc(100% - 300px) !important;
|
||||
left: 300px !important;
|
||||
}
|
||||
.home-main .home-TUIKit .callkit-drag-container.callkit-drag-container-pc {
|
||||
left: calc(50% - 25rem + 150px);
|
||||
}
|
||||
}
|
||||
}
|
237
src/views/im/styles/web/login.scss
Normal file
@ -0,0 +1,237 @@
|
||||
@import "../common.scss";
|
||||
.login {
|
||||
flex: 1;
|
||||
@include flex(column, center, stretch);
|
||||
min-width: 980px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: #ffffff;
|
||||
.login-main {
|
||||
flex: 1;
|
||||
@include flex(column, center, stretch);
|
||||
padding-bottom: 5vw;
|
||||
.login-main-content {
|
||||
flex: 1;
|
||||
@include flex(row, space-between, center);
|
||||
padding: 0 6vh;
|
||||
width: 100%;
|
||||
max-width: 100rem;
|
||||
align-self: center;
|
||||
background: url("../assets/image/login-background.png") no-repeat;
|
||||
background-position: center left;
|
||||
.login-main-adv {
|
||||
@include flex(column, flex-start, flex-start);
|
||||
.login-main-adv-introduce {
|
||||
font-size: 3rem;
|
||||
line-height: 4.2rem;
|
||||
font-family: PingFangSC-Regular;
|
||||
font-weight: 400;
|
||||
color: #000000;
|
||||
}
|
||||
}
|
||||
|
||||
.login-sale {
|
||||
margin-top: 40px;
|
||||
padding: 8px 16px;
|
||||
font-size: 1.4rem;
|
||||
line-height: 2rem;
|
||||
border-radius: 6px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
color: #ffffff;
|
||||
background: url("../assets/image/adv-bg.svg") no-repeat;
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
.icon {
|
||||
margin: 0 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.small-txt {
|
||||
width: 42rem;
|
||||
font-size: 2.6rem;
|
||||
line-height: 3.6rem;
|
||||
}
|
||||
|
||||
.checked-text {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
font-size: 0.88rem;
|
||||
line-height: 1.73rem;
|
||||
font-family: PingFangSC-Regular;
|
||||
font-weight: 400;
|
||||
color: #bbbbbb;
|
||||
letter-spacing: 0;
|
||||
a {
|
||||
color: #006ef0;
|
||||
}
|
||||
}
|
||||
.login-form {
|
||||
box-sizing: border-box;
|
||||
width: 22.41rem;
|
||||
|
||||
.login-title {
|
||||
display: flex;
|
||||
letter-spacing: 0;
|
||||
font-family: PingFangSC-Medium;
|
||||
font-weight: 500;
|
||||
color: #000000;
|
||||
img {
|
||||
width: 4.61rem;
|
||||
height: 3.23rem;
|
||||
}
|
||||
p {
|
||||
padding-left: 10.5px;
|
||||
font-size: 1.8rem;
|
||||
line-height: 2.7rem;
|
||||
align-items: center;
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
.login-form-item {
|
||||
margin: 18px 0;
|
||||
.el-select {
|
||||
width: 100%;
|
||||
font-size: 1rem;
|
||||
padding-top: 28px;
|
||||
line-height: 1.73rem;
|
||||
font-weight: 400;
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
.el-input__inner {
|
||||
width: 356.4px;
|
||||
height: 54px;
|
||||
margin-top: 12px;
|
||||
border-radius: 4.8px;
|
||||
background: #ffffff;
|
||||
border: 1.2px solid #dddddd;
|
||||
}
|
||||
|
||||
.input-with-select {
|
||||
margin-top: 14px;
|
||||
input {
|
||||
height: 40px;
|
||||
}
|
||||
}
|
||||
.el-input-group__append {
|
||||
.code-box {
|
||||
color: #006eff;
|
||||
}
|
||||
}
|
||||
.login-form-item-disabled {
|
||||
cursor: pointer;
|
||||
background: #f4f5f9;
|
||||
border: 1.2px solid #dddddd;
|
||||
color: #111111;
|
||||
letter-spacing: 0;
|
||||
border-radius: 4.8px;
|
||||
width: 100%;
|
||||
margin-top: 28px;
|
||||
padding: 14px 11px;
|
||||
box-sizing: border-box;
|
||||
font-size: 1rem;
|
||||
line-height: 1.2rem;
|
||||
|
||||
label {
|
||||
cursor: pointer;
|
||||
color: #999999;
|
||||
padding-right: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.login-form-footer {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
text-decoration: none;
|
||||
a {
|
||||
color: #006ef0;
|
||||
}
|
||||
}
|
||||
|
||||
.login-btn {
|
||||
flex: 1;
|
||||
@include flex(column, center, stretch);
|
||||
.btn {
|
||||
width: 100%;
|
||||
flex: 1;
|
||||
height: 3rem;
|
||||
font-size: 1.25rem;
|
||||
font-weight: 400;
|
||||
letter-spacing: 0;
|
||||
border: 1px solid #006eff;
|
||||
border-radius: 5px;
|
||||
color: #006eff;
|
||||
margin-bottom: 10px;
|
||||
background-color: transparent;
|
||||
cursor: pointer;
|
||||
|
||||
&:disabled {
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
&-primary {
|
||||
background: #006eff;
|
||||
color: #ffffff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.login-main-middle {
|
||||
height: 130px;
|
||||
width: 100%;
|
||||
max-width: 100rem;
|
||||
align-self: center;
|
||||
padding: 0 1.6rem 20px;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
|
||||
.login-main-middle-box {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
.login-main-footer {
|
||||
box-sizing: border-box;
|
||||
padding: 0 1.6rem;
|
||||
width: 100%;
|
||||
max-width: 100rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
align-self: center;
|
||||
background: rgba(231, 242, 255, 0.4);
|
||||
.mask {
|
||||
flex: 0 0 25%;
|
||||
padding: 1.6rem 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
.mask-top {
|
||||
word-break: break-all;
|
||||
white-space: nowrap;
|
||||
font-size: 3rem;
|
||||
height: 4.19rem;
|
||||
font-family: PingFangSC-Regular;
|
||||
font-weight: 400;
|
||||
color: #006eff;
|
||||
letter-spacing: 0;
|
||||
}
|
||||
.mask-under {
|
||||
opacity: 0.49;
|
||||
font-weight: 400;
|
||||
font-size: 1.2rem;
|
||||
font-family: PingFangSC-Regular;
|
||||
color: #000;
|
||||
letter-spacing: 0;
|
||||
height: 62px;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
124
src/views/im/styles/web/profile.scss
Normal file
@ -0,0 +1,124 @@
|
||||
/* stylelint-disable-next-line selector-class-pattern */
|
||||
.TUI-profile {
|
||||
background: #fff;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
|
||||
&-basic {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
|
||||
&-avatar {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
border-radius: 5px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
&-info {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
font-size: 14px;
|
||||
|
||||
&-nick {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
&-id {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
overflow: hidden;
|
||||
|
||||
&-label {
|
||||
font-weight: 400;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
&-value {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-setting {
|
||||
&-item {
|
||||
height: 40px;
|
||||
padding-left: 14px;
|
||||
padding-right: 8px;
|
||||
display: flex;
|
||||
line-height: 40px;
|
||||
text-align: center;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(0, 110, 255, 0.1);
|
||||
|
||||
/* stylelint-disable-next-line selector-class-pattern */
|
||||
.TUI-profile-setting-item-children {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
&-label {
|
||||
font-size: 14px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
/* stylelint-disable-next-line no-descending-specificity */
|
||||
&-children {
|
||||
display: none;
|
||||
position: absolute;
|
||||
left: 100%;
|
||||
min-width: 167px;
|
||||
border-radius: 0 4px 4px 0;
|
||||
z-index: 2;
|
||||
background: #fff;
|
||||
box-shadow: 2px 1px 6px 0 rgba(2, 16, 43, 0.15);
|
||||
|
||||
&-item {
|
||||
height: 40px;
|
||||
padding-left: 14px;
|
||||
padding-right: 8px;
|
||||
display: flex;
|
||||
line-height: 40px;
|
||||
text-align: center;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(0, 110, 255, 0.1);
|
||||
}
|
||||
|
||||
&-label {
|
||||
font-size: 14px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
flex: 1;
|
||||
padding-right: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -24,10 +24,15 @@ export default defineConfig(({ mode, command }) => {
|
||||
open: true,
|
||||
proxy: {
|
||||
[env.VITE_APP_BASE_API]: {
|
||||
target: 'http://localhost:8080',
|
||||
target: 'http://192.168.1.250:8080',
|
||||
changeOrigin: true,
|
||||
ws: true,
|
||||
rewrite: (path) => path.replace(new RegExp('^' + env.VITE_APP_BASE_API), '')
|
||||
rewrite: (path) => path.replace(new RegExp('^' + env.VITE_APP_BASE_API), ''),
|
||||
bypass(req, res, options) {
|
||||
const proxyURL = options.target + options.rewrite(req.url);
|
||||
console.log('请求的真实api地址===>', proxyURL);
|
||||
res.setHeader('x-req-proxyURL', proxyURL); // 设置真实请求地址
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|