diff --git a/.gitignore b/.gitignore index 08353997..aeb005d4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ backend/.venv/ +node_modules/ frontend/.next/ frontend/.next-dev-log/ frontend/node_modules/ diff --git a/apps/contract-web/.env.example b/apps/contract-web/.env.example new file mode 100644 index 00000000..d87fd5e8 --- /dev/null +++ b/apps/contract-web/.env.example @@ -0,0 +1 @@ +NEXT_PUBLIC_CONTRACT_API_BASE_URL=http://localhost:8100 diff --git a/apps/contract-web/.gitkeep b/apps/contract-web/.gitkeep deleted file mode 100644 index 8b137891..00000000 --- a/apps/contract-web/.gitkeep +++ /dev/null @@ -1 +0,0 @@ - diff --git a/apps/contract-web/README.md b/apps/contract-web/README.md new file mode 100644 index 00000000..c08128e9 --- /dev/null +++ b/apps/contract-web/README.md @@ -0,0 +1,19 @@ +# Contract Web + +Next.js app for the V2 contract platform. + +## Local Run + +```powershell +npm install +npm run web:dev +``` + +Default URL: `http://localhost:3000` + +## Validate + +```powershell +npm run web:typecheck +npm run web:build +``` diff --git a/apps/contract-web/next.config.ts b/apps/contract-web/next.config.ts new file mode 100644 index 00000000..ce199092 --- /dev/null +++ b/apps/contract-web/next.config.ts @@ -0,0 +1,7 @@ +import type { NextConfig } from "next"; + +const nextConfig: NextConfig = { + transpilePackages: ["@yuqei/design-system"] +}; + +export default nextConfig; diff --git a/apps/contract-web/package.json b/apps/contract-web/package.json new file mode 100644 index 00000000..434698ae --- /dev/null +++ b/apps/contract-web/package.json @@ -0,0 +1,24 @@ +{ + "name": "@yuqei/contract-web", + "version": "0.1.0", + "private": true, + "scripts": { + "dev": "next dev -p 3000", + "build": "next build", + "start": "next start -p 3000", + "typecheck": "tsc --noEmit" + }, + "dependencies": { + "@yuqei/design-system": "0.1.0", + "lucide-react": "1.21.0", + "next": "16.2.9", + "react": "19.2.7", + "react-dom": "19.2.7" + }, + "devDependencies": { + "@types/node": "26.0.0", + "@types/react": "19.2.17", + "@types/react-dom": "19.2.3", + "typescript": "5.9.3" + } +} diff --git a/apps/contract-web/src/app/admin/page.tsx b/apps/contract-web/src/app/admin/page.tsx new file mode 100644 index 00000000..0df88a02 --- /dev/null +++ b/apps/contract-web/src/app/admin/page.tsx @@ -0,0 +1,47 @@ +import { Settings, ShieldCheck, SlidersHorizontal } from "lucide-react"; + +const adminSections = [ + { + title: "企业权限", + description: "组织、角色、合同可见范围和操作边界。", + icon: ShieldCheck + }, + { + title: "AI 参数", + description: "模型连接、运行参数、提示词版本和审计策略。", + icon: SlidersHorizontal + }, + { + title: "系统设置", + description: "文件存储、通知、备份、健康检查和部署配置。", + icon: Settings + } +]; + +export default function AdminPage() { + return ( + <> +
+
+

管理区

+

管理员能力集中管理,业务用户保持简洁主流程。

+
+
+ +
+ {adminSections.map((section) => { + const Icon = section.icon; + return ( +
+
+ +

{section.title}

+

{section.description}

+
+
+ ); + })} +
+ + ); +} diff --git a/apps/contract-web/src/app/contracts/[id]/page.tsx b/apps/contract-web/src/app/contracts/[id]/page.tsx new file mode 100644 index 00000000..1bef89fe --- /dev/null +++ b/apps/contract-web/src/app/contracts/[id]/page.tsx @@ -0,0 +1,146 @@ +import Link from "next/link"; +import { Archive, Download, FilePenLine, GitCompare, Send } from "lucide-react"; +import { contracts } from "@/lib/mock-data"; + +type PageProps = { + params: Promise<{ + id: string; + }>; +}; + +export default async function ContractDetailPage({ params }: PageProps) { + const { id } = await params; + const contract = contracts.find((item) => item.id === id) ?? contracts[0]; + + return ( + <> +
+
+

{contract.title}

+

{contract.code} · {contract.counterparty} · 更新时间 {contract.updatedAt}

+
+ + 返回合同列表 + +
+ +
+
+ 下一步操作:{contract.nextAction} + 只把当前最应该做的动作放到首位,其余能力继续保留但不抢视线。 +
+
+ + + +
+
+ +
+ 概览 + 正文预览 + 审批 + 版本 + 审计 +
+ +
+
+
+
+

合同概览

+ {contract.status} +
+
+
+
合同金额
+ {contract.amount} +
+
+
业务负责人
+ {contract.owner} +
+
+
相对方
+ {contract.counterparty} +
+
+
下一步
+ {contract.nextAction} +
+
+
+ +
+
+

正文预览

+ +
+
+
+

{contract.title}

+

甲方与乙方基于真实交易背景,经平等协商,形成本合同。双方应按约定履行交付、验收、付款、保密和违约责任。

+

法律审查意见、审批意见、版本差异和履约证据会在侧栏集中折叠展示,正文区域保持干净可读。

+
+
+
+
+ + +
+ + ); +} diff --git a/apps/contract-web/src/app/contracts/page.tsx b/apps/contract-web/src/app/contracts/page.tsx new file mode 100644 index 00000000..52a00eec --- /dev/null +++ b/apps/contract-web/src/app/contracts/page.tsx @@ -0,0 +1,64 @@ +import Link from "next/link"; +import { Download, FilePlus2, Search } from "lucide-react"; +import { contracts } from "@/lib/mock-data"; + +export default function ContractsPage() { + return ( + <> +
+
+

合同

+

按下一步动作组织合同,而不是把所有流程一次性压给用户。

+
+ + + 快速起草 + +
+ +
+ + +
+ + + + + + + + + + + + + + {contracts.map((contract) => ( + + + + + + + + + ))} + +
合同相对方状态下一步更新时间操作
+ + {contract.title} + +
{contract.code}
+
{contract.counterparty} + {contract.status} + {contract.nextAction}{contract.updatedAt} + +
+ + ); +} diff --git a/apps/contract-web/src/app/files/page.tsx b/apps/contract-web/src/app/files/page.tsx new file mode 100644 index 00000000..756f5570 --- /dev/null +++ b/apps/contract-web/src/app/files/page.tsx @@ -0,0 +1,67 @@ +import Link from "next/link"; +import { Download, Eye, Filter } from "lucide-react"; +import { files } from "@/lib/mock-data"; + +export default function FilesPage() { + return ( + <> +
+
+

合同仓库

+

按文件、关联合同、类型和上传时间统一管理合同资产。

+
+ +
+ +
+ + +
+ + + + + + + + + + + + + {files.map((file) => ( + + + + + + + + ))} + +
文件关联合同类型上传时间操作
+ {file.name} +
{file.size}
+
+ + {file.contractTitle} + + {file.type}{file.uploadedAt} +
+ + +
+
+ + ); +} diff --git a/apps/contract-web/src/app/globals.css b/apps/contract-web/src/app/globals.css new file mode 100644 index 00000000..d27ab18b --- /dev/null +++ b/apps/contract-web/src/app/globals.css @@ -0,0 +1,504 @@ +:root { + color-scheme: light; + --ink: #172033; + --muted: #667085; + --line: #d9e0ea; + --canvas: #f6f8fb; + --surface: #ffffff; + --primary: #2457d6; + --primary-soft: #eaf0ff; + --success: #16794c; + --success-soft: #e7f6ef; + --warning: #b35b00; + --warning-soft: #fff3df; + --danger: #bd2d2d; + --danger-soft: #fdecec; + --accent: #0b7a75; + --accent-soft: #e4f5f3; +} + +* { + box-sizing: border-box; +} + +html, +body { + min-height: 100%; + margin: 0; +} + +body { + color: var(--ink); + background: var(--canvas); + font-family: Inter, "Segoe UI", "PingFang SC", "Microsoft YaHei", Arial, sans-serif; +} + +a { + color: inherit; + text-decoration: none; +} + +button, +input, +select { + font: inherit; +} + +.app-shell { + display: grid; + grid-template-columns: 248px minmax(0, 1fr); + min-height: 100vh; +} + +.app-sidebar { + position: sticky; + top: 0; + height: 100vh; + padding: 20px 16px; + color: #f8fbff; + background: #16233f; + border-right: 1px solid rgba(255, 255, 255, 0.08); +} + +.brand-block { + display: grid; + gap: 4px; + padding: 4px 8px 18px; +} + +.brand-title { + font-size: 18px; + font-weight: 750; + letter-spacing: 0; +} + +.brand-subtitle { + color: #bac6d9; + font-size: 12px; +} + +.nav-group { + display: grid; + gap: 6px; + margin-top: 12px; +} + +.nav-group-title { + margin: 18px 8px 8px; + color: #91a1bc; + font-size: 12px; +} + +.nav-link { + display: flex; + align-items: center; + gap: 10px; + min-height: 40px; + padding: 0 10px; + border-radius: 8px; + color: #d8e2f2; +} + +.nav-link svg { + flex: 0 0 auto; +} + +.nav-link:hover, +.nav-link-active { + color: #ffffff; + background: rgba(255, 255, 255, 0.12); +} + +.app-main { + display: grid; + grid-template-rows: 64px minmax(0, 1fr); + min-width: 0; +} + +.topbar { + position: sticky; + z-index: 10; + top: 0; + display: flex; + align-items: center; + justify-content: space-between; + gap: 16px; + min-width: 0; + height: 64px; + padding: 0 28px; + background: rgba(246, 248, 251, 0.92); + border-bottom: 1px solid var(--line); + backdrop-filter: blur(12px); +} + +.topbar-title { + overflow: hidden; + font-size: 16px; + font-weight: 700; + text-overflow: ellipsis; + white-space: nowrap; +} + +.topbar-actions { + display: flex; + align-items: center; + gap: 8px; +} + +.content { + width: min(100%, 1440px); + margin: 0 auto; + padding: 24px 28px 40px; +} + +.page-heading { + display: flex; + align-items: flex-end; + justify-content: space-between; + gap: 20px; + margin-bottom: 20px; +} + +.page-heading h1 { + margin: 0; + font-size: 28px; + line-height: 1.2; + letter-spacing: 0; +} + +.page-heading p { + margin: 6px 0 0; + color: var(--muted); + line-height: 1.6; +} + +.button { + display: inline-flex; + align-items: center; + justify-content: center; + gap: 8px; + min-height: 36px; + padding: 0 14px; + border: 1px solid var(--line); + border-radius: 8px; + color: var(--ink); + background: var(--surface); + cursor: pointer; +} + +.button-primary { + color: #ffffff; + border-color: var(--primary); + background: var(--primary); +} + +.button-soft { + color: var(--primary); + border-color: transparent; + background: var(--primary-soft); +} + +.icon-button { + width: 36px; + min-width: 36px; + padding: 0; +} + +.panel { + border: 1px solid var(--line); + border-radius: 8px; + background: var(--surface); +} + +.panel-header { + display: flex; + align-items: center; + justify-content: space-between; + gap: 12px; + padding: 16px 18px; + border-bottom: 1px solid var(--line); +} + +.panel-title { + margin: 0; + font-size: 16px; + font-weight: 750; +} + +.panel-body { + padding: 18px; +} + +.split-layout { + display: grid; + grid-template-columns: minmax(0, 1.4fr) minmax(320px, 0.7fr); + gap: 16px; +} + +.metric-row { + display: grid; + grid-template-columns: repeat(4, minmax(0, 1fr)); + gap: 12px; + margin-bottom: 16px; +} + +.metric { + padding: 16px; + border: 1px solid var(--line); + border-radius: 8px; + background: var(--surface); +} + +.metric-value { + font-size: 24px; + font-weight: 800; +} + +.metric-label { + margin-top: 4px; + color: var(--muted); + font-size: 13px; +} + +.list { + display: grid; + gap: 10px; +} + +.list-item { + display: grid; + gap: 8px; + padding: 14px; + border: 1px solid var(--line); + border-radius: 8px; + background: var(--surface); +} + +.list-item-header { + display: flex; + align-items: center; + justify-content: space-between; + gap: 12px; +} + +.item-title { + min-width: 0; + font-weight: 700; +} + +.item-title svg { + vertical-align: -3px; +} + +.item-meta { + color: var(--muted); + font-size: 13px; +} + +.toolbar { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: 10px; + margin-bottom: 14px; +} + +.search-input { + min-width: min(100%, 360px); + min-height: 38px; + padding: 0 12px; + border: 1px solid var(--line); + border-radius: 8px; + background: #ffffff; +} + +.tag { + display: inline-flex; + align-items: center; + width: fit-content; + min-height: 24px; + padding: 0 8px; + border-radius: 999px; + color: var(--muted); + background: #edf1f7; + font-size: 12px; + white-space: nowrap; +} + +.tag-success { + color: var(--success); + background: var(--success-soft); +} + +.tag-warning { + color: var(--warning); + background: var(--warning-soft); +} + +.tag-primary { + color: var(--primary); + background: var(--primary-soft); +} + +.tag-danger { + color: var(--danger); + background: var(--danger-soft); +} + +.flow-strip { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); + gap: 10px; +} + +.flow-step { + padding: 14px; + border: 1px solid var(--line); + border-radius: 8px; + background: #fbfcfe; +} + +.flow-step-title { + font-weight: 750; +} + +.flow-step p { + margin: 6px 0 0; + color: var(--muted); + font-size: 13px; + line-height: 1.5; +} + +.next-action { + display: flex; + align-items: center; + justify-content: space-between; + gap: 14px; + padding: 16px 18px; + border: 1px solid #bfd0ff; + border-radius: 8px; + background: #f5f8ff; +} + +.next-action strong { + display: block; + margin-bottom: 4px; +} + +.muted { + color: var(--muted); +} + +.grid-two { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 16px; +} + +.detail-grid { + display: grid; + grid-template-columns: minmax(0, 1fr) 320px; + gap: 16px; + margin-top: 16px; +} + +.document-preview { + min-height: 420px; + padding: 28px; + border: 1px solid var(--line); + border-radius: 8px; + background: #ffffff; + line-height: 1.8; +} + +.document-preview h2 { + margin: 0 0 16px; + font-size: 22px; + text-align: center; +} + +.table { + width: 100%; + border-collapse: collapse; + overflow: hidden; + border: 1px solid var(--line); + border-radius: 8px; + background: var(--surface); +} + +.table th, +.table td { + padding: 12px 14px; + border-bottom: 1px solid var(--line); + text-align: left; + vertical-align: middle; +} + +.table th { + color: var(--muted); + font-size: 13px; + font-weight: 650; + background: #f8fafc; +} + +.table tr:last-child td { + border-bottom: 0; +} + +details.panel summary { + cursor: pointer; + list-style: none; +} + +details.panel summary::-webkit-details-marker { + display: none; +} + +@media (max-width: 980px) { + .app-shell { + grid-template-columns: 1fr; + } + + .app-sidebar { + position: static; + height: auto; + } + + .nav-group { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } + + .split-layout, + .detail-grid, + .grid-two { + grid-template-columns: 1fr; + } + + .metric-row, + .flow-strip { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } +} + +@media (max-width: 640px) { + .content, + .topbar { + padding-left: 16px; + padding-right: 16px; + } + + .page-heading { + align-items: flex-start; + flex-direction: column; + } + + .metric-row, + .flow-strip, + .nav-group { + grid-template-columns: 1fr; + } + + .topbar-actions { + display: none; + } +} diff --git a/apps/contract-web/src/app/health/page.tsx b/apps/contract-web/src/app/health/page.tsx new file mode 100644 index 00000000..0746fc6d --- /dev/null +++ b/apps/contract-web/src/app/health/page.tsx @@ -0,0 +1,15 @@ +import { SystemHealthPanel } from "@/features/system/system-health-panel"; + +export default function HealthPage() { + return ( + <> +
+
+

系统健康

+

上线前检查前端、合同 API、AI 平台和后台任务状态。

+
+
+ + + ); +} diff --git a/apps/contract-web/src/app/layout.tsx b/apps/contract-web/src/app/layout.tsx new file mode 100644 index 00000000..54691cfe --- /dev/null +++ b/apps/contract-web/src/app/layout.tsx @@ -0,0 +1,23 @@ +import type { Metadata } from "next"; +import type { ReactNode } from "react"; +import { AppShell } from "@/components/app-shell"; +import "./globals.css"; + +export const metadata: Metadata = { + title: "钰麒合同 V2", + description: "企业合同智能起草、审查、协同与归档平台" +}; + +export default function RootLayout({ + children +}: Readonly<{ + children: ReactNode; +}>) { + return ( + + + {children} + + + ); +} diff --git a/apps/contract-web/src/app/page.tsx b/apps/contract-web/src/app/page.tsx new file mode 100644 index 00000000..bd1571ec --- /dev/null +++ b/apps/contract-web/src/app/page.tsx @@ -0,0 +1,5 @@ +import { WorkspacePage } from "@/features/workspace/workspace-page"; + +export default function Home() { + return ; +} diff --git a/apps/contract-web/src/app/search/page.tsx b/apps/contract-web/src/app/search/page.tsx new file mode 100644 index 00000000..0ae2542e --- /dev/null +++ b/apps/contract-web/src/app/search/page.tsx @@ -0,0 +1,46 @@ +import Link from "next/link"; +import { Search } from "lucide-react"; +import { searchGroups } from "@/lib/mock-data"; + +export default function SearchPage() { + return ( + <> +
+
+

统一搜索

+

标题就是主入口,结果按合同、审查、文件、模板分组展示。

+
+
+ +
+ + +
+ +
+ {searchGroups.map((group) => ( +
+
+

{group.title}

+ {group.items.length} 条 +
+
+ {group.items.map((item) => ( + +
+ {item.title} + {item.updatedAt} +
+ {item.summary} + + ))} +
+
+ ))} +
+ + ); +} diff --git a/apps/contract-web/src/app/workspace/page.tsx b/apps/contract-web/src/app/workspace/page.tsx new file mode 100644 index 00000000..76beca9b --- /dev/null +++ b/apps/contract-web/src/app/workspace/page.tsx @@ -0,0 +1,5 @@ +import { WorkspacePage } from "@/features/workspace/workspace-page"; + +export default function Page() { + return ; +} diff --git a/apps/contract-web/src/components/app-shell.tsx b/apps/contract-web/src/components/app-shell.tsx new file mode 100644 index 00000000..7bad7b9d --- /dev/null +++ b/apps/contract-web/src/components/app-shell.tsx @@ -0,0 +1,97 @@ +"use client"; + +import type { ReactNode } from "react"; +import Link from "next/link"; +import { usePathname } from "next/navigation"; +import { + Activity, + Archive, + FileSearch, + Files, + Home, + LayoutDashboard, + Search, + Settings +} from "lucide-react"; + +const mainNav = [ + { href: "/workspace", label: "工作台", icon: Home }, + { href: "/contracts", label: "合同", icon: FileSearch }, + { href: "/search", label: "统一搜索", icon: Search }, + { href: "/files", label: "合同仓库", icon: Files } +]; + +const adminNav = [ + { href: "/admin", label: "管理区", icon: Settings }, + { href: "/health", label: "系统健康", icon: Activity } +]; + +export function AppShell({ children }: { children: ReactNode }) { + const pathname = usePathname(); + + return ( +
+ + +
+
+
{resolveTitle(pathname)}
+
+ + + 待我处理 + + + + 新建合同 + +
+
+
{children}
+
+
+ ); +} + +function resolveTitle(pathname: string): string { + if (pathname.startsWith("/contracts/")) return "合同详情"; + if (pathname.startsWith("/contracts")) return "合同主流程"; + if (pathname.startsWith("/search")) return "统一搜索"; + if (pathname.startsWith("/files")) return "合同仓库"; + if (pathname.startsWith("/admin")) return "管理区"; + if (pathname.startsWith("/health")) return "系统健康"; + return "工作台"; +} diff --git a/apps/contract-web/src/features/system/system-health-panel.tsx b/apps/contract-web/src/features/system/system-health-panel.tsx new file mode 100644 index 00000000..79eb66ae --- /dev/null +++ b/apps/contract-web/src/features/system/system-health-panel.tsx @@ -0,0 +1,70 @@ +"use client"; + +import { useEffect, useState } from "react"; +import { Activity, RefreshCcw } from "lucide-react"; + +type HealthState = + | { status: "checking" } + | { status: "ok"; service: string; version: string; environment: string } + | { status: "error"; message: string }; + +const apiBaseUrl = process.env.NEXT_PUBLIC_CONTRACT_API_BASE_URL ?? "http://localhost:8100"; + +export function SystemHealthPanel() { + const [health, setHealth] = useState({ status: "checking" }); + + async function checkHealth() { + setHealth({ status: "checking" }); + try { + const response = await fetch(`${apiBaseUrl}/health`, { cache: "no-store" }); + if (!response.ok) { + throw new Error(`HTTP ${response.status}`); + } + const data = await response.json() as { service: string; version: string; environment: string }; + setHealth({ status: "ok", ...data }); + } catch (error) { + setHealth({ + status: "error", + message: error instanceof Error ? error.message : "unknown error" + }); + } + } + + useEffect(() => { + void checkHealth(); + }, []); + + return ( +
+
+

合同 API

+ +
+
+
+
+ + {apiBaseUrl} + + {health.status === "ok" && 正常} + {health.status === "checking" && 检查中} + {health.status === "error" && 未连接} +
+ {health.status === "ok" && ( + + {health.service} · {health.version} · {health.environment} + + )} + {health.status === "error" && ( + + {health.message} + + )} +
+
+
+ ); +} diff --git a/apps/contract-web/src/features/workspace/workspace-page.tsx b/apps/contract-web/src/features/workspace/workspace-page.tsx new file mode 100644 index 00000000..df56376f --- /dev/null +++ b/apps/contract-web/src/features/workspace/workspace-page.tsx @@ -0,0 +1,103 @@ +import Link from "next/link"; +import { FilePlus2, Gavel, Inbox, Search, UploadCloud } from "lucide-react"; +import { mainFlow } from "@yuqei/design-system"; +import { tasks } from "@/lib/mock-data"; + +export function WorkspacePage() { + return ( + <> +
+
+

工作台

+

只突出待我处理和快速发起,复杂能力收进对应页面和管理区。

+
+
+ + + 起草合同 + + + + 搜索 + +
+
+ +
+
+
6
+
待我处理
+
+
+
12
+
进行中合同
+
+
+
3
+
本周到期
+
+
+
98%
+
审计覆盖
+
+
+ +
+
+
+

待我处理

+ 优先 +
+
+ {tasks.map((task) => ( + +
+ {task.title} + {task.type} +
+ {task.summary} + + ))} +
+
+ + +
+ + ); +} diff --git a/apps/contract-web/src/lib/mock-data.ts b/apps/contract-web/src/lib/mock-data.ts new file mode 100644 index 00000000..a2a92806 --- /dev/null +++ b/apps/contract-web/src/lib/mock-data.ts @@ -0,0 +1,120 @@ +export const contracts = [ + { + id: "contract-001", + title: "技术服务合同", + code: "HT-2026-0001", + counterparty: "北京辰星科技有限公司", + status: "审查中", + statusTone: "tag-warning", + nextAction: "法务确认付款和验收条款", + updatedAt: "今天 10:18", + amount: "¥ 280,000", + owner: "张敏" + }, + { + id: "contract-002", + title: "房屋租赁合同", + code: "HT-2026-0002", + counterparty: "内蒙古青禾置业", + status: "待提交", + statusTone: "tag-primary", + nextAction: "补充租赁期限后提交", + updatedAt: "昨天 18:42", + amount: "¥ 96,000", + owner: "王磊" + }, + { + id: "contract-003", + title: "采购框架协议", + code: "HT-2026-0003", + counterparty: "上海景云供应链", + status: "已归档", + statusTone: "tag-success", + nextAction: "跟踪履约节点", + updatedAt: "2026-06-20", + amount: "¥ 1,200,000", + owner: "李娜" + } +] as const; + +export const tasks = [ + { + id: "task-001", + title: "技术服务合同需要法务审查", + type: "审查", + tone: "tag-warning", + summary: "付款节点、验收标准和违约责任需要形成处理意见。", + href: "/contracts/contract-001" + }, + { + id: "task-002", + title: "房屋租赁合同待补充期限", + type: "起草", + tone: "tag-primary", + summary: "补齐租赁期限、保证金和交付条件后即可提交。", + href: "/contracts/contract-002" + }, + { + id: "task-003", + title: "采购框架协议履约节点到期", + type: "履约", + tone: "tag-success", + summary: "本周需要上传首批交付验收证据。", + href: "/contracts/contract-003" + } +] as const; + +export const searchGroups = [ + { + title: "合同", + items: contracts.map((contract) => ({ + title: contract.title, + summary: `${contract.counterparty} · ${contract.nextAction}`, + updatedAt: contract.updatedAt, + href: `/contracts/${contract.id}` + })) + }, + { + title: "审查意见", + items: [ + { + title: "付款条款风险意见", + summary: "建议明确验收通过后的付款期限和逾期责任。", + updatedAt: "今天 09:50", + href: "/contracts/contract-001" + } + ] + }, + { + title: "文件", + items: [ + { + title: "技术服务合同-审查版.docx", + summary: "来自合同仓库,已关联技术服务合同。", + updatedAt: "今天 10:21", + href: "/files" + } + ] + } +] as const; + +export const files = [ + { + id: "file-001", + name: "技术服务合同-审查版.docx", + contractId: "contract-001", + contractTitle: "技术服务合同", + type: "审查版", + size: "128 KB", + uploadedAt: "今天 10:21" + }, + { + id: "file-002", + name: "房屋租赁合同-草稿.pdf", + contractId: "contract-002", + contractTitle: "房屋租赁合同", + type: "草稿", + size: "364 KB", + uploadedAt: "昨天 19:03" + } +] as const; diff --git a/apps/contract-web/tsconfig.json b/apps/contract-web/tsconfig.json new file mode 100644 index 00000000..4b9fd76c --- /dev/null +++ b/apps/contract-web/tsconfig.json @@ -0,0 +1,25 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "baseUrl": ".", + "paths": { + "@/*": [ + "./src/*" + ] + }, + "plugins": [ + { + "name": "next" + } + ] + }, + "include": [ + "next-env.d.ts", + ".next/types/**/*.ts", + "**/*.ts", + "**/*.tsx" + ], + "exclude": [ + "node_modules" + ] +} diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 00000000..f70032ba --- /dev/null +++ b/package-lock.json @@ -0,0 +1,1058 @@ +{ + "name": "yuqei-ai-contract-platform-v2", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "yuqei-ai-contract-platform-v2", + "version": "0.1.0", + "workspaces": [ + "apps/*", + "packages/*", + "sdks/*" + ], + "devDependencies": { + "playwright": "^1.61.0" + } + }, + "apps/contract-web": { + "name": "@yuqei/contract-web", + "version": "0.1.0", + "dependencies": { + "@yuqei/design-system": "0.1.0", + "lucide-react": "1.21.0", + "next": "16.2.9", + "react": "19.2.7", + "react-dom": "19.2.7" + }, + "devDependencies": { + "@types/node": "26.0.0", + "@types/react": "19.2.17", + "@types/react-dom": "19.2.3", + "typescript": "5.9.3" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.1.tgz", + "integrity": "sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@img/colour": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.1.0.tgz", + "integrity": "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/@img/sharp-darwin-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz", + "integrity": "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-arm64": "1.2.4" + } + }, + "node_modules/@img/sharp-darwin-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz", + "integrity": "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-x64": "1.2.4" + } + }, + "node_modules/@img/sharp-libvips-darwin-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz", + "integrity": "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-darwin-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz", + "integrity": "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz", + "integrity": "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==", + "cpu": [ + "arm" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz", + "integrity": "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-ppc64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.4.tgz", + "integrity": "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==", + "cpu": [ + "ppc64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-riscv64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.2.4.tgz", + "integrity": "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==", + "cpu": [ + "riscv64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-s390x": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.4.tgz", + "integrity": "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==", + "cpu": [ + "s390x" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz", + "integrity": "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz", + "integrity": "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz", + "integrity": "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-linux-arm": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz", + "integrity": "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==", + "cpu": [ + "arm" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz", + "integrity": "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-ppc64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.5.tgz", + "integrity": "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==", + "cpu": [ + "ppc64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-ppc64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-riscv64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.34.5.tgz", + "integrity": "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==", + "cpu": [ + "riscv64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-riscv64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-s390x": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.5.tgz", + "integrity": "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==", + "cpu": [ + "s390x" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-s390x": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz", + "integrity": "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-x64": "1.2.4" + } + }, + "node_modules/@img/sharp-linuxmusl-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz", + "integrity": "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-arm64": "1.2.4" + } + }, + "node_modules/@img/sharp-linuxmusl-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz", + "integrity": "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-x64": "1.2.4" + } + }, + "node_modules/@img/sharp-wasm32": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.5.tgz", + "integrity": "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==", + "cpu": [ + "wasm32" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", + "optional": true, + "dependencies": { + "@emnapi/runtime": "^1.7.0" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz", + "integrity": "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-ia32": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.5.tgz", + "integrity": "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==", + "cpu": [ + "ia32" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz", + "integrity": "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@next/env": { + "version": "16.2.9", + "resolved": "https://registry.npmjs.org/@next/env/-/env-16.2.9.tgz", + "integrity": "sha512-ki5VxxXfzD/9TDe13wyeTKIjQTAwBVpnr8KhRDUr8ltMUq1/NBpWNT5tiPoxiGl+PHM4X2ahSOiPk6iAimIzPg==", + "license": "MIT" + }, + "node_modules/@next/swc-darwin-arm64": { + "version": "16.2.9", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.2.9.tgz", + "integrity": "sha512-HkfxNYUCmcct0Xsqib5KxqMSHV4AHJq857BNRchyBDs4YS19aHzVfn1kDuBYKqLLQBjXgnkIsjV2Kd4d2wzYhw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-darwin-x64": { + "version": "16.2.9", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.2.9.tgz", + "integrity": "sha512-7IAtK4MeybpqRV9GRABWEhJ62mOS+rzWOzOTFie4cSEtm12xsoOMJRcECoZx3FHPzFAqN/IJtHqWAFOLfl152w==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-gnu": { + "version": "16.2.9", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.2.9.tgz", + "integrity": "sha512-hBD75iWpUtkL9SmQmcRhmLomn9jgkPzCEkbOcLgHymPEKzv+6ONy13RRiIEz/iEObjkS2Jlb5gYS2XGoS3X4rw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-musl": { + "version": "16.2.9", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.2.9.tgz", + "integrity": "sha512-qZTI3pf9SGc/obr8NkQAekBxmp1QK+kVm+VAf3BALLfFAj+1kUhkTxmrWpVos9R/UYIA8AWX2p6cGI5WdwzVUA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-gnu": { + "version": "16.2.9", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.2.9.tgz", + "integrity": "sha512-xm0HfRNX+UkH4R3c18ynswjj5o5uEj/7iI9p9omdtTSIsRCzQqkGMA+10nzJ4EHnYC3as65IMhbbl5fWRUWHYg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-musl": { + "version": "16.2.9", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.2.9.tgz", + "integrity": "sha512-QumimHkGEG6vM3PfEDWKyKen03NcqLOkeKB1EfcPe7VxzmEiCa4jNnMyBn/US5zcd/VE1CI+O8Ovb3lfjVHfGw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-arm64-msvc": { + "version": "16.2.9", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.2.9.tgz", + "integrity": "sha512-hzQpKZvw8rAwI6A2uQh6SacCSvNAXaIkPNsWwzqqfRiIMiXMfH936skDhz1OO6KpvdKkJrgHHtqQOq5PIXOvdQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-x64-msvc": { + "version": "16.2.9", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.2.9.tgz", + "integrity": "sha512-qr2VL3Ce5QrwgO2yh1ujSBawrimjVKX8FGF/cOynmdYKJY0BdHpGVNIRK1tqONB10Vkm25Ub1BD2bkjWs4+96w==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@swc/helpers": { + "version": "0.5.15", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz", + "integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.8.0" + } + }, + "node_modules/@types/node": { + "version": "26.0.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-26.0.0.tgz", + "integrity": "sha512-vf2YFi1iY9lHGwNJMs01biZFbKJkrZR1T6/MlzjhJLPdntOHLhTrDSnSVcdtvjihi4VQNlrFRIxLsDBlQpAipA==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~8.3.0" + } + }, + "node_modules/@types/react": { + "version": "19.2.17", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.17.tgz", + "integrity": "sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==", + "dev": true, + "license": "MIT", + "dependencies": { + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", + "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.2.0" + } + }, + "node_modules/@yuqei/contract-web": { + "resolved": "apps/contract-web", + "link": true + }, + "node_modules/@yuqei/design-system": { + "resolved": "packages/design-system", + "link": true + }, + "node_modules/baseline-browser-mapping": { + "version": "2.10.38", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.38.tgz", + "integrity": "sha512-31/02mVB4yuQU6adKk5SlY6m+mxDwUq5KZkyYgnLrrKl7TEm1+3PyDtDBz2kOv/wxZz41GHsvV1A/u6RmiyBvw==", + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001799", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001799.tgz", + "integrity": "sha512-hG1bReV+OUU+MOqK4t/ZWI0tZOyz3rqS9XuhOUz1cIcbwBKjOyJEJuw9ER5JuNyqxNk8u/JUVbGibBOL1yrjFw==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/client-only": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", + "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==", + "license": "MIT" + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "license": "Apache-2.0", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/lucide-react": { + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-1.21.0.tgz", + "integrity": "sha512-reEZMXq8Qdd5jg5XYkQ5TR1fB/GiQ7ih4vcrthYDtgjSDwh0i6/YLiGjsWsIwgN49gpAnd4J2elSNzncMEEUUQ==", + "license": "ISC", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.15", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.15.tgz", + "integrity": "sha512-y7Wygv/7mEOvxTuEQDB8StXdMRBWf1kR/tlhAzBRUFkB2jfcLOAxO/SHmOO2zgz1pVgK29/kyupn059/bCHdjA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/next": { + "version": "16.2.9", + "resolved": "https://registry.npmjs.org/next/-/next-16.2.9.tgz", + "integrity": "sha512-MEOJiq/UvuezAdqVSceHbqDgZt1kDw2tpGVOlsdIoJsQdbN2JY2hpVG4xnXGkbdJUOEWhnRfiu/O4Hpc9Juwww==", + "license": "MIT", + "dependencies": { + "@next/env": "16.2.9", + "@swc/helpers": "0.5.15", + "baseline-browser-mapping": "^2.9.19", + "caniuse-lite": "^1.0.30001579", + "postcss": "8.4.31", + "styled-jsx": "5.1.6" + }, + "bin": { + "next": "dist/bin/next" + }, + "engines": { + "node": ">=20.9.0" + }, + "optionalDependencies": { + "@next/swc-darwin-arm64": "16.2.9", + "@next/swc-darwin-x64": "16.2.9", + "@next/swc-linux-arm64-gnu": "16.2.9", + "@next/swc-linux-arm64-musl": "16.2.9", + "@next/swc-linux-x64-gnu": "16.2.9", + "@next/swc-linux-x64-musl": "16.2.9", + "@next/swc-win32-arm64-msvc": "16.2.9", + "@next/swc-win32-x64-msvc": "16.2.9", + "sharp": "^0.34.5" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.1.0", + "@playwright/test": "^1.51.1", + "babel-plugin-react-compiler": "*", + "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", + "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", + "sass": "^1.3.0" + }, + "peerDependenciesMeta": { + "@opentelemetry/api": { + "optional": true + }, + "@playwright/test": { + "optional": true + }, + "babel-plugin-react-compiler": { + "optional": true + }, + "sass": { + "optional": true + } + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/playwright": { + "version": "1.61.0", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.61.0.tgz", + "integrity": "sha512-Z+7BeeqQPRRzklHsVFP4KTGIyMxKUmfeRA4WisM6G3/XW6nwGeX6fX9qYaDa+CiUqpOkb2f6X3nar05R3kSuJQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright-core": "1.61.0" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.61.0", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.61.0.tgz", + "integrity": "sha512-caX7TrY3Ml6egyDX0WUcTHDxodl/b51y5wJOdCEA36QviK/s2g081hvmGs8eaE3DWb6NYZQ6BjO/QkNRPenoPA==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/postcss": { + "version": "8.5.15", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz", + "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.12", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/react": { + "version": "19.2.7", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.7.tgz", + "integrity": "sha512-HNe9WslTbXmFK8o8cmwgAeJFSBvt1bPdHCVKtaaV+WlAN36mpT4hcRpwbf3fY56ar2oIXzsBpOAiIRHAdY0OlQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.2.7", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.7.tgz", + "integrity": "sha512-t0BRVXvbiE/o20Hfw669rLbMCDWtYZLvmJigy2f0MxsXF+71pxhR3xOkspmsO8h3ZlNzyibAmtCa3l4lYKk6gQ==", + "license": "MIT", + "dependencies": { + "scheduler": "^0.27.0" + }, + "peerDependencies": { + "react": "^19.2.7" + } + }, + "node_modules/scheduler": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "license": "ISC", + "optional": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/sharp": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz", + "integrity": "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==", + "hasInstallScript": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@img/colour": "^1.0.0", + "detect-libc": "^2.1.2", + "semver": "^7.7.3" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-darwin-arm64": "0.34.5", + "@img/sharp-darwin-x64": "0.34.5", + "@img/sharp-libvips-darwin-arm64": "1.2.4", + "@img/sharp-libvips-darwin-x64": "1.2.4", + "@img/sharp-libvips-linux-arm": "1.2.4", + "@img/sharp-libvips-linux-arm64": "1.2.4", + "@img/sharp-libvips-linux-ppc64": "1.2.4", + "@img/sharp-libvips-linux-riscv64": "1.2.4", + "@img/sharp-libvips-linux-s390x": "1.2.4", + "@img/sharp-libvips-linux-x64": "1.2.4", + "@img/sharp-libvips-linuxmusl-arm64": "1.2.4", + "@img/sharp-libvips-linuxmusl-x64": "1.2.4", + "@img/sharp-linux-arm": "0.34.5", + "@img/sharp-linux-arm64": "0.34.5", + "@img/sharp-linux-ppc64": "0.34.5", + "@img/sharp-linux-riscv64": "0.34.5", + "@img/sharp-linux-s390x": "0.34.5", + "@img/sharp-linux-x64": "0.34.5", + "@img/sharp-linuxmusl-arm64": "0.34.5", + "@img/sharp-linuxmusl-x64": "0.34.5", + "@img/sharp-wasm32": "0.34.5", + "@img/sharp-win32-arm64": "0.34.5", + "@img/sharp-win32-ia32": "0.34.5", + "@img/sharp-win32-x64": "0.34.5" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/styled-jsx": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.6.tgz", + "integrity": "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==", + "license": "MIT", + "dependencies": { + "client-only": "0.0.1" + }, + "engines": { + "node": ">= 12.0.0" + }, + "peerDependencies": { + "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-8.3.0.tgz", + "integrity": "sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==", + "dev": true, + "license": "MIT" + }, + "packages/design-system": { + "name": "@yuqei/design-system", + "version": "0.1.0" + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 00000000..81665f3b --- /dev/null +++ b/package.json @@ -0,0 +1,23 @@ +{ + "name": "yuqei-ai-contract-platform-v2", + "version": "0.1.0", + "private": true, + "packageManager": "npm@10.9.7", + "workspaces": [ + "apps/*", + "packages/*", + "sdks/*" + ], + "scripts": { + "test": "python -m pytest", + "web:dev": "npm --workspace @yuqei/contract-web run dev", + "web:build": "npm --workspace @yuqei/contract-web run build", + "web:typecheck": "npm --workspace @yuqei/contract-web run typecheck" + }, + "overrides": { + "postcss": "8.5.15" + }, + "devDependencies": { + "playwright": "^1.61.0" + } +} diff --git a/packages/design-system/.gitkeep b/packages/design-system/.gitkeep deleted file mode 100644 index 8b137891..00000000 --- a/packages/design-system/.gitkeep +++ /dev/null @@ -1 +0,0 @@ - diff --git a/packages/design-system/README.md b/packages/design-system/README.md new file mode 100644 index 00000000..0fe17af2 --- /dev/null +++ b/packages/design-system/README.md @@ -0,0 +1,5 @@ +# Yuqei Design System + +Shared V2 design tokens and workflow primitives. + +This package starts intentionally small. It holds product language, layout constants, tokens, and workflow metadata before it grows into a component library. diff --git a/packages/design-system/package.json b/packages/design-system/package.json new file mode 100644 index 00000000..abd0bc21 --- /dev/null +++ b/packages/design-system/package.json @@ -0,0 +1,13 @@ +{ + "name": "@yuqei/design-system", + "version": "0.1.0", + "private": true, + "type": "module", + "types": "./src/index.ts", + "exports": { + ".": "./src/index.ts" + }, + "files": [ + "src" + ] +} diff --git a/packages/design-system/src/index.ts b/packages/design-system/src/index.ts new file mode 100644 index 00000000..3b16516e --- /dev/null +++ b/packages/design-system/src/index.ts @@ -0,0 +1,2 @@ +export * from "./tokens"; +export * from "./workflow"; diff --git a/packages/design-system/src/tokens.ts b/packages/design-system/src/tokens.ts new file mode 100644 index 00000000..7df263ea --- /dev/null +++ b/packages/design-system/src/tokens.ts @@ -0,0 +1,33 @@ +export const brandTokens = { + color: { + ink: "#172033", + muted: "#667085", + line: "#d9e0ea", + canvas: "#f6f8fb", + surface: "#ffffff", + primary: "#2457d6", + primarySoft: "#eaf0ff", + success: "#16794c", + successSoft: "#e7f6ef", + warning: "#b35b00", + warningSoft: "#fff3df", + danger: "#bd2d2d", + dangerSoft: "#fdecec", + accent: "#0b7a75", + accentSoft: "#e4f5f3" + }, + radius: { + sm: "6px", + md: "8px" + }, + shadow: { + panel: "0 10px 30px rgba(16, 24, 40, 0.08)" + }, + layout: { + sidebarWidth: "248px", + topbarHeight: "64px", + contentMaxWidth: "1440px" + } +} as const; + +export type BrandTokens = typeof brandTokens; diff --git a/packages/design-system/src/workflow.ts b/packages/design-system/src/workflow.ts new file mode 100644 index 00000000..c0a2a288 --- /dev/null +++ b/packages/design-system/src/workflow.ts @@ -0,0 +1,24 @@ +export const mainFlow = [ + { + key: "draft", + title: "合同起草", + description: "从模板或智能问答快速生成合同初稿。" + }, + { + key: "review", + title: "法律审查", + description: "审查风险、补齐依据、形成处理意见。" + }, + { + key: "approve", + title: "协同审批", + description: "按条件触发审批,不默认压迫所有用户。" + }, + { + key: "archive", + title: "归档履约", + description: "沉淀文件、审计、版本和履约证据。" + } +] as const; + +export type MainFlowStep = (typeof mainFlow)[number]; diff --git a/project-docs/V2前端基础工程与轻量化体验底座记录-2026-06-22.md b/project-docs/V2前端基础工程与轻量化体验底座记录-2026-06-22.md new file mode 100644 index 00000000..dc5594f0 --- /dev/null +++ b/project-docs/V2前端基础工程与轻量化体验底座记录-2026-06-22.md @@ -0,0 +1,118 @@ +# V2 前端基础工程与轻量化体验底座记录 + +日期:2026-06-22 + +## 1. 本轮目标 + +承接 T0-5,建立 V2 前端基础工程和设计系统底座,同时把企业主线的轻量化体验原则落到第一版页面结构里。 + +## 2. 已完成内容 + +### Workspace + +已建立根 npm workspace: + +- `package.json` +- `package-lock.json` +- `tsconfig.base.json` + +根命令: + +```powershell +npm run web:dev +npm run web:typecheck +npm run web:build +``` + +### Design System + +目录:`packages/design-system` + +已建立: + +- 品牌颜色、布局、圆角、阴影 tokens。 +- 企业主流程 `mainFlow` 元数据。 +- package export 边界。 + +### Contract Web + +目录:`apps/contract-web` + +已建立: + +- Next.js App Router 工程。 +- 全局布局和左侧主导航。 +- 工作台。 +- 合同列表。 +- 合同详情。 +- 统一搜索。 +- 合同仓库。 +- 管理区。 +- 系统健康页。 + +## 3. 体验原则落地 + +本轮页面遵循以下原则: + +- 工作台只突出“待我处理”和“快速发起”。 +- 主流程导航只保留:工作台、合同、统一搜索、合同仓库。 +- 管理员能力集中到“管理区”。 +- 合同详情首屏突出“下一步操作”。 +- 审批、版本、履约、审计在合同详情侧栏折叠呈现。 +- 统一搜索结果标题就是主入口,减少重复“打开”按钮。 +- 合同仓库保留文件预览、关联合同和批量下载入口。 + +## 4. 验证结果 + +已通过: + +```powershell +npm audit --audit-level=moderate +npm run web:typecheck +npm run web:build +python -m pytest +``` + +结果: + +- npm audit:0 vulnerabilities。 +- TypeScript:通过。 +- Next.js production build:通过。 +- 后端 pytest:6 passed。 + +页面验收: + +- `/` +- `/workspace` +- `/contracts` +- `/contracts/contract-001` +- `/search` +- `/files` +- `/admin` +- `/health` + +截图输出: + +```text +output/playwright/v2-front-foundation/ +``` + +## 5. 当前边界 + +本轮仍使用 mock 数据,不包含: + +- 登录认证。 +- 真实合同 API 对接。 +- 真实文件上传/下载。 +- 真实搜索查询。 +- 真实审批提交。 +- AI 问答和审查调用。 + +## 6. 下一步建议 + +继续进入 S2/S3 的最小闭环: + +1. 建立 AI Platform MVP 的数据模型和 `/api/v1/legal/qa` 假实现。 +2. 建立 Python SDK MVP,使 `contract-api` 只能通过 SDK 调用 `ai-platform-api`。 +3. 建立 Contract API 的工作台和合同列表真实接口。 +4. 前端从 mock 数据切换到 Contract API。 diff --git a/tsconfig.base.json b/tsconfig.base.json new file mode 100644 index 00000000..54c2b0f0 --- /dev/null +++ b/tsconfig.base.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "target": "ES2022", + "lib": [ + "dom", + "dom.iterable", + "es2022" + ], + "allowJs": false, + "skipLibCheck": true, + "strict": true, + "noEmit": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "bundler", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "preserve", + "incremental": true + } +}