@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/public/index.html
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
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
|
+
</body>
|
|
12
|
+
</html>
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="dev-shell" :class="{ 'dev-shell--child': isChildPage }">
|
|
3
|
+
<DevOpenerLauncher v-if="!isChildPage" class="dev-shell__launcher" />
|
|
4
|
+
<q-banner v-else rounded dense class="dev-child-hint q-ma-sm">
|
|
5
|
+
Opener 子页联调 · trace: <code>{{ childTrace }}</code> — 初始化结果见下方组件(成功则出现刷新/提交按钮)
|
|
6
|
+
</q-banner>
|
|
7
|
+
<div class="entry">
|
|
8
|
+
<View ref="sheetRef" :xnbContext="xnbContext" />
|
|
9
|
+
</div>
|
|
10
|
+
</div>
|
|
11
|
+
</template>
|
|
12
|
+
|
|
13
|
+
<script lang="ts">
|
|
14
|
+
import { computed, defineComponent, reactive, ref } from 'vue'
|
|
15
|
+
import { Notify, Loading } from 'quasar'
|
|
16
|
+
import { DevXNBBitable } from './mockXNBBitable'
|
|
17
|
+
import DevOpenerLauncher from './components/DevOpenerLauncher.vue'
|
|
18
|
+
import { isDevOpenerChildPage } from './utils/devOpenerHost'
|
|
19
|
+
|
|
20
|
+
export default defineComponent({
|
|
21
|
+
components: { DevOpenerLauncher },
|
|
22
|
+
setup () {
|
|
23
|
+
const isChildPage = isDevOpenerChildPage()
|
|
24
|
+
const childTrace = computed(() => new URLSearchParams(window.location.search).get('trace') || '—')
|
|
25
|
+
const cellParams = reactive({
|
|
26
|
+
bookPath: '/dev/notebook/doe',
|
|
27
|
+
uid: 'dev-cell-001'
|
|
28
|
+
})
|
|
29
|
+
const viewRef = ref()
|
|
30
|
+
|
|
31
|
+
const DEV_REQUEST_URL = import.meta.env.VITE_REQUEST_URL || ''
|
|
32
|
+
|
|
33
|
+
const userData: Record<string, any> = {
|
|
34
|
+
projectURL: JSON.stringify({ request_url: DEV_REQUEST_URL })
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const xnbContext = {
|
|
38
|
+
bookPath: cellParams.bookPath,
|
|
39
|
+
cellUid: cellParams.uid,
|
|
40
|
+
XNBUtil: {
|
|
41
|
+
async getWikiTables (_url: string): Promise<any> {
|
|
42
|
+
return { bitable: 'dev-bitable', tables: [] }
|
|
43
|
+
},
|
|
44
|
+
async getLarkBitableById (_bitable: string, _tableId: string, _opts?: any): Promise<any[]> {
|
|
45
|
+
return []
|
|
46
|
+
},
|
|
47
|
+
async batchCreateRecords (_opts: any): Promise<any> {
|
|
48
|
+
return { records: [] }
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
notifySuccess (msg: string): void {
|
|
52
|
+
Notify.create({ type: 'positive', message: String(msg), position: 'top', timeout: 3000 })
|
|
53
|
+
},
|
|
54
|
+
notifyError (msg: any): void {
|
|
55
|
+
const text = msg instanceof Error ? msg.message : String(msg)
|
|
56
|
+
Notify.create({ type: 'negative', message: text, position: 'top', timeout: 5000 })
|
|
57
|
+
},
|
|
58
|
+
loadingShow (opts?: any): void {
|
|
59
|
+
Loading.show(typeof opts === 'string' ? { message: opts } : opts)
|
|
60
|
+
},
|
|
61
|
+
loadingHide (): void {
|
|
62
|
+
Loading.hide()
|
|
63
|
+
},
|
|
64
|
+
userData,
|
|
65
|
+
getUserData (): Record<string, any> {
|
|
66
|
+
return userData
|
|
67
|
+
},
|
|
68
|
+
updateUserData (data: any): void {
|
|
69
|
+
Object.assign(userData, data)
|
|
70
|
+
},
|
|
71
|
+
mergeUserData (data: any): void {
|
|
72
|
+
Object.assign(userData, data)
|
|
73
|
+
},
|
|
74
|
+
getInstanceById (_id: string): any { return null },
|
|
75
|
+
getInstanceValueById (_id: string): any { return null },
|
|
76
|
+
setInstanceValueById (_id: string, _value: any): void { /* noop */ },
|
|
77
|
+
async saveBitableConfig (_bitable: Record<string, any>): Promise<void> {
|
|
78
|
+
localStorage.setItem('DEV_BITABLE_CONFIG', JSON.stringify(_bitable))
|
|
79
|
+
},
|
|
80
|
+
async getBitableConfig (): Promise<string> {
|
|
81
|
+
return localStorage.getItem('DEV_BITABLE_CONFIG') || '{}'
|
|
82
|
+
},
|
|
83
|
+
XNBBitable: DevXNBBitable
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
window.xnb.store.set('params', cellParams)
|
|
87
|
+
|
|
88
|
+
return {
|
|
89
|
+
isChildPage,
|
|
90
|
+
childTrace,
|
|
91
|
+
cellParams,
|
|
92
|
+
viewRef,
|
|
93
|
+
xnbContext
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
})
|
|
97
|
+
</script>
|
|
98
|
+
|
|
99
|
+
<style lang="scss">
|
|
100
|
+
html,
|
|
101
|
+
body,
|
|
102
|
+
#app {
|
|
103
|
+
margin: 0;
|
|
104
|
+
padding: 0;
|
|
105
|
+
height: 100%;
|
|
106
|
+
width: 100%;
|
|
107
|
+
overflow: hidden;
|
|
108
|
+
box-sizing: border-box;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
#app {
|
|
112
|
+
font-family: Arial, Helvetica, sans-serif;
|
|
113
|
+
-webkit-font-smoothing: antialiased;
|
|
114
|
+
-moz-osx-font-smoothing: grayscale;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.dev-shell {
|
|
118
|
+
display: flex;
|
|
119
|
+
flex-direction: column;
|
|
120
|
+
height: 100%;
|
|
121
|
+
width: 100%;
|
|
122
|
+
box-sizing: border-box;
|
|
123
|
+
&--child .entry {
|
|
124
|
+
flex: 1;
|
|
125
|
+
min-height: 0;
|
|
126
|
+
}
|
|
127
|
+
&__launcher {
|
|
128
|
+
flex-shrink: 0;
|
|
129
|
+
margin: 8px 8px 0;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
.dev-child-hint {
|
|
134
|
+
flex-shrink: 0;
|
|
135
|
+
background: #fffbeb;
|
|
136
|
+
border: 1px solid #f0e4b8;
|
|
137
|
+
code {
|
|
138
|
+
font-size: 0.75rem;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
.entry {
|
|
143
|
+
font-family: Arial, Helvetica, sans-serif;
|
|
144
|
+
box-sizing: border-box;
|
|
145
|
+
flex: 1;
|
|
146
|
+
min-height: 0;
|
|
147
|
+
width: 100%;
|
|
148
|
+
margin: 0;
|
|
149
|
+
overflow-y: auto;
|
|
150
|
+
}
|
|
151
|
+
</style>
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<q-banner rounded dense class="dev-opener-launcher q-mb-sm">
|
|
3
|
+
<div class="text-subtitle2 q-mb-xs">Opener 联调(模拟宿主打开子页)</div>
|
|
4
|
+
<p class="text-caption text-grey-8 q-mb-sm">
|
|
5
|
+
点击下方按钮在新窗口打开子页;子页通过 <code>?trace=</code> 与 <code>postMessage</code> 拉取下方 JSON。
|
|
6
|
+
组件:<strong>{{ componentId }}</strong>
|
|
7
|
+
</p>
|
|
8
|
+
<q-input
|
|
9
|
+
v-model="payloadText"
|
|
10
|
+
type="textarea"
|
|
11
|
+
autogrow
|
|
12
|
+
dense
|
|
13
|
+
outlined
|
|
14
|
+
label="模拟 opener payload(JSON)"
|
|
15
|
+
:error="parseError != null"
|
|
16
|
+
:error-message="parseError || undefined"
|
|
17
|
+
class="q-mb-sm"
|
|
18
|
+
/>
|
|
19
|
+
<div class="row items-center q-gutter-sm flex-wrap">
|
|
20
|
+
<q-btn
|
|
21
|
+
color="primary"
|
|
22
|
+
dense
|
|
23
|
+
unelevated
|
|
24
|
+
label="以 opener 方式打开子页"
|
|
25
|
+
:disable="parseError != null"
|
|
26
|
+
@click="onOpenChild"
|
|
27
|
+
/>
|
|
28
|
+
<span v-if="lastTrace" class="text-caption text-grey-7">
|
|
29
|
+
最近 trace: <code>{{ lastTrace }}</code>
|
|
30
|
+
<span v-if="childBlocked" class="text-negative">(弹窗被拦截,请允许本站点弹窗)</span>
|
|
31
|
+
</span>
|
|
32
|
+
</div>
|
|
33
|
+
</q-banner>
|
|
34
|
+
</template>
|
|
35
|
+
|
|
36
|
+
<script lang="ts">
|
|
37
|
+
import { defineComponent, onMounted, onUnmounted, ref, watch } from 'vue'
|
|
38
|
+
import { parseDevOpenerInitFromEnv } from '@/utils/openerInitParams'
|
|
39
|
+
import {
|
|
40
|
+
createDevOpenerTrace,
|
|
41
|
+
installDevOpenerHost,
|
|
42
|
+
openDevOpenerChild
|
|
43
|
+
} from '../utils/devOpenerHost'
|
|
44
|
+
import type { DevOpenerHostHandle } from '../utils/devOpenerHost'
|
|
45
|
+
|
|
46
|
+
const DEFAULT_PAYLOAD = {
|
|
47
|
+
ticket_ids: [450, 453],
|
|
48
|
+
valve_id: 0
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function defaultPayloadText (): string {
|
|
52
|
+
const fromEnv = parseDevOpenerInitFromEnv()
|
|
53
|
+
if (fromEnv != null) {
|
|
54
|
+
try {
|
|
55
|
+
return JSON.stringify(fromEnv, null, 2)
|
|
56
|
+
} catch {
|
|
57
|
+
/* fall through */
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return JSON.stringify(DEFAULT_PAYLOAD, null, 2)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function parsePayloadJson (text: string): { value: unknown | null; error: string | null } {
|
|
64
|
+
const trimmed = text.trim()
|
|
65
|
+
if (trimmed === '') return { value: null, error: 'JSON 不能为空' }
|
|
66
|
+
try {
|
|
67
|
+
return { value: JSON.parse(trimmed) as unknown, error: null }
|
|
68
|
+
} catch {
|
|
69
|
+
return { value: null, error: '不是合法 JSON' }
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export default defineComponent({
|
|
74
|
+
name: 'DevOpenerLauncher',
|
|
75
|
+
setup () {
|
|
76
|
+
const componentId = import.meta.env.VITE_COMPONENT_ID || 'bitable'
|
|
77
|
+
const payloadText = ref(defaultPayloadText())
|
|
78
|
+
const parseError = ref<string | null>(null)
|
|
79
|
+
const lastTrace = ref<string | null>(null)
|
|
80
|
+
const childBlocked = ref(false)
|
|
81
|
+
|
|
82
|
+
let hostHandle: DevOpenerHostHandle | null = null
|
|
83
|
+
|
|
84
|
+
function syncParseError (): void {
|
|
85
|
+
parseError.value = parsePayloadJson(payloadText.value).error
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function getPayload (): unknown {
|
|
89
|
+
const { value, error } = parsePayloadJson(payloadText.value)
|
|
90
|
+
if (error != null) throw new Error(error)
|
|
91
|
+
return value
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function onOpenChild (): void {
|
|
95
|
+
syncParseError()
|
|
96
|
+
if (parseError.value != null) return
|
|
97
|
+
|
|
98
|
+
const trace = createDevOpenerTrace()
|
|
99
|
+
lastTrace.value = trace
|
|
100
|
+
childBlocked.value = false
|
|
101
|
+
|
|
102
|
+
const child = openDevOpenerChild(trace)
|
|
103
|
+
if (child == null) {
|
|
104
|
+
childBlocked.value = true
|
|
105
|
+
console.warn('[devOpenerHost] window.open 返回 null,可能被浏览器拦截')
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
watch(payloadText, () => {
|
|
110
|
+
syncParseError()
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
onMounted(() => {
|
|
114
|
+
syncParseError()
|
|
115
|
+
hostHandle = installDevOpenerHost(() => getPayload())
|
|
116
|
+
})
|
|
117
|
+
|
|
118
|
+
onUnmounted(() => {
|
|
119
|
+
hostHandle?.dispose()
|
|
120
|
+
hostHandle = null
|
|
121
|
+
})
|
|
122
|
+
|
|
123
|
+
return {
|
|
124
|
+
componentId,
|
|
125
|
+
payloadText,
|
|
126
|
+
parseError,
|
|
127
|
+
lastTrace,
|
|
128
|
+
childBlocked,
|
|
129
|
+
onOpenChild
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
})
|
|
133
|
+
</script>
|
|
134
|
+
|
|
135
|
+
<style scoped lang="scss">
|
|
136
|
+
.dev-opener-launcher {
|
|
137
|
+
background: #f0f7ff;
|
|
138
|
+
border: 1px solid #c5d9f0;
|
|
139
|
+
code {
|
|
140
|
+
font-size: 0.75rem;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
</style>
|
package/skills/lab-orbit-component-builder/examples/xnb-component-template/dev/src/global.d.ts
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
declare module '@xtalpi/webb-api'
|
|
2
|
+
declare module 'axios'
|
|
3
|
+
declare module 'lodash'
|
|
4
|
+
|
|
5
|
+
interface XnbHttpClient {
|
|
6
|
+
request: (options: {
|
|
7
|
+
method: string;
|
|
8
|
+
url: string;
|
|
9
|
+
headers?: Record<string, string>;
|
|
10
|
+
responseType?: number;
|
|
11
|
+
query?: Record<string, string>;
|
|
12
|
+
body?: { type: string; data: any };
|
|
13
|
+
}) => Promise<{ data: any; status: number; ok: boolean; headers: Record<string, string> }>;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
interface XnbHttp {
|
|
17
|
+
client: XnbHttpClient;
|
|
18
|
+
Body: {
|
|
19
|
+
json: (data: any) => { type: string; data: any };
|
|
20
|
+
text: (text: string) => { type: string; data: string };
|
|
21
|
+
form: (data: Record<string, any>) => { type: string; data: Record<string, any> };
|
|
22
|
+
};
|
|
23
|
+
ResponseType: {
|
|
24
|
+
JSON: number;
|
|
25
|
+
Text: number;
|
|
26
|
+
Binary: number;
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
interface XnbChoreo {
|
|
31
|
+
getUserToken: (bookPath?: string) => Promise<string>;
|
|
32
|
+
getUserInfo: (options?: any) => Promise<{ userName: string; email: string }>;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
interface Xnb {
|
|
36
|
+
book: Record<string, (...args: any[]) => any>;
|
|
37
|
+
store: Record<string, (...args: any[]) => any>;
|
|
38
|
+
event: any;
|
|
39
|
+
kernel: Record<string, (...args: any[]) => any>;
|
|
40
|
+
choreo: XnbChoreo;
|
|
41
|
+
http: XnbHttp;
|
|
42
|
+
app: Record<string, (...args: any[]) => any>;
|
|
43
|
+
utils: Record<string, any>;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
interface WebbApi {
|
|
47
|
+
register: (name: string, value: any) => void;
|
|
48
|
+
getUrl: () => { webbHost: string };
|
|
49
|
+
store: Record<string, (...args: any[]) => any>;
|
|
50
|
+
utils: Record<string, any>;
|
|
51
|
+
event?: { on: (...args: any[]) => void; emit: (...args: any[]) => void; off: (...args: any[]) => void };
|
|
52
|
+
ui: {
|
|
53
|
+
message: (opts: { type?: string; message: string }) => void;
|
|
54
|
+
};
|
|
55
|
+
method: {
|
|
56
|
+
call: (module: string, method: string, ...args: any[]) => any;
|
|
57
|
+
};
|
|
58
|
+
[key: string]: any;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
interface QuasarGlobal {
|
|
62
|
+
loading: { show: (opts?: any) => void; hide: () => void };
|
|
63
|
+
notify: (opts: any) => void;
|
|
64
|
+
dialog: (opts: any) => any;
|
|
65
|
+
dark: any;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
interface Window {
|
|
69
|
+
Vue: any;
|
|
70
|
+
vueInstance: any;
|
|
71
|
+
webb: WebbApi;
|
|
72
|
+
xnb: Xnb;
|
|
73
|
+
$q: QuasarGlobal;
|
|
74
|
+
}
|
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
import * as Vue from 'vue'
|
|
2
|
+
import dayjs from 'dayjs'
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
Quasar,
|
|
6
|
+
Notify,
|
|
7
|
+
Loading,
|
|
8
|
+
Dialog,
|
|
9
|
+
Dark,
|
|
10
|
+
QBtn,
|
|
11
|
+
QIcon,
|
|
12
|
+
QBanner,
|
|
13
|
+
QSpace,
|
|
14
|
+
QSeparator,
|
|
15
|
+
QTable,
|
|
16
|
+
QTd,
|
|
17
|
+
QTr,
|
|
18
|
+
QTh,
|
|
19
|
+
QChip,
|
|
20
|
+
QInput,
|
|
21
|
+
QSelect,
|
|
22
|
+
QToggle,
|
|
23
|
+
QBadge,
|
|
24
|
+
QList,
|
|
25
|
+
QItem,
|
|
26
|
+
QItemSection,
|
|
27
|
+
QCard,
|
|
28
|
+
QCardSection,
|
|
29
|
+
QCardActions,
|
|
30
|
+
QDialog,
|
|
31
|
+
QLinearProgress,
|
|
32
|
+
QTooltip,
|
|
33
|
+
QCheckbox,
|
|
34
|
+
QSpinnerGears,
|
|
35
|
+
QSpinnerDots,
|
|
36
|
+
QPagination,
|
|
37
|
+
QExpansionItem,
|
|
38
|
+
ClosePopup,
|
|
39
|
+
Ripple
|
|
40
|
+
} from 'quasar'
|
|
41
|
+
import quasarLangEN from 'quasar/lang/en-US'
|
|
42
|
+
import '@quasar/extras/material-icons/material-icons.css'
|
|
43
|
+
import 'quasar/src/css/index.sass'
|
|
44
|
+
|
|
45
|
+
import { Webb } from '@xtalpi/webb-api'
|
|
46
|
+
import axios from 'axios'
|
|
47
|
+
import lodash from 'lodash'
|
|
48
|
+
|
|
49
|
+
import App from './App.vue'
|
|
50
|
+
|
|
51
|
+
// ==================== 多入口视图加载 ====================
|
|
52
|
+
|
|
53
|
+
const COMPONENT_ID = import.meta.env.VITE_COMPONENT_ID || 'bitable'
|
|
54
|
+
const viewModules = import.meta.glob('../../src/views/*.vue', { eager: true })
|
|
55
|
+
const viewKey = `../../src/views/${COMPONENT_ID}.vue`
|
|
56
|
+
const viewModule = viewModules[viewKey] as { default: any } | undefined
|
|
57
|
+
if (!viewModule) {
|
|
58
|
+
const available = Object.keys(viewModules).map((k: string) => k.replace('../../src/views/', '').replace('.vue', '')).join(', ')
|
|
59
|
+
throw new Error(
|
|
60
|
+
`[dev] VITE_COMPONENT_ID=${COMPONENT_ID} 无对应视图。当前已有: ${available}`
|
|
61
|
+
)
|
|
62
|
+
}
|
|
63
|
+
const View = viewModule.default
|
|
64
|
+
|
|
65
|
+
// ==================== Store ====================
|
|
66
|
+
|
|
67
|
+
const cached: Record<string, any> = {}
|
|
68
|
+
const store = {
|
|
69
|
+
getToken: (): string | null => localStorage.getItem('access_token'),
|
|
70
|
+
onLogout: (): void => {},
|
|
71
|
+
set: (key: string, value: any): void => {
|
|
72
|
+
cached[key] = value
|
|
73
|
+
},
|
|
74
|
+
get: (key: string): any => {
|
|
75
|
+
return cached[key]
|
|
76
|
+
},
|
|
77
|
+
getUser: (): any => ({
|
|
78
|
+
email: 'dev@local.test',
|
|
79
|
+
userName: 'DevUser'
|
|
80
|
+
})
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const utils = {
|
|
84
|
+
lodash,
|
|
85
|
+
axios
|
|
86
|
+
}
|
|
87
|
+
Webb.register('store', store)
|
|
88
|
+
Webb.register('utils', utils)
|
|
89
|
+
|
|
90
|
+
const app = Vue.createApp(App)
|
|
91
|
+
|
|
92
|
+
app.use(Quasar, {
|
|
93
|
+
plugins: {
|
|
94
|
+
Notify,
|
|
95
|
+
Loading,
|
|
96
|
+
Dialog
|
|
97
|
+
},
|
|
98
|
+
components: {
|
|
99
|
+
QBtn,
|
|
100
|
+
QIcon,
|
|
101
|
+
QBanner,
|
|
102
|
+
QSpace,
|
|
103
|
+
QSeparator,
|
|
104
|
+
QTable,
|
|
105
|
+
QTd,
|
|
106
|
+
QTr,
|
|
107
|
+
QTh,
|
|
108
|
+
QChip,
|
|
109
|
+
QInput,
|
|
110
|
+
QSelect,
|
|
111
|
+
QToggle,
|
|
112
|
+
QBadge,
|
|
113
|
+
QList,
|
|
114
|
+
QItem,
|
|
115
|
+
QItemSection,
|
|
116
|
+
QCard,
|
|
117
|
+
QCardSection,
|
|
118
|
+
QCardActions,
|
|
119
|
+
QDialog,
|
|
120
|
+
QLinearProgress,
|
|
121
|
+
QTooltip,
|
|
122
|
+
QCheckbox,
|
|
123
|
+
QSpinnerGears,
|
|
124
|
+
QSpinnerDots,
|
|
125
|
+
QPagination,
|
|
126
|
+
QExpansionItem
|
|
127
|
+
},
|
|
128
|
+
directives: {
|
|
129
|
+
ClosePopup,
|
|
130
|
+
Ripple
|
|
131
|
+
},
|
|
132
|
+
lang: quasarLangEN
|
|
133
|
+
})
|
|
134
|
+
Dark.set(false)
|
|
135
|
+
|
|
136
|
+
app.component('View', View)
|
|
137
|
+
|
|
138
|
+
window.Vue = Vue
|
|
139
|
+
window.vueInstance = app
|
|
140
|
+
window.webb = (Webb as unknown as any)
|
|
141
|
+
|
|
142
|
+
if (!window.webb.getUrl) {
|
|
143
|
+
window.webb.getUrl = (): { webbHost: string } => ({
|
|
144
|
+
webbHost: import.meta.env.VITE_REQUEST_URL || `${window.location.protocol}//${window.location.host}`
|
|
145
|
+
})
|
|
146
|
+
}
|
|
147
|
+
if (!window.webb.ui) {
|
|
148
|
+
window.webb.ui = {
|
|
149
|
+
message (opts: any): void {
|
|
150
|
+
const type = opts?.type === 'error' ? 'negative' : opts?.type === 'success' ? 'positive' : 'info'
|
|
151
|
+
Notify.create({ type, message: opts?.message || '', position: 'top', timeout: 3000 })
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
if (!window.webb.method) {
|
|
156
|
+
window.webb.method = {
|
|
157
|
+
call (_module: string, _method: string, ..._args: any[]): any {
|
|
158
|
+
console.log(`[dev mock] webb.method.call(${_module}, ${_method})`, _args)
|
|
159
|
+
return {}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// ==================== Mock: window.xnb ====================
|
|
165
|
+
|
|
166
|
+
const DEV_TOKEN = import.meta.env.VITE_DEV_TOKEN || ''
|
|
167
|
+
|
|
168
|
+
const ResponseType = { JSON: 1, Text: 2, Binary: 3 }
|
|
169
|
+
|
|
170
|
+
const Body = {
|
|
171
|
+
json: (data: any): { type: string; data: any } => ({ type: 'json', data }),
|
|
172
|
+
text: (text: string): { type: string; data: string } => ({ type: 'text', data: text }),
|
|
173
|
+
form: (data: Record<string, any>): { type: string; data: Record<string, any> } => ({ type: 'form', data })
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const httpClient = {
|
|
177
|
+
async request (options: {
|
|
178
|
+
method: string;
|
|
179
|
+
url: string;
|
|
180
|
+
headers?: Record<string, string>;
|
|
181
|
+
responseType?: number;
|
|
182
|
+
query?: Record<string, string | number | boolean | string[] | null | undefined>;
|
|
183
|
+
body?: { type: string; data: any };
|
|
184
|
+
}): Promise<any> {
|
|
185
|
+
const { method, url, headers, query, body } = options
|
|
186
|
+
|
|
187
|
+
const axiosConfig: Record<string, any> = {
|
|
188
|
+
method: method.toLowerCase(),
|
|
189
|
+
url,
|
|
190
|
+
headers: headers || {}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
if (query != null && Object.keys(query).length > 0) {
|
|
194
|
+
axiosConfig.params = query
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
if (body) {
|
|
198
|
+
axiosConfig.data = body.data
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
try {
|
|
202
|
+
const res = await axios(axiosConfig)
|
|
203
|
+
return {
|
|
204
|
+
data: res.data,
|
|
205
|
+
headers: res.headers as Record<string, string>
|
|
206
|
+
}
|
|
207
|
+
} catch (err: any) {
|
|
208
|
+
if (err.response) {
|
|
209
|
+
return {
|
|
210
|
+
data: err.response.data,
|
|
211
|
+
headers: err.response.headers as Record<string, string>
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
throw err
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
window.xnb = {
|
|
220
|
+
book: {
|
|
221
|
+
async getCell (): Promise<any> {
|
|
222
|
+
const _d = localStorage.getItem('CH_CELL_DATA')
|
|
223
|
+
return { data: _d ? JSON.parse(_d) : {} }
|
|
224
|
+
},
|
|
225
|
+
async updateCellData (_bookPath: string, _cellUid: string, data: any): Promise<void> {
|
|
226
|
+
localStorage.setItem('CH_CELL_DATA', JSON.stringify(data))
|
|
227
|
+
},
|
|
228
|
+
async getBookMeta (_bookPath: string): Promise<any> {
|
|
229
|
+
return {
|
|
230
|
+
name: 'DevBook',
|
|
231
|
+
runtimes: {
|
|
232
|
+
bookId: 'dev-book-001',
|
|
233
|
+
project: { data_link: '', project_id: 'dev-project-001', project_name: 'Dev Project' }
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
},
|
|
237
|
+
async getBookFromRemoteRepo (_bookId: string): Promise<any> {
|
|
238
|
+
return { parent: { id: 1, name: 'DevFolder' }, creator: 'DevUser', name: 'DevBook', page_number: 1 }
|
|
239
|
+
},
|
|
240
|
+
async getCurrentBookPermission (_type: string): Promise<boolean> {
|
|
241
|
+
return true
|
|
242
|
+
}
|
|
243
|
+
},
|
|
244
|
+
|
|
245
|
+
store,
|
|
246
|
+
event: window.webb?.event || { on: (): void => {}, emit: (): void => {}, off: (): void => {} },
|
|
247
|
+
|
|
248
|
+
kernel: {
|
|
249
|
+
async runCode (_bookPath: string, _code: string, onUpdate: any): Promise<void> {
|
|
250
|
+
onUpdate('status: 200')
|
|
251
|
+
}
|
|
252
|
+
},
|
|
253
|
+
|
|
254
|
+
choreo: {
|
|
255
|
+
async getUserToken (_bookPath?: string): Promise<string> {
|
|
256
|
+
if (!DEV_TOKEN) {
|
|
257
|
+
console.warn('[dev mock] VITE_DEV_TOKEN 未在 .env.local 中配置')
|
|
258
|
+
}
|
|
259
|
+
return DEV_TOKEN
|
|
260
|
+
},
|
|
261
|
+
async getUserInfo (_options?: any): Promise<{ userName: string; email: string }> {
|
|
262
|
+
return { userName: 'DevUser', email: 'dev@local.test' }
|
|
263
|
+
}
|
|
264
|
+
},
|
|
265
|
+
|
|
266
|
+
http: { client: httpClient, Body, ResponseType },
|
|
267
|
+
|
|
268
|
+
app: {
|
|
269
|
+
alarm (info: string, _options?: any): void {
|
|
270
|
+
Notify.create({ type: 'warning', message: `[Alarm] ${info}`, position: 'top' })
|
|
271
|
+
},
|
|
272
|
+
notifySuccess (content: string, _options?: any): void {
|
|
273
|
+
Notify.create({ type: 'positive', message: content, position: 'top' })
|
|
274
|
+
}
|
|
275
|
+
},
|
|
276
|
+
|
|
277
|
+
utils: { dayjs, lodash }
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
app.mount('#app')
|
|
281
|
+
|
|
282
|
+
window.$q = {
|
|
283
|
+
loading: {
|
|
284
|
+
show (opts?: any): void {
|
|
285
|
+
Loading.show(typeof opts === 'string' ? { message: opts } : opts)
|
|
286
|
+
},
|
|
287
|
+
hide (): void {
|
|
288
|
+
Loading.hide()
|
|
289
|
+
}
|
|
290
|
+
},
|
|
291
|
+
notify: Notify.create.bind(Notify),
|
|
292
|
+
dialog: Dialog.create.bind(Dialog),
|
|
293
|
+
dark: Dark
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
axios.interceptors.request.use((config: any) => {
|
|
297
|
+
if (config.headers?.Authorization) return config
|
|
298
|
+
const token = DEV_TOKEN || localStorage.getItem('access_token')
|
|
299
|
+
if (token && config.headers) {
|
|
300
|
+
config.headers.Authorization = `Bearer ${token}`
|
|
301
|
+
}
|
|
302
|
+
return config
|
|
303
|
+
}, (err: any) => {
|
|
304
|
+
return Promise.reject(err)
|
|
305
|
+
})
|