fix(ws): 发送 WebSocket 协议级 Ping 控制帧防止 60s 后连接断开
writePump 只发 ActionCable 文本 JSON ping,从不发 websocket.PingMessage, 导致 readPump 的 PongHandler 永远不触发,ReadDeadline(60s) 到期后连接 被强制关闭。前端每 60 秒弹出"离线""重连"通知。 修复:在 ticker 中先发 PingMessage 控制帧(浏览器自动回 Pong 重置 ReadDeadline),再发 ActionCable 文本 ping(保活 ConnectionMonitor)。 同时包含此前会话中的其他变更: - 移除安全设置(SAML)页面及路由 - 新增超级管理员控制台前端页面 - platform agent_bots 路由使用 Platform* handler - 超级管理员入口改为 SPA 内路由跳转
This commit is contained in:
@@ -59,6 +59,7 @@ import copilotMessages from './captain/copilotMessages';
|
||||
import captainScenarios from './captain/scenarios';
|
||||
import captainTools from './captain/tools';
|
||||
import captainCustomTools from './captain/customTools';
|
||||
import platform from './modules/platform';
|
||||
|
||||
const plugins = [];
|
||||
|
||||
@@ -123,6 +124,7 @@ export default createStore({
|
||||
captainScenarios,
|
||||
captainTools,
|
||||
captainCustomTools,
|
||||
platform,
|
||||
},
|
||||
plugins,
|
||||
});
|
||||
|
||||
@@ -0,0 +1,394 @@
|
||||
import types from '../mutation-types';
|
||||
import PlatformAPI from '../../api/platform';
|
||||
import { throwErrorMessage } from '../utils/api';
|
||||
|
||||
export const state = {
|
||||
accounts: [],
|
||||
users: [],
|
||||
agentBots: [],
|
||||
installationConfigs: [],
|
||||
uiFlags: {
|
||||
isFetchingAccounts: false,
|
||||
isFetchingUsers: false,
|
||||
isFetchingAgentBots: false,
|
||||
isFetchingConfigs: false,
|
||||
isCreating: false,
|
||||
isUpdating: false,
|
||||
isDeleting: false,
|
||||
},
|
||||
};
|
||||
|
||||
export const getters = {
|
||||
getAccounts: $state => $state.accounts,
|
||||
getUsers: $state => $state.users,
|
||||
getPlatformAgentBots: $state => $state.agentBots,
|
||||
getInstallationConfigs: $state => $state.installationConfigs,
|
||||
getUIFlags: $state => $state.uiFlags,
|
||||
};
|
||||
|
||||
export const actions = {
|
||||
// ── Accounts ──────────────────────────────────────────
|
||||
fetchAccounts: async ({ commit }, params) => {
|
||||
commit(types.SET_PLATFORM_UI_FLAG, { isFetchingAccounts: true });
|
||||
try {
|
||||
const response = await PlatformAPI.getAccounts(params);
|
||||
const payload = response.data?.data || response.data || [];
|
||||
commit(types.SET_PLATFORM_ACCOUNTS, payload);
|
||||
return payload;
|
||||
} catch (error) {
|
||||
throwErrorMessage(error);
|
||||
} finally {
|
||||
commit(types.SET_PLATFORM_UI_FLAG, { isFetchingAccounts: false });
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
createAccount: async ({ commit }, accountData) => {
|
||||
commit(types.SET_PLATFORM_UI_FLAG, { isCreating: true });
|
||||
try {
|
||||
const response = await PlatformAPI.createAccount(accountData);
|
||||
const payload = response.data?.data || response.data;
|
||||
commit(types.ADD_PLATFORM_ACCOUNT, payload);
|
||||
return payload;
|
||||
} catch (error) {
|
||||
throwErrorMessage(error);
|
||||
} finally {
|
||||
commit(types.SET_PLATFORM_UI_FLAG, { isCreating: false });
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
updateAccount: async ({ commit }, { id, data }) => {
|
||||
commit(types.SET_PLATFORM_UI_FLAG, { isUpdating: true });
|
||||
try {
|
||||
const response = await PlatformAPI.updateAccount(id, data);
|
||||
commit(types.EDIT_PLATFORM_ACCOUNT, response.data);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
throwErrorMessage(error);
|
||||
} finally {
|
||||
commit(types.SET_PLATFORM_UI_FLAG, { isUpdating: false });
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
deleteAccount: async ({ commit }, id) => {
|
||||
commit(types.SET_PLATFORM_UI_FLAG, { isDeleting: true });
|
||||
try {
|
||||
await PlatformAPI.deleteAccount(id);
|
||||
commit(types.DELETE_PLATFORM_ACCOUNT, id);
|
||||
} catch (error) {
|
||||
throwErrorMessage(error);
|
||||
} finally {
|
||||
commit(types.SET_PLATFORM_UI_FLAG, { isDeleting: false });
|
||||
}
|
||||
},
|
||||
|
||||
// ── Users ─────────────────────────────────────────────
|
||||
fetchUsers: async ({ commit }, params) => {
|
||||
commit(types.SET_PLATFORM_UI_FLAG, { isFetchingUsers: true });
|
||||
try {
|
||||
const response = await PlatformAPI.getUsers(params);
|
||||
const payload = response.data?.data || response.data || [];
|
||||
commit(types.SET_PLATFORM_USERS, payload);
|
||||
return payload;
|
||||
} catch (error) {
|
||||
throwErrorMessage(error);
|
||||
} finally {
|
||||
commit(types.SET_PLATFORM_UI_FLAG, { isFetchingUsers: false });
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
createUser: async ({ commit }, userData) => {
|
||||
commit(types.SET_PLATFORM_UI_FLAG, { isCreating: true });
|
||||
try {
|
||||
const response = await PlatformAPI.createUser(userData);
|
||||
const payload = response.data?.data || response.data;
|
||||
commit(types.ADD_PLATFORM_USER, payload);
|
||||
return payload;
|
||||
} catch (error) {
|
||||
throwErrorMessage(error);
|
||||
} finally {
|
||||
commit(types.SET_PLATFORM_UI_FLAG, { isCreating: false });
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
updateUser: async ({ commit }, { id, data }) => {
|
||||
commit(types.SET_PLATFORM_UI_FLAG, { isUpdating: true });
|
||||
try {
|
||||
const response = await PlatformAPI.updateUser(id, data);
|
||||
commit(types.EDIT_PLATFORM_USER, response.data);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
throwErrorMessage(error);
|
||||
} finally {
|
||||
commit(types.SET_PLATFORM_UI_FLAG, { isUpdating: false });
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
deleteUser: async ({ commit }, id) => {
|
||||
commit(types.SET_PLATFORM_UI_FLAG, { isDeleting: true });
|
||||
try {
|
||||
await PlatformAPI.deleteUser(id);
|
||||
commit(types.DELETE_PLATFORM_USER, id);
|
||||
} catch (error) {
|
||||
throwErrorMessage(error);
|
||||
} finally {
|
||||
commit(types.SET_PLATFORM_UI_FLAG, { isDeleting: false });
|
||||
}
|
||||
},
|
||||
|
||||
// ── Agent Bots (platform-level) ───────────────────────
|
||||
fetchAgentBots: async ({ commit }, params) => {
|
||||
commit(types.SET_PLATFORM_UI_FLAG, { isFetchingAgentBots: true });
|
||||
try {
|
||||
const response = await PlatformAPI.getAgentBots(params);
|
||||
const payload = response.data?.data || response.data || [];
|
||||
commit(types.SET_PLATFORM_AGENT_BOTS, payload);
|
||||
return payload;
|
||||
} catch (error) {
|
||||
throwErrorMessage(error);
|
||||
} finally {
|
||||
commit(types.SET_PLATFORM_UI_FLAG, { isFetchingAgentBots: false });
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
createAgentBot: async ({ commit }, botData) => {
|
||||
commit(types.SET_PLATFORM_UI_FLAG, { isCreating: true });
|
||||
try {
|
||||
const response = await PlatformAPI.createAgentBot(botData);
|
||||
const payload = response.data?.data || response.data;
|
||||
commit(types.ADD_PLATFORM_AGENT_BOT, payload);
|
||||
return payload;
|
||||
} catch (error) {
|
||||
throwErrorMessage(error);
|
||||
} finally {
|
||||
commit(types.SET_PLATFORM_UI_FLAG, { isCreating: false });
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
updateAgentBot: async ({ commit }, { id, data }) => {
|
||||
commit(types.SET_PLATFORM_UI_FLAG, { isUpdating: true });
|
||||
try {
|
||||
const response = await PlatformAPI.updateAgentBot(id, data);
|
||||
commit(types.EDIT_PLATFORM_AGENT_BOT, response.data);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
throwErrorMessage(error);
|
||||
} finally {
|
||||
commit(types.SET_PLATFORM_UI_FLAG, { isUpdating: false });
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
deleteAgentBot: async ({ commit }, id) => {
|
||||
commit(types.SET_PLATFORM_UI_FLAG, { isDeleting: true });
|
||||
try {
|
||||
await PlatformAPI.deleteAgentBot(id);
|
||||
commit(types.DELETE_PLATFORM_AGENT_BOT, id);
|
||||
} catch (error) {
|
||||
throwErrorMessage(error);
|
||||
} finally {
|
||||
commit(types.SET_PLATFORM_UI_FLAG, { isDeleting: false });
|
||||
}
|
||||
},
|
||||
|
||||
// ── Installation Config ───────────────────────────────
|
||||
fetchInstallationConfigs: async ({ commit }, params) => {
|
||||
commit(types.SET_PLATFORM_UI_FLAG, { isFetchingConfigs: true });
|
||||
try {
|
||||
const response = await PlatformAPI.getInstallationConfigs(params);
|
||||
const payload = response.data?.data || response.data || [];
|
||||
commit(types.SET_INSTALLATION_CONFIGS, payload);
|
||||
return payload;
|
||||
} catch (error) {
|
||||
throwErrorMessage(error);
|
||||
} finally {
|
||||
commit(types.SET_PLATFORM_UI_FLAG, { isFetchingConfigs: false });
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
createInstallationConfig: async ({ commit }, configData) => {
|
||||
commit(types.SET_PLATFORM_UI_FLAG, { isCreating: true });
|
||||
try {
|
||||
const response = await PlatformAPI.createInstallationConfig(configData);
|
||||
const payload = response.data?.data || response.data;
|
||||
commit(types.ADD_INSTALLATION_CONFIG, payload);
|
||||
return payload;
|
||||
} catch (error) {
|
||||
throwErrorMessage(error);
|
||||
} finally {
|
||||
commit(types.SET_PLATFORM_UI_FLAG, { isCreating: false });
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
updateInstallationConfig: async ({ commit }, { id, data }) => {
|
||||
commit(types.SET_PLATFORM_UI_FLAG, { isUpdating: true });
|
||||
try {
|
||||
const response = await PlatformAPI.updateInstallationConfig(id, data);
|
||||
commit(types.EDIT_INSTALLATION_CONFIG, response.data);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
throwErrorMessage(error);
|
||||
} finally {
|
||||
commit(types.SET_PLATFORM_UI_FLAG, { isUpdating: false });
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
deleteInstallationConfig: async ({ commit }, id) => {
|
||||
commit(types.SET_PLATFORM_UI_FLAG, { isDeleting: true });
|
||||
try {
|
||||
await PlatformAPI.deleteInstallationConfig(id);
|
||||
commit(types.DELETE_INSTALLATION_CONFIG, id);
|
||||
} catch (error) {
|
||||
throwErrorMessage(error);
|
||||
} finally {
|
||||
commit(types.SET_PLATFORM_UI_FLAG, { isDeleting: false });
|
||||
}
|
||||
},
|
||||
|
||||
// ── Banners ───────────────────────────────────────────
|
||||
fetchBanners: async ({ commit }, params) => {
|
||||
commit(types.SET_PLATFORM_UI_FLAG, { isFetchingBanners: true });
|
||||
try {
|
||||
const response = await PlatformAPI.getBanners(params);
|
||||
const payload = response.data?.data || response.data || [];
|
||||
commit(types.SET_PLATFORM_BANNERS, payload);
|
||||
return payload;
|
||||
} catch (error) {
|
||||
throwErrorMessage(error);
|
||||
} finally {
|
||||
commit(types.SET_PLATFORM_UI_FLAG, { isFetchingBanners: false });
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
createBanner: async ({ commit }, bannerData) => {
|
||||
commit(types.SET_PLATFORM_UI_FLAG, { isCreating: true });
|
||||
try {
|
||||
const response = await PlatformAPI.createBanner(bannerData);
|
||||
const payload = response.data?.data || response.data;
|
||||
commit(types.ADD_PLATFORM_BANNER, payload);
|
||||
return payload;
|
||||
} catch (error) {
|
||||
throwErrorMessage(error);
|
||||
} finally {
|
||||
commit(types.SET_PLATFORM_UI_FLAG, { isCreating: false });
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
updateBanner: async ({ commit }, { id, data }) => {
|
||||
commit(types.SET_PLATFORM_UI_FLAG, { isUpdating: true });
|
||||
try {
|
||||
const response = await PlatformAPI.updateBanner(id, data);
|
||||
commit(types.EDIT_PLATFORM_BANNER, response.data);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
throwErrorMessage(error);
|
||||
} finally {
|
||||
commit(types.SET_PLATFORM_UI_FLAG, { isUpdating: false });
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
deleteBanner: async ({ commit }, id) => {
|
||||
commit(types.SET_PLATFORM_UI_FLAG, { isDeleting: true });
|
||||
try {
|
||||
await PlatformAPI.deleteBanner(id);
|
||||
commit(types.DELETE_PLATFORM_BANNER, id);
|
||||
} catch (error) {
|
||||
throwErrorMessage(error);
|
||||
} finally {
|
||||
commit(types.SET_PLATFORM_UI_FLAG, { isDeleting: false });
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export const mutations = {
|
||||
[types.SET_PLATFORM_UI_FLAG]($state, data) {
|
||||
$state.uiFlags = { ...$state.uiFlags, ...data };
|
||||
},
|
||||
|
||||
// Accounts
|
||||
[types.SET_PLATFORM_ACCOUNTS]($state, data) {
|
||||
$state.accounts = Array.isArray(data) ? data : data?.payload || [];
|
||||
},
|
||||
[types.ADD_PLATFORM_ACCOUNT]($state, account) {
|
||||
$state.accounts.unshift(account);
|
||||
},
|
||||
[types.EDIT_PLATFORM_ACCOUNT]($state, account) {
|
||||
const idx = $state.accounts.findIndex(a => a.id === account.id);
|
||||
if (idx !== -1) $state.accounts[idx] = account;
|
||||
},
|
||||
[types.DELETE_PLATFORM_ACCOUNT]($state, id) {
|
||||
$state.accounts = $state.accounts.filter(a => a.id !== id);
|
||||
},
|
||||
|
||||
// Users
|
||||
[types.SET_PLATFORM_USERS]($state, data) {
|
||||
$state.users = Array.isArray(data) ? data : data?.payload || [];
|
||||
},
|
||||
[types.ADD_PLATFORM_USER]($state, user) {
|
||||
$state.users.unshift(user);
|
||||
},
|
||||
[types.EDIT_PLATFORM_USER]($state, user) {
|
||||
const idx = $state.users.findIndex(u => u.id === user.id);
|
||||
if (idx !== -1) $state.users[idx] = user;
|
||||
},
|
||||
[types.DELETE_PLATFORM_USER]($state, id) {
|
||||
$state.users = $state.users.filter(u => u.id !== id);
|
||||
},
|
||||
|
||||
// Agent Bots
|
||||
[types.SET_PLATFORM_AGENT_BOTS]($state, data) {
|
||||
$state.agentBots = Array.isArray(data) ? data : data?.payload || [];
|
||||
},
|
||||
[types.ADD_PLATFORM_AGENT_BOT]($state, bot) {
|
||||
$state.agentBots.unshift(bot);
|
||||
},
|
||||
[types.EDIT_PLATFORM_AGENT_BOT]($state, bot) {
|
||||
const idx = $state.agentBots.findIndex(b => b.id === bot.id);
|
||||
if (idx !== -1) $state.agentBots[idx] = bot;
|
||||
},
|
||||
[types.DELETE_PLATFORM_AGENT_BOT]($state, id) {
|
||||
$state.agentBots = $state.agentBots.filter(b => b.id !== id);
|
||||
},
|
||||
|
||||
// Installation Configs
|
||||
[types.SET_INSTALLATION_CONFIGS]($state, data) {
|
||||
$state.installationConfigs = Array.isArray(data)
|
||||
? data
|
||||
: data?.payload || [];
|
||||
},
|
||||
[types.ADD_INSTALLATION_CONFIG]($state, config) {
|
||||
$state.installationConfigs.unshift(config);
|
||||
},
|
||||
[types.EDIT_INSTALLATION_CONFIG]($state, config) {
|
||||
const idx = $state.installationConfigs.findIndex(
|
||||
c => c.id === config.id
|
||||
);
|
||||
if (idx !== -1) $state.installationConfigs[idx] = config;
|
||||
},
|
||||
[types.DELETE_INSTALLATION_CONFIG]($state, id) {
|
||||
$state.installationConfigs = $state.installationConfigs.filter(
|
||||
c => c.id !== id
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
export default {
|
||||
namespaced: true,
|
||||
actions,
|
||||
state,
|
||||
getters,
|
||||
mutations,
|
||||
};
|
||||
@@ -392,4 +392,23 @@ export default {
|
||||
EDIT_AGENT_CAPACITY_POLICIES_INBOXES: 'EDIT_AGENT_CAPACITY_POLICIES_INBOXES',
|
||||
DELETE_AGENT_CAPACITY_POLICIES_INBOXES:
|
||||
'DELETE_AGENT_CAPACITY_POLICIES_INBOXES',
|
||||
|
||||
// Platform (Super Admin)
|
||||
SET_PLATFORM_UI_FLAG: 'SET_PLATFORM_UI_FLAG',
|
||||
SET_PLATFORM_ACCOUNTS: 'SET_PLATFORM_ACCOUNTS',
|
||||
ADD_PLATFORM_ACCOUNT: 'ADD_PLATFORM_ACCOUNT',
|
||||
EDIT_PLATFORM_ACCOUNT: 'EDIT_PLATFORM_ACCOUNT',
|
||||
DELETE_PLATFORM_ACCOUNT: 'DELETE_PLATFORM_ACCOUNT',
|
||||
SET_PLATFORM_USERS: 'SET_PLATFORM_USERS',
|
||||
ADD_PLATFORM_USER: 'ADD_PLATFORM_USER',
|
||||
EDIT_PLATFORM_USER: 'EDIT_PLATFORM_USER',
|
||||
DELETE_PLATFORM_USER: 'DELETE_PLATFORM_USER',
|
||||
SET_PLATFORM_AGENT_BOTS: 'SET_PLATFORM_AGENT_BOTS',
|
||||
ADD_PLATFORM_AGENT_BOT: 'ADD_PLATFORM_AGENT_BOT',
|
||||
EDIT_PLATFORM_AGENT_BOT: 'EDIT_PLATFORM_AGENT_BOT',
|
||||
DELETE_PLATFORM_AGENT_BOT: 'DELETE_PLATFORM_AGENT_BOT',
|
||||
SET_INSTALLATION_CONFIGS: 'SET_INSTALLATION_CONFIGS',
|
||||
ADD_INSTALLATION_CONFIG: 'ADD_INSTALLATION_CONFIG',
|
||||
EDIT_INSTALLATION_CONFIG: 'EDIT_INSTALLATION_CONFIG',
|
||||
DELETE_INSTALLATION_CONFIG: 'DELETE_INSTALLATION_CONFIG',
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user