import type { PropType } from 'vue'; import type { QqbotApi } from '#/api/qqbot'; import type { QqbotNapcatApi } from '#/api/qqbot/napcat'; import { defineComponent, ref, watch } from 'vue'; import { Drawer, Spin, Tag } from 'antdv-next'; import { getQqbotNapcatRuntimeDetail } from '#/api/qqbot/napcat'; import { getQqbotStatusColor, getQqbotStatusLabel } from '../../modules/status'; const ADrawer = Drawer as any; const ASpin = Spin as any; export default defineComponent({ name: 'NapcatRuntimeProfileDrawer', props: { account: { default: undefined, type: Object as PropType, }, open: { default: false, type: Boolean, }, }, emits: ['close', 'update:open'], setup(props, { emit }) { const detail = ref(); const loading = ref(false); watch( () => [props.open, props.account?.id] as const, () => { if (props.open && props.account?.id) void loadDetail(); }, { immediate: true }, ); /** * Loads sanitized runtime profile evidence for the selected account. */ async function loadDetail() { if (!props.account?.id) return; loading.value = true; try { detail.value = await getQqbotNapcatRuntimeDetail(props.account.id); } finally { loading.value = false; } } /** * Emits both drawer close contracts used by existing QQBot views. */ function closeDrawer() { emit('update:open', false); emit('close'); } /** * Renders compact key/value evidence rows without exposing interactive controls. * @param label - Human readable field label. * @param value - Runtime evidence value already sanitized by the API. */ const renderField = (label: string, value: unknown) => { return (
{label} {formatValue(value)}
); }; /** * Renders a JSON evidence block for profile sections. * @param title - Section title shown above the evidence block. * @param value - Sanitized profile object returned by the API. */ const renderJsonBlock = (title: string, value: unknown) => { if (!value) return null; return (

{title}

            {JSON.stringify(value, null, 2)}
          
); }; /** * Converts scalar runtime evidence into stable display text. * @param value - Sanitized value from profile detail. * @returns Display text for compact rows. */ function formatValue(value: unknown) { if (value === undefined || value === null || value === '') return '-'; if (typeof value === 'object') return JSON.stringify(value); return `${value}`; } const renderSummary = () => { const napcat = props.account?.napcat; const runtimeProfile = (detail.value?.runtimeProfile as Record | undefined) || napcat?.runtimeProfile; return (
Profile {getQqbotStatusLabel(napcat?.profileStatus)} 风险 {getQqbotStatusLabel(napcat?.riskMode)}
{renderField('账号', props.account?.selfId)} {renderField('镜像', runtimeProfile?.imageRef)} {renderField('Locale', runtimeProfile?.locale)} {renderField('SHM', runtimeProfile?.shmSize)} {renderField('检查超时', detail.value?.inspectionTimeoutMs)}
); }; return () => ( {renderSummary()} {renderJsonBlock('Runtime Profile', detail.value?.runtimeProfile)} {renderJsonBlock('Protocol Profile', detail.value?.protocolProfile)} {renderJsonBlock( 'Session Behavior', detail.value?.sessionBehaviorProfile, )} {renderJsonBlock('Risk Mode', detail.value?.riskMode)} {renderJsonBlock('Login Events', detail.value?.loginEvents)} ); }, });