fix: 修复4个已知BUG — P1 ChatList/P2 错误密码/P3 Copilot崩溃/P3超管entrypoint
P1: ChatList.vue — 添加 conversationStats watch fallback,检测 stats>0
但 chatList 为空时自动触发 fetchConversations
P2: api.js parseAPIErrorResponse — 处理 error 字段为对象时提取 .message
P3: CopilotContainer.vue — activeAssistant 判空保护
P3: 新建 super_admin.html + vite.config.ts rewrite 规则
(注:entrypoint 仅含样式,Vue应用代码待补)
防御: NotificationTable.vue — 可选链保护 primary_actor.meta 路径
This commit is contained in:
@@ -797,6 +797,19 @@ onMounted(() => {
|
||||
}
|
||||
});
|
||||
|
||||
// Fallback: if fetchAllConversations wasn't triggered during onMounted
|
||||
// (e.g., race condition with route transition), retry after store settles.
|
||||
// Uses a one-shot watch on conversationStats to detect empty state.
|
||||
const _fallbackWatch = watch(conversationStats, (stats) => {
|
||||
if (!stats) return;
|
||||
const totalCount = (stats.mineCount || 0) + (stats.unAssignedCount || 0) + (stats.allCount || 0);
|
||||
// If stats show conversations exist but chatList is empty, re-fetch
|
||||
if (totalCount > 0 && chatLists.value.length === 0 && !chatListLoading.value) {
|
||||
_fallbackWatch(); // unwatch immediately — one-shot
|
||||
fetchConversations();
|
||||
}
|
||||
}, { immediate: false });
|
||||
|
||||
const deleteConversationDialogRef = ref(null);
|
||||
const selectedConversationId = ref(null);
|
||||
|
||||
|
||||
@@ -66,7 +66,10 @@ const activeAssistant = computed(() => {
|
||||
if (inboxMatchedAssistant) return inboxMatchedAssistant;
|
||||
}
|
||||
// If neither of the above is available, the first assistant in the account takes preference.
|
||||
return assistants.value[0];
|
||||
if (assistants.value && assistants.value.length > 0) {
|
||||
return assistants.value[0];
|
||||
}
|
||||
return null;
|
||||
});
|
||||
|
||||
const closeCopilotPanel = () => {
|
||||
|
||||
+3
-3
@@ -108,10 +108,10 @@ export default {
|
||||
</td>
|
||||
<td class="thumbnail--column">
|
||||
<Avatar
|
||||
v-if="notificationItem.primary_actor.meta.assignee"
|
||||
:src="notificationItem.primary_actor.meta.assignee.thumbnail"
|
||||
v-if="notificationItem.primary_actor?.meta?.assignee"
|
||||
:src="notificationItem.primary_actor?.meta?.assignee?.thumbnail || ''"
|
||||
:size="28"
|
||||
:name="notificationItem.primary_actor.meta.assignee.name"
|
||||
:name="notificationItem.primary_actor?.meta?.assignee?.name || ''"
|
||||
rounded-full
|
||||
/>
|
||||
</td>
|
||||
|
||||
@@ -92,12 +92,27 @@ export const parseAPIErrorResponse = error => {
|
||||
return error?.response?.data?.message;
|
||||
}
|
||||
if (error?.response?.data?.error) {
|
||||
return error?.response?.data?.error;
|
||||
// error could be a string or an object with a message property
|
||||
if (typeof error.response.data.error === 'string') {
|
||||
return error.response.data.error;
|
||||
}
|
||||
if (error.response.data.error?.message) {
|
||||
return error.response.data.error.message;
|
||||
}
|
||||
return JSON.stringify(error.response.data.error);
|
||||
}
|
||||
if (error?.response?.data?.errors) {
|
||||
return error?.response?.data?.errors[0];
|
||||
const first = error.response.data.errors;
|
||||
if (Array.isArray(first)) {
|
||||
return first[0];
|
||||
}
|
||||
return first;
|
||||
}
|
||||
return error;
|
||||
// Fallback: return a useful default message rather than the raw error object
|
||||
if (error?.message && typeof error.message === 'string') {
|
||||
return error.message;
|
||||
}
|
||||
return 'Request failed. Please try again.';
|
||||
};
|
||||
|
||||
export const throwErrorMessage = error => {
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no, user-scalable=0" />
|
||||
<title>GoChat Super Admin</title>
|
||||
<link rel="icon" type="image/png" href="/favicon-32x32.png" />
|
||||
<script>
|
||||
(function () {
|
||||
var cfg = window.__GOCHAT_CONFIG__ || {};
|
||||
window.chatwootConfig = Object.assign(
|
||||
{
|
||||
hostURL: '',
|
||||
helpCenterURL: '',
|
||||
fbAppId: '',
|
||||
instagramAppId: '',
|
||||
tiktokAppId: '',
|
||||
googleOAuthClientId: '',
|
||||
googleOAuthCallbackUrl: '',
|
||||
allowedLoginMethods: ['email'],
|
||||
fbApiVersion: '',
|
||||
whatsappAppId: '',
|
||||
whatsappConfigurationId: '',
|
||||
whatsappApiVersion: '',
|
||||
signupEnabled: 'false',
|
||||
isMfaEnabled: 'false',
|
||||
inboxEventsEnabled: 'false',
|
||||
selectedLocale: 'zh_CN',
|
||||
enabledLanguages: [
|
||||
{ name: '中文', iso_639_1_code: 'zh_CN' },
|
||||
{ name: 'English', iso_639_1_code: 'en' },
|
||||
],
|
||||
helpUrls: {},
|
||||
},
|
||||
cfg
|
||||
);
|
||||
window.globalConfig = Object.assign(
|
||||
{
|
||||
INSTALLATION_NAME: 'GoChat',
|
||||
CREATE_NEW_ACCOUNT_FROM_DASHBOARD: false,
|
||||
DISPLAY_MANIFEST: false,
|
||||
LOGO_THUMBNAIL: '/favicon-32x32.png',
|
||||
},
|
||||
cfg.globalConfig || {}
|
||||
);
|
||||
window.errorLoggingConfig = '';
|
||||
window.browserConfig = { browser_name: navigator.userAgent };
|
||||
|
||||
// sync auth tokens from cookie to localStorage
|
||||
(function() {
|
||||
try {
|
||||
var cookies = document.cookie.split('; ');
|
||||
var sessionCookie = cookies.find(function(c) { return c.startsWith('cw_d_session_info='); });
|
||||
if (sessionCookie) {
|
||||
var raw = decodeURIComponent(sessionCookie.split('=').slice(1).join('='));
|
||||
var extract = function(key) {
|
||||
var match = raw.match(new RegExp('"' + key + '":"([^"]+)"'));
|
||||
return match ? match[1] : '';
|
||||
};
|
||||
var token = extract('access-token');
|
||||
if (token) {
|
||||
localStorage.setItem('access-token', token);
|
||||
localStorage.setItem('client', extract('client'));
|
||||
localStorage.setItem('uid', extract('uid'));
|
||||
localStorage.setItem('token-type', extract('token-type') || 'Bearer');
|
||||
localStorage.setItem('expiry', extract('expiry'));
|
||||
}
|
||||
}
|
||||
} catch(e) { /* ignore */ }
|
||||
})();
|
||||
})();
|
||||
</script>
|
||||
</head>
|
||||
<body class="text-slate-600">
|
||||
<div id="app"></div>
|
||||
<noscript>This app works best with JavaScript enabled.</noscript>
|
||||
<script type="module" src="/app/javascript/entrypoints/superadmin.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -88,6 +88,7 @@ export default defineConfig({
|
||||
historyApiFallback: {
|
||||
rewrites: [
|
||||
{ from: /^\/widget/, to: '/widget.html' },
|
||||
{ from: /^\/super_admin/, to: '/super_admin.html' },
|
||||
],
|
||||
},
|
||||
proxy: {
|
||||
|
||||
Reference in New Issue
Block a user