🎈 perf: comprehensive dashboard improvements
- Enhance i18n error handling and code quality - Fix SSE data processing in chat page - Improve responsive design for extension page - Add better debugging tools for development"
This commit is contained in:
@@ -57,13 +57,15 @@ export function useI18n() {
|
||||
value = value[k];
|
||||
} else {
|
||||
console.warn(`Translation key not found: ${key}`);
|
||||
return key; // 返回键名作为回退
|
||||
// 返回带括号的键名,便于在开发时识别缺失的翻译
|
||||
return `[MISSING: ${key}]`;
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof value !== 'string') {
|
||||
console.warn(`Translation value is not string: ${key}`);
|
||||
return key;
|
||||
console.warn(`Translation value is not string: ${key}`, value);
|
||||
// 返回带括号的键名,便于在开发时识别类型错误的翻译
|
||||
return `[INVALID: ${key}]`;
|
||||
}
|
||||
|
||||
// 此时value确定是string类型
|
||||
|
||||
@@ -127,70 +127,45 @@ export class I18nLoader {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 通用模块加载器 - 减少重复代码,提高可维护性
|
||||
*/
|
||||
private async loadModules(
|
||||
locale: string,
|
||||
prefix: string,
|
||||
overrideList: string[] = []
|
||||
): Promise<any> {
|
||||
// 使用覆盖列表或从注册表中筛选符合前缀的模块名
|
||||
const moduleNames = overrideList.length > 0
|
||||
? overrideList
|
||||
: Array.from(this.moduleRegistry.keys()).filter(key => key.startsWith(prefix));
|
||||
|
||||
const results = await Promise.all(
|
||||
moduleNames.map(module => this.loadModule(locale, module))
|
||||
);
|
||||
|
||||
return this.mergeModules(results, moduleNames);
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载核心模块(最高优先级)
|
||||
*/
|
||||
async loadCoreModules(locale: string): Promise<any> {
|
||||
const coreModules = [
|
||||
'core/common',
|
||||
'core/actions',
|
||||
'core/status',
|
||||
'core/navigation',
|
||||
'core/header'
|
||||
];
|
||||
|
||||
const results = await Promise.all(
|
||||
coreModules.map(module => this.loadModule(locale, module))
|
||||
);
|
||||
|
||||
return this.mergeModules(results, coreModules);
|
||||
return this.loadModules(locale, 'core');
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载功能模块
|
||||
*/
|
||||
async loadFeatureModules(locale: string, features?: string[]): Promise<any> {
|
||||
const featureModules = features || [
|
||||
'features/chat',
|
||||
'features/extension',
|
||||
'features/conversation',
|
||||
'features/tooluse',
|
||||
'features/provider',
|
||||
'features/platform',
|
||||
'features/config',
|
||||
'features/console',
|
||||
'features/about',
|
||||
'features/settings',
|
||||
'features/auth',
|
||||
'features/chart',
|
||||
'features/dashboard',
|
||||
'features/alkaid/index',
|
||||
'features/alkaid/knowledge-base',
|
||||
'features/alkaid/memory'
|
||||
];
|
||||
|
||||
const results = await Promise.all(
|
||||
featureModules.map(module => this.loadModule(locale, module))
|
||||
);
|
||||
|
||||
return this.mergeModules(results, featureModules);
|
||||
return this.loadModules(locale, 'features', features || []);
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载消息模块
|
||||
*/
|
||||
async loadMessageModules(locale: string): Promise<any> {
|
||||
const messageModules = [
|
||||
'messages/errors',
|
||||
'messages/success',
|
||||
'messages/validation'
|
||||
];
|
||||
|
||||
const results = await Promise.all(
|
||||
messageModules.map(module => this.loadModule(locale, module))
|
||||
);
|
||||
|
||||
return this.mergeModules(results, messageModules);
|
||||
return this.loadModules(locale, 'messages');
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -594,7 +594,25 @@ export default {
|
||||
console.log(line)
|
||||
|
||||
// data: {"type": "plain", "data": "helloworld"}
|
||||
let chunk_json = JSON.parse(line.replace('data: ', ''));
|
||||
let chunk_json;
|
||||
try {
|
||||
chunk_json = JSON.parse(line.replace('data: ', ''));
|
||||
} catch (parseError) {
|
||||
console.warn('JSON解析失败:', line, parseError);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 检查解析后的数据是否有效
|
||||
if (!chunk_json || typeof chunk_json !== 'object') {
|
||||
console.warn('无效的数据对象:', chunk_json);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 检查是否有type字段
|
||||
if (!chunk_json.hasOwnProperty('type')) {
|
||||
console.warn('数据缺少type字段:', chunk_json);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (chunk_json.type === 'heartbeat') {
|
||||
continue; // 心跳包
|
||||
|
||||
@@ -568,8 +568,10 @@ onMounted(async () => {
|
||||
<!-- 标签页 -->
|
||||
<v-card-text>
|
||||
|
||||
<div class="d-flex align-center mb-2" style="justify-content: space-between;">
|
||||
<v-tabs v-model="activeTab" color="primary" class="mb-4">
|
||||
<!-- 标签栏和搜索栏 - 响应式布局 -->
|
||||
<div class="mb-4">
|
||||
<!-- 标签栏 -->
|
||||
<v-tabs v-model="activeTab" color="primary" class="mb-3">
|
||||
<v-tab value="installed">
|
||||
<v-icon class="mr-2">mdi-puzzle</v-icon>
|
||||
{{ tm('tabs.installed') }}
|
||||
@@ -580,20 +582,40 @@ onMounted(async () => {
|
||||
</v-tab>
|
||||
</v-tabs>
|
||||
|
||||
|
||||
<v-text-field v-if="activeTab == 'market'" style="max-width: 300px;" v-model="marketSearch" density="compact"
|
||||
:label="tm('search.marketPlaceholder')" prepend-inner-icon="mdi-magnify" variant="solo-filled" flat hide-details
|
||||
single-line></v-text-field>
|
||||
<v-text-field v-else style="max-width: 300px;" v-model="pluginSearch" density="compact" :label="tm('search.placeholder')" prepend-inner-icon="mdi-magnify"
|
||||
variant="solo-filled" flat hide-details single-line></v-text-field>
|
||||
|
||||
<!-- 搜索栏 - 在移动端时独占一行 -->
|
||||
<v-row class="mb-2">
|
||||
<v-col cols="12" sm="6" md="4" lg="3">
|
||||
<v-text-field
|
||||
v-if="activeTab == 'market'"
|
||||
v-model="marketSearch"
|
||||
density="compact"
|
||||
:label="tm('search.marketPlaceholder')"
|
||||
prepend-inner-icon="mdi-magnify"
|
||||
variant="solo-filled"
|
||||
flat
|
||||
hide-details
|
||||
single-line>
|
||||
</v-text-field>
|
||||
<v-text-field
|
||||
v-else
|
||||
v-model="pluginSearch"
|
||||
density="compact"
|
||||
:label="tm('search.placeholder')"
|
||||
prepend-inner-icon="mdi-magnify"
|
||||
variant="solo-filled"
|
||||
flat
|
||||
hide-details
|
||||
single-line>
|
||||
</v-text-field>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- 已安装插件标签页内容 -->
|
||||
<v-tab-item v-show="activeTab === 'installed'">
|
||||
<v-row class="mb-4">
|
||||
<v-col cols="12" sm="6" md="6" class="d-flex align-center">
|
||||
<v-col cols="12" class="d-flex align-center flex-wrap ga-2">
|
||||
<v-btn-group variant="outlined" density="comfortable" color="primary">
|
||||
<v-btn @click="isListView = false" :color="!isListView ? 'primary' : undefined"
|
||||
:variant="!isListView ? 'flat' : 'outlined'">
|
||||
@@ -605,13 +627,14 @@ onMounted(async () => {
|
||||
</v-btn>
|
||||
</v-btn-group>
|
||||
|
||||
<v-btn class="ml-2" @click="toggleShowReserved" prepend-icon="mdi-eye-settings-outline"
|
||||
:color="showReserved ? 'primary' : undefined" :variant="showReserved ? 'flat' : 'outlined'">
|
||||
<v-btn @click="toggleShowReserved" prepend-icon="mdi-eye-settings-outline"
|
||||
:color="showReserved ? 'primary' : undefined" :variant="showReserved ? 'flat' : 'outlined'"
|
||||
class="flex-shrink-0">
|
||||
{{ showReserved ? tm('buttons.hideSystemPlugins') : tm('buttons.showSystemPlugins') }}
|
||||
</v-btn>
|
||||
|
||||
<v-btn class="ml-2" prepend-icon="mdi-tune-vertical" color="primary" variant="outlined"
|
||||
@click="getPlatformEnableConfig">
|
||||
<v-btn prepend-icon="mdi-tune-vertical" color="primary" variant="outlined"
|
||||
@click="getPlatformEnableConfig" class="flex-shrink-0">
|
||||
{{ tm('buttons.platformConfig') }}
|
||||
</v-btn>
|
||||
</v-col>
|
||||
|
||||
Reference in New Issue
Block a user