feat(ui): Phase 8 UI/UX optimization and system documentation update

## Sidebar Enhancement
- Change tabs to icon + small label layout for better space utilization
- Add Teams tab with team collaboration entry point

## Settings Page Improvements
- Connect theme toggle to gatewayStore.saveQuickConfig for persistence
- Remove OpenFang backend download section, simplify UI
- Add time range filter to UsageStats (7d/30d/all)
- Add stat cards with icons (sessions, messages, input/output tokens)
- Add token usage overview bar chart
- Add 8 ZCLAW system skill definitions with categories

## Bug Fixes
- Fix ChannelList duplicate content with deduplication logic
- Integrate CreateTriggerModal in TriggersPanel
- Add independent SecurityStatusPanel with 12 default enabled layers
- Change workflow view to use SchedulerPanel as unified entry

## New Components
- CreateTriggerModal: Event trigger creation modal
- HandApprovalModal: Hand approval workflow dialog
- HandParamsForm: Enhanced Hand parameter form
- SecurityLayersPanel: 16-layer security status display

## Architecture
- Add TOML config parsing support (toml-utils.ts, config-parser.ts)
- Add request timeout and retry mechanism (request-helper.ts)
- Add secure token storage (secure-storage.ts, secure_storage.rs)

## Tests
- Add unit tests for config-parser, toml-utils, request-helper
- Add team-client and teamStore tests

## Documentation
- Update SYSTEM_ANALYSIS.md with Phase 8 completion
- UI completion: 100% (30/30 components)
- API coverage: 93% (63/68 endpoints)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
iven
2026-03-15 14:12:11 +08:00
parent bf79c06d4a
commit 3e81bd3e50
30 changed files with 8875 additions and 284 deletions

View File

@@ -8,6 +8,13 @@ const CHANNEL_ICONS: Record<string, string> = {
wechat: '微',
};
// 可用频道类型(用于显示未配置的频道)
const AVAILABLE_CHANNEL_TYPES = [
{ type: 'feishu', name: '飞书 (Feishu)' },
{ type: 'wechat', name: '微信' },
{ type: 'qqbot', name: 'QQ 机器人' },
];
interface ChannelListProps {
onOpenSettings?: () => void;
}
@@ -27,6 +34,17 @@ export function ChannelList({ onOpenSettings }: ChannelListProps) {
loadPluginStatus().then(() => loadChannels());
};
// 去重:基于 channel id
const uniqueChannels = channels.filter((ch, index, self) =>
index === self.findIndex(c => c.id === ch.id)
);
// 获取已配置的频道类型
const configuredTypes = new Set(uniqueChannels.map(c => c.type));
// 未配置的频道类型
const unconfiguredTypes = AVAILABLE_CHANNEL_TYPES.filter(ct => !configuredTypes.has(ct.type));
if (!connected) {
return (
<div className="flex flex-col items-center justify-center h-full text-gray-400 text-xs px-4 text-center">
@@ -53,7 +71,7 @@ export function ChannelList({ onOpenSettings }: ChannelListProps) {
<div className="flex-1 overflow-y-auto custom-scrollbar">
{/* Configured channels */}
{channels.map((ch) => (
{uniqueChannels.map((ch) => (
<div
key={ch.id}
className="flex items-center gap-3 px-3 py-3 hover:bg-gray-100 border-b border-gray-50"
@@ -77,29 +95,18 @@ export function ChannelList({ onOpenSettings }: ChannelListProps) {
</div>
))}
{/* Always show available channels that aren't configured */}
{!channels.find(c => c.type === 'feishu') && (
<div className="flex items-center gap-3 px-3 py-3 hover:bg-gray-100 border-b border-gray-50 opacity-60">
{/* Unconfigured channels - 只显示一次 */}
{unconfiguredTypes.map((ct) => (
<div key={ct.type} className="flex items-center gap-3 px-3 py-3 hover:bg-gray-100 border-b border-gray-50 opacity-60">
<div className="w-8 h-8 rounded-lg flex items-center justify-center text-white text-xs font-bold flex-shrink-0 bg-gray-300">
{CHANNEL_ICONS[ct.type] || <MessageCircle className="w-4 h-4" />}
</div>
<div className="flex-1 min-w-0">
<div className="text-xs font-medium text-gray-600"> (Feishu)</div>
<div className="text-xs font-medium text-gray-600">{ct.name}</div>
<div className="text-[11px] text-gray-400"></div>
</div>
</div>
)}
{!channels.find(c => c.type === 'qqbot') && (
<div className="flex items-center gap-3 px-3 py-3 hover:bg-gray-100 border-b border-gray-50 opacity-60">
<div className="w-8 h-8 rounded-lg flex items-center justify-center text-white text-xs font-bold flex-shrink-0 bg-gray-300">
QQ
</div>
<div className="flex-1 min-w-0">
<div className="text-xs font-medium text-gray-600">QQ </div>
<div className="text-[11px] text-gray-400"></div>
</div>
</div>
)}
))}
{/* Help text */}
<div className="px-3 py-4 text-center">