From bbc4dce0b61b44447f84732d841b8a66e3a2f4be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BC=96=E7=A0=81=E5=B7=A5=E7=A8=8B=E5=B8=88?= Date: Thu, 20 Aug 2026 16:21:40 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E9=AA=8C=E6=94=B6=E5=8C=85=E5=86=99?= =?UTF-8?q?=E5=85=A5=E5=85=AC=E5=8F=B8=E5=86=85=E7=BD=91=E5=9C=B0=E5=9D=80?= =?UTF-8?q?=EF=BC=8C=E9=81=BF=E5=85=8D=20Windows=20=E7=A9=BA=20VITE=20?= =?UTF-8?q?=E4=B8=8E=20Android=20=E5=81=87=E5=9F=9F=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Windows 补 .env.production 与 endpoints 兜底;Android 默认 host/端口改为内网,启动后重写 HttpUtil/ApiService,Urls 改为 getter。 Co-authored-by: Cursor Co-authored-by: multica-agent --- mobile-next/lib/company/config/bootstrap.dart | 3 +- mobile-next/openim_common/lib/src/config.dart | 11 +++--- mobile-next/openim_common/lib/src/urls.dart | 35 +++++++++++-------- .../lib/src/utils/http_util.dart | 29 ++++++++++----- pc-client/.env.production | 6 ++++ pc-client/src/api/imApi.ts | 5 +-- pc-client/src/config/endpoints.ts | 11 ++++++ pc-client/src/layout/useGlobalEvents.tsx | 5 +-- .../src/pages/contact/myFriends/index.tsx | 3 +- pc-client/src/pages/login/LoginForm.tsx | 3 +- 10 files changed, 76 insertions(+), 35 deletions(-) create mode 100644 pc-client/.env.production create mode 100644 pc-client/src/config/endpoints.ts diff --git a/mobile-next/lib/company/config/bootstrap.dart b/mobile-next/lib/company/config/bootstrap.dart index e6ef18c..cfe4e06 100644 --- a/mobile-next/lib/company/config/bootstrap.dart +++ b/mobile-next/lib/company/config/bootstrap.dart @@ -10,6 +10,7 @@ class CompanyBootstrap { static Future install() async { applyOfficialStylesFromTokens(); await DataSp.putServerConfig(AppEndpoints.toServerConfig()); - ApiService().setBaseUrl(AppEndpoints.host); + HttpUtil.setBaseUrl(AppEndpoints.apiAddr); + ApiService().setBaseUrl(AppEndpoints.apiAddr); } } diff --git a/mobile-next/openim_common/lib/src/config.dart b/mobile-next/openim_common/lib/src/config.dart index 91cecb4..8be0b8a 100644 --- a/mobile-next/openim_common/lib/src/config.dart +++ b/mobile-next/openim_common/lib/src/config.dart @@ -20,7 +20,7 @@ class Config { await Hive.initFlutter(path); MediaKit.ensureInitialized(); HttpUtil.init(); - ApiService().setBaseUrl(serverIp); + ApiService().setBaseUrl(imApiUrl); } catch (_) {} runApp(); @@ -65,9 +65,10 @@ class Config { static const friendScheme = "io.openim.app/addFriend/"; static const groupScheme = "io.openim.app/joinGroup/"; - static const _host = "your-server-ip or your-domain"; + static const _host = "192.168.200.11"; - static const _ipRegex = '((2[0-4]\\d|25[0-5]|[01]?\\d\\d?)\\.){3}(2[0-4]\\d|25[0-5]|[01]?\\d\\d?)'; + static const _ipRegex = + '((2[0-4]\\d|25[0-5]|[01]?\\d\\d?)\\.){3}(2[0-4]\\d|25[0-5]|[01]?\\d\\d?)'; static bool get _isIP => RegExp(_ipRegex).hasMatch(_host); @@ -86,7 +87,7 @@ class Config { if (null != server) { url = server['chatTokenUrl']; } - return url ?? (_isIP ? "http://$_host:10009" : "https://$_host/chat"); + return url ?? (_isIP ? "http://$_host:10010" : "https://$_host/chat"); } static String get appAuthUrl { @@ -95,7 +96,7 @@ class Config { if (null != server) { url = server['authUrl']; } - return url ?? (_isIP ? "http://$_host:10008" : "https://$_host/chat"); + return url ?? (_isIP ? "http://$_host:10010" : "https://$_host/chat"); } static String get imApiUrl { diff --git a/mobile-next/openim_common/lib/src/urls.dart b/mobile-next/openim_common/lib/src/urls.dart index 5ede5a0..f967e73 100644 --- a/mobile-next/openim_common/lib/src/urls.dart +++ b/mobile-next/openim_common/lib/src/urls.dart @@ -1,22 +1,27 @@ import 'config.dart'; class Urls { - static final onlineStatus = "${Config.imApiUrl}/manager/get_users_online_status"; - static final queryAllUsers = "${Config.imApiUrl}/manager/get_all_users_uid"; - static final updateUserInfo = "${Config.appAuthUrl}/user/update"; - static final searchFriendInfo = "${Config.appAuthUrl}/friend/search"; - static final getUsersFullInfo = "${Config.appAuthUrl}/user/find/full"; - static final searchUserFullInfo = "${Config.appAuthUrl}/user/search/full"; + static String get onlineStatus => + "${Config.imApiUrl}/manager/get_users_online_status"; + static String get queryAllUsers => + "${Config.imApiUrl}/manager/get_all_users_uid"; + static String get updateUserInfo => "${Config.appAuthUrl}/user/update"; + static String get searchFriendInfo => "${Config.appAuthUrl}/friend/search"; + static String get getUsersFullInfo => "${Config.appAuthUrl}/user/find/full"; + static String get searchUserFullInfo => + "${Config.appAuthUrl}/user/search/full"; - static final getVerificationCode = "${Config.appAuthUrl}/account/code/send"; - static final checkVerificationCode = "${Config.appAuthUrl}/account/code/verify"; - static final register = "${Config.appAuthUrl}/account/register"; + static String get getVerificationCode => + "${Config.appAuthUrl}/account/code/send"; + static String get checkVerificationCode => + "${Config.appAuthUrl}/account/code/verify"; + static String get register => "${Config.appAuthUrl}/account/register"; - static final resetPwd = "${Config.appAuthUrl}/account/password/reset"; - static final changePwd = "${Config.appAuthUrl}/account/password/change"; - static final login = "${Config.appAuthUrl}/account/login"; + static String get resetPwd => "${Config.appAuthUrl}/account/password/reset"; + static String get changePwd => "${Config.appAuthUrl}/account/password/change"; + static String get login => "${Config.appAuthUrl}/account/login"; - static final upgrade = "${Config.appAuthUrl}/app/check"; - static final getClientConfig = '${Config.appAuthUrl}/client_config/get'; - static final getTokenForRTC = "${Config.appAuthUrl}/user/rtc/get_token"; + static String get upgrade => "${Config.appAuthUrl}/app/check"; + static String get getClientConfig => '${Config.appAuthUrl}/client_config/get'; + static String get getTokenForRTC => "${Config.appAuthUrl}/user/rtc/get_token"; } diff --git a/mobile-next/openim_common/lib/src/utils/http_util.dart b/mobile-next/openim_common/lib/src/utils/http_util.dart index 8340da1..b7a6858 100644 --- a/mobile-next/openim_common/lib/src/utils/http_util.dart +++ b/mobile-next/openim_common/lib/src/utils/http_util.dart @@ -39,7 +39,12 @@ class HttpUtil { dio.options.receiveTimeout = const Duration(seconds: 30); } - static String get operationID => DateTime.now().millisecondsSinceEpoch.toString(); + static void setBaseUrl(String url) { + dio.options.baseUrl = url; + } + + static String get operationID => + DateTime.now().millisecondsSinceEpoch.toString(); static Future post( String path, { @@ -103,8 +108,11 @@ class HttpUtil { final bytes = await File(compressPath ?? path).readAsBytes(); final mf = MultipartFile.fromBytes(bytes, filename: fileName); - var formData = - FormData.fromMap({'operationID': '${DateTime.now().millisecondsSinceEpoch}', 'fileType': 1, 'file': mf}); + var formData = FormData.fromMap({ + 'operationID': '${DateTime.now().millisecondsSinceEpoch}', + 'fileType': 1, + 'file': mf + }); var resp = await dio.post>( "${Config.imApiUrl}/third/minio_upload", @@ -151,12 +159,14 @@ class HttpUtil { onCompletion?.call(); intervalDo.drop( fun: () async { - saveFileToGallerySaver(File(cachePath), showTaost: EasyLoading.isShow); + saveFileToGallerySaver(File(cachePath), + showTaost: EasyLoading.isShow); }, milliseconds: 1500); } if (count == total) { - saveFileToGallerySaver(File(cachePath), showTaost: EasyLoading.isShow); + saveFileToGallerySaver(File(cachePath), + showTaost: EasyLoading.isShow); } }, ); @@ -166,7 +176,8 @@ class HttpUtil { var byteData = await image.toByteData(format: ImageByteFormat.png); if (byteData != null) { Uint8List uint8list = byteData.buffer.asUint8List(); - var result = await ImageGallerySaverPlus.saveImage(Uint8List.fromList(uint8list)); + var result = + await ImageGallerySaverPlus.saveImage(Uint8List.fromList(uint8list)); if (result != null) { var tips = StrRes.saveSuccessfully; if (Platform.isAndroid) { @@ -214,13 +225,15 @@ class HttpUtil { ); } - static Future saveFileToGallerySaver(File file, {String? name, bool showTaost = true}) async { + static Future saveFileToGallerySaver(File file, + {String? name, bool showTaost = true}) async { Permissions.storage(() async { var tips = StrRes.saveSuccessfully; Logger.print('saveFileToGallerySaver: ${file.path}'); final imageBytes = await file.readAsBytes(); - final result = await ImageGallerySaverPlus.saveImage(imageBytes, name: name); + final result = + await ImageGallerySaverPlus.saveImage(imageBytes, name: name); if (result != null && showTaost) { if (Platform.isAndroid) { final filePath = result['filePath'].split('//').last; diff --git a/pc-client/.env.production b/pc-client/.env.production new file mode 100644 index 0000000..7221850 --- /dev/null +++ b/pc-client/.env.production @@ -0,0 +1,6 @@ +# 生产/验收包写入的公司内网地址。vite build 默认 mode=production 会加载本文件。 +# 不要依赖本机未入库的 .env:缺文件时 VITE_* 会变成 undefined,登录会变成网络失败。 +VITE_WS_URL=ws://192.168.200.11:10001 +VITE_API_URL=http://192.168.200.11:10002 +VITE_ACCOUNT_URL=http://192.168.200.11:10010 +VITE_LIVEKIT_URL=ws://192.168.200.11:17880 diff --git a/pc-client/src/api/imApi.ts b/pc-client/src/api/imApi.ts index cfde7fb..87ec0ad 100644 --- a/pc-client/src/api/imApi.ts +++ b/pc-client/src/api/imApi.ts @@ -1,5 +1,6 @@ import axios from "axios"; +import { ACCOUNT_URL, LIVEKIT_URL } from "@/config/endpoints"; import { getIMToken } from "@/utils/storage"; // RTC(音视频通话)令牌改由自研账号服务签发(原 OpenIM chat 服务 :10008 已下线)。 @@ -15,7 +16,7 @@ export const getRtcConnectData = async (room: string, identity: string) => { msg: string; data: { token: string }; }>( - `${import.meta.env.VITE_ACCOUNT_URL}/api/rtc_token`, + `${ACCOUNT_URL}/api/rtc_token`, { room, identity }, { headers: { Authorization: `Bearer ${imToken}` } }, ); @@ -24,7 +25,7 @@ export const getRtcConnectData = async (room: string, identity: string) => { } return { data: { - serverUrl: import.meta.env.VITE_LIVEKIT_URL as string, + serverUrl: LIVEKIT_URL, token: res.data.token, }, }; diff --git a/pc-client/src/config/endpoints.ts b/pc-client/src/config/endpoints.ts new file mode 100644 index 0000000..11c81f1 --- /dev/null +++ b/pc-client/src/config/endpoints.ts @@ -0,0 +1,11 @@ +/** 公司内网接口。Vite 未注入 VITE_* 时不得变成 undefined。 */ +const COMPANY_HOST = "192.168.200.11"; + +export const API_URL = + import.meta.env.VITE_API_URL || `http://${COMPANY_HOST}:10002`; +export const WS_URL = + import.meta.env.VITE_WS_URL || `ws://${COMPANY_HOST}:10001`; +export const ACCOUNT_URL = + import.meta.env.VITE_ACCOUNT_URL || `http://${COMPANY_HOST}:10010`; +export const LIVEKIT_URL = + import.meta.env.VITE_LIVEKIT_URL || `ws://${COMPANY_HOST}:17880`; diff --git a/pc-client/src/layout/useGlobalEvents.tsx b/pc-client/src/layout/useGlobalEvents.tsx index b236ec3..68f8b61 100644 --- a/pc-client/src/layout/useGlobalEvents.tsx +++ b/pc-client/src/layout/useGlobalEvents.tsx @@ -19,6 +19,7 @@ import { useEffect, useRef } from "react"; import { useNavigate } from "react-router-dom"; import { CustomType } from "@/constants"; +import { API_URL, WS_URL } from "@/config/endpoints"; import { pushNewMessage, updateOneMessage, @@ -123,8 +124,8 @@ export function useGlobalEvent() { const IMToken = (await getIMToken()) as string; const IMUserID = (await getIMUserID()) as string; try { - const apiAddr = import.meta.env.VITE_API_URL; - const wsAddr = import.meta.env.VITE_WS_URL; + const apiAddr = API_URL; + const wsAddr = WS_URL; if (window.electronAPI) { await IMSDK.initSDK({ platformID: window.electronAPI?.getPlatform() ?? 5, diff --git a/pc-client/src/pages/contact/myFriends/index.tsx b/pc-client/src/pages/contact/myFriends/index.tsx index 8e41db4..59f6eb1 100644 --- a/pc-client/src/pages/contact/myFriends/index.tsx +++ b/pc-client/src/pages/contact/myFriends/index.tsx @@ -5,6 +5,7 @@ import { useCallback, useEffect, useMemo, useState } from "react"; import { useTranslation } from "react-i18next"; import { GroupedVirtuoso } from "react-virtuoso"; +import { ACCOUNT_URL } from "@/config/endpoints"; import { useContactStore } from "@/store"; import { emit } from "@/utils/events"; import { getIMToken } from "@/utils/storage"; @@ -29,7 +30,7 @@ export const MyFriends = () => { return; } const { data } = await axios.get( - `${import.meta.env.VITE_ACCOUNT_URL}/api/directory`, + `${ACCOUNT_URL}/api/directory`, { params: { keyword: "", limit: 100 }, headers: { Authorization: `Bearer ${token}` }, diff --git a/pc-client/src/pages/login/LoginForm.tsx b/pc-client/src/pages/login/LoginForm.tsx index 0b610e5..bb4d6ee 100644 --- a/pc-client/src/pages/login/LoginForm.tsx +++ b/pc-client/src/pages/login/LoginForm.tsx @@ -4,6 +4,7 @@ import { t } from "i18next"; import { useState } from "react"; import { useNavigate } from "react-router-dom"; +import { ACCOUNT_URL } from "@/config/endpoints"; import { setIMProfile } from "@/utils/storage"; interface LoginResult { @@ -29,7 +30,7 @@ const LoginForm = ({ onBanner }: LoginFormProps) => { setLoading(true); try { const { data: res } = await axios.post( - `${import.meta.env.VITE_ACCOUNT_URL}/api/login`, + `${ACCOUNT_URL}/api/login`, { staffNo: values.staffNo.trim(), password: values.password,