@yuku123/z-frontend-common 0.2.9 → 1.0.0
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/LICENSE +25 -0
- package/README.md +55 -42
- package/dist/index.js +1 -0
- package/package.json +49 -44
- package/src/components/ErrorBoundary/index.jsx +24 -77
- package/src/components/Layout/index.jsx +141 -38
- package/src/components/LoginPage/index.jsx +47 -21
- package/src/components/StatusTag/index.jsx +14 -12
- package/src/index.js +32 -38
- package/src/services/request.js +74 -4
- package/dist/z-frontend-common.css +0 -1
- package/dist/z-frontend-common.es.js +0 -51275
- package/dist/z-frontend-common.umd.js +0 -459
- package/src/components/Ctc/Layout.jsx +0 -330
- package/src/components/Ctc/Layout.module.css +0 -145
- package/src/components/Ctc/agentTeam/index.tsx +0 -308
- package/src/components/Ctc/login/AuthPage.module.css +0 -26
- package/src/components/Ctc/login/AuthPage.tsx +0 -235
- package/src/components/Ctc/login/index.less +0 -49
- package/src/components/Ctc/login/index.tsx +0 -142
- package/src/components/Ctc/uc/UCLogin.tsx +0 -31
- package/src/components/Ctc/uc/UCPhoneLogin.tsx +0 -62
- package/src/components/Ctc/uc/UCRegister.tsx +0 -37
- package/src/components/Ctc/uc/UCResetPassword.tsx +0 -69
- package/src/components/Ctc/uc/index.tsx +0 -15
- package/src/components/Ctc/userPanel/index.tsx +0 -999
- package/src/components/Ctc/webide/index.tsx +0 -272
- package/src/components/LowCode/LowCodeModel.jsx +0 -962
- package/src/components/LowCode/LowCodePage.jsx +0 -31
- package/src/components/LowCode/LowCodeRuntime.jsx +0 -335
- package/src/components/LowCode/MaterializePage.jsx +0 -235
- package/src/components/LowCode/index.js +0 -1
- package/src/components/MockPlatform/CurlImportModal.jsx +0 -362
- package/src/components/MockPlatform/EndpointsTab.jsx +0 -509
- package/src/components/MockPlatform/EnvironmentsTab.jsx +0 -212
- package/src/components/MockPlatform/MockTemplateHelper.jsx +0 -200
- package/src/components/MockPlatform/OpenApiImportModal.jsx +0 -305
- package/src/components/MockPlatform/RecordingsTab.jsx +0 -397
- package/src/components/MockPlatform/RequestLogsTab.jsx +0 -239
- package/src/components/MockPlatform/ScenariosTab.jsx +0 -236
- package/src/components/MockPlatform/TestCasesTab.jsx +0 -462
- package/src/components/MockPlatform/index.jsx +0 -127
- package/src/components/Overview.jsx +0 -74
- package/src/dev.jsx +0 -28
- package/src/services/agentTeam.js +0 -7
- package/src/services/api.js +0 -84
- package/src/services/ctcAc.js +0 -7
- package/src/services/ctcAcDomain.js +0 -7
- package/src/services/ctcAuthorization.js +0 -7
- package/src/services/ctcSurl.js +0 -7
- package/src/services/ctcUser.js +0 -7
- package/src/services/job.js +0 -7
- package/src/services/metaApp.js +0 -7
- package/src/services/privateConfig.js +0 -7
- package/src/services/webide.js +0 -6
- package/src/services/workspace.js +0 -21
- package/src/utils/request.ts +0 -102
|
@@ -1,37 +1,57 @@
|
|
|
1
|
-
import {useState} from 'react'
|
|
2
|
-
import {Button, Card, Form, Input, message} from 'antd'
|
|
3
|
-
import {LockOutlined, UserOutlined} from '@ant-design/icons'
|
|
4
|
-
import request from '../../
|
|
1
|
+
import { useState } from 'react'
|
|
2
|
+
import { Alert, Button, Card, Form, Input, message } from 'antd'
|
|
3
|
+
import { LockOutlined, UserOutlined } from '@ant-design/icons'
|
|
4
|
+
import { request } from '../../services/request'
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
7
|
+
* 统一登录页(lead 008 §16)—— mockAuth / 真实 API 双模式:
|
|
8
|
+
* <ul>
|
|
9
|
+
* <li>{@code mockAuth} 传入 → 纯前端校验(admin/123456 硬编码顶替,CTC/SSO 接入前短期形态),
|
|
10
|
+
* 登录成功写 localStorage.token + userInfo 并跳 redirectUrl</li>
|
|
11
|
+
* <li>{@code mockAuth} 缺省 → POST {@code loginApi}(CTC 中央认证),后端签发 token</li>
|
|
12
|
+
* </ul>
|
|
13
|
+
*
|
|
14
|
+
* @param {string} [title='统一管理平台'] 卡片标题
|
|
15
|
+
* @param {Object} [mockAuth] {username, password, user:{name, role}} 本地 mock 校验配置
|
|
16
|
+
* @param {string} [loginApi='/auth/login'] 真实登录端点(mockAuth 缺省时生效)
|
|
17
|
+
* @param {string} [redirectUrl='/'] 登录成功跳转
|
|
18
|
+
* @param {Function} [onSuccess] 登录成功回调(覆盖 redirectUrl 跳转)
|
|
13
19
|
*/
|
|
14
20
|
export default function LoginPage({
|
|
15
21
|
title = '统一管理平台',
|
|
22
|
+
mockAuth,
|
|
16
23
|
loginApi = '/auth/login',
|
|
17
24
|
redirectUrl = '/',
|
|
18
25
|
onSuccess,
|
|
19
26
|
}) {
|
|
20
27
|
const [loading, setLoading] = useState(false)
|
|
21
28
|
|
|
29
|
+
const persistAndRedirect = (user) => {
|
|
30
|
+
localStorage.setItem('token', mockAuth ? 'mock-' + mockAuth.username : user?.token || 'token')
|
|
31
|
+
localStorage.setItem('userInfo', JSON.stringify(user || {}))
|
|
32
|
+
message.success('登录成功' + (mockAuth ? '(mock 模式,待 CTC/SSO 接入)' : ''))
|
|
33
|
+
if (onSuccess) onSuccess(user)
|
|
34
|
+
else window.location.href = redirectUrl
|
|
35
|
+
}
|
|
36
|
+
|
|
22
37
|
const handleSubmit = async (values) => {
|
|
23
38
|
setLoading(true)
|
|
24
39
|
try {
|
|
40
|
+
if (mockAuth) {
|
|
41
|
+
if (values.username === mockAuth.username && values.password === mockAuth.password) {
|
|
42
|
+
persistAndRedirect(mockAuth.user)
|
|
43
|
+
} else {
|
|
44
|
+
message.error('用户名或密码错误')
|
|
45
|
+
}
|
|
46
|
+
return
|
|
47
|
+
}
|
|
25
48
|
const res = await request.post(loginApi, values)
|
|
26
|
-
if (res
|
|
49
|
+
if (res?.token) {
|
|
27
50
|
localStorage.setItem('token', res.token)
|
|
28
51
|
localStorage.setItem('userInfo', JSON.stringify(res.user || res))
|
|
29
52
|
message.success('登录成功')
|
|
30
|
-
if (onSuccess)
|
|
31
|
-
|
|
32
|
-
} else {
|
|
33
|
-
window.location.href = redirectUrl
|
|
34
|
-
}
|
|
53
|
+
if (onSuccess) onSuccess(res)
|
|
54
|
+
else window.location.href = redirectUrl
|
|
35
55
|
} else {
|
|
36
56
|
message.error('登录失败:未获取到 token')
|
|
37
57
|
}
|
|
@@ -47,13 +67,19 @@ export default function LoginPage({
|
|
|
47
67
|
height: '100vh', display: 'flex', justifyContent: 'center', alignItems: 'center',
|
|
48
68
|
background: '#f0f2f5',
|
|
49
69
|
}}>
|
|
50
|
-
<Card title={title} style={{width: 400}}>
|
|
70
|
+
<Card title={title} style={{ width: 400 }}>
|
|
71
|
+
{mockAuth && (
|
|
72
|
+
<Alert
|
|
73
|
+
type="info" showIcon style={{ marginBottom: 16 }}
|
|
74
|
+
message={`Mock 模式:用户名 ${mockAuth.username} / 密码 ${mockAuth.password}`}
|
|
75
|
+
/>
|
|
76
|
+
)}
|
|
51
77
|
<Form onFinish={handleSubmit} size="large">
|
|
52
|
-
<Form.Item name="username" rules={[{required: true, message: '请输入用户名'}]}>
|
|
53
|
-
<Input prefix={<UserOutlined/>} placeholder="用户名"/>
|
|
78
|
+
<Form.Item name="username" rules={[{ required: true, message: '请输入用户名' }]}>
|
|
79
|
+
<Input prefix={<UserOutlined />} placeholder="用户名" />
|
|
54
80
|
</Form.Item>
|
|
55
|
-
<Form.Item name="password" rules={[{required: true, message: '请输入密码'}]}>
|
|
56
|
-
<Input.Password prefix={<LockOutlined/>} placeholder="密码"/>
|
|
81
|
+
<Form.Item name="password" rules={[{ required: true, message: '请输入密码' }]}>
|
|
82
|
+
<Input.Password prefix={<LockOutlined />} placeholder="密码" />
|
|
57
83
|
</Form.Item>
|
|
58
84
|
<Form.Item>
|
|
59
85
|
<Button type="primary" htmlType="submit" loading={loading} block>
|
|
@@ -1,16 +1,18 @@
|
|
|
1
|
-
import {Tag} from 'antd'
|
|
1
|
+
import { Tag } from 'antd'
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
3
|
+
/** 0.1.1 契约保留:数值/枚举 → 语义色 Tag 的默认映射。 */
|
|
4
|
+
export const defaultStatusMap = {
|
|
5
|
+
1: { color: 'green', text: '正常' },
|
|
6
|
+
0: { color: 'red', text: '禁用' },
|
|
7
|
+
pending: { color: 'orange', text: '待处理' },
|
|
8
|
+
approved: { color: 'blue', text: '已通过' },
|
|
9
|
+
rejected: { color: 'red', text: '已拒绝' },
|
|
9
10
|
}
|
|
10
11
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
/**
|
|
13
|
+
* 状态标签。props 与 0.1.1 一致:status + 可选 map(覆盖/追加 defaultStatusMap)。
|
|
14
|
+
*/
|
|
15
|
+
export default function StatusTag({ status, map }) {
|
|
16
|
+
const conf = map?.[status] || defaultStatusMap[status] || { color: 'default', text: String(status) }
|
|
17
|
+
return <Tag color={conf.color}>{conf.text}</Tag>
|
|
14
18
|
}
|
|
15
|
-
|
|
16
|
-
export {defaultStatusMap}
|
package/src/index.js
CHANGED
|
@@ -1,42 +1,36 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
/**
|
|
2
|
+
* z-frontend-common 桶导出 —— lead 008 前端开发规范唯一承载仓。
|
|
3
|
+
*
|
|
4
|
+
* 40+ 仓 suit 的 AppLayout / LoginPage 唯一来源;21 个 <repo>-component 的
|
|
5
|
+
* services 层消费 createRequest / request / authRequest。
|
|
6
|
+
*
|
|
7
|
+
* API 契约与 0.1.1 完全兼容(ErrorBoundary / LoginPage / StatusTag /
|
|
8
|
+
* authRequest / createRequest / defaultStatusMap / request /
|
|
9
|
+
* setupInterceptors + default 桶),AppLayout 升级为 §1/§11/§12/§15/§16
|
|
10
|
+
* 规范版,LoginPage 扩展 mockAuth 双模式(§16)。
|
|
11
|
+
*/
|
|
9
12
|
|
|
10
|
-
|
|
11
|
-
export {default as
|
|
12
|
-
export {default as
|
|
13
|
-
export {default as
|
|
14
|
-
export {default as AgentTeamIM} from './components/Ctc/agentTeam'
|
|
15
|
-
export {default as UserPanel} from './components/Ctc/userPanel'
|
|
16
|
-
export {default as Webide} from './components/Ctc/webide'
|
|
13
|
+
export { AppLayout } from './components/Layout/index.jsx'
|
|
14
|
+
export { default as LoginPage } from './components/LoginPage/index.jsx'
|
|
15
|
+
export { default as StatusTag, defaultStatusMap } from './components/StatusTag/index.jsx'
|
|
16
|
+
export { default as ErrorBoundary } from './components/ErrorBoundary/index.jsx'
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
export {default as UCResetPassword} from './components/Ctc/uc/UCResetPassword'
|
|
18
|
+
import { AppLayout } from './components/Layout/index.jsx'
|
|
19
|
+
import StatusTag, { defaultStatusMap } from './components/StatusTag/index.jsx'
|
|
20
|
+
import LoginPage from './components/LoginPage/index.jsx'
|
|
21
|
+
import ErrorBoundary from './components/ErrorBoundary/index.jsx'
|
|
22
|
+
import { createRequest, setupInterceptors, unwrapResponse, request, authRequest } from './services/request.js'
|
|
24
23
|
|
|
25
|
-
|
|
26
|
-
export {default as LowCodePage} from './components/LowCode/LowCodePage'
|
|
27
|
-
export {default as LowCodeRuntime} from './components/LowCode/LowCodeRuntime'
|
|
28
|
-
export {default as LowCodeModel} from './components/LowCode/LowCodeModel'
|
|
29
|
-
export {default as MaterializePage} from './components/LowCode/MaterializePage'
|
|
30
|
-
|
|
31
|
-
// Mock 平台 (工具平台)
|
|
32
|
-
export {default as MockPlatform} from './components/MockPlatform/index'
|
|
33
|
-
export {default as EndpointsTab} from './components/MockPlatform/EndpointsTab'
|
|
34
|
-
export {default as ScenariosTab} from './components/MockPlatform/ScenariosTab'
|
|
35
|
-
export {default as TestCasesTab} from './components/MockPlatform/TestCasesTab'
|
|
36
|
-
export {default as RequestLogsTab} from './components/MockPlatform/RequestLogsTab'
|
|
37
|
-
export {default as RecordingsTab} from './components/MockPlatform/RecordingsTab'
|
|
38
|
-
export {default as EnvironmentsTab} from './components/MockPlatform/EnvironmentsTab'
|
|
39
|
-
export {default as MockTemplateHelper} from './components/MockPlatform/MockTemplateHelper'
|
|
40
|
-
export {default as CurlImportModal} from './components/MockPlatform/CurlImportModal'
|
|
41
|
-
export {default as OpenApiImportModal} from './components/MockPlatform/OpenApiImportModal'
|
|
24
|
+
export { createRequest, setupInterceptors, unwrapResponse, request, authRequest }
|
|
42
25
|
|
|
26
|
+
// 0.1.1 default 桶契约原样保留(Ge 对象),老调用方 `import zfc from '@yuku123/z-frontend-common'` 不断
|
|
27
|
+
export default {
|
|
28
|
+
AppLayout,
|
|
29
|
+
StatusTag,
|
|
30
|
+
defaultStatusMap,
|
|
31
|
+
LoginPage,
|
|
32
|
+
ErrorBoundary,
|
|
33
|
+
request,
|
|
34
|
+
authRequest,
|
|
35
|
+
createRequest,
|
|
36
|
+
}
|
package/src/services/request.js
CHANGED
|
@@ -1,6 +1,76 @@
|
|
|
1
|
+
import axios from 'axios'
|
|
2
|
+
import { message } from 'antd'
|
|
3
|
+
|
|
1
4
|
/**
|
|
2
|
-
*
|
|
5
|
+
* 统一响应解包:z-opc 后端走 {code, data, message} 包装(Spring MVC 统一返回体),
|
|
6
|
+
* 独立 standalone 后端可能返回裸数据。有 code+data 双键就按包装解,否则原样透传。
|
|
7
|
+
* (z-vector standalone 实测坑:不解包全站拿 undefined —— 见 z-vector 仓 2026-10-11 修痕。)
|
|
3
8
|
*/
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
9
|
+
export function unwrapResponse(body) {
|
|
10
|
+
if (body && typeof body === 'object' && 'code' in body && 'data' in body) {
|
|
11
|
+
return body.code !== 200
|
|
12
|
+
? Promise.reject(new Error(body.message || '请求失败'))
|
|
13
|
+
: body.data
|
|
14
|
+
}
|
|
15
|
+
return body
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* axios 拦截器装配(request / authRequest 预建实例与 createRequest 工厂共用)。
|
|
20
|
+
* 与 0.1.1 的 API 契约逐字段一致,21 个 component 仓的 services 层在消费,不能改签名。
|
|
21
|
+
*/
|
|
22
|
+
export function setupInterceptors(instance, options = {}) {
|
|
23
|
+
const {
|
|
24
|
+
tokenKey = 'token',
|
|
25
|
+
userInfoKey = 'userInfo',
|
|
26
|
+
unauthorizedRedirect = '/login',
|
|
27
|
+
} = options
|
|
28
|
+
|
|
29
|
+
instance.interceptors.request.use((config) => {
|
|
30
|
+
const token = localStorage.getItem(tokenKey)
|
|
31
|
+
if (token) config.headers.Authorization = `Bearer ${token}`
|
|
32
|
+
return config
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
instance.interceptors.response.use(
|
|
36
|
+
(response) => unwrapResponse(response.data),
|
|
37
|
+
(error) => {
|
|
38
|
+
const status = error.response?.status
|
|
39
|
+
if (status === 401) {
|
|
40
|
+
localStorage.removeItem(tokenKey)
|
|
41
|
+
localStorage.removeItem(userInfoKey)
|
|
42
|
+
window.location.href = unauthorizedRedirect
|
|
43
|
+
} else if (status === 403) {
|
|
44
|
+
console.error('没有权限访问该资源')
|
|
45
|
+
} else if (status === 500) {
|
|
46
|
+
console.error('服务器内部错误')
|
|
47
|
+
}
|
|
48
|
+
return Promise.reject(error)
|
|
49
|
+
},
|
|
50
|
+
)
|
|
51
|
+
return instance
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* axios 实例工厂 —— 21 个 <repo>-component 的 services/api.js 用它建各自的请求实例。
|
|
56
|
+
* @param {Object} options
|
|
57
|
+
* @param {string} [options.baseURL='/api']
|
|
58
|
+
* @param {number} [options.timeout=10000]
|
|
59
|
+
* @param {string} [options.tokenKey='token']
|
|
60
|
+
* @param {string} [options.userInfoKey='userInfo']
|
|
61
|
+
* @param {string} [options.unauthorizedRedirect='/login']
|
|
62
|
+
*/
|
|
63
|
+
export function createRequest(options = {}) {
|
|
64
|
+
const instance = axios.create({
|
|
65
|
+
baseURL: options.baseURL ?? '/api',
|
|
66
|
+
timeout: options.timeout ?? 10000,
|
|
67
|
+
})
|
|
68
|
+
return setupInterceptors(instance, {
|
|
69
|
+
tokenKey: options.tokenKey,
|
|
70
|
+
userInfoKey: options.userInfoKey,
|
|
71
|
+
unauthorizedRedirect: options.unauthorizedRedirect,
|
|
72
|
+
})
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export const request = createRequest()
|
|
76
|
+
export const authRequest = createRequest()
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
._layout_1puwg_1{min-height:100vh}._header_1puwg_5{display:flex;justify-content:space-between;align-items:center;padding:0 24px;background:#001529;height:48px;line-height:48px}._logo_1puwg_15{display:flex;align-items:center}._logoText_1puwg_20{color:#fff;font-size:16px;font-weight:600}._headerRight_1puwg_26{display:flex;align-items:center}._userInfo_1puwg_31{display:flex;align-items:center;cursor:pointer;color:#fff}._userName_1puwg_38{margin-left:8px;color:#fff}._mainLayout_1puwg_43{margin-top:0;min-height:calc(100vh - 48px)}._sider_1puwg_48{background:#fff;min-height:calc(100vh - 48px)}._menu_1puwg_53{border-right:none}._collapsedBtn_1puwg_57{position:absolute;bottom:16px;left:50%;transform:translate(-50%);cursor:pointer;padding:8px 16px;background:#f5f5f5;border-radius:4px;color:#666}._collapsedBtn_1puwg_57:hover{background:#e6f7ff;color:#1890ff}._content_1puwg_74{padding:24px;background:#f5f5f5;min-height:calc(100vh - 48px);overflow:auto}._userDropdownPanel_1puwg_81{background:#fff;border-radius:8px;box-shadow:0 6px 16px #0000001f;padding:16px;width:360px}._tenantSection_1puwg_89{display:flex;align-items:center;gap:12px}._tenantLabel_1puwg_95{font-size:14px;color:#666;white-space:nowrap}._tenantCascader_1puwg_101{flex:1}._panelDivider_1puwg_105{margin:12px 0}._userSection_1puwg_109{display:flex;flex-direction:column;gap:8px}._userInfoRow_1puwg_115{display:flex;font-size:14px;line-height:1.6}._userInfoLabel_1puwg_121{color:#999;width:70px;flex-shrink:0}._menuSection_1puwg_127{display:flex;flex-direction:column}._menuItem_1puwg_132{display:flex;align-items:center;gap:8px;padding:8px 12px;cursor:pointer;border-radius:4px;font-size:14px;color:#333}._menuItem_1puwg_132:hover{background:#f5f5f5}._container_tti32_1{min-height:100vh;display:flex;align-items:center;justify-content:center;background:linear-gradient(135deg,#667eea,#764ba2)}._content_tti32_9{width:400px;padding:20px}._card_tti32_14{border-radius:8px;box-shadow:0 4px 20px #0000001a}._header_tti32_19{text-align:center;margin-bottom:24px}._header_tti32_19 h3{margin-bottom:8px}
|