@tencentcloud/ai-desk-customer-uniapp
Version:
uni-app Vue2/Vue3 UIKit for AI Desk
321 lines (290 loc) • 10.3 kB
text/typescript
import {
isCustomerServiceMessage,
isThinkingMessage,
isMessageInvisible,
clearChatStorage,
} from './utils/index';
import TUIChatEngine, {
TUIChatService,
TUIConversationService,
IMessageModel,
TUITranslateService,
SendMessageParams,
SendMessageOptions,
TUIUserService,
TUIStore,
StoreName,
func,
} from './@aidesk/uikit-engine';
import Log from './utils/logger';
import { version } from './package.json'
import { Toast, TOAST_TYPE } from "./components/common/Toast/index-uniapp";
import { vueVersion } from "./adapter-vue-uniapp";
import { switchReadStatus, transferToTaskFlow, transferToHuman, validateUserID, updateCustomStore } from "./utils/utils";
import state from "./utils/state";
import { USER_DEFAULT_AVATAR } from "./constant";
import { ITransferToTaskFlowModel, ITransferToHumanModel } from "./interface";
interface IInitWithProfile {
SDKAppID: number,
userID: string,
userSig: string,
nickName?: string,
avatar?: string,
customerServiceID?: string,
scene?: string;
}
interface IProfile {
nick?: string,
avatar?: string,
}
export default class TUICustomerServer {
private isLoggedIn: boolean;
static instance: TUICustomerServer;
private customerServiceIDList: any[];
private currentCustomerServiceID: string;
private loggedInUserID: string;
private myProfile: IProfile;
private bindOnActionConversation: func;
private paramsForActiveAgain: any;
private _scene: string;
constructor() {
this.customerServiceIDList = ['@customer_service_account'];
this.currentCustomerServiceID = this.customerServiceIDList[0];
this.isLoggedIn = false;
this.loggedInUserID = '';
this.myProfile = { avatar: USER_DEFAULT_AVATAR };
this.bindOnActionConversation = this.onActiveConversation.bind(this);
this._scene = '';
}
static getInstance(): TUICustomerServer {
if (!TUICustomerServer.instance) {
TUICustomerServer.instance = new TUICustomerServer();
}
return TUICustomerServer.instance;
}
private async loginCustomerUIKit(SDKAppID:number, userID:string, userSig:string) {
clearChatStorage(SDKAppID, userID);
return TUIChatEngine.login({
SDKAppID,
userID,
userSig,
useUploadPlugin: true,
scene: this._scene,
}).then(() => {
Log.i(`login success. userID:${userID}`);
this.isLoggedIn = true;
this.loggedInUserID = userID;
TUIStore.watch(StoreName.CUSTOM, {
'activeConversation': this.bindOnActionConversation,
});
this.switchConversation(`C2C${this.currentCustomerServiceID}`);
switchReadStatus(state.get('showReadStatus'));
TUIChatEngine.chat.callExperimentalAPI('isFeatureEnabledForStat', Math.pow(2, 42));
})
.catch((error) => {
Toast({
message: TUITranslateService.t('TUIChat.登录失败'),
type: TOAST_TYPE.ERROR,
duration: 30000,
});
Log.l(error);
})
}
public async init(SDKAppID:number, userID:string, userSig:string) {
Log.l(`TUICustomerServer.init vue:${vueVersion} version:${version} SDKAppID:${SDKAppID} userID:${userID}` +
` isLoggedIn:${this.isLoggedIn} loggedInUserID:${this.loggedInUserID} currentCustomerServiceID:${this.currentCustomerServiceID}`);
if (userID) {
const ret = validateUserID(userID);
if (ret > 0) {
// Ensure i18n is configured first.
setTimeout(() => {
let reason = '';
if (ret === 1) {
reason = TUITranslateService.t("AIDesk.userID 只能包含可打印 ASCII 字符");
} else if (ret === 2) {
reason = TUITranslateService.t("AIDesk.userID 不能包含'administrator'");
} else if (ret === 3) {
reason = TUITranslateService.t("AIDesk.userID 长度不能超过45字节");
}
Toast({
message: reason,
type: TOAST_TYPE.ERROR,
duration: 30000,
});
}, 500);
return;
}
}
if (this.isLoggedIn) {
if (this.loggedInUserID === userID) {
await this.switchConversation(`C2C${this.currentCustomerServiceID}`);
return;
}
return this.unInit().finally(() => {
this.isLoggedIn = false;
this.loginCustomerUIKit(SDKAppID, userID, userSig);
});
} else {
return this.loginCustomerUIKit(SDKAppID, userID, userSig);
}
}
public async initWithProfile(options: IInitWithProfile) {
const { SDKAppID, userID, userSig, nickName, avatar, customerServiceID, scene } = options;
Log.l(`TUICustomerServer.initWithProfile version:${version}`);
if (nickName) {
// chat 个人资料的昵称是 nick
this.myProfile.nick = nickName;
} else {
this.myProfile.nick = '';
}
if (avatar) {
this.myProfile.avatar = avatar;
} else {
this.myProfile.avatar = USER_DEFAULT_AVATAR;
}
if (customerServiceID) {
this.currentCustomerServiceID = customerServiceID;
if (!this.customerServiceIDList.includes(this.currentCustomerServiceID)) {
this.customerServiceIDList.push(this.currentCustomerServiceID);
}
}
if (scene) {
this._scene = scene;
} else {
if (vueVersion === 2) {
this._scene = 'aidesk-customer-uni-vue2';
} else if (vueVersion === 3) {
this._scene = 'aidesk-customer-uni-vue3';
}
}
return this.init(SDKAppID, userID, userSig);
}
public async unInit() {
Log.l(`TUICustomerServer.unInit`);
TUIStore.unwatch(StoreName.CUSTOM, {
'activeConversation': this.bindOnActionConversation,
});
this.isLoggedIn = false;
// 清理预加载缓存
let preloadedEmojiMap = state.get('preloadedEmojiMap');
if (preloadedEmojiMap) {
preloadedEmojiMap.clear();
}
return TUIChatEngine.logout();
}
public sendTextMessage(options: SendMessageParams, sendMessageOptions?: SendMessageOptions) {
return TUIChatService.sendTextMessage(options, sendMessageOptions);
}
public sendCustomMessage(options: SendMessageParams, sendMessageOptions?: SendMessageOptions) {
return TUIChatService.sendCustomMessage(options, sendMessageOptions);
};
public changeLanguage(language: string) {
return TUITranslateService.changeLanguage(language).then(() => {
Log.i(`language changed to ${language}`);
});
}
public getLoggedInUserID() {
return this.loggedInUserID;
}
// Determine if the current session is a customer service session
public isCustomerConversation(conversationID: string) {
const userID = (conversationID && conversationID.slice(3)) || '';
return this.customerServiceIDList.indexOf(userID) > -1;
}
// Determine if the current message is a customer service message
public isCustomerServicePluginMessage(message: IMessageModel) {
if (!message || !this.isCustomerConversation(message.conversationID)) {
return false;
}
if (isThinkingMessage(message)) {
return false;
}
return isCustomerServiceMessage(message) || isMessageInvisible(message);
}
public onGetExtension(extensionID: string) {
if (extensionID === TUIConstants.TUIContact.EXTENSION.CONTACT_LIST.EXT_ID) {
return [
{
weight: 0,
icon: '',
text: '智能客服',
data: {
name: 'customer',
accountList: this.customerServiceIDList,
},
},
];
}
}
/**
* Set up multiple customer service ID
* @param list
*/
public setCustomerServiceIDList(list: Array<string>) {
if (!Array.isArray(list) || list.length === 0) {
return;
}
this.customerServiceIDList = list;
this.currentCustomerServiceID = list[0];
Log.i(`TUICustomerServer.setCustomerServiceIDList`, this.customerServiceIDList);
}
public transferToTaskFlow(options: ITransferToTaskFlowModel) {
transferToTaskFlow(this.currentCustomerServiceID, options.taskFlowID, options.description);
}
public transferToHuman(options: ITransferToHumanModel) {
transferToHuman(this.currentCustomerServiceID, options.groupID, options.specificMemberList, options.description);
}
/**
* Clear conversation unread count
* @param conversationID
*/
public clearConversationUnreadCount(conversationID?: string) {
Log.l(`TUICustomerServer.clearConversationUnreadCount conversationID:${conversationID}`);
if (conversationID) {
TUIConversationService.setMessageRead(conversationID);
} else {
TUIConversationService.setMessageRead('C2C@customer_service_account');
}
}
private onActiveConversation(params: any) {
if (!params) {
return;
}
Log.l(`TUICustomerServer.onActiveConversation options:`, params);
if (this.isCustomerConversation(params.conversationID)) {
// 如果有资料,确保资料更新完成(或失败)后再激活会话服务流
if (Object.keys(this.myProfile).length > 0) {
Log.l(`TUICustomerServer.onActiveConversation updateMyProfile:${JSON.stringify(this.myProfile)}`);
TUIUserService.updateMyProfile({...this.myProfile}).finally(() => {
this.activeServiceFlow(params);
});
} else {
this.activeServiceFlow(params);
}
}
}
private async switchConversation(conversationID: string) {
const ret = await TUIConversationService.switchConversation(conversationID);
// -100002 即要切换的会话 ID 跟当前已打开的会话 ID 相同,这个时候我们重发 src 7,确保服务流状态正确
if (ret.code === -100002) {
this.activeServiceFlow(this.paramsForActiveAgain);
}
}
// 激活会话服务流
private activeServiceFlow(params: any) {
Log.l(`TUICustomerServer.activeServiceFlow params:`, params);
this.paramsForActiveAgain = { ...params };
TUIChatService.sendCustomMessage({
to: params.conversationID.slice(3),
conversationType: TUIChatEngine.TYPES.CONV_C2C,
payload: {
data: JSON.stringify({
src: '7',
customerServicePlugin: 0,
triggeredContent: typeof params.robotLang === 'undefined' ? undefined : { language: params.robotLang }
}),
},
}, { onlineUserOnly: true });
Log.w(`TUICustomerServer.activeServiceFlow src 7 sent`);
}
}