init
This commit is contained in:
2025-06-27 17:42:38 +08:00
commit bd6402478b
5317 changed files with 785994 additions and 0 deletions
@@ -0,0 +1,62 @@
const directiveList:any = [{
name: 'TUILongPress',
callback: (el:Element, binding:any, vNode:any) => {
// 确保提供的表达式是函数
if (typeof binding.value !== 'function') {
// 获取组件名称
const compName = vNode.context.name;
// 将警告传递给控制台
let warn = `[longpress:] provided expression '${binding.expression}' is not afunction, but has to be `;
if (compName) {
warn += `Found in component '${compName}' `;
}
console.warn(warn);
}
// 定义变量
let pressTimer:any = null;
// 定义函数处理程序
// 创建计时器( 1秒后执行函数 )
const start = (e:any) => {
if (e.type === 'click' && e.button !== 0) {
return;
}
if (pressTimer === null) {
pressTimer = setTimeout(() => {
// 执行函数
handler(e);
}, 1000);
}
};
// 取消计时器
const cancel = (e:any) => {
// 检查计时器是否有值
if (pressTimer !== null) {
clearTimeout(pressTimer);
pressTimer = null;
}
};
// 运行函数
const handler = (e:any) => {
// 执行传递给指令的方法
binding.value(e);
};
// 添加事件监听器
el.addEventListener('mousedown', start, false);
el.addEventListener('touchstart', start, false);
// 取消计时器
el.addEventListener('click', cancel);
el.addEventListener('mouseout', cancel);
el.addEventListener('touchend', cancel);
el.addEventListener('touchcancel', cancel);
},
}];
const directive = (app: any) => {
directiveList.map((item:any) => {
app.directive(item.name, {
beforeMount: item.callback,
});
});
};
export default directive;
+19
View File
@@ -0,0 +1,19 @@
const browser = function () {
const ua:any = navigator.userAgent,
isWindowsPhone = /(?:Windows Phone)/.test(ua),
isSymbian = /(?:SymbianOS)/.test(ua) || isWindowsPhone,
isAndroid = /(?:Android)/.test(ua),
isFireFox = /(?:Firefox)/.test(ua),
isTablet = /(?:iPad|PlayBook)/.test(ua) || (isAndroid && !/(?:Mobile)/.test(ua)) || (isFireFox && /(?:Tablet)/.test(ua)),
isPhone = /(?:iPhone)/.test(ua) && !isTablet,
isPc = !isPhone && !isAndroid && !isSymbian;
return {
isTablet: isTablet,
isPhone: isPhone,
isAndroid: isAndroid,
isPC: isPc,
isH5: isPhone || isAndroid || isTablet,
};
};
export default browser;
@@ -0,0 +1,290 @@
import { isTypingMessage, JSONToObject } from "../../TUIComponents/container/TUIChat/utils/utils";
import TIM from "tim-js-sdk/tim-js-friendship";
class TUINotification {
public allowNotifications = true;
public showPreviews = true;
public notificationTitle = '腾讯云 IM ';
public notificationIcon = 'https://web.sdk.qcloud.com/im/demo/latest/faviconnew.png';
static TUICore: any;
static instance: TUINotification;
constructor(params?: {
allowNotifications?: boolean,
showPreviews?: boolean
notificationTitle?: string,
notificationIcon?: string,
}) {
if (!params) return;
(params?.allowNotifications !== undefined) && (this.allowNotifications = params.allowNotifications);
(params?.showPreviews !== undefined) && (this.showPreviews = params.showPreviews);
(params?.notificationTitle !== undefined) && (this.notificationTitle = params.notificationTitle);
(params?.notificationIcon !== undefined) && (this.notificationIcon = params.notificationIcon);
}
/**
* 获取 TUINotification 实例
*
* @returns {TUINotification}
*/
static getInstance(options?: any): TUINotification {
if (!TUINotification.instance) {
TUINotification.instance = new TUINotification(options);
}
return TUINotification.instance;
}
/**
* 挂载到 TUICore
*
* @param {TUICore} TUICore TUICore实例
*/
static plugin(TUICore: any, options?: any): void {
TUICore.config.notification = this.getInstance(options);
this.TUICore = TUICore;
}
/**
* 挂载到 vue 实例的上
*
* @param {app} app vue的实例
*/
static install(app: any): void {
app.use(this.getInstance());
}
public setNotificationConfiguration(params?: {
allowNotifications?: boolean,
showPreviews?: boolean
notificationTitle?: string,
notificationIcon?: string,
}): void {
if (!params) return;
(params?.allowNotifications !== undefined) && (this.allowNotifications = params.allowNotifications);
(params?.showPreviews !== undefined) && (this.showPreviews = params.showPreviews);
(params?.notificationTitle !== undefined) && (this.notificationTitle = params.notificationTitle);
(params?.notificationIcon !== undefined) && (this.notificationIcon = params.notificationIcon);
}
public async notify(message: any): Promise<void> {
if (!this.allowNotifications) {
return;
}
if (!this.checkNotificationAbility()) {
return;
}
if (!await this.requestNotificationPermission()) {
return;
}
await this.handleNotification(message);
}
public checkNotificationAbility(): boolean {
if (!('Notification' in window) || window.Notification.permission === 'denied') {
return false;
}
return true;
}
public requestNotificationPermission(): Promise<boolean> {
return new Promise((resolve, reject) => {
if (!window?.Notification) reject(false);
if (window.Notification.permission === 'granted') {
resolve(true);
}
window.Notification.requestPermission().then(permission => {
// 如果用户同意,就可以向他们发送通知
if (permission === 'granted') {
resolve(true);
}
}).catch(() => {
reject(false);
})
})
}
public async handleNotification(message: any): Promise<void> {
if (!this._isMessageNeedNotification(message)) return;
const notificationType = this._handleNotificationType(message);
let content;
let options = {
badge: this.notificationIcon,
icon: this.notificationIcon,
body: '',
requireInteraction: false,
}
switch (notificationType) {
case 'call':
content = this._handleCallNotificationContent(message);
if (!content?.content) {
return;
}
options.body = content.content;
options.requireInteraction = !content.callEnd;
break;
case 'chat':
options.body = await this._handleChatNotificationContent(message);
options.requireInteraction = false;
break;
}
const notification = new Notification(this.notificationTitle, options);
notification.onclick = () => {
window.focus();
if (!message || !message?.conversationID) {
return;
}
const TUIConversationServer = TUINotification?.TUICore?.TUIServer?.TUIConversation;
if (message?.conversationType === TIM.TYPES.CONV_C2C || message?.conversationType === TIM.TYPES.CONV_GROUP) {
TUIConversationServer?.getConversationProfile(message?.conversationID).then((imResponse: any) => {
imResponse?.data?.conversation && TUIConversationServer.handleCurrentConversation(imResponse?.data?.conversation);
})
}
notification.close()
}
}
private _isMessageNeedNotification(message: any): boolean {
if (!message || !message?.ID || !message?.type ||
message?.isRevoked || message?.isDeleted ||
(isTypingMessage && isTypingMessage(message))) {
return false;
}
if (message?.type === TIM.TYPES.MSG_GRP_TIP || message?.type === TIM.TYPES.MSG_GRP_SYS_NOTICE) {
return false;
}
const currentConversationID = TUINotification?.TUICore?.TUIServer?.TUIConversation?.currentStore?.currentConversationID;
if (this.checkPageFocus() && message?.conversationID === currentConversationID) {
return false;
}
return true;
}
private _handleNotificationType(message: any): string {
if (message.type === TIM.TYPES.MSG_CUSTOM) {
const payloadData = JSONToObject(message?.payload?.data);
if (payloadData?.businessID === 1 || payloadData?.businessID === 'av_call') {
return 'call';
}
}
return 'chat';
}
private async _handleChatNotificationContent(message: any): Promise<string> {
let content = '';
if (!message || !message?.ID || !message?.type) {
return content
}
switch (this.showPreviews) {
case true:
content = await this._handleChatNotificationContentTitle(message);
content += this._handleChatNotificationContentText(message);
break;
case false:
content = '您有' + await TUINotification?.TUICore?.tim?.getTotalUnreadMessageCount() + '条新消息';
break;
default:
break;
}
return content;
}
private async _handleChatNotificationContentTitle(message: any): Promise<string> {
let title = '';
switch (message?.conversationType) {
case TIM.TYPES.CONV_C2C:
title = (message?.nick || message?.from) + ': ';
break;
case TIM.TYPES.CONV_GROUP:
title = message?.conversationID + ': ';
await TUINotification?.TUICore?.tim?.getConversationProfile(message?.conversationID)?.then((imResponse: any) => {
title = (imResponse?.data?.conversation?.groupProfile?.name || message?.conversationID) + ': ';
}).catch(() => {
title = message?.conversationID + ': ';
})
break;
case TIM.TYPES.CONV_SYSTEM:
title = '系统消息: ';
break;
default:
break;
}
return title;
}
private _handleChatNotificationContentText(message: any): string {
let content = '';
switch (message.type) {
case TIM.TYPES.MSG_TEXT:
content += message?.payload?.text;
break;
case TIM.TYPES.MSG_CUSTOM:
content += '[自定义消息]';
break;
case TIM.TYPES.MSG_IMAGE:
content += '[图片]';
break;
case TIM.TYPES.MSG_AUDIO:
content += '[语音]';
break;
case TIM.TYPES.MSG_VIDEO:
content += '[视频]';
break;
case TIM.TYPES.MSG_FILE:
content += '[文件]';
break;
case TIM.TYPES.MSG_FACE:
content += '[表情]';
break;
case TIM.TYPES.MSG_MERGER:
content += '[聊天记录]';
break;
case TIM.TYPES.MSG_LOCATION:
content += '[位置]';
break;
default:
break;
}
return content;
}
private _handleCallNotificationContent(message: any): { content: string, callEnd: boolean } {
let content = '';
let callEnd = false;
try {
if (message.type === TIM.TYPES.MSG_CUSTOM) {
const callInfo = JSONToObject(message?.payload?.data);
const callDataInfo = JSONToObject(callInfo.data);
if (callInfo?.businessID === 1) {
if (callInfo.actionType === 1 && (
(callInfo.groupID && callInfo.timeout > 0) ||
((!callInfo.call_end && callInfo.call_end !== 0) &&
!callInfo.groupID &&
!(callDataInfo?.data && (callDataInfo?.data.cmd === 'switchToAudio' || callDataInfo?.data.cmd === 'switchToVideo')))
)) {
content = this.showPreviews ? `${callInfo.inviter} 发起通话` : `您有一个通话请求`;
callEnd = false;
} else if (callInfo.actionType === 2) {
content = this.showPreviews ? `${callInfo.inviter} 取消通话` : `通话取消`;
callEnd = true;
}
}
}
} catch (error: any) {
console.warn(error);
}
return {
content,
callEnd
}
}
public checkPageFocus(): boolean {
return document.hasFocus();
}
}
export default TUINotification;
@@ -0,0 +1,21 @@
const data = {
theme: 'dark',
};
function plugin(TUICore:any) {
TUICore.setCommonStore(data);
}
function install(app:any) {
console.log('app', app);
}
const TUIColor = {
name: 'TUITheme',
plugin,
install,
};
export default TUIColor;
@@ -0,0 +1,88 @@
import { createI18n, useI18n } from 'vue-i18n';
import messages from '../../locales';
class TUIi18n {
public messages = {
en: {},
zh_cn: {},
};
public i18n: any;
static instance: TUIi18n;
constructor(messages:any) {
this.messages = messages;
}
/**
* 获取 TUIi18n 实例
*
* @returns {TUIi18n}
*/
static getInstance() {
if (!TUIi18n.instance) {
TUIi18n.instance = new TUIi18n(messages);
}
return TUIi18n.instance;
}
/**
* 注入需要国际化的词条
*
* @param {Object} messages 数据对象
* @returns {messages} 全部国际化词条
*/
public provideMessage(messages: any) {
this.messages.en = { ...this.messages.en, ...messages.en };
this.messages.zh_cn = { ...this.messages.zh_cn, ...messages.zh_cn };
return this.messages;
}
/**
* 使用国际化
*
* @returns {useI18n} 国际化使用函数
*/
public useI18n() {
return useI18n();
}
/**
* 挂载到 vue 实例的上
*
* @param {app} app vue的实例
*/
static install(app: any) {
const that = TUIi18n.getInstance();
// const lang = navigator.language.substr(0, 2);
const lang = 'zh';
that.i18n = createI18n({
legacy: false, // 使用Composition API,这里必须设置为false
globalInjection: true,
global: true,
locale: lang === 'zh' ? 'zh_cn' : lang,
fallbackLocale: 'zh_cn', // 默认语言
messages: that.messages,
});
app.use(that.i18n);
}
/**
* 挂载到 TUICore
*
* @param {TUICore} TUICore TUICore实例
*/
static plugin(TUICore:any) {
TUICore.config.i18n = TUIi18n.getInstance();
}
}
/**
* 国际化标识
*
* @returns {locale} 国际化标识
*/
export function useI18nLocale() {
return TUIi18n.getInstance().i18n.global.locale;
}
export default TUIi18n;
+7
View File
@@ -0,0 +1,7 @@
import TUITheme from './TUITheme';
import TUIi18n from './TUIi18n';
import TUIEnv from './TUIEnv';
import TUIDirective from './TUIDirective';
import TUINotification from './TUINotification';
export { TUITheme, TUIi18n, TUIEnv, TUIDirective, TUINotification };