@yuku123/z-frontend-common 0.1.2 → 0.1.4
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/dist/z-frontend-common.css +1 -0
- package/dist/z-frontend-common.es.js +6154 -300
- package/dist/z-frontend-common.umd.js +22 -4
- package/package.json +4 -3
- package/src/components/Ctc/Layout.jsx +328 -0
- package/src/components/Ctc/Layout.module.css +145 -0
- package/src/components/Ctc/agentTeam/index.tsx +308 -0
- package/src/components/Ctc/login/AuthPage.module.css +26 -0
- package/src/components/Ctc/login/AuthPage.tsx +235 -0
- package/src/components/Ctc/login/index.less +49 -0
- package/src/components/Ctc/login/index.tsx +142 -0
- package/src/components/Ctc/userPanel/index.tsx +998 -0
- package/src/components/Ctc/webide/index.tsx +272 -0
- package/src/components/LowCode/LowCodeModel.jsx +962 -0
- package/src/components/LowCode/LowCodePage.jsx +31 -0
- package/src/components/LowCode/LowCodeRuntime.jsx +335 -0
- package/src/components/LowCode/MaterializePage.jsx +235 -0
- package/src/components/LowCode/index.js +1 -0
- package/src/components/MockPlatform/CurlImportModal.jsx +362 -0
- package/src/components/MockPlatform/EndpointsTab.jsx +509 -0
- package/src/components/MockPlatform/EnvironmentsTab.jsx +212 -0
- package/src/components/MockPlatform/MockTemplateHelper.jsx +200 -0
- package/src/components/MockPlatform/OpenApiImportModal.jsx +305 -0
- package/src/components/MockPlatform/RecordingsTab.jsx +397 -0
- package/src/components/MockPlatform/RequestLogsTab.jsx +239 -0
- package/src/components/MockPlatform/ScenariosTab.jsx +236 -0
- package/src/components/MockPlatform/TestCasesTab.jsx +462 -0
- package/src/components/MockPlatform/index.jsx +127 -0
- package/src/components/Overview.jsx +74 -0
- package/src/index.js +27 -27
- package/src/services/agentTeam.js +7 -0
- package/src/services/api.js +84 -0
- package/src/services/ctcAc.js +7 -0
- package/src/services/ctcAcDomain.js +7 -0
- package/src/services/ctcAuthorization.js +7 -0
- package/src/services/ctcSurl.js +7 -0
- package/src/services/ctcUser.js +7 -0
- package/src/services/job.js +7 -0
- package/src/services/metaApp.js +7 -0
- package/src/services/privateConfig.js +7 -0
- package/src/services/request.js +6 -0
- package/src/services/webide.js +6 -0
- package/src/services/workspace.js +21 -0
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
import {useRef, useState} from 'react'
|
|
2
|
+
import {ActionType, PageContainer, ProColumns, ProForm, ProFormSelect, ProFormText, ProFormTextArea, ProTable} from '@ant-design/pro-components'
|
|
3
|
+
import {Button, Drawer, Form, Input, message, Select, Space, Tag, Tooltip} from 'antd'
|
|
4
|
+
import {
|
|
5
|
+
CodeOutlined,
|
|
6
|
+
DeleteOutlined,
|
|
7
|
+
FileTextOutlined,
|
|
8
|
+
PauseOutlined,
|
|
9
|
+
PlayCircleOutlined,
|
|
10
|
+
ReloadOutlined,
|
|
11
|
+
PlusOutlined
|
|
12
|
+
} from '@ant-design/icons'
|
|
13
|
+
import {webideApi, type ZInspectRequest, type WebIdeContainer, type WebIdeMode} from '@/services/webide'
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* WebIDE 容器管理 (z-webide)
|
|
17
|
+
*
|
|
18
|
+
* 端点:
|
|
19
|
+
* - POST /api/webide/inspect
|
|
20
|
+
* - GET /api/webide/code-server/list
|
|
21
|
+
* - POST /api/webide/code-server/{id}/start
|
|
22
|
+
* - POST /api/webide/code-server/{id}/stop
|
|
23
|
+
* - DELETE /api/webide/code-server/{id}
|
|
24
|
+
* - GET /api/webide/code-server/{id}/logs?lines=100
|
|
25
|
+
*/
|
|
26
|
+
const STATUS_MAP: Record<string, {text: string; color: string}> = {
|
|
27
|
+
CREATING: {text: '创建中', color: 'processing'},
|
|
28
|
+
RUNNING: {text: '运行中', color: 'success'},
|
|
29
|
+
STOPPED: {text: '已停止', color: 'default'},
|
|
30
|
+
ERROR: {text: '错误', color: 'error'},
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const MODE_MAP: Record<WebIdeMode, {text: string; color: string}> = {
|
|
34
|
+
GIT: {text: 'GIT 模式', color: 'blue'},
|
|
35
|
+
SHARED: {text: 'SHARED 模式', color: 'purple'},
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export default function WebIdeManagement() {
|
|
39
|
+
const actionRef = useRef<ActionType | undefined>(undefined)
|
|
40
|
+
const [inspectOpen, setInspectOpen] = useState(false)
|
|
41
|
+
const [logsOpen, setLogsOpen] = useState(false)
|
|
42
|
+
const [logs, setLogs] = useState<string[]>([])
|
|
43
|
+
const [logsTarget, setLogsTarget] = useState<WebIdeContainer | null>(null)
|
|
44
|
+
const [inspecting, setInspecting] = useState(false)
|
|
45
|
+
const [form] = Form.useForm<ZInspectRequest>()
|
|
46
|
+
|
|
47
|
+
const request_ = async () => {
|
|
48
|
+
try {
|
|
49
|
+
const res = await webideApi.listContainers()
|
|
50
|
+
return {data: res || [], success: true, total: (res || []).length}
|
|
51
|
+
} catch (e: any) {
|
|
52
|
+
message.warning('后端未就绪,显示空列表:' + (e?.message || '未知错误'))
|
|
53
|
+
return {data: [], success: false, total: 0}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const handleInspect = async () => {
|
|
58
|
+
try {
|
|
59
|
+
const values = await form.validateFields()
|
|
60
|
+
setInspecting(true)
|
|
61
|
+
const res = await webideApi.inspect(values)
|
|
62
|
+
message.success(`WebIDE 创建成功:${res.url}`)
|
|
63
|
+
setInspectOpen(false)
|
|
64
|
+
form.resetFields()
|
|
65
|
+
actionRef.current?.reload()
|
|
66
|
+
// 新窗口打开 IDE
|
|
67
|
+
if (res.url) {
|
|
68
|
+
window.open(res.url, '_blank')
|
|
69
|
+
}
|
|
70
|
+
} catch (e: any) {
|
|
71
|
+
if (e?.errorFields) return
|
|
72
|
+
message.error('创建失败:' + (e?.message || '未知错误'))
|
|
73
|
+
} finally {
|
|
74
|
+
setInspecting(false)
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const handleStart = async (id: string) => {
|
|
79
|
+
try {
|
|
80
|
+
await webideApi.startContainer(id)
|
|
81
|
+
message.success('已启动')
|
|
82
|
+
actionRef.current?.reload()
|
|
83
|
+
} catch (e: any) {
|
|
84
|
+
message.error('启动失败:' + (e?.message || '未知错误'))
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const handleStop = async (id: string) => {
|
|
89
|
+
try {
|
|
90
|
+
await webideApi.stopContainer(id)
|
|
91
|
+
message.success('已停止')
|
|
92
|
+
actionRef.current?.reload()
|
|
93
|
+
} catch (e: any) {
|
|
94
|
+
message.error('停止失败:' + (e?.message || '未知错误'))
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const handleRemove = async (id: string) => {
|
|
99
|
+
try {
|
|
100
|
+
await webideApi.removeContainer(id)
|
|
101
|
+
message.success('已删除')
|
|
102
|
+
actionRef.current?.reload()
|
|
103
|
+
} catch (e: any) {
|
|
104
|
+
message.error('删除失败:' + (e?.message || '未知错误'))
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const openLogs = async (r: WebIdeContainer) => {
|
|
109
|
+
setLogsTarget(r)
|
|
110
|
+
setLogsOpen(true)
|
|
111
|
+
setLogs(['加载中...'])
|
|
112
|
+
try {
|
|
113
|
+
const res = await webideApi.getLogs(r.containerId, 200)
|
|
114
|
+
setLogs(res?.lines || [])
|
|
115
|
+
} catch (e: any) {
|
|
116
|
+
setLogs([`加载日志失败:${e?.message || '未知错误'}`])
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const columns: ProColumns<WebIdeContainer>[] = [
|
|
121
|
+
{title: '容器ID', dataIndex: 'containerId', width: 200, fixed: 'left', ellipsis: true},
|
|
122
|
+
{
|
|
123
|
+
title: '模式', dataIndex: 'mode', width: 110,
|
|
124
|
+
render: (_, r) => {
|
|
125
|
+
const m = MODE_MAP[r.mode] || {text: r.mode, color: 'default'}
|
|
126
|
+
return <Tag color={m.color}>{m.text}</Tag>
|
|
127
|
+
},
|
|
128
|
+
},
|
|
129
|
+
{title: 'Git URL', dataIndex: 'gitUrl', width: 200, ellipsis: true},
|
|
130
|
+
{title: '分支', dataIndex: 'branch', width: 100},
|
|
131
|
+
{
|
|
132
|
+
title: '状态', dataIndex: 'status', width: 100,
|
|
133
|
+
render: (_, r) => {
|
|
134
|
+
const s = STATUS_MAP[r.status] || {text: r.status, color: 'default'}
|
|
135
|
+
return <Tag color={s.color}>{s.text}</Tag>
|
|
136
|
+
},
|
|
137
|
+
},
|
|
138
|
+
{title: 'URL', dataIndex: 'url', width: 200, ellipsis: true,
|
|
139
|
+
render: (_, r) => r.url ? <a href={r.url} target="_blank" rel="noreferrer">{r.url}</a> : '-'},
|
|
140
|
+
{title: 'CPU%', dataIndex: 'cpuUsage', width: 80,
|
|
141
|
+
render: (v) => typeof v === 'number' ? `${v.toFixed(1)}%` : '-'},
|
|
142
|
+
{title: '内存%', dataIndex: 'memoryUsage', width: 80,
|
|
143
|
+
render: (v) => typeof v === 'number' ? `${v.toFixed(1)}%` : '-'},
|
|
144
|
+
{title: '创建时间', dataIndex: 'createdAt', width: 170, valueType: 'dateTime'},
|
|
145
|
+
{
|
|
146
|
+
title: '操作', valueType: 'option', width: 240, fixed: 'right',
|
|
147
|
+
render: (_, record) => [
|
|
148
|
+
<Tooltip key="start" title="启动">
|
|
149
|
+
<Button type="text" size="small" icon={<PlayCircleOutlined/>}
|
|
150
|
+
onClick={() => handleStart(record.containerId)}>启动</Button>
|
|
151
|
+
</Tooltip>,
|
|
152
|
+
<Tooltip key="stop" title="停止">
|
|
153
|
+
<Button type="text" size="small" icon={<PauseOutlined/>}
|
|
154
|
+
onClick={() => handleStop(record.containerId)}>停止</Button>
|
|
155
|
+
</Tooltip>,
|
|
156
|
+
<Tooltip key="logs" title="查看日志">
|
|
157
|
+
<Button type="text" size="small" icon={<FileTextOutlined/>}
|
|
158
|
+
onClick={() => openLogs(record)}>日志</Button>
|
|
159
|
+
</Tooltip>,
|
|
160
|
+
<Tooltip key="remove" title="删除">
|
|
161
|
+
<Button type="text" danger size="small" icon={<DeleteOutlined/>}
|
|
162
|
+
onClick={() => handleRemove(record.containerId)}>删除</Button>
|
|
163
|
+
</Tooltip>,
|
|
164
|
+
],
|
|
165
|
+
},
|
|
166
|
+
]
|
|
167
|
+
|
|
168
|
+
return (
|
|
169
|
+
<PageContainer
|
|
170
|
+
header={{
|
|
171
|
+
title: 'WebIDE 容器管理 (z-webide)',
|
|
172
|
+
subTitle: '基于 code-server 的容器化 WebIDE',
|
|
173
|
+
breadcrumb: {},
|
|
174
|
+
}}
|
|
175
|
+
>
|
|
176
|
+
<ProTable<WebIdeContainer>
|
|
177
|
+
actionRef={actionRef}
|
|
178
|
+
rowKey="containerId"
|
|
179
|
+
columns={columns}
|
|
180
|
+
request={request_}
|
|
181
|
+
search={false}
|
|
182
|
+
pagination={{pageSize: 20}}
|
|
183
|
+
headerTitle="容器列表"
|
|
184
|
+
toolBarRender={() => [
|
|
185
|
+
<Button key="add" type="primary" icon={<PlusOutlined/>} onClick={() => setInspectOpen(true)}>
|
|
186
|
+
新建 WebIDE
|
|
187
|
+
</Button>,
|
|
188
|
+
<Button key="reload" icon={<ReloadOutlined/>} onClick={() => actionRef.current?.reload()}>
|
|
189
|
+
刷新
|
|
190
|
+
</Button>,
|
|
191
|
+
]}
|
|
192
|
+
/>
|
|
193
|
+
|
|
194
|
+
{/* 新建 WebIDE Modal */}
|
|
195
|
+
<Drawer
|
|
196
|
+
title={<Space><CodeOutlined/> 新建 WebIDE</Space>}
|
|
197
|
+
open={inspectOpen}
|
|
198
|
+
onClose={() => setInspectOpen(false)}
|
|
199
|
+
width={520}
|
|
200
|
+
extra={
|
|
201
|
+
<Space>
|
|
202
|
+
<Button onClick={() => setInspectOpen(false)}>取消</Button>
|
|
203
|
+
<Button type="primary" loading={inspecting} onClick={handleInspect}>
|
|
204
|
+
创建并打开
|
|
205
|
+
</Button>
|
|
206
|
+
</Space>
|
|
207
|
+
}
|
|
208
|
+
>
|
|
209
|
+
<WebIdeInspectForm form={form}/>
|
|
210
|
+
</Drawer>
|
|
211
|
+
|
|
212
|
+
{/* 日志抽屉 */}
|
|
213
|
+
<Drawer
|
|
214
|
+
title={logsTarget ? `容器日志 — ${logsTarget.containerId}` : '容器日志'}
|
|
215
|
+
open={logsOpen}
|
|
216
|
+
onClose={() => setLogsOpen(false)}
|
|
217
|
+
width={720}
|
|
218
|
+
>
|
|
219
|
+
<pre style={{
|
|
220
|
+
background: '#1e1e1e', color: '#d4d4d4', padding: 12, borderRadius: 4,
|
|
221
|
+
fontFamily: 'Menlo, Consolas, monospace', fontSize: 12,
|
|
222
|
+
maxHeight: '70vh', overflow: 'auto', whiteSpace: 'pre-wrap',
|
|
223
|
+
}}>
|
|
224
|
+
{logs.join('\n')}
|
|
225
|
+
</pre>
|
|
226
|
+
</Drawer>
|
|
227
|
+
</PageContainer>
|
|
228
|
+
)
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// Inspect 表单 (从 Drawer 主体中抽离以避免组件重渲染)
|
|
232
|
+
function WebIdeInspectForm({form}: {form: any}) {
|
|
233
|
+
const {mode, setMode} = useInspectMode()
|
|
234
|
+
return (
|
|
235
|
+
<Form form={form} layout="vertical" style={{marginTop: 16}}
|
|
236
|
+
initialValues={{mode: 'GIT' as WebIdeMode}}>
|
|
237
|
+
<Form.Item name="mode" label="模式" rules={[{required: true}]}>
|
|
238
|
+
<Select
|
|
239
|
+
onChange={v => setMode(v)}
|
|
240
|
+
options={[
|
|
241
|
+
{value: 'GIT', label: 'GIT 模式 (从仓库克隆)'},
|
|
242
|
+
{value: 'SHARED', label: 'SHARED 模式 (共享工作区)'},
|
|
243
|
+
]}
|
|
244
|
+
/>
|
|
245
|
+
</Form.Item>
|
|
246
|
+
{mode === 'GIT' && (
|
|
247
|
+
<>
|
|
248
|
+
<Form.Item name="gitUrl" label="Git URL" rules={[{required: true, type: 'url'}]}
|
|
249
|
+
extra="支持 https://github.com/xxx/yyy.git">
|
|
250
|
+
<Input placeholder="https://github.com/your/repo.git"/>
|
|
251
|
+
</Form.Item>
|
|
252
|
+
<Form.Item name="branch" label="分支">
|
|
253
|
+
<Input placeholder="main (默认)"/>
|
|
254
|
+
</Form.Item>
|
|
255
|
+
</>
|
|
256
|
+
)}
|
|
257
|
+
{mode === 'SHARED' && (
|
|
258
|
+
<Form.Item name="shareKey" label="共享 Key" rules={[{required: true}]}>
|
|
259
|
+
<Input placeholder="SHARED-XXXXXX"/>
|
|
260
|
+
</Form.Item>
|
|
261
|
+
)}
|
|
262
|
+
<Form.Item name="tenantCode" label="租户编码 (可选)">
|
|
263
|
+
<Input placeholder="default"/>
|
|
264
|
+
</Form.Item>
|
|
265
|
+
</Form>
|
|
266
|
+
)
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
function useInspectMode() {
|
|
270
|
+
const [mode, setMode] = useState<WebIdeMode>('GIT')
|
|
271
|
+
return {mode, setMode}
|
|
272
|
+
}
|