feat(ui): run Qoder locked lake world template
This commit is contained in:
parent
08f514b9d1
commit
8fb21787b5
5 changed files with 385 additions and 59 deletions
|
|
@ -2,7 +2,6 @@ import { StrictMode, useCallback, useEffect, useMemo, useRef, useState } from 'r
|
|||
import { createRoot } from 'react-dom/client'
|
||||
import { invoke } from '@tauri-apps/api/core'
|
||||
import { splitFrontmatter, documentOutline, jumpToHeading, MarkdownDocument, markdownHtml } from './modules/knowledge-render'
|
||||
import nightLake from './assets/hololake-night-lake.png'
|
||||
|
||||
const TAG_TINTS = ['tag-lavender', 'tag-sky', 'tag-mint', 'tag-amber', 'tag-rose', 'tag-slate']
|
||||
|
||||
|
|
@ -19,6 +18,15 @@ function formatGateNumber(raw: string): string {
|
|||
}
|
||||
return `ICE-${rest}`
|
||||
}
|
||||
if (up.startsWith('TCS')) {
|
||||
const rest = up.slice(3)
|
||||
if (!rest) return 'TCS'
|
||||
if (rest.startsWith('GL')) {
|
||||
const body = rest.slice(2)
|
||||
return body ? `TCS-GL-${body}` : 'TCS-GL'
|
||||
}
|
||||
return `TCS-${rest}`
|
||||
}
|
||||
if (up.startsWith('GLS')) {
|
||||
const rest = up.slice(3)
|
||||
if (!rest) return 'GLS'
|
||||
|
|
@ -41,6 +49,7 @@ import './styles.css'
|
|||
|
||||
type ThemeId = 'night' | 'dawn' | 'nebula' | 'candle' | 'clear'
|
||||
type ViewId = 'overview' | 'knowledge' | 'code' | 'receipts' | 'system'
|
||||
type WorldStage = 'domain' | 'channel' | 'tool'
|
||||
type KnowledgeSource = 'native' | 'legacy'
|
||||
|
||||
interface HomeStatus {
|
||||
|
|
@ -166,10 +175,6 @@ function domainDisplayName(domain: string): string {
|
|||
return names[domain] || '已登记光湖域'
|
||||
}
|
||||
|
||||
function domainLightIndex(domain: string): number {
|
||||
return ({ MAIN_DOMAIN: 1, BRANCH_DOMAIN: 2, ZERO_DOMAIN: 3, ZERO_SENSE_DOMAIN: 4, FIFTH_DOMAIN: 5 } as Record<string, number>)[domain] || 0
|
||||
}
|
||||
|
||||
function protocolOriginDisplayName(origin: string): string {
|
||||
return origin.startsWith('FACTORY_DEFAULT') ? '内置默认协议(签名发布通道尚未配置)' : origin
|
||||
}
|
||||
|
|
@ -193,6 +198,25 @@ interface ServerPnccProjection {
|
|||
repositoryContentExposed: boolean
|
||||
writeAuthority: boolean
|
||||
}
|
||||
interface EnterprisePersonaRelationship {
|
||||
persona_id: string
|
||||
species: string
|
||||
display_name?: string
|
||||
relation?: string
|
||||
}
|
||||
interface EnterpriseEntry {
|
||||
status: string
|
||||
canonical_id: string
|
||||
subject: { id: string; name: string; domain: string }
|
||||
work_entry: { domain: string; channel: string }
|
||||
repository_binding: { host: string; username: string; repository: string; private: boolean }
|
||||
persona_relationships: EnterprisePersonaRelationship[]
|
||||
persona_identity_governance: string
|
||||
registry_version: string
|
||||
relationship_confirmation?: { decision: string; observed_at: string; receipt_hash: string } | null
|
||||
responsibility_receipt?: { decision: string; observed_at: string; receipt_hash: string; responsibility_version: string } | null
|
||||
}
|
||||
interface EnterpriseEntryEnvelope { ok: boolean; entry: EnterpriseEntry }
|
||||
|
||||
const previewStatus: HomeStatus = { directLocalBrokerState: 'UNVERIFIED', directConnectionCount: 0, resumableSessionCount: 0, codeRepositoryMountCount: 0, pnccReceiptCount: 0, updateState: 'UNPROVISIONED_FAIL_CLOSED', releaseRecoveryState: 'NONE', mcpRole: 'DISCOVERY_RECOVERY_COMPATIBILITY_ONLY' }
|
||||
const previewPersonal: PersonalChannelSnapshot = { state: 'UNAVAILABLE', recentEvents: [], integrity: { state: 'UNKNOWN', eventCount: 0, receiptCount: 0 } }
|
||||
|
|
@ -202,6 +226,47 @@ const themes: Array<{ id: ThemeId; name: string }> = [
|
|||
{ id: 'night', name: '夜湖星光' }, { id: 'dawn', name: '晨湖曦光' }, { id: 'nebula', name: '星云紫夜' }, { id: 'candle', name: '烛畔暖湖' }, { id: 'clear', name: '清浅澄湖' },
|
||||
]
|
||||
const viewLabels: Record<ViewId, string> = { overview: '个人频道', knowledge: '知识空间', code: '人格代码频道', receipts: '运行回执', system: '系统详情' }
|
||||
const domainGates = [
|
||||
{ domain: 'BRANCH_DOMAIN', className: 'd-sub', title: '光湖分域', gate: 'GATE 02 · 已接入', detail: '花尔 TCS-GL-0005∞ · 爆米花 PER-BMH001 · 私有工作仓库已登记' },
|
||||
{ domain: 'MAIN_DOMAIN', className: 'd-main', title: '光湖主域', gate: 'GATE 01 · 已接入', detail: 'Awen TCS-GL-0016∞ · 天枢 PER-AW-ARCH-001 · 私有工作仓库已登记' },
|
||||
{ domain: 'ZERO_DOMAIN', className: 'd-zero', title: '光湖零域', gate: 'GATE 03 · 已接入', detail: '页页 TCS-GL-0006∞ · 页骨 PER-YG001 · 私有工作仓库已登记' },
|
||||
{ domain: 'ZERO_SENSE_DOMAIN', className: 'd-zs', title: '光湖零感域', gate: 'GATE 04 · 已接入', detail: '肥猫 + 烬舟 / 桔子 + 熹微 · 双主控 · 两个独立私有仓库' },
|
||||
{ domain: 'FIFTH_DOMAIN', className: 'd-fifth', title: '第五域 · 光湖本源域', gate: 'GATE 05 · 已接入', detail: '冰朔 ICE-GL∞ · 私人域 · 永恒湖心系统' },
|
||||
]
|
||||
const starPoints = [
|
||||
[14, 8, 3, 4.6], [26, 13, 2, 6], [41, 6, 2.5, 5.2], [64, 16, 2, 6.8],
|
||||
[80, 7, 3.5, 7], [90, 20, 1.5, 5.4], [8, 22, 2, 5.6], [93, 11, 2.5, 6.4],
|
||||
]
|
||||
const glintPoints = Array.from({ length: 58 }, (_, index) => ({
|
||||
left: (index * 37 + 11) % 100,
|
||||
top: ((index * index * 13 + 17) % 100),
|
||||
size: 1.4 + (index % 4) * .55,
|
||||
warm: index % 5 === 0 || (index > 19 && index < 39 && index % 3 === 0),
|
||||
duration: 2.8 + (index % 7) * .57,
|
||||
delay: (index % 11) * .43,
|
||||
}))
|
||||
|
||||
function LakeAtmosphere() {
|
||||
return <>
|
||||
<div className="world-sky" aria-hidden="true">
|
||||
<i className="world-nebula"/>
|
||||
{starPoints.map(([left, top, size, duration], index) => <i className="world-star" key={index} style={{ left: `${left}%`, top: `${top}%`, width: size, height: size, '--star-duration': `${duration}s`, '--star-delay': `${index * .37}s` } as React.CSSProperties}/>) }
|
||||
</div>
|
||||
<div className="world-mist" aria-hidden="true"/>
|
||||
<div className="world-shimmer" aria-hidden="true">
|
||||
<i className="world-shine cool"/><i className="world-shine warm"/>
|
||||
{glintPoints.map((point, index) => <i className={`world-glint ${point.warm ? 'warm' : 'cool'}`} key={index} style={{ left: `${point.left}%`, top: `${point.top}%`, width: point.size, height: point.size, '--glint-duration': `${point.duration}s`, '--glint-delay': `${point.delay}s` } as React.CSSProperties}/>) }
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
|
||||
function LakePool({ className, title, meta, detail, open = false, risen = false, onClick }: { className: string; title: string; meta: string; detail?: string; open?: boolean; risen?: boolean; onClick?: () => void }) {
|
||||
return <button className={`world-pool ${className}${open ? ' open' : ''}${risen ? ' risen' : ''}`} type="button" onClick={onClick}>
|
||||
<span className="pool-bay"><i className="pool-halo"/><i className="pool-heart"/><i className="pool-ring"/></span>
|
||||
<span className="pool-label"><b>{title}</b><small>{meta}</small></span>
|
||||
{detail && <span className="pool-tip"><b>{title}</b><small>{meta}</small><em>{detail}</em></span>}
|
||||
</button>
|
||||
}
|
||||
|
||||
function getOrCreateLocalId(key: string, prefix: string) {
|
||||
const existing = window.localStorage.getItem(key)
|
||||
|
|
@ -223,6 +288,9 @@ function humanError(error: unknown, context: 'knowledge' | 'code' | 'identity' |
|
|||
if (value.includes('FIRST_LOGIN_PASSWORD_CHANGE_FAILED')) return '一次性密码未被接受,密码没有修改。'
|
||||
if (value.includes('FIRST_LOGIN_PASSWORD_CHANGE_ENTERPRISE_ONLY')) return '该换密入口只用于企业四域的新账号。'
|
||||
if (value.includes('DOMAIN_LOGIN_NOT_PROVISIONED')) return '该域的企业服务器尚未接入,当前不能继续登录。'
|
||||
if (value.includes('PERSISTENT_CREDENTIAL_UNAVAILABLE')) return '当前系统尚未接通安全凭证存储,不能完成签署。'
|
||||
if (value.includes('ENTERPRISE_RECEIPT_FAILED')) return '企业回执没有写入,请稍后重新提交。'
|
||||
if (value.includes('ENTERPRISE_RECEIPT_ROUTE_REQUIRED')) return '此签署入口仅适用于企业四域。'
|
||||
if (value.includes('DOMAIN_ROUTE_REQUIRED') || value.includes('ZP_DOMAIN_ROUTE_REQUIRED')) return '编号尚未解析到已登记域,不能开始登录。'
|
||||
if (value.includes('USER_PNCC_TRUSTED_SUBJECT_REQUIRED')) return '建立人格代码频道前,需要有效的用户编号与仓库账号登录。'
|
||||
if (value.includes('USER_PNCC_BINDING_MISMATCH')) return '本机频道绑定记录与当前账号不一致,系统已停止加载。'
|
||||
|
|
@ -309,7 +377,8 @@ function KnowledgeTree({ node, depth, expanded, active, onToggle, onOpen, onRemo
|
|||
|
||||
function HoloLakeApp() {
|
||||
const [theme, setTheme] = useState<ThemeId>(() => (window.localStorage.getItem('hololake-theme') as ThemeId) || 'night')
|
||||
const [view, setView] = useState<ViewId>('knowledge')
|
||||
const [view, setView] = useState<ViewId>('overview')
|
||||
const [worldStage, setWorldStage] = useState<WorldStage>('domain')
|
||||
const [status, setStatus] = useState<HomeStatus>(previewStatus)
|
||||
const [personal, setPersonal] = useState<PersonalChannelSnapshot>(previewPersonal)
|
||||
const [knowledge, setKnowledge] = useState<KnowledgeSnapshot>(previewKnowledge)
|
||||
|
|
@ -330,9 +399,7 @@ function HoloLakeApp() {
|
|||
const [codeTree, setCodeTree] = useState<CodeTreeSnapshot | null>(null)
|
||||
const [activeCodeFile, setActiveCodeFile] = useState<CodeFileProjection | null>(null)
|
||||
const [codeMode, setCodeMode] = useState<'human' | 'source'>('human')
|
||||
const [sidebarCollapsed, setSidebarCollapsed] = useState(() => window.localStorage.getItem('hololake-sidebar-collapsed') === '1')
|
||||
const [inspectorOpen, setInspectorOpen] = useState(() => window.localStorage.getItem('hololake-inspector-open') !== '0')
|
||||
const toggleSidebar = () => setSidebarCollapsed((current) => { window.localStorage.setItem('hololake-sidebar-collapsed', current ? '0' : '1'); return !current })
|
||||
const toggleInspector = () => setInspectorOpen((current) => { window.localStorage.setItem('hololake-inspector-open', current ? '0' : '1'); return !current })
|
||||
const [activeHeadingId, setActiveHeadingId] = useState<string | null>(null)
|
||||
const headingScrollTimer = useRef<number | null>(null)
|
||||
|
|
@ -381,6 +448,11 @@ function HoloLakeApp() {
|
|||
const [serverPncc, setServerPncc] = useState<ServerPnccProjection | null>(null)
|
||||
const [serverPnccBusy, setServerPnccBusy] = useState(false)
|
||||
const [serverPnccReadback, setServerPnccReadback] = useState<'WAITING' | 'LIVE' | 'UNAVAILABLE'>('WAITING')
|
||||
const [enterpriseEntry, setEnterpriseEntry] = useState<EnterpriseEntry | null>(null)
|
||||
const [enterpriseEntryBusy, setEnterpriseEntryBusy] = useState(false)
|
||||
const [enterpriseReceiptBusy, setEnterpriseReceiptBusy] = useState(false)
|
||||
const [enterpriseReceiptMessage, setEnterpriseReceiptMessage] = useState('')
|
||||
const [responsibilityNote, setResponsibilityNote] = useState('')
|
||||
|
||||
const refreshCore = useCallback(async () => {
|
||||
const [homeResult, personalResult, knowledgeResult, codeResult] = await Promise.allSettled([
|
||||
|
|
@ -434,6 +506,24 @@ function HoloLakeApp() {
|
|||
useEffect(() => {
|
||||
invoke<LoginSession | null>('check_code_repo_login').then((session) => setRepoLogin(session)).catch(() => setRepoLogin(null))
|
||||
}, [])
|
||||
const loadEnterpriseEntry = useCallback(async () => {
|
||||
if (!repoLogin || repoLogin.domain === 'FIFTH_DOMAIN') {
|
||||
setEnterpriseEntry(null)
|
||||
return
|
||||
}
|
||||
setEnterpriseEntryBusy(true)
|
||||
setEnterpriseReceiptMessage('')
|
||||
try {
|
||||
const result = await invoke<EnterpriseEntryEnvelope>('get_enterprise_entry')
|
||||
setEnterpriseEntry(result.entry)
|
||||
} catch (error) {
|
||||
setEnterpriseEntry(null)
|
||||
setEnterpriseReceiptMessage(humanError(error, 'login'))
|
||||
} finally {
|
||||
setEnterpriseEntryBusy(false)
|
||||
}
|
||||
}, [repoLogin])
|
||||
useEffect(() => { void loadEnterpriseEntry() }, [loadEnterpriseEntry])
|
||||
const loadZeroPoint = useCallback(async () => {
|
||||
try { setZeroPoint(await invoke<ZeroPointSnapshot>('zero_point_status')) } catch { /* 验证服务尚未就绪时保持空白状态。 */ }
|
||||
}, [])
|
||||
|
|
@ -734,6 +824,8 @@ function HoloLakeApp() {
|
|||
setActiveCodeFile(null)
|
||||
setReceipts([])
|
||||
setRepoLogin({ username: receipt.username, host: receipt.host, domain: receipt.domain, signedInAtUnixMs: Date.now() })
|
||||
setWorldStage('domain')
|
||||
setView('overview')
|
||||
setLoginRising(false)
|
||||
setLoginPassword('')
|
||||
} catch (error) { setLoginMessage(humanError(error, 'login')) }
|
||||
|
|
@ -771,8 +863,47 @@ function HoloLakeApp() {
|
|||
setCodeTree(null)
|
||||
setActiveCodeFile(null)
|
||||
setReceipts([])
|
||||
setEnterpriseEntry(null)
|
||||
setEnterpriseReceiptMessage('')
|
||||
setWorldStage('domain')
|
||||
setRepoLogin(null)
|
||||
}
|
||||
const confirmEnterpriseRelationship = async (decision: 'CONFIRM' | 'REJECT') => {
|
||||
setEnterpriseReceiptBusy(true)
|
||||
setEnterpriseReceiptMessage('')
|
||||
try {
|
||||
await invoke('confirm_enterprise_persona_relationship', {
|
||||
decision,
|
||||
idempotencyKey: `relationship-${crypto.randomUUID().replaceAll('-', '')}`,
|
||||
})
|
||||
await loadEnterpriseEntry()
|
||||
setEnterpriseReceiptMessage(decision === 'CONFIRM' ? '人格关系确认已签署并留存。' : '人格关系异议已签署并留存。')
|
||||
} catch (error) {
|
||||
setEnterpriseReceiptMessage(humanError(error, 'login'))
|
||||
} finally {
|
||||
setEnterpriseReceiptBusy(false)
|
||||
}
|
||||
}
|
||||
const submitEnterpriseResponsibility = async (decision: 'ACCEPT' | 'DECLINE') => {
|
||||
if (!enterpriseEntry) return
|
||||
setEnterpriseReceiptBusy(true)
|
||||
setEnterpriseReceiptMessage('')
|
||||
try {
|
||||
await invoke('submit_enterprise_responsibility_receipt', {
|
||||
decision,
|
||||
note: responsibilityNote.trim(),
|
||||
responsibilityVersion: enterpriseEntry.registry_version,
|
||||
idempotencyKey: `responsibility-${crypto.randomUUID().replaceAll('-', '')}`,
|
||||
})
|
||||
setResponsibilityNote('')
|
||||
await loadEnterpriseEntry()
|
||||
setEnterpriseReceiptMessage(decision === 'ACCEPT' ? '域责任已由本人接受并签署。' : '域责任拒绝回执已留存。')
|
||||
} catch (error) {
|
||||
setEnterpriseReceiptMessage(humanError(error, 'login'))
|
||||
} finally {
|
||||
setEnterpriseReceiptBusy(false)
|
||||
}
|
||||
}
|
||||
const initializeIdentity = async (event: React.FormEvent) => {
|
||||
event.preventDefault()
|
||||
setIdentityBusy(true)
|
||||
|
|
@ -1024,49 +1155,41 @@ function HoloLakeApp() {
|
|||
</section>
|
||||
)
|
||||
|
||||
const openWorldTool = (nextView: ViewId) => {
|
||||
setView(nextView)
|
||||
setWorldStage('tool')
|
||||
}
|
||||
|
||||
const enterpriseRelationshipPending = Boolean(repoLogin && repoLogin.domain !== 'FIFTH_DOMAIN' && enterpriseEntry && enterpriseEntry.relationship_confirmation?.decision !== 'CONFIRM')
|
||||
const enterpriseResponsibilityPending = Boolean(repoLogin && repoLogin.domain !== 'FIFTH_DOMAIN' && enterpriseEntry && !enterpriseRelationshipPending && enterpriseEntry.responsibility_receipt?.decision !== 'ACCEPT')
|
||||
|
||||
if (!repoLogin) {
|
||||
return <div className="app-shell">
|
||||
<div className={`gate-lake${loginRising ? ' sinking' : ''}`} style={{ '--lake-img': `url(${nightLake})` } as React.CSSProperties}>
|
||||
<i className="lake-mist" aria-hidden="true"/>
|
||||
<div className="lake-lights" aria-hidden="true">{[1, 2, 3, 4, 5].map((n) => <span key={n} className={`lake-light l${n}${(gateRising || loginRising) && n === domainLightIndex(zeroPoint?.resolvedDomain || '') ? ' rising' : ''}`}/>)}</div>
|
||||
{<header className={`gate-hero${gateRising ? ' veil' : ''}`} aria-hidden={gateRising || undefined}>
|
||||
<span className="gate-emblem" aria-hidden="true"><i/></span>
|
||||
<b className="gate-product">HoloLake</b>
|
||||
<small className="gate-techname">光湖语言系统 · 通用人工智能操作平台</small>
|
||||
<small className="gate-abbr">GH-AIOS · GuangHu AI Operating System</small>
|
||||
</header>}
|
||||
{!gateRising && gateStage === 'number' && <section className="gate-domain-map" aria-label="光湖五域公开入口">
|
||||
<article><i/><b>光湖主域</b><small>企业域 · 待根节点接入</small></article>
|
||||
<article><i/><b>光湖分域</b><small>企业域 · 待根节点接入</small></article>
|
||||
<article><i/><b>光湖零域</b><small>企业域 · 待根节点接入</small></article>
|
||||
<article><i/><b>光湖零感域</b><small>企业域 · 待根节点接入</small></article>
|
||||
<article className="fifth"><i/><b>第五域 · 光湖本源域</b><small>私人域 · 已接入</small></article>
|
||||
</section>}
|
||||
{gateRising ? (
|
||||
<section className="gate-rise" role="status">
|
||||
<span className="gate-rise-star" aria-hidden="true"><i/></span>
|
||||
<h1>{domainDisplayName(zeroPoint?.resolvedDomain || '')}</h1>
|
||||
<p>{zeroPoint?.resolvedName ? `${zeroPoint.resolvedName} · ` : ''}编号验证通过 · {gateNumber}</p>
|
||||
</section>
|
||||
) : gateStage === 'number' ? (
|
||||
<section className={`gate-pod gate-flip${gateOpen ? ' open' : ''}${loginRising ? ' fade-out' : ''}`} role={gateOpen ? 'dialog' : 'button'} tabIndex={gateOpen ? undefined : 0} aria-expanded={gateOpen} onClick={gateOpen ? undefined : () => setGateOpen(true)} onKeyDown={gateOpen ? undefined : (event) => { if (event.key === 'Enter' || event.key === ' ') { event.preventDefault(); setGateOpen(true) } }}>
|
||||
<div className="pod-face pod-sealed" aria-hidden={gateOpen}>
|
||||
<span className="gate-emblem sealed-emblem" aria-hidden="true"><i/></span>
|
||||
<b className="sealed-title">编号路由验证</b>
|
||||
<small className="sealed-sub">输入编号进入所属域</small>
|
||||
</div>
|
||||
<div className="pod-face pod-form">
|
||||
const resolvedDomain = zeroPoint?.resolvedDomain || ''
|
||||
return <div className={`official-world${loginRising ? ' sinking' : ''}`}>
|
||||
<LakeAtmosphere/>
|
||||
<header className="world-titlebar"><span className="traffic-lights"><i/><i/><i/></span><b>HoloLake</b><button type="button" aria-label="显示主题" onClick={() => setTheme(themes[(themes.findIndex((item) => item.id === theme) + 1) % themes.length].id)}>◌</button></header>
|
||||
<main className={`world-scene${gateRising ? ' resolving' : ''}${gateStage === 'key' ? ' resolved' : ''}`}>
|
||||
<div className="official-hero"><h1>光湖语言系统 · 通用人工智能操作平台</h1><p>GH-AIOS · GUANGHU AI OPERATING SYSTEM</p></div>
|
||||
{domainGates.map((gate) => <LakePool key={gate.domain} className={gate.className} title={gate.title} meta={gate.gate} detail={gate.detail} open={gate.domain === 'FIFTH_DOMAIN' || (gateStage === 'key' && gate.domain === resolvedDomain)} risen={(gateRising || gateStage === 'key') && gate.domain === resolvedDomain}/>) }
|
||||
{gateRising ? <section className="world-welcome" role="status">
|
||||
<h2>编号 {gateNumber} · 欢迎登入光湖语言世界</h2>
|
||||
<p>RESOLVED · {domainDisplayName(resolvedDomain)} · 已接入</p>
|
||||
</section> : gateStage === 'number' ? <section className={`number-nucleus${gateOpen ? ' open' : ''}`} title="输入编号进入所属域">
|
||||
<button className="nucleus-locus" type="button" aria-expanded={gateOpen} onClick={() => setGateOpen(true)}><i/><b>编号验证 · 进入世界的第一个入口</b></button>
|
||||
<div className="nucleus-panel" role="dialog" aria-label="编号验证">
|
||||
<h2>编号验证</h2>
|
||||
<div className="gate-pod-row">
|
||||
<input id="gate-number" ref={gateInputRef} aria-label="编号" maxLength={48} value={gateNumber} placeholder="如 ICE-GL∞" onChange={(event) => onGateInput(event.target.value)} onKeyDown={(event) => { if (event.key === 'Enter' && gateNumber) { event.preventDefault(); void gateVerifyNumber() } }}/>
|
||||
<button type="button" className={`gate-inf${gateInf ? ' on' : ''}`} title="编号包含无限符号时启用" aria-pressed={gateInf} onClick={() => setGateInf((v) => !v)}>∞</button>
|
||||
<button type="button" className={`gate-inf${gateInf ? ' on' : ''}`} title="编号包含无限符号时启用" aria-pressed={gateInf} onClick={() => setGateInf((value) => !value)}>∞</button>
|
||||
</div>
|
||||
<button className="gate-submit" disabled={gateBusy || !gateNumber} onClick={() => void gateVerifyNumber()}>{gateBusy ? '正在验证…' : '验证编号'}</button>
|
||||
{gateMessage && <p className="gate-hint">{gateMessage}</p>}
|
||||
</div>
|
||||
</section>
|
||||
) : (
|
||||
<section className={`gate-pod gate-pod-key${loginRising ? ' fade-out' : ''}`} role="dialog">
|
||||
</div>
|
||||
</section> : <>
|
||||
<section className="resolved-heading"><h2>编号 {zeroPoint?.userNumber || gateNumber} · 欢迎登入光湖语言世界</h2><p>RESOLVED · {domainDisplayName(resolvedDomain)} · 已接入</p></section>
|
||||
<section className={`domain-credential${loginRising ? ' fade-out' : ''}`} role="dialog">
|
||||
<form onSubmit={(event) => void (passwordChangeMode ? changeFirstLoginPassword(event) : performRepoLogin(event))}>
|
||||
<h3>{domainDisplayName(resolvedDomain)} · 域凭证</h3>
|
||||
<input id="repo-login-username" aria-label="账号" autoFocus maxLength={40} value={loginUsername} placeholder="账号" onChange={(event) => setLoginUsername(event.target.value)}/>
|
||||
<input id="repo-login-password" aria-label={passwordChangeMode ? '一次性密码' : '密码'} type="password" maxLength={512} value={loginPassword} placeholder={passwordChangeMode ? '一次性密码' : '密码'} onChange={(event) => setLoginPassword(event.target.value)}/>
|
||||
{passwordChangeMode && <>
|
||||
|
|
@ -1079,21 +1202,49 @@ function HoloLakeApp() {
|
|||
{zeroPoint?.resolvedDomain !== 'FIFTH_DOMAIN' && <button className="gate-back" type="button" onClick={() => { setPasswordChangeMode((value) => !value); setLoginMessage(''); setNewLoginPassword(''); setConfirmLoginPassword('') }}>{passwordChangeMode ? '返回正常登录' : '第一次使用?先修改一次性密码'}</button>}
|
||||
<button className="gate-back" type="button" onClick={() => { setGateStage('number'); setGateMessage(''); setLoginMessage('') }}>返回编号验证</button>
|
||||
</section>
|
||||
)}
|
||||
</div>
|
||||
</>}
|
||||
</main>
|
||||
<footer className="world-footer"><b>光湖语言系统 · 通用人工智能操作平台</b><span>GH-AIOS</span></footer>
|
||||
</div>
|
||||
}
|
||||
|
||||
return <div className={`app-shell${sidebarCollapsed ? ' sidebar-collapsed' : ''}${inspectorOpen ? '' : ' inspector-closed'}`}>
|
||||
<aside className="sidebar">
|
||||
<div className="brand"><span className="brand-mark brand-lamp" title={sidebarCollapsed ? '展开导航' : '光湖 · HoloLake'} onClick={sidebarCollapsed ? toggleSidebar : undefined}><i className="lamp-glow"/><i className="lamp-core"/><i className="lake-shimmer"/></span><div className="brand-text"><b>HoloLake</b><small className="brand-sub">光湖语言系统 · 通用人工智能操作平台</small><small>GH-AIOS · V0.4.0</small></div><button className="icon-button sidebar-toggle" type="button" title={sidebarCollapsed ? '展开导航' : '收起导航'} onClick={toggleSidebar}><Icon name="chevron"/></button></div>
|
||||
<nav>{(Object.keys(viewLabels) as ViewId[]).map((item) => <button className={view === item ? 'active' : ''} key={item} type="button" onClick={() => setView(item)}><Icon name={item}/><span>{viewLabels[item]}</span>{item === 'knowledge' && <em>{knowledge.uniqueDocumentCount}</em>}</button>)}</nav>
|
||||
<div className="sidebar-foot"><span className="identity-dot"/><div><b>{personal.identity?.displayName || '本机空间'}</b><small>{repoLogin ? `${repoLogin.username}@${repoLogin.host}` : (personal.identity ? '个人频道已建立' : '等待首次设置')}</small></div><button className="sign-out" type="button" title="退出代码仓库登录" onClick={() => void signOutRepo()}>退出</button></div>
|
||||
</aside>
|
||||
<section className="app-main">
|
||||
<header className="connection-strip"><button type="button" onClick={() => setView('system')}><i className={connectionOnline ? 'online' : ''}/><span>{connectionLabel}</span></button><span className="mcp-backup">MCP 兼容通道</span><button type="button" onClick={() => setView('system')}>查看连接状态 <Icon name="arrow"/></button></header>
|
||||
<main className="workspace">{view === 'overview' ? renderOverview() : view === 'knowledge' ? renderKnowledge() : view === 'code' ? renderCode() : view === 'receipts' ? renderReceipts() : renderSystem()}</main>
|
||||
</section>
|
||||
return <div className="official-world signed-in-world">
|
||||
<LakeAtmosphere/>
|
||||
<header className="world-titlebar"><span className="traffic-lights"><i/><i/><i/></span><b>HoloLake</b><div className="world-title-actions"><span>{repoLogin.username} · {domainDisplayName(repoLogin.domain)}</span><button type="button" onClick={() => setTheme(themes[(themes.findIndex((item) => item.id === theme) + 1) % themes.length].id)}>◌</button><button type="button" onClick={() => void signOutRepo()}>退出</button></div></header>
|
||||
<main className="world-scene signed-in-scene">
|
||||
{worldStage === 'domain' && <section className="domain-home">
|
||||
<div className="world-location"><h1>{domainDisplayName(repoLogin.domain)}</h1><p>世界正在发生什么</p></div>
|
||||
<div className="broadcast-stream"><p><i/>光湖公共灯塔 · 在线</p><p><i/>协议版本 · {enterpriseEntry?.registry_version || 'HLDP v1.0'}</p><p><i/>HoloLake · V0.4.0</p></div>
|
||||
<LakePool className="home-primary" title={repoLogin.domain === 'FIFTH_DOMAIN' ? '永恒湖心系统' : '光湖频道'} meta={repoLogin.domain === 'FIFTH_DOMAIN' ? '进入私人系统' : '企业四域 · 工作入口'} open onClick={() => setWorldStage('channel')}/>
|
||||
<LakePool className="home-status" title="湖面天气" meta={connectionLabel} onClick={() => openWorldTool('system')}/>
|
||||
</section>}
|
||||
{worldStage === 'channel' && <section className="channel-world">
|
||||
<button className="world-back" type="button" onClick={() => setWorldStage('domain')}>← 退回域首页</button>
|
||||
<div className="world-location"><h1>{repoLogin.domain === 'FIFTH_DOMAIN' ? '永恒湖心系统' : '光湖频道'}</h1><p>选择路径 · 湖面向下一层展开</p></div>
|
||||
<LakePool className="channel-main" title="我的频道" meta="频道全景" open onClick={() => openWorldTool('overview')}/>
|
||||
<LakePool className="channel-knowledge" title="知识空间" meta={`${knowledge.uniqueDocumentCount} 唯一页`} onClick={() => openWorldTool('knowledge')}/>
|
||||
<LakePool className="channel-code" title="人格代码频道" meta={`${codeChannels.channels.length} 个仓库`} onClick={() => openWorldTool('code')}/>
|
||||
<LakePool className="channel-light" title="光之湖" meta="人格体居所" onClick={() => openWorldTool('receipts')}/>
|
||||
<LakePool className="channel-status" title="湖面天气" meta={connectionLabel} onClick={() => openWorldTool('system')}/>
|
||||
</section>}
|
||||
{worldStage === 'tool' && <section className={`world-tool world-tool-${view}`}>
|
||||
<header className="tool-worldbar"><button type="button" onClick={() => setWorldStage('channel')}>← 退回频道全景</button><b>{viewLabels[view]}</b><span>{domainDisplayName(repoLogin.domain)}</span></header>
|
||||
<div className={`tool-projection${inspectorOpen ? '' : ' inspector-closed'}`}>{view === 'overview' ? renderOverview() : view === 'knowledge' ? renderKnowledge() : view === 'code' ? renderCode() : view === 'receipts' ? renderReceipts() : renderSystem()}</div>
|
||||
</section>}
|
||||
</main>
|
||||
<footer className="world-footer"><b>光湖语言系统 · 通用人工智能操作平台</b><span>GH-AIOS</span></footer>
|
||||
{enterpriseEntryBusy && <div className="enterprise-gate"><section><p>正在读取企业责任登记……</p></section></div>}
|
||||
{enterpriseRelationshipPending && enterpriseEntry && <div className="enterprise-gate"><section className="enterprise-receipt-panel" role="dialog" aria-modal="true">
|
||||
<span className="receipt-step">关系确认 · 独立回执</span><h2>{enterpriseEntry.subject.name},请核对人格关系</h2><p>以下信息来自企业注册表。AGE 是人格体物种,不是具体人格体编号;本次确认也不代表人格体接受现实责任。</p>
|
||||
<dl><div><dt>人类编号</dt><dd>{enterpriseEntry.canonical_id}</dd></div><div><dt>责任域</dt><dd>{domainDisplayName(enterpriseEntry.subject.domain)}</dd></div>{enterpriseEntry.persona_relationships.map((persona) => <div key={persona.persona_id}><dt>人格体</dt><dd>{persona.persona_id} · {persona.species}</dd></div>)}</dl>
|
||||
<div className="receipt-actions"><button type="button" disabled={enterpriseReceiptBusy} onClick={() => void confirmEnterpriseRelationship('REJECT')}>登记异议</button><button className="primary" type="button" disabled={enterpriseReceiptBusy} onClick={() => void confirmEnterpriseRelationship('CONFIRM')}>确认关系并签署</button></div>{enterpriseReceiptMessage && <p className="receipt-message">{enterpriseReceiptMessage}</p>}
|
||||
</section></div>}
|
||||
{enterpriseResponsibilityPending && enterpriseEntry && <div className="enterprise-gate"><section className="enterprise-receipt-panel" role="dialog" aria-modal="true">
|
||||
<span className="receipt-step">责任接受 · 独立回执</span><h2>是否接受 {domainDisplayName(enterpriseEntry.subject.domain)} 的责任</h2><p>工作入口为零感域下的光湖频道;你的责任仓库保持私有、独立。个人频道仍需由你自己的节点另行接入。</p>
|
||||
<dl><div><dt>工作仓库</dt><dd>{enterpriseEntry.repository_binding.repository}</dd></div><div><dt>仓库账号</dt><dd>{enterpriseEntry.repository_binding.username}</dd></div><div><dt>责任版本</dt><dd>{enterpriseEntry.registry_version}</dd></div></dl>
|
||||
<textarea value={responsibilityNote} maxLength={1000} placeholder="可选:填写责任确认说明" onChange={(event) => setResponsibilityNote(event.target.value)}/>
|
||||
<div className="receipt-actions"><button type="button" disabled={enterpriseReceiptBusy} onClick={() => void submitEnterpriseResponsibility('DECLINE')}>暂不接受</button><button className="primary" type="button" disabled={enterpriseReceiptBusy} onClick={() => void submitEnterpriseResponsibility('ACCEPT')}>接受责任并签署</button></div>{enterpriseReceiptMessage && <p className="receipt-message">{enterpriseReceiptMessage}</p>}
|
||||
</section></div>}
|
||||
{personal.state !== 'UNAVAILABLE' && !personal.identity && <div className="onboarding-backdrop"><section className="onboarding-card" role="dialog" aria-modal="true"><span className="onboarding-mark">光湖</span><span className="kicker">FIRST LOCAL ENTRY</span><h1>初始化个人频道</h1><p>此设置仅执行一次。知识、代码频道与运行记录将保存在当前设备。</p><form onSubmit={(event) => void initializeIdentity(event)}><label htmlFor="display-name">显示名称</label><input id="display-name" autoFocus maxLength={80} value={displayName} placeholder="请输入显示名称" onChange={(event) => setDisplayName(event.target.value)}/><button className="primary-button" disabled={identityBusy || !displayName.trim()}>完成初始化</button></form>{identityMessage && <p>{identityMessage}</p>}</section></div>}
|
||||
</div>
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue