新增 pc-client:畅联 PC 端工程(Electron+React,按确认效果图改造,B-59)

- 基于 openim-electron-demo 改造:工号+密码登录(自研账号服务)、会话列表/聊天窗/通讯录界面重做
- 文字/语音/文件/图片消息、文件拖拽发送、表情面板、一对一语音通话(LiveKit)
- RTC 令牌对接账号服务带鉴权版 /api/rtc_token(Bearer imToken + {room,identity})
- account-service: CORS Allow-Headers 补 authorization(浏览器/渲染进程跨域调 rtc_token 需要)
- 附本地 mock 账号服务(scripts/mock-account-server.js)与截图联调脚本
This commit is contained in:
KIMI
2026-08-09 09:11:06 +08:00
parent b95159f7eb
commit 7ce40e356f
284 changed files with 31599 additions and 7 deletions
+14
View File
@@ -0,0 +1,14 @@
import { message } from "@/AntdGlobalComp";
import { ErrCodeMap } from "@/constants";
interface ErrorData {
errCode: number;
errMsg?: string;
}
export const errorHandle = (err: unknown) => {
const errData = err as ErrorData;
if (errData.errMsg) {
message.error(ErrCodeMap[errData.errCode] || errData.errMsg);
}
};
+31
View File
@@ -0,0 +1,31 @@
import axios from "axios";
import { getIMToken } from "@/utils/storage";
// RTC(音视频通话)令牌改由自研账号服务签发(原 OpenIM chat 服务 :10008 已下线)。
// 账号服务 /api/rtc_token 用登录拿到的 IM token 鉴权(Authorization: Bearer),
// 返回形状保持 { data: { serverUrl, token } }RtcCallModal 调用处无需改动。
export const getRtcConnectData = async (room: string, identity: string) => {
const imToken = await getIMToken();
if (!imToken) {
return Promise.reject(new Error("登录已过期,请重新登录"));
}
const { data: res } = await axios.post<{
code: number;
msg: string;
data: { token: string };
}>(
`${import.meta.env.VITE_ACCOUNT_URL}/api/rtc_token`,
{ room, identity },
{ headers: { Authorization: `Bearer ${imToken}` } },
);
if (res.code !== 0) {
return Promise.reject(new Error(res.msg || "获取通话令牌失败"));
}
return {
data: {
serverUrl: import.meta.env.VITE_LIVEKIT_URL as string,
token: res.data.token,
},
};
};
+89
View File
@@ -0,0 +1,89 @@
import type { MessageReceiveOptType } from "@openim/wasm-client-sdk";
import { IMSDK } from "@/layout/MainContentWrap";
// 原 OpenIM chat 业务服务(:10008)已下线,用户信息相关接口全部改走 OpenIM SDK。
// 以下导出保持原有函数签名和返回形状({ data: { users } } 等),调用处无需大改。
export interface BusinessUserInfo {
userID: string;
password: string;
account: string;
phoneNumber: string;
areaCode: string;
email: string;
nickname: string;
faceURL: string;
gender: number;
level: number;
birth: number;
allowAddFriend: BusinessAllowType;
allowBeep: BusinessAllowType;
allowVibration: BusinessAllowType;
globalRecvMsgOpt: MessageReceiveOptType;
}
export enum BusinessAllowType {
Allow = 1,
NotAllow = 2,
}
// 批量获取用户信息(原 chat 服务 /user/find/full
// SDK 只提供公开资料(userID/nickname/faceURL/ex),手机号、邮箱等原业务字段不再有值。
export const getBusinessUserInfo = async (userIDs: string[]) => {
const { data } = await IMSDK.getUsersInfo(userIDs);
return {
data: {
users: data as unknown as BusinessUserInfo[],
},
};
};
// 按工号精确查找用户(原 chat 服务 /user/search/full
export const searchBusinessUserInfo = async (keyword: string) => {
try {
const { data } = await IMSDK.getUsersInfo([keyword]);
return {
data: {
total: data.length,
users: data as unknown as BusinessUserInfo[],
},
};
} catch {
// 查不到(用户不存在等)统一按无结果处理,由调用处提示“未搜索到相关结果”
return {
data: {
total: 0,
users: [] as BusinessUserInfo[],
},
};
}
};
interface UpdateBusinessUserInfoParams {
email: string;
nickname: string;
faceURL: string;
gender: number;
birth: number;
allowAddFriend: number;
allowBeep: number;
allowVibration: number;
globalRecvMsgOpt: number;
}
// 更新个人资料(原 chat 服务 /user/update
// OpenIM 只支持同步昵称/头像等字段,邮箱、性别、生日等业务字段仅更新本地,不会落服务端。
export const updateBusinessUserInfo = async (
params: Partial<UpdateBusinessUserInfoParams>,
) => {
const imFields: { nickname?: string; faceURL?: string; globalRecvMsgOpt?: MessageReceiveOptType } =
{};
if (params.nickname !== undefined) imFields.nickname = params.nickname;
if (params.faceURL !== undefined) imFields.faceURL = params.faceURL;
if (params.globalRecvMsgOpt !== undefined) {
imFields.globalRecvMsgOpt = params.globalRecvMsgOpt as MessageReceiveOptType;
}
await IMSDK.setSelfInfo(imFields);
return { data: {} };
};