Commit aa7e3917 authored by yuguo's avatar yuguo

feat(ai-assistant): add embedded view types, registry, and wrapper

Co-Authored-By: default avatarClaude Opus 4.6 <noreply@anthropic.com>
parent b2232985
'use client';
import React, { useState, useEffect, type ComponentType } from 'react';
import { Button, Spin, Typography } from 'antd';
import { CloseOutlined, ExpandOutlined } from '@ant-design/icons';
import { useRouter } from 'next/navigation';
import { getEmbedLoader, type EmbedComponentProps } from './registry';
const { Text } = Typography;
interface EmbedWrapperProps {
pageCode: string;
pageName: string;
operation: 'view_list' | 'open_add' | 'open_edit';
route: string;
params?: Record<string, unknown>;
onClose: () => void;
onNavigate?: (pageCode: string, operation?: string, params?: Record<string, unknown>) => void;
}
const EmbedWrapper: React.FC<EmbedWrapperProps> = ({
pageCode, pageName, operation, route, params, onClose, onNavigate,
}) => {
const router = useRouter();
const [Component, setComponent] = useState<ComponentType<EmbedComponentProps> | null>(null);
const [error, setError] = useState(false);
useEffect(() => {
const loader = getEmbedLoader(pageCode);
if (!loader) { setError(true); return; }
loader().then(mod => setComponent(() => mod.default)).catch(() => setError(true));
}, [pageCode]);
return (
<div style={{
border: '1px solid #e5e7eb', borderRadius: 12, overflow: 'hidden',
background: '#fff', display: 'flex', flexDirection: 'column',
maxHeight: 420,
}}>
<div style={{
padding: '8px 12px', background: '#f9fafb', borderBottom: '1px solid #f3f4f6',
display: 'flex', alignItems: 'center', justifyContent: 'space-between',
}}>
<Text strong style={{ fontSize: 13 }}>{pageName}</Text>
<div style={{ display: 'flex', gap: 4 }}>
<Button type="text" size="small" icon={<ExpandOutlined />}
onClick={() => router.push(route)} title="在新页面打开" />
<Button type="text" size="small" icon={<CloseOutlined />}
onClick={onClose} title="关闭" />
</div>
</div>
<div style={{ flex: 1, overflow: 'auto', padding: 12 }}>
{error ? (
<div style={{ textAlign: 'center', padding: 24, color: '#9ca3af' }}>
<div>暂不支持嵌入显示</div>
<Button type="link" size="small" onClick={() => router.push(route)}>
前往完整页面
</Button>
</div>
) : Component ? (
<Component
pageCode={pageCode}
operation={operation}
params={params}
onNavigate={onNavigate}
onClose={onClose}
/>
) : (
<div style={{ textAlign: 'center', padding: 24 }}><Spin /></div>
)}
</div>
</div>
);
};
export default EmbedWrapper;
import type { ComponentType } from 'react';
export interface EmbedComponentProps {
pageCode: string;
operation: 'view_list' | 'open_add' | 'open_edit';
params?: Record<string, unknown>;
onNavigate?: (pageCode: string, operation?: string, params?: Record<string, unknown>) => void;
onClose?: () => void;
}
const registry: Record<string, () => Promise<{ default: ComponentType<EmbedComponentProps> }>> = {
patient_management: () => import('./EmbedPatientList'),
doctor_management: () => import('./EmbedDoctorList'),
department_management: () => import('./EmbedDepartmentList'),
find_doctor: () => import('./EmbedFindDoctor'),
my_consultations: () => import('./EmbedConsultList'),
pre_consult: () => import('./EmbedPreConsult'),
};
export function isEmbeddable(pageCode: string): boolean {
return pageCode in registry;
}
export function getEmbedLoader(pageCode: string) {
return registry[pageCode] ?? null;
}
...@@ -6,11 +6,34 @@ export interface ToolCall { ...@@ -6,11 +6,34 @@ export interface ToolCall {
success: boolean; success: boolean;
} }
export interface AgentAction {
action: string;
page: string;
page_code: string;
operation: string;
route: string;
params?: Record<string, unknown>;
}
export interface EmbeddedView {
pageCode: string;
pageName: string;
operation: 'view_list' | 'open_add' | 'open_edit';
route: string;
params?: Record<string, unknown>;
}
export interface QuickItem {
label: string;
type: 'text' | 'embed';
embed?: EmbeddedView;
}
export interface ChatMessage { export interface ChatMessage {
role: 'user' | 'assistant' | 'system'; role: 'user' | 'assistant' | 'system';
content: string; content: string;
toolCalls?: ToolCall[]; toolCalls?: ToolCall[];
meta?: { iterations?: number; tokens?: number; agent_id?: string; workflow_id?: string }; meta?: { iterations?: number; tokens?: number; agent_id?: string; workflow_id?: string; actions?: AgentAction[] };
timestamp: Date; timestamp: Date;
streaming?: boolean; streaming?: boolean;
_id?: number; _id?: number;
...@@ -55,8 +78,26 @@ export const ROLE_THEME: Record<WidgetRole, { gradient: string; label: string; s ...@@ -55,8 +78,26 @@ export const ROLE_THEME: Record<WidgetRole, { gradient: string; label: string; s
}, },
}; };
export const QUICK_ITEMS: Record<WidgetRole, string[]> = { export const QUICK_ITEMS: Record<WidgetRole, QuickItem[]> = {
patient: ['头痛', '发热', '咳嗽', '腹痛', '乏力', '失眠'], patient: [
doctor: ['鉴别诊断建议', '用药方案推荐', '检查项目建议'], { label: '预问诊', type: 'embed', embed: { pageCode: 'pre_consult', pageName: '预问诊', operation: 'view_list', route: '/patient/pre-consult' } },
admin: ['今日运营概况', 'Agent运行状态', '异常告警排查'], { label: '找医生', type: 'embed', embed: { pageCode: 'find_doctor', pageName: '找医生', operation: 'view_list', route: '/patient/doctors' } },
{ label: '我的问诊', type: 'embed', embed: { pageCode: 'my_consultations', pageName: '我的问诊', operation: 'view_list', route: '/patient/consult' } },
{ label: '头痛', type: 'text' },
{ label: '发热', type: 'text' },
{ label: '咳嗽', type: 'text' },
],
doctor: [
{ label: '鉴别诊断建议', type: 'text' },
{ label: '用药方案推荐', type: 'text' },
{ label: '检查项目建议', type: 'text' },
],
admin: [
{ label: '注册医生', type: 'embed', embed: { pageCode: 'doctor_management', pageName: '医生管理', operation: 'open_add', route: '/admin/doctors?action=add' } },
{ label: '添加科室', type: 'embed', embed: { pageCode: 'department_management', pageName: '科室管理', operation: 'open_add', route: '/admin/departments?action=add' } },
{ label: '患者列表', type: 'embed', embed: { pageCode: 'patient_management', pageName: '患者管理', operation: 'view_list', route: '/admin/patients' } },
{ label: '医生列表', type: 'embed', embed: { pageCode: 'doctor_management', pageName: '医生管理', operation: 'view_list', route: '/admin/doctors' } },
{ label: '查看运营数据', type: 'text' },
{ label: '管理Agent', type: 'text' },
],
}; };
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment