Sync OneOS workspace with new prototypes, annotations, and Gitea remote fix.

Add vehicle-h2-fee-ledger, customer-management, lease and self-operated ledgers, annotation sources, agent skills, and vite annotation runtime support. Update vehicle management, contract templates, and lease contract flows.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
王冕
2026-06-30 15:27:23 +08:00
parent 00ca1846af
commit af29b26fe8
309 changed files with 73875 additions and 3838 deletions

View File

@@ -0,0 +1,101 @@
{
"documentVersion": 1,
"format": "axhub-annotation-source",
"data": {
"version": 2,
"prototypeName": "standalone-annotation-demo",
"pageId": "overview",
"updatedAt": 1779667200000,
"nodes": [
{
"id": "overview-hero",
"index": 1,
"title": "运行时总览",
"pageId": "overview",
"locator": {
"selectors": ["[data-annotation-id=\"overview-hero\"]"],
"fingerprint": "section|overview-hero",
"path": []
},
"aiPrompt": "说明独立页面如何接入标注运行时。",
"annotationText": "",
"hasMarkdown": true,
"color": "#D97706",
"images": [],
"createdAt": 1779667200000,
"updatedAt": 1779667200000
},
{
"id": "state-card",
"index": 2,
"title": "结果状态",
"pageId": "states",
"locator": {
"selectors": ["[data-annotation-id=\"state-card\"]"],
"fingerprint": "article|state-card",
"path": []
},
"aiPrompt": "演示标注 controls 如何驱动页面状态。",
"annotationText": "在标注面板里切换结果状态,页面应该同步展示成功或失败。",
"hasMarkdown": false,
"color": "#059669",
"images": [],
"controls": [
{
"type": "segmented",
"attributeId": "result_state",
"displayName": "结果状态",
"initialValue": "success",
"options": [
{ "label": "成功", "value": "success" },
{ "label": "失败", "value": "failure" }
]
}
],
"createdAt": 1779667200000,
"updatedAt": 1779667200000
}
]
},
"markdownMap": {
"overview-hero": "# 独立接入说明\n\n`@axhub/annotation` 只负责运行时展示。宿主页面负责提供数据源、稳定选择器和目录 route 行为。"
},
"assetMap": {},
"directory": {
"nodes": [
{
"type": "folder",
"id": "demo-root",
"title": "示例目录",
"defaultExpanded": true,
"children": [
{
"type": "route",
"id": "route-overview",
"title": "运行时总览",
"route": "overview"
},
{
"type": "route",
"id": "route-states",
"title": "状态标注",
"route": "states"
},
{
"type": "markdown",
"id": "doc-usage",
"title": "接入说明",
"markdown": "# 接入说明\n\nReact 使用 `AnnotationViewer`;普通 HTML 使用 `createAnnotationViewer`。"
},
{
"type": "link",
"id": "docs-link",
"title": "包文档",
"href": "https://www.npmjs.com/package/@axhub/annotation",
"target": "blank"
}
]
}
]
}
}

View File

@@ -0,0 +1,31 @@
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Axhub Annotation HTML Example</title>
</head>
<body>
<nav>
<button type="button" data-route="overview">运行时总览</button>
<button type="button" data-route="states">状态标注</button>
</nav>
<section data-page="overview">
<section data-annotation-id="overview-hero">
<h1>@axhub/annotation</h1>
<p>这是一个普通 HTML 宿主接入示例。</p>
</section>
</section>
<section data-page="states" hidden>
<article data-annotation-id="state-card">
<strong data-result-label>成功</strong>
<h2 data-result-title>发布完成</h2>
<p>在标注面板里切换结果状态,页面会同步变化。</p>
</article>
</section>
<script type="module" src="./html-example.ts"></script>
</body>
</html>

View File

@@ -0,0 +1,69 @@
import {
createAnnotationViewer,
type AnnotationDirectoryRouteNode,
type AnnotationSourceDocument,
type ProtoDevState,
} from '@axhub/annotation';
import annotationSource from './annotation-source.json';
type PageId = 'overview' | 'states';
let currentPageId: PageId = 'overview';
function normalizePageId(value: unknown): PageId {
return value === 'states' ? 'states' : 'overview';
}
function renderPage(pageId: PageId): void {
currentPageId = pageId;
document.querySelectorAll<HTMLElement>('[data-page]').forEach((page) => {
page.hidden = page.dataset.page !== pageId;
});
}
function renderState(state: ProtoDevState): void {
const isFailure = state.result_state === 'failure';
const label = document.querySelector('[data-result-label]');
const title = document.querySelector('[data-result-title]');
if (label) label.textContent = isFailure ? '失败' : '成功';
if (title) title.textContent = isFailure ? '发布失败' : '发布完成';
}
const viewer = createAnnotationViewer({
source: annotationSource as AnnotationSourceDocument,
options: {
getCurrentPageId: () => currentPageId,
showToolbar: true,
showThemeToggle: true,
showColorFilter: true,
onDirectoryRoute: (node: AnnotationDirectoryRouteNode) => {
renderPage(normalizePageId(node.route));
viewer.refresh();
},
},
});
document.querySelectorAll<HTMLButtonElement>('[data-route]').forEach((button) => {
button.addEventListener('click', () => {
renderPage(normalizePageId(button.dataset.route));
viewer.refresh();
});
});
void viewer.start().then(() => {
const attach = () => {
const protoDev = window.__AXHUB_PROTO_DEV__;
if (!protoDev) {
window.setTimeout(attach, 80);
return;
}
renderState(protoDev.getState());
protoDev.subscribe(() => renderState(protoDev.getState()));
};
attach();
});
renderPage(currentPageId);

View File

@@ -0,0 +1,71 @@
import React from 'react';
import {
AnnotationViewer,
useProtoDevState,
type AnnotationDirectoryRouteNode,
type AnnotationSourceDocument,
type AnnotationViewerOptions,
} from '@axhub/annotation';
import annotationSource from './annotation-source.json';
type PageId = 'overview' | 'states';
type ResultState = 'success' | 'failure';
function normalizePageId(value: unknown): PageId {
return value === 'states' ? 'states' : 'overview';
}
function normalizeResultState(value: unknown): ResultState {
return value === 'failure' ? 'failure' : 'success';
}
function StateCard() {
const protoState = useProtoDevState<{ result_state?: ResultState }>();
const resultState = normalizeResultState(protoState.result_state);
const isSuccess = resultState === 'success';
return (
<article data-annotation-id="state-card">
<strong>{isSuccess ? '成功' : '失败'}</strong>
<h2>{isSuccess ? '发布完成' : '发布失败'}</h2>
<p>{isSuccess ? '可以继续评审标注内容。' : '需要展示失败原因和重试入口。'}</p>
</article>
);
}
export function AnnotationStandaloneReactExample() {
const [pageId, setPageId] = React.useState<PageId>('overview');
const options = React.useMemo<AnnotationViewerOptions>(() => ({
currentPageId: pageId,
showToolbar: true,
showThemeToggle: true,
showColorFilter: true,
onDirectoryRoute: (node: AnnotationDirectoryRouteNode) => {
setPageId(normalizePageId(node.route));
},
}), [pageId]);
return (
<main>
<nav>
<button type="button" onClick={() => setPageId('overview')}></button>
<button type="button" onClick={() => setPageId('states')}></button>
</nav>
{pageId === 'overview' ? (
<section data-annotation-id="overview-hero">
<h1>@axhub/annotation</h1>
<p> React </p>
</section>
) : (
<StateCard />
)}
<AnnotationViewer
source={annotationSource as AnnotationSourceDocument}
options={options}
/>
</main>
);
}