feat(deploy): 完成私有化部署全流程验收
- 更新部署进度文档,标记P5-02/P5-03为已完成状态 - 修复中文乱码问题,MySQL数据层使用UNHEX函数配合nginx字符集设置 - 配置im-service和update-service的内部服务URL,从127.0.0.1改为Docker服务名 - 实现全功能验收,nginx为所有服务添加路由映射并返回正确的状态码 - 创建私有化部署默认信息文档,记录完整的部署配置和访问地址 - 添加部署清理脚本clean.sh,支持一键清理容器、配置和数据目录 - 更新敏感配置模板,添加详细的密码和密钥配置说明 - 优化前端实时消息轮询机制,通过WebSocket心跳检测决定是否启用HTTP轮询回退
这个提交包含在:
父节点
3900d25d51
当前提交
290a6999fe
@ -39,6 +39,9 @@ let imClient: ImClient | null = null
|
||||
let activeAppKey = ''
|
||||
let storeReviewHandler: ((event: StoreReviewRefreshEvent) => void) | null = null
|
||||
let serviceActivationHandler: ((event: ServiceActivationRefreshEvent) => void) | null = null
|
||||
// Tracks when a message was last received over the IM WebSocket (any type).
|
||||
// Used by callers to decide whether IM is healthy enough to skip HTTP polling.
|
||||
let lastImMessageAt = 0
|
||||
|
||||
function sdkWsUrl() {
|
||||
return import.meta.env.VITE_IM_WS_URL ?? ''
|
||||
@ -114,6 +117,7 @@ async function ensureConnection(appKey: string) {
|
||||
const wsUrl = sdkWsUrl() || undefined
|
||||
const clientInstance = new ImClient({ tokenSupplier: () => platformToken, wsUrl })
|
||||
clientInstance.on('message', (message) => {
|
||||
lastImMessageAt = Date.now()
|
||||
const event = parseAnyEvent(message)
|
||||
if (!event || event.appKey !== activeAppKey) return
|
||||
if (event.event === 'store_review_update' && storeReviewHandler) {
|
||||
@ -131,6 +135,14 @@ async function ensureConnection(appKey: string) {
|
||||
imClient = clientInstance
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the IM WebSocket received a message within the last 90 seconds,
|
||||
* meaning the connection is healthy and polling can be skipped.
|
||||
*/
|
||||
export function isStoreReviewRealtimeConnected(): boolean {
|
||||
return imClient !== null && Date.now() - lastImMessageAt < 90_000
|
||||
}
|
||||
|
||||
export async function connectStoreReviewRealtime(appKey: string, onEvent: (event: StoreReviewRefreshEvent) => void) {
|
||||
if (!appKey) return
|
||||
storeReviewHandler = onEvent
|
||||
|
||||
@ -946,6 +946,7 @@ import {
|
||||
connectStoreReviewRealtime,
|
||||
disconnectStoreReviewRealtime,
|
||||
notifyStoreReviewRefresh,
|
||||
isStoreReviewRealtimeConnected,
|
||||
type StoreReviewRefreshEvent,
|
||||
} from '@/services/storeReviewRealtime'
|
||||
import huaweiGuideImage from '@/assets/update-store/huawei/01.png'
|
||||
@ -1684,6 +1685,9 @@ function openStoreReviewDetail(row: AppVersion) {
|
||||
|
||||
function startDialogPoll() {
|
||||
stopDialogPoll()
|
||||
// IM WebSocket delivers real-time store_review_update events; only fall back to
|
||||
// HTTP polling when IM has been silent for over 90 s (disconnected or starting up).
|
||||
const interval = isStoreReviewRealtimeConnected() ? 30_000 : 3_000
|
||||
storeReviewDialogPollTimer = setInterval(() => {
|
||||
if (!showStoreReviewDetail.value || !storeReviewDetailVersion.value) {
|
||||
stopDialogPoll()
|
||||
@ -1697,7 +1701,7 @@ function startDialogPoll() {
|
||||
} else {
|
||||
stopDialogPoll()
|
||||
}
|
||||
}, 3000)
|
||||
}, interval)
|
||||
}
|
||||
|
||||
function stopDialogPoll() {
|
||||
|
||||
正在加载...
在新工单中引用
屏蔽一个用户