@xtalpi/agentic-lab-skills 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/package.json +14 -0
- package/skills/lab-flow-designer/SKILL.md +360 -0
- package/skills/lab-flow-designer/embedded-template/SKILL.md +84 -0
- package/skills/lab-flow-designer/embedded-template/pools//345/205/245/345/217/243/346/261/240.md +12 -0
- package/skills/lab-flow-designer/embedded-template/pools//345/207/272/345/217/243/346/261/240.md +12 -0
- package/skills/lab-flow-designer/embedded-template/scripts//347/244/272/344/276/213/346/225/260/346/215/256/344/270/216/346/240/241/351/252/214/351/227/250/346/216/247.js +149 -0
- package/skills/lab-flow-designer/embedded-template/valves//347/244/272/344/276/213/346/225/260/346/215/256/344/270/216/346/240/241/351/252/214/351/227/250/346/216/247.md +100 -0
- package/skills/lab-flow-designer/references/agentic-lab-processer.md +101 -0
- package/skills/lab-flow-designer/references/agentic-lab-sdk.md +440 -0
- package/skills/lab-flow-designer/references/rhea-api/README.md +7 -0
- package/skills/lab-flow-designer/references/rhea-api/execute_process_batch.md +58 -0
- package/skills/lab-flow-designer/references/skill-package-layout.md +199 -0
- package/skills/lab-flow-designer/references//344/270/232/345/212/241/346/265/201/347/250/213/346/226/207/346/241/243/346/240/207/345/207/206.md +208 -0
- package/skills/lab-orbit-component-builder/SKILL.md +305 -0
- package/skills/lab-orbit-component-builder/examples/xnb-component-template/.env.local.example +27 -0
- package/skills/lab-orbit-component-builder/examples/xnb-component-template/.eslintignore +7 -0
- package/skills/lab-orbit-component-builder/examples/xnb-component-template/.eslintrc.cjs +88 -0
- package/skills/lab-orbit-component-builder/examples/xnb-component-template/.nvmrc +1 -0
- package/skills/lab-orbit-component-builder/examples/xnb-component-template/AgenticAppAPI.md +268 -0
- package/skills/lab-orbit-component-builder/examples/xnb-component-template/Jenkinsfile +106 -0
- package/skills/lab-orbit-component-builder/examples/xnb-component-template/OrbitAPI.md +453 -0
- package/skills/lab-orbit-component-builder/examples/xnb-component-template/README.md +176 -0
- package/skills/lab-orbit-component-builder/examples/xnb-component-template/dev/public/index.html +12 -0
- package/skills/lab-orbit-component-builder/examples/xnb-component-template/dev/src/App.vue +151 -0
- package/skills/lab-orbit-component-builder/examples/xnb-component-template/dev/src/components/DevOpenerLauncher.vue +143 -0
- package/skills/lab-orbit-component-builder/examples/xnb-component-template/dev/src/global.d.ts +74 -0
- package/skills/lab-orbit-component-builder/examples/xnb-component-template/dev/src/main.ts +305 -0
- package/skills/lab-orbit-component-builder/examples/xnb-component-template/dev/src/mockXNBBitable.ts +119 -0
- package/skills/lab-orbit-component-builder/examples/xnb-component-template/dev/src/shims-vue.d.ts +6 -0
- package/skills/lab-orbit-component-builder/examples/xnb-component-template/dev/src/utils/devOpenerHost.ts +75 -0
- package/skills/lab-orbit-component-builder/examples/xnb-component-template/index.html +13 -0
- package/skills/lab-orbit-component-builder/examples/xnb-component-template/package.json +57 -0
- package/skills/lab-orbit-component-builder/examples/xnb-component-template/src/api/agenticlabTickets.ts +110 -0
- package/skills/lab-orbit-component-builder/examples/xnb-component-template/src/entries/bitable.ts +4 -0
- package/skills/lab-orbit-component-builder/examples/xnb-component-template/src/entries/custom-page.ts +4 -0
- package/skills/lab-orbit-component-builder/examples/xnb-component-template/src/index.ts +1 -0
- package/skills/lab-orbit-component-builder/examples/xnb-component-template/src/styles/orbit-quasar-host.scss +19 -0
- package/skills/lab-orbit-component-builder/examples/xnb-component-template/src/types/context.ts +15 -0
- package/skills/lab-orbit-component-builder/examples/xnb-component-template/src/types/xnb-context.ts +70 -0
- package/skills/lab-orbit-component-builder/examples/xnb-component-template/src/use/useBitablePage.ts +180 -0
- package/skills/lab-orbit-component-builder/examples/xnb-component-template/src/use/useSuperCellDemo.ts +257 -0
- package/skills/lab-orbit-component-builder/examples/xnb-component-template/src/use/useSuperTableBitableLifecycle.ts +547 -0
- package/skills/lab-orbit-component-builder/examples/xnb-component-template/src/utils/openerInitParams.ts +158 -0
- package/skills/lab-orbit-component-builder/examples/xnb-component-template/src/utils/openerTicketIds.ts +32 -0
- package/skills/lab-orbit-component-builder/examples/xnb-component-template/src/utils/orbitHttpClient.ts +110 -0
- package/skills/lab-orbit-component-builder/examples/xnb-component-template/src/utils/request.ts +92 -0
- package/skills/lab-orbit-component-builder/examples/xnb-component-template/src/views/bitable.vue +65 -0
- package/skills/lab-orbit-component-builder/examples/xnb-component-template/src/views/custom-page.vue +140 -0
- package/skills/lab-orbit-component-builder/examples/xnb-component-template/tsconfig.json +48 -0
- package/skills/lab-orbit-component-builder/examples/xnb-component-template/vite.config.ts +165 -0
- package/skills/lab-orbit-component-builder/examples/xnb-component-template/vite.dev.config.ts +51 -0
- package/skills/lab-orbit-component-builder/references/flow-document-human-ui.md +65 -0
- package/skills/lab-orbit-component-builder/references/pool-schema-to-columns.md +67 -0
- package/skills/lab-orbit-component-builder/references/vue-template-checklist.md +113 -0
- package/skills/lab-orbit-component-builder/references/xnb-context-vue-props.md +49 -0
- package/skills/lab-orbit-component-builder/references/xnbitable-vue-parity.md +32 -0
package/skills/lab-orbit-component-builder/examples/xnb-component-template/dev/src/mockXNBBitable.ts
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import type { DemoBitableSheet, XNBBitableChoreo } from '../../src/types/xnb-context'
|
|
2
|
+
|
|
3
|
+
/** 与 `useSuperTableBitableLifecycle` 中 listSub.index 对齐,便于 dev 命中子表 */
|
|
4
|
+
const DEV_DEFAULT_INDEX = 'sheet-demo'
|
|
5
|
+
const DEV_DEFAULT_NAME = '演示'
|
|
6
|
+
|
|
7
|
+
type BitableItem = { id: string; fields: Record<string, string>; visible?: boolean }
|
|
8
|
+
|
|
9
|
+
type MainBitable = {
|
|
10
|
+
index: string
|
|
11
|
+
name: string
|
|
12
|
+
row: number
|
|
13
|
+
items: BitableItem[]
|
|
14
|
+
data_columns: Array<Record<string, unknown>>
|
|
15
|
+
config: Record<string, unknown>
|
|
16
|
+
xnb_show_sheetbar?: boolean
|
|
17
|
+
xnb_hide_statisticbar?: boolean
|
|
18
|
+
xnb_hide_toolbar?: boolean
|
|
19
|
+
xnb_hide_formulaBar?: boolean
|
|
20
|
+
xnb_excel_with_bg?: boolean
|
|
21
|
+
xnb_height?: string
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Dev 专用:模拟宿主注入的 XNBBitable,便于 `bitable` 视图演练
|
|
26
|
+
* `new XNBBitable({ bookPath, cellUid })` 与 `getSubCell` / `getAllSubBitable` / `addColumns` 等调用链。
|
|
27
|
+
* 真机行为以 Orbit / 业务实现为准。
|
|
28
|
+
*/
|
|
29
|
+
export class DevXNBBitable implements XNBBitableChoreo {
|
|
30
|
+
bookPath: string
|
|
31
|
+
cellUid: string
|
|
32
|
+
|
|
33
|
+
private readonly main: MainBitable
|
|
34
|
+
|
|
35
|
+
constructor (opts: { bookPath: string; cellUid: string }) {
|
|
36
|
+
this.bookPath = opts.bookPath
|
|
37
|
+
this.cellUid = opts.cellUid
|
|
38
|
+
this.main = {
|
|
39
|
+
index: DEV_DEFAULT_INDEX,
|
|
40
|
+
name: DEV_DEFAULT_NAME,
|
|
41
|
+
row: 200,
|
|
42
|
+
items: [],
|
|
43
|
+
data_columns: [],
|
|
44
|
+
config: {}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
async getSubCell (): Promise<string | null> {
|
|
49
|
+
return `mock-subcell::${this.cellUid}`
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
async getAllSubBitable (refresh?: boolean): Promise<DemoBitableSheet[]> {
|
|
53
|
+
if (refresh === true) {
|
|
54
|
+
/* dev mock 不区分 refresh;与真机签名对齐 */
|
|
55
|
+
}
|
|
56
|
+
return [this.main]
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async getSubBitable (refresh?: boolean): Promise<DemoBitableSheet> {
|
|
60
|
+
if (refresh === true) {
|
|
61
|
+
/* dev mock 不区分 refresh;与真机签名对齐 */
|
|
62
|
+
}
|
|
63
|
+
return this.main
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
async addColumns (bitable: Record<string, unknown>, cols: unknown[], extra: unknown[]): Promise<void> {
|
|
67
|
+
if (Array.isArray(extra) && extra.length > 0) {
|
|
68
|
+
/* 第三参占位;真机可能传列元数据 */
|
|
69
|
+
}
|
|
70
|
+
const list = Array.isArray(cols) ? cols : []
|
|
71
|
+
const prev = Array.isArray(bitable.data_columns)
|
|
72
|
+
? (bitable.data_columns as Array<Record<string, unknown>>)
|
|
73
|
+
: []
|
|
74
|
+
const offset = prev.length
|
|
75
|
+
bitable.data_columns = [
|
|
76
|
+
...prev,
|
|
77
|
+
...list.map((col: unknown, i: number) => ({
|
|
78
|
+
...(typeof col === 'object' && col !== null ? (col as Record<string, unknown>) : {}),
|
|
79
|
+
c: offset + i
|
|
80
|
+
}))
|
|
81
|
+
]
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
async createSubBitable (bitables: unknown[], sheetName: string): Promise<string> {
|
|
85
|
+
console.log('[DevXNBBitable] createSubBitable', sheetName, bitables)
|
|
86
|
+
const first = bitables[0] as Partial<MainBitable> | undefined
|
|
87
|
+
if (first != null) {
|
|
88
|
+
if (typeof first.index === 'string') this.main.index = first.index
|
|
89
|
+
if (typeof first.name === 'string') this.main.name = first.name
|
|
90
|
+
if (typeof first.row === 'number') this.main.row = first.row
|
|
91
|
+
if (Array.isArray(first.items)) this.main.items = [...first.items] as BitableItem[]
|
|
92
|
+
if (Array.isArray(first.data_columns)) {
|
|
93
|
+
this.main.data_columns = [...first.data_columns] as MainBitable['data_columns']
|
|
94
|
+
}
|
|
95
|
+
if (first.config != null && typeof first.config === 'object' && !Array.isArray(first.config)) {
|
|
96
|
+
this.main.config = { ...(first.config as Record<string, unknown>) }
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return `mock-created-${sheetName}`
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
async updateSubBitable (bitables: unknown[], _opts?: Record<string, unknown>): Promise<void> {
|
|
103
|
+
const first = bitables[0] as Partial<MainBitable> | undefined
|
|
104
|
+
if (first == null) return
|
|
105
|
+
if (first !== this.main) {
|
|
106
|
+
if (Array.isArray(first.items)) this.main.items = [...first.items] as BitableItem[]
|
|
107
|
+
if (Array.isArray(first.data_columns)) {
|
|
108
|
+
this.main.data_columns = [...first.data_columns]
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
console.log('[DevXNBBitable] updateSubBitable', bitables, _opts)
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
async delay (ms: number): Promise<void> {
|
|
115
|
+
await new Promise<void>((resolve: () => void) => {
|
|
116
|
+
setTimeout(resolve, ms)
|
|
117
|
+
})
|
|
118
|
+
}
|
|
119
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dev 联调:当前页作为 opener 宿主,子页带 `?trace=` 调用 `fetchOpenerInitPayload`。
|
|
3
|
+
* 回包格式与流程页一致:`get-data-response` + 平铺 `ticket_ids` / `valve_id`。
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { OPENER_MSG_GET_DATA_RESPONSE } from '@/utils/openerInitParams'
|
|
7
|
+
|
|
8
|
+
export const DEV_OPENER_CHILD_QUERY = 'devOpenerChild'
|
|
9
|
+
|
|
10
|
+
export function isDevOpenerChildPage (): boolean {
|
|
11
|
+
const params = new URLSearchParams(window.location.search)
|
|
12
|
+
return (
|
|
13
|
+
params.get(DEV_OPENER_CHILD_QUERY) === '1'
|
|
14
|
+
&& window.opener != null
|
|
15
|
+
&& !window.opener.closed
|
|
16
|
+
)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function createDevOpenerTrace (): string {
|
|
20
|
+
return `dev-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface DevOpenerHostHandle {
|
|
24
|
+
dispose: () => void
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function flatFieldsFromPayload (payload: unknown): Record<string, unknown> {
|
|
28
|
+
if (payload == null || typeof payload !== 'object') return {}
|
|
29
|
+
const p = payload as Record<string, unknown>
|
|
30
|
+
const out: Record<string, unknown> = {}
|
|
31
|
+
if ('ticket_ids' in p) out.ticket_ids = p.ticket_ids
|
|
32
|
+
if ('valve_id' in p) out.valve_id = p.valve_id
|
|
33
|
+
return out
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* 监听子页 `{ msg: 'get-data', trace }`,回 `{ msg: 'get-data-response', trace, ticket_ids, valve_id }`。
|
|
38
|
+
*/
|
|
39
|
+
export function installDevOpenerHost (getPayload: () => unknown): DevOpenerHostHandle {
|
|
40
|
+
const onMessage = (e: MessageEvent): void => {
|
|
41
|
+
if (e.source == null || e.source === window) return
|
|
42
|
+
const d = e.data as Record<string, unknown> | null
|
|
43
|
+
if (d == null || typeof d !== 'object') return
|
|
44
|
+
if (d.msg !== 'get-data') return
|
|
45
|
+
const { trace } = d
|
|
46
|
+
if (typeof trace !== 'string' || trace === '') return
|
|
47
|
+
|
|
48
|
+
const flat = flatFieldsFromPayload(getPayload())
|
|
49
|
+
const child = e.source as Window
|
|
50
|
+
window.setTimeout(() => {
|
|
51
|
+
child.postMessage(
|
|
52
|
+
{ msg: OPENER_MSG_GET_DATA_RESPONSE, trace, ...flat },
|
|
53
|
+
'*'
|
|
54
|
+
)
|
|
55
|
+
console.log('[devOpenerHost] 已回包 get-data-response', { trace, ...flat })
|
|
56
|
+
}, 0)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
window.addEventListener('message', onMessage)
|
|
60
|
+
return {
|
|
61
|
+
dispose: (): void => {
|
|
62
|
+
window.removeEventListener('message', onMessage)
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* 打开子页(同源),URL 携带 `trace` 与 `devOpenerChild=1`。
|
|
69
|
+
*/
|
|
70
|
+
export function openDevOpenerChild (trace: string): Window | null {
|
|
71
|
+
const url = new URL(window.location.href)
|
|
72
|
+
url.searchParams.set('trace', trace)
|
|
73
|
+
url.searchParams.set(DEV_OPENER_CHILD_QUERY, '1')
|
|
74
|
+
return window.open(url.toString(), `dev-opener-${trace}`)
|
|
75
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
6
|
+
<meta name="viewport" content="width=device-width,initial-scale=1.0,user-scalable=no">
|
|
7
|
+
<title>Xnb Component Dev</title>
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
<div id="app"></div>
|
|
11
|
+
<script type="module" src="/dev/src/main.ts"></script>
|
|
12
|
+
</body>
|
|
13
|
+
</html>
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "xnbOrbitComponent",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"author": "yansen.lei",
|
|
5
|
+
"main": "./dist/DemoOrbitBitable.umd.js",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"engines": {
|
|
8
|
+
"node": ">=22"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"dev": "vite --config vite.dev.config.ts",
|
|
12
|
+
"dev:bitable": "VITE_COMPONENT_ID=bitable vite --config vite.dev.config.ts",
|
|
13
|
+
"dev:custom-page": "VITE_COMPONENT_ID=custom-page vite --config vite.dev.config.ts",
|
|
14
|
+
"build": "vite build --mode func",
|
|
15
|
+
"build:bitable": "VITE_COMPONENT_ID=bitable vite build --mode func",
|
|
16
|
+
"build:custom-page": "VITE_COMPONENT_ID=custom-page vite build --mode func",
|
|
17
|
+
"build:all": "npm run build:bitable && npm run build:custom-page",
|
|
18
|
+
"build:es": "vite build",
|
|
19
|
+
"lint": "eslint --ext .js,.ts,.tsx,.vue src"
|
|
20
|
+
},
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"@vueuse/core": "^10.2.1"
|
|
23
|
+
},
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"dayjs": "^1.11.7",
|
|
26
|
+
"@quasar/extras": "^1.14.1",
|
|
27
|
+
"@quasar/vite-plugin": "1.6.0",
|
|
28
|
+
"@typescript-eslint/eslint-plugin": "^7.0.0",
|
|
29
|
+
"@typescript-eslint/parser": "^7.0.0",
|
|
30
|
+
"@vitejs/plugin-vue": "^5.0.0",
|
|
31
|
+
"@vue/compiler-sfc": "3.2.29",
|
|
32
|
+
"@xtalpi/webb-api": "0.1.0",
|
|
33
|
+
"axios": "^1.7.0",
|
|
34
|
+
"eslint": "^8.57.0",
|
|
35
|
+
"eslint-plugin-vue": "^9.28.0",
|
|
36
|
+
"lodash": "^4.17.21",
|
|
37
|
+
"quasar": "2.12.7",
|
|
38
|
+
"rollup-plugin-external-globals": "^0.13.0",
|
|
39
|
+
"sass": "~1.77.6",
|
|
40
|
+
"typescript": "~5.5.0",
|
|
41
|
+
"vite": "^5.4.0",
|
|
42
|
+
"vite-plugin-compression": "^0.5.1",
|
|
43
|
+
"vite-plugin-css-injected-by-js": "^3.5.2",
|
|
44
|
+
"vue": "3.2.29"
|
|
45
|
+
},
|
|
46
|
+
"webb": {
|
|
47
|
+
"name": "DemoOrbitVueLib",
|
|
48
|
+
"type": "element",
|
|
49
|
+
"exports": [
|
|
50
|
+
{
|
|
51
|
+
"name": "View",
|
|
52
|
+
"category": "view"
|
|
53
|
+
}
|
|
54
|
+
],
|
|
55
|
+
"dependencies": {}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AgenticLab App:Ticket 列表 HTTP。
|
|
3
|
+
* 请求走 **`orbitRequestJson`**(`src/utils/orbitHttpClient.ts`),优先 **`window.xnb.http.client.request`**,见 **OrbitAPI.md** §6.3。
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { orbitRequestJson } from '@/utils/orbitHttpClient'
|
|
7
|
+
|
|
8
|
+
export interface FetchAgenticlabTicketListParams {
|
|
9
|
+
/** 无尾部斜杠亦可,如 `https://agenticlab.example.com`;嵌入 Orbit 且仅用 http.client 时仍建议填写以便回退 fetch */
|
|
10
|
+
baseUrl: string
|
|
11
|
+
/**
|
|
12
|
+
* 可选静态 Bearer;为空时依次尝试:
|
|
13
|
+
* `await window.xnb.choreo.getUserToken()`(无参)、`VITE_DEV_TOKEN`。
|
|
14
|
+
*/
|
|
15
|
+
token?: string
|
|
16
|
+
/** 业务工单号列表,对应 query `ticket_id__in`(多值逗号拼接) */
|
|
17
|
+
ticketIds: string[]
|
|
18
|
+
limit?: number
|
|
19
|
+
offset?: number
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function joinBaseAndPath (baseUrl: string, path: string): string {
|
|
23
|
+
const trimmed = baseUrl.replace(/\/+$/, '')
|
|
24
|
+
const p = path.startsWith('/') ? path : `/${path}`
|
|
25
|
+
return `${trimmed}${p}`
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async function resolveBearerToken (opts: { token?: string }): Promise<string | undefined> {
|
|
29
|
+
if (opts.token != null && opts.token !== '') return opts.token
|
|
30
|
+
const w = window as Window & { xnb?: { choreo?: { getUserToken?: () => Promise<string> } } }
|
|
31
|
+
const getToken = w.xnb?.choreo?.getUserToken
|
|
32
|
+
if (getToken != null) {
|
|
33
|
+
try {
|
|
34
|
+
return await getToken()
|
|
35
|
+
} catch {
|
|
36
|
+
return undefined
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
const env = import.meta.env.VITE_DEV_TOKEN
|
|
40
|
+
return env != null && env !== '' ? env : undefined
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* `GET /api/ticket/list`,`ticket_id__in` 为逗号拼接的 ticket 业务号(与 `detail.ticket_id` 对应)。
|
|
45
|
+
*/
|
|
46
|
+
export async function fetchAgenticlabTicketList (params: FetchAgenticlabTicketListParams): Promise<unknown[]> {
|
|
47
|
+
const { baseUrl, token, ticketIds, limit = 999999, offset = 0 } = params
|
|
48
|
+
if (!baseUrl || ticketIds.length === 0) return []
|
|
49
|
+
|
|
50
|
+
const url = joinBaseAndPath(baseUrl, '/api/ticket/list')
|
|
51
|
+
const bearer = await resolveBearerToken({ token })
|
|
52
|
+
const headers: Record<string, string> = { Accept: 'application/json' }
|
|
53
|
+
if (bearer != null && bearer !== '') {
|
|
54
|
+
headers.Authorization = `Bearer ${bearer}`
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const raw = await orbitRequestJson({
|
|
58
|
+
method: 'get',
|
|
59
|
+
url,
|
|
60
|
+
headers,
|
|
61
|
+
query: {
|
|
62
|
+
limit,
|
|
63
|
+
offset,
|
|
64
|
+
ticket_id__in: ticketIds.join(',')
|
|
65
|
+
}
|
|
66
|
+
})
|
|
67
|
+
const body = raw as { code?: number; msg?: string; data?: { list?: unknown[] } }
|
|
68
|
+
if (body.code !== 200) {
|
|
69
|
+
throw new Error(body.msg != null && body.msg !== '' ? String(body.msg) : `业务 code ${String(body.code)}`)
|
|
70
|
+
}
|
|
71
|
+
return body.data?.list ?? []
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export interface PostAgenticlabExecutionCompleteParams {
|
|
75
|
+
baseUrl: string
|
|
76
|
+
token?: string
|
|
77
|
+
/** 门控 / 执行实例标识,与后端约定一致;缺省可由 opener 或环境变量提供 */
|
|
78
|
+
valveId: number
|
|
79
|
+
/** 与列表项结构一致的工单对象数组,字段须与 `GET /api/ticket/list` 的 `list[]` 项对齐(含编辑后的 `detail` 等) */
|
|
80
|
+
tickets: Record<string, unknown>[]
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* `POST /api/execution/complete`:提交编辑后的Ticket列表,由后端完成执行闭环。
|
|
85
|
+
*/
|
|
86
|
+
export async function postAgenticlabExecutionComplete (params: PostAgenticlabExecutionCompleteParams): Promise<void> {
|
|
87
|
+
const { baseUrl, token, valveId, tickets } = params
|
|
88
|
+
if (!baseUrl) throw new Error('缺少 AgenticLab baseUrl')
|
|
89
|
+
|
|
90
|
+
const url = joinBaseAndPath(baseUrl, '/api/execution/complete')
|
|
91
|
+
const bearer = await resolveBearerToken({ token })
|
|
92
|
+
const headers: Record<string, string> = {
|
|
93
|
+
Accept: 'application/json',
|
|
94
|
+
'Content-Type': 'application/json; charset=utf-8'
|
|
95
|
+
}
|
|
96
|
+
if (bearer != null && bearer !== '') {
|
|
97
|
+
headers.Authorization = `Bearer ${bearer}`
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const raw = await orbitRequestJson({
|
|
101
|
+
method: 'post',
|
|
102
|
+
url,
|
|
103
|
+
headers,
|
|
104
|
+
jsonBody: { valve_id: valveId, tickets }
|
|
105
|
+
})
|
|
106
|
+
const body = raw as { code?: number; msg?: string }
|
|
107
|
+
if (body.code !== 200) {
|
|
108
|
+
throw new Error(body.msg != null && body.msg !== '' ? String(body.msg) : `业务 code ${String(body.code)}`)
|
|
109
|
+
}
|
|
110
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { View, packageData } from './entries/bitable'
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Orbit Cell 内 Quasar 子树:根节点加 `class="orbit-quasar-host"` 后,本节点以下生效。
|
|
3
|
+
* - 主色:`color="primary"` / `.bg-primary` → `var(--q-primary)`
|
|
4
|
+
* - `q-btn`:紧凑内边距;关闭默认全大写
|
|
5
|
+
*
|
|
6
|
+
* 复用:在 SFC 的 `<style scoped lang="scss">` 内首行 `@import '@/styles/orbit-quasar-host.scss';`
|
|
7
|
+
* (须 scoped + `:deep(.q-btn)`,否则子组件 DOM 无法命中)
|
|
8
|
+
* 主题调整:新增/修改主色或全局 `q-btn` 表现请只改本文件;页面结构见 `src/views/bitable.vue`。
|
|
9
|
+
* 按钮分工:`primary` 仅提交等持久化写回;`outline` 仅刷新/检查等页面数据交互(见 studio-orbit-vue-component SKILL 规则 2)。
|
|
10
|
+
*/
|
|
11
|
+
.orbit-quasar-host {
|
|
12
|
+
--orbit-primary: #123aff;
|
|
13
|
+
--q-primary: var(--orbit-primary);
|
|
14
|
+
|
|
15
|
+
:deep(.q-btn) {
|
|
16
|
+
padding: 0 10px;
|
|
17
|
+
text-transform: none;
|
|
18
|
+
}
|
|
19
|
+
}
|
package/skills/lab-orbit-component-builder/examples/xnb-component-template/src/types/context.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface XnbContext {
|
|
2
|
+
bookPath: string
|
|
3
|
+
cellUid: string
|
|
4
|
+
notifySuccess: (msg: string) => void
|
|
5
|
+
notifyError: (msg: any) => void
|
|
6
|
+
loadingShow: (opts?: any) => void
|
|
7
|
+
loadingHide: () => void
|
|
8
|
+
userData: Record<string, any>
|
|
9
|
+
getUserData: () => Record<string, any>
|
|
10
|
+
updateUserData: (data: any) => void
|
|
11
|
+
mergeUserData: (data: any) => void
|
|
12
|
+
getInstanceById: (id: string) => any
|
|
13
|
+
getInstanceValueById: (id: string) => any
|
|
14
|
+
setInstanceValueById: (id: string, value: any) => void
|
|
15
|
+
}
|
package/skills/lab-orbit-component-builder/examples/xnb-component-template/src/types/xnb-context.ts
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 与「超级表格 / 子 Cell」协作相关的 xnbContext 形状(精简版,便于本模板内类型对齐)。
|
|
3
|
+
* 完整类型定义以你们宿主或正式项目中的 `Types/context` 等为准;本处仅保留模板示例所需字段。
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* 单张子表在 XNBBitable 侧的常见形状(`getSubBitable` / `getAllSubBitable` 返回值对齐用)。
|
|
8
|
+
* 宿主实现字段可能更多;此处保留示例所需最小集。
|
|
9
|
+
*/
|
|
10
|
+
export interface DemoBitableSheet {
|
|
11
|
+
index?: string
|
|
12
|
+
name?: string
|
|
13
|
+
row?: number
|
|
14
|
+
items: unknown[]
|
|
15
|
+
data_columns: unknown[]
|
|
16
|
+
config?: unknown
|
|
17
|
+
[key: string]: unknown
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** 子表创建时单张 bitable 的配置骨架(创建前常补全 items / data_columns / config) */
|
|
21
|
+
export interface DemoSubBitableOption {
|
|
22
|
+
index?: string
|
|
23
|
+
name?: string
|
|
24
|
+
rowFocus?: number
|
|
25
|
+
columnFocus?: number
|
|
26
|
+
items?: unknown[]
|
|
27
|
+
data_columns?: unknown[]
|
|
28
|
+
config?: unknown[]
|
|
29
|
+
[key: string]: unknown
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** 宿主注入的 XNBBitable 构造函数(典型用法:`new XNBBitable({ bookPath, cellUid })`) */
|
|
33
|
+
export interface XNBBitableChoreo {
|
|
34
|
+
getSubCell (): Promise<string | null>
|
|
35
|
+
createSubBitable (bitables: unknown[], sheetName: string): Promise<string>
|
|
36
|
+
/** 多子表时用于按 `index` 命中目标子表;单表场景常返回长度为 1 的数组 */
|
|
37
|
+
getAllSubBitable (refresh?: boolean): Promise<DemoBitableSheet[]>
|
|
38
|
+
getSubBitable (refresh?: boolean): Promise<DemoBitableSheet>
|
|
39
|
+
/**
|
|
40
|
+
* 为子表追加列定义(常见签名第三参为 `[]`)。
|
|
41
|
+
* 与 `bitable-list-lifecycle.js` 一致:重建列前常先清空 `bitable.data_columns` 再调用。
|
|
42
|
+
*/
|
|
43
|
+
addColumns (bitable: Record<string, unknown>, dataColumns: unknown[], extra: unknown[]): Promise<void>
|
|
44
|
+
updateSubBitable (bitables: unknown[], opts?: Record<string, unknown>): Promise<void>
|
|
45
|
+
delay (ms: number): Promise<void>
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export type XNBBitableConstructor = new (opts: { bookPath: string; cellUid: string }) => XNBBitableChoreo
|
|
49
|
+
|
|
50
|
+
/** window.xnb.event 最小形状(仅示例里 on/off/emit) */
|
|
51
|
+
export interface XnbEventBus {
|
|
52
|
+
on: (channel: string, handler: (...args: unknown[]) => void) => void
|
|
53
|
+
off: (channel: string, handler: (...args: unknown[]) => void) => void
|
|
54
|
+
emit: (channel: string, ...args: unknown[]) => void
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** 超级表格 Cell 场景下 xnbContext 常用字段(宿主注入上下文 + XNBBitable 类) */
|
|
58
|
+
export interface XnbSuperCellContext {
|
|
59
|
+
bookPath: string
|
|
60
|
+
cellUid: string
|
|
61
|
+
/** 类本身,由宿主注入;dev 环境见 dev/src/mockXNBBitable.ts */
|
|
62
|
+
XNBBitable?: XNBBitableConstructor
|
|
63
|
+
loadingShow?: (opts?: unknown) => void
|
|
64
|
+
loadingHide?: () => void
|
|
65
|
+
notifySuccess?: (msg: string) => void
|
|
66
|
+
notifyError?: (msg: unknown, ...rest: unknown[]) => void
|
|
67
|
+
getUserData?: () => Record<string, unknown>
|
|
68
|
+
updateUserData?: (data: Record<string, unknown>) => Promise<void> | void
|
|
69
|
+
[key: string]: unknown
|
|
70
|
+
}
|
package/skills/lab-orbit-component-builder/examples/xnb-component-template/src/use/useBitablePage.ts
ADDED
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import { computed, onMounted, ref, watch } from 'vue'
|
|
2
|
+
import type { ComputedRef, Ref } from 'vue'
|
|
3
|
+
import { useQuasar } from 'quasar'
|
|
4
|
+
import type { XnbSuperCellContext } from '@/types/xnb-context'
|
|
5
|
+
import type { OpenerInitResult } from '@/utils/openerInitParams'
|
|
6
|
+
import { fetchOpenerInitPayload } from '@/utils/openerInitParams'
|
|
7
|
+
import { useSuperTableBitableLifecycle } from '@/use/useSuperTableBitableLifecycle'
|
|
8
|
+
|
|
9
|
+
export interface UseBitablePageResult {
|
|
10
|
+
openerInitReady: Ref<boolean>
|
|
11
|
+
openerInitError: Ref<unknown>
|
|
12
|
+
openerErrorText: ComputedRef<string>
|
|
13
|
+
busyRefresh: Ref<boolean>
|
|
14
|
+
busyCheck: Ref<boolean>
|
|
15
|
+
busySubmit: Ref<boolean>
|
|
16
|
+
lastRowCount: Ref<number>
|
|
17
|
+
onRefresh: () => Promise<void>
|
|
18
|
+
onCheck: () => Promise<void>
|
|
19
|
+
onSubmit: () => Promise<void>
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* 超级表格 Cell 页:opener 初始化 + `useSuperTableBitableLifecycle`(刷新 / 检查 / 提交)。
|
|
24
|
+
*/
|
|
25
|
+
export function useBitablePage (getContext: () => XnbSuperCellContext): UseBitablePageResult {
|
|
26
|
+
const $q = useQuasar()
|
|
27
|
+
|
|
28
|
+
function confirmDataMutation (title: string, message: string): Promise<boolean> {
|
|
29
|
+
return new Promise<boolean>((resolve: (v: boolean) => void) => {
|
|
30
|
+
let settled = false
|
|
31
|
+
const finish = (v: boolean): void => {
|
|
32
|
+
if (settled) return
|
|
33
|
+
settled = true
|
|
34
|
+
resolve(v)
|
|
35
|
+
}
|
|
36
|
+
$q.dialog({
|
|
37
|
+
title,
|
|
38
|
+
message,
|
|
39
|
+
persistent: true,
|
|
40
|
+
ok: { label: '确定', color: 'primary', flat: false },
|
|
41
|
+
cancel: { label: '取消', flat: true, color: 'grey-8' }
|
|
42
|
+
})
|
|
43
|
+
.onOk(() => {
|
|
44
|
+
finish(true)
|
|
45
|
+
})
|
|
46
|
+
.onCancel(() => {
|
|
47
|
+
finish(false)
|
|
48
|
+
})
|
|
49
|
+
.onDismiss(() => {
|
|
50
|
+
finish(false)
|
|
51
|
+
})
|
|
52
|
+
})
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const openerInit = ref<OpenerInitResult | null>(null)
|
|
56
|
+
const openerInitError = ref<unknown>(null)
|
|
57
|
+
const openerInitReady = ref(false)
|
|
58
|
+
|
|
59
|
+
const openerPayload = computed(() => {
|
|
60
|
+
if (openerInit.value?.ok === true) return openerInit.value.payload
|
|
61
|
+
return null
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
const openerErrorText = computed(() => '没有获得有效参数,请关闭页面重试。')
|
|
65
|
+
|
|
66
|
+
const { choreo, lastRowCount, bootstrap, refreshTable, checkRows, submitRows } = useSuperTableBitableLifecycle(
|
|
67
|
+
getContext,
|
|
68
|
+
() => openerPayload.value
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
const busyRefresh = ref(false)
|
|
72
|
+
const busyCheck = ref(false)
|
|
73
|
+
const busySubmit = ref(false)
|
|
74
|
+
|
|
75
|
+
async function runOpenerInit (): Promise<void> {
|
|
76
|
+
const ctx = getContext()
|
|
77
|
+
try {
|
|
78
|
+
openerInit.value = await fetchOpenerInitPayload({
|
|
79
|
+
loadingShow: () => {
|
|
80
|
+
ctx.loadingShow?.()
|
|
81
|
+
},
|
|
82
|
+
loadingHide: () => {
|
|
83
|
+
ctx.loadingHide?.()
|
|
84
|
+
},
|
|
85
|
+
notifyError: (msg: unknown, ...rest: unknown[]) => {
|
|
86
|
+
console.warn('[opener] init error:', msg, ...rest)
|
|
87
|
+
}
|
|
88
|
+
})
|
|
89
|
+
if (openerInit.value && !openerInit.value.ok) {
|
|
90
|
+
console.warn('[opener] init not ok:', openerInit.value.skipped)
|
|
91
|
+
openerInitError.value = new Error(openerInit.value.skipped || 'init-failed')
|
|
92
|
+
}
|
|
93
|
+
} catch (err) {
|
|
94
|
+
console.warn('[opener] init exception:', err)
|
|
95
|
+
openerInitError.value = err
|
|
96
|
+
} finally {
|
|
97
|
+
openerInitReady.value = true
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
async function runBootstrapSafe (): Promise<void> {
|
|
102
|
+
if (!choreo.value) return
|
|
103
|
+
try {
|
|
104
|
+
await bootstrap()
|
|
105
|
+
} catch {
|
|
106
|
+
/* composable 内已 notify */
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
async function onRefresh (): Promise<void> {
|
|
111
|
+
const ok = await confirmDataMutation(
|
|
112
|
+
'确认刷新',
|
|
113
|
+
'将重新拉取数据并覆盖当前表格内容,是否继续?'
|
|
114
|
+
)
|
|
115
|
+
if (!ok) return
|
|
116
|
+
busyRefresh.value = true
|
|
117
|
+
try {
|
|
118
|
+
await refreshTable({})
|
|
119
|
+
} finally {
|
|
120
|
+
busyRefresh.value = false
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
async function onCheck (): Promise<void> {
|
|
125
|
+
busyCheck.value = true
|
|
126
|
+
try {
|
|
127
|
+
await checkRows()
|
|
128
|
+
} finally {
|
|
129
|
+
busyCheck.value = false
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
async function onSubmit (): Promise<void> {
|
|
134
|
+
const ok = await confirmDataMutation(
|
|
135
|
+
'确认提交',
|
|
136
|
+
'将把当前表格中的工单提交至服务器(execution/complete),是否继续?'
|
|
137
|
+
)
|
|
138
|
+
if (!ok) return
|
|
139
|
+
busySubmit.value = true
|
|
140
|
+
try {
|
|
141
|
+
await submitRows()
|
|
142
|
+
} finally {
|
|
143
|
+
busySubmit.value = false
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
onMounted(() => {
|
|
148
|
+
runOpenerInit().catch(() => {})
|
|
149
|
+
})
|
|
150
|
+
|
|
151
|
+
watch(
|
|
152
|
+
[openerInitReady, openerPayload, choreo],
|
|
153
|
+
() => {
|
|
154
|
+
if (!openerInitReady.value || !choreo.value) return
|
|
155
|
+
runBootstrapSafe().catch(() => {})
|
|
156
|
+
},
|
|
157
|
+
{ immediate: true }
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
watch(
|
|
161
|
+
() => [getContext().bookPath, getContext().cellUid, getContext().XNBBitable] as const,
|
|
162
|
+
() => {
|
|
163
|
+
if (!openerInitReady.value || !choreo.value) return
|
|
164
|
+
runBootstrapSafe().catch(() => {})
|
|
165
|
+
}
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
return {
|
|
169
|
+
openerInitReady,
|
|
170
|
+
openerInitError,
|
|
171
|
+
openerErrorText,
|
|
172
|
+
busyRefresh,
|
|
173
|
+
busyCheck,
|
|
174
|
+
busySubmit,
|
|
175
|
+
lastRowCount,
|
|
176
|
+
onRefresh,
|
|
177
|
+
onCheck,
|
|
178
|
+
onSubmit
|
|
179
|
+
}
|
|
180
|
+
}
|