新增 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)与截图联调脚本
@@ -0,0 +1,18 @@
|
||||
import { App } from "antd";
|
||||
import type { MessageInstance } from "antd/es/message/interface";
|
||||
import type { ModalStaticFunctions } from "antd/es/modal/confirm";
|
||||
import type { NotificationInstance } from "antd/es/notification/interface";
|
||||
|
||||
let message: MessageInstance;
|
||||
let notification: NotificationInstance;
|
||||
let modal: Omit<ModalStaticFunctions, "warn">;
|
||||
|
||||
export default () => {
|
||||
const staticFunction = App.useApp();
|
||||
message = staticFunction.message;
|
||||
modal = staticFunction.modal;
|
||||
notification = staticFunction.notification;
|
||||
return null;
|
||||
};
|
||||
|
||||
export { message, modal, notification };
|
||||
@@ -0,0 +1,44 @@
|
||||
import { App as AntdApp, ConfigProvider, theme } from "antd";
|
||||
import enUS from "antd/locale/en_US";
|
||||
import zhCN from "antd/locale/zh_CN";
|
||||
import { Suspense, useEffect } from "react";
|
||||
import { QueryClient, QueryClientProvider } from "react-query";
|
||||
import { ReactQueryDevtools } from "react-query/devtools";
|
||||
import { RouterProvider } from "react-router-dom";
|
||||
|
||||
import AntdGlobalComp from "./AntdGlobalComp";
|
||||
import router from "./routes";
|
||||
import { useUserStore } from "./store";
|
||||
|
||||
function App() {
|
||||
const locale = useUserStore((state) => state.appSettings.locale);
|
||||
const queryClient = new QueryClient({
|
||||
defaultOptions: {
|
||||
queries: {
|
||||
refetchOnWindowFocus: false,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<ConfigProvider
|
||||
autoInsertSpaceInButton={false}
|
||||
locale={locale === "zh-CN" ? zhCN : enUS}
|
||||
theme={{
|
||||
token: { colorPrimary: "#0073D9" },
|
||||
}}
|
||||
>
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<Suspense fallback={<div>loading...</div>}>
|
||||
<AntdApp>
|
||||
<AntdGlobalComp />
|
||||
<RouterProvider router={router} />
|
||||
</AntdApp>
|
||||
</Suspense>
|
||||
<ReactQueryDevtools initialIsOpen={false} />
|
||||
</QueryClientProvider>
|
||||
</ConfigProvider>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
@@ -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);
|
||||
}
|
||||
};
|
||||
@@ -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,
|
||||
},
|
||||
};
|
||||
};
|
||||
@@ -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: {} };
|
||||
};
|
||||
|
After Width: | Height: | Size: 6.2 KiB |
|
After Width: | Height: | Size: 6.9 KiB |
|
After Width: | Height: | Size: 6.7 KiB |
|
After Width: | Height: | Size: 4.3 KiB |
|
After Width: | Height: | Size: 6.0 KiB |
|
After Width: | Height: | Size: 6.3 KiB |
|
After Width: | Height: | Size: 961 B |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 669 B |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 649 B |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 894 B |
|
After Width: | Height: | Size: 884 B |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 719 B |
|
After Width: | Height: | Size: 761 B |
|
After Width: | Height: | Size: 1007 B |
|
After Width: | Height: | Size: 624 B |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 855 B |
|
After Width: | Height: | Size: 907 B |
|
After Width: | Height: | Size: 807 B |
|
After Width: | Height: | Size: 795 B |
|
After Width: | Height: | Size: 792 B |
|
After Width: | Height: | Size: 928 B |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 695 B |
|
After Width: | Height: | Size: 360 B |
|
After Width: | Height: | Size: 900 B |
|
After Width: | Height: | Size: 499 B |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 3.3 KiB |
|
After Width: | Height: | Size: 3.3 KiB |
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 3.3 KiB |
|
After Width: | Height: | Size: 3.3 KiB |
|
After Width: | Height: | Size: 771 B |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 827 B |
|
After Width: | Height: | Size: 817 B |
|
After Width: | Height: | Size: 723 B |
|
After Width: | Height: | Size: 723 B |
|
After Width: | Height: | Size: 817 B |
|
After Width: | Height: | Size: 818 B |
|
After Width: | Height: | Size: 780 B |
|
After Width: | Height: | Size: 778 B |
|
After Width: | Height: | Size: 188 KiB |
|
After Width: | Height: | Size: 446 B |
|
After Width: | Height: | Size: 912 B |
|
After Width: | Height: | Size: 499 B |
|
After Width: | Height: | Size: 661 B |
|
After Width: | Height: | Size: 362 B |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 141 B |
|
After Width: | Height: | Size: 833 B |
|
After Width: | Height: | Size: 61 KiB |
|
After Width: | Height: | Size: 43 KiB |
|
After Width: | Height: | Size: 485 B |
|
After Width: | Height: | Size: 846 B |
|
After Width: | Height: | Size: 602 B |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 946 B |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 391 B |
|
After Width: | Height: | Size: 367 B |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 412 B |
|
After Width: | Height: | Size: 440 B |
|
After Width: | Height: | Size: 500 B |
|
After Width: | Height: | Size: 670 B |
|
After Width: | Height: | Size: 141 KiB |
|
After Width: | Height: | Size: 913 B |
|
After Width: | Height: | Size: 897 B |
|
After Width: | Height: | Size: 893 B |
|
After Width: | Height: | Size: 880 B |
|
After Width: | Height: | Size: 1.2 KiB |