更新label.json,添加查询参数和请求格式以支持新的API需求

This commit is contained in:
Zhuym 2025-01-28 17:31:46 +08:00
parent 40ade5bcdb
commit 4922677215
3 changed files with 286 additions and 120 deletions

View File

@ -8,10 +8,11 @@
},
"endpoint": "/qr",
"method": "GET",
"queryParams": ["qrcode"],
"fields": [
{
"id": "qrcode",
"label": "二维码内容",
"label": "SGWCMAID0000...",
"type": "text",
"required": true
}
@ -26,6 +27,7 @@
},
"endpoint": "/ticket",
"method": "GET",
"queryParams": ["userid"],
"fields": [
{
"id": "userid",
@ -44,6 +46,7 @@
},
"endpoint": "/mapstock",
"method": "GET",
"queryParams": ["userid"],
"fields": [
{
"id": "userid",
@ -62,6 +65,7 @@
},
"endpoint": "/unlock",
"method": "GET",
"queryParams": ["userid"],
"fields": [
{
"id": "userid",
@ -80,6 +84,7 @@
},
"endpoint": "/music",
"method": "POST",
"requestFormat": "json",
"fields": [
{
"id": "userId",

BIN
favicon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

View File

@ -1,35 +1,11 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<!-- PWA 支持 -->
<link rel="manifest" href="manifest.json">
<meta name="theme-color" content="#1976d2">
<link rel="apple-touch-icon" href="icons/icon-192x192.png">
<!-- OpenGraph 标签 -->
<meta property="og:title" content="TsumugiBoshi|纺星">
<meta property="og:description" content="神秘API调试工具">
<meta property="og:image" content="icons/og-image.png">
<meta property="og:url" content="https://your-domain.com">
<meta property="og:type" content="website">
<title>TsumugiBoshi|纺星</title>
<!--
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
<script src="https://unpkg.com/react@17/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@17/umd/react-dom.production.min.js"></script>
<script src="https://unpkg.com/@babel/standalone@7.21.5/babel.min.js"></script>
<script src="https://unpkg.com/@mui/material@5.14.0/umd/material-ui.production.min.js"></script>
//-->
<!-- 使用本地js代替CDN -->
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<!-- Material Icons -->
<link rel="stylesheet" href="https://fonts.loli.net/icon?family=Material+Icons">
<!-- React 依赖 -->
<script src="js\react.production.min.js"></script>
<script src="js\react-dom.production.min.js"></script>
@ -39,16 +15,15 @@
<!-- Material UI 组件库 -->
<script src="js\material-ui.production.min.js"></script>
<link rel="shortcut icon" href="favicon.png">
<style>
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
font-family: Arial, sans-serif;
min-height: 100vh;
display: flex;
flex-direction: column;
font-size: 16px;
}
#root {
flex: 1;
@ -105,110 +80,153 @@
background-color: #f8f9fa;
border-radius: 4px;
}
@media (max-width: 600px) {
.MuiContainer-root {
padding: 8px !important;
}
.MuiPaper-root {
padding: 12px !important;
}
.MuiTypography-h4 {
font-size: 1.5rem !important;
}
.MuiTypography-h6 {
font-size: 1.1rem !important;
}
.MuiTab-root {
min-height: 48px !important;
padding: 6px 12px !important;
font-size: 0.8rem !important;
}
.backend-selector {
margin-top: 1rem;
padding: 1rem;
}
h4.MuiTypography-root {
font-size: 1.5rem;
}
.scrollable-tabs::-webkit-scrollbar {
display: none;
}
.api-description {
font-size: 0.875rem;
padding: 8px;
}
}
/* 移动端优化 */
@media (max-width: 600px) {
.MuiContainer-root {
padding: 8px !important;
}
.MuiPaper-root {
padding: 8px !important;
}
.MuiTypography-h4 {
font-size: 1.25rem !important;
margin-bottom: 0.5rem !important;
}
.MuiTypography-h6 {
font-size: 1rem !important;
}
.MuiTab-root {
min-width: auto !important;
padding: 6px 8px !important;
font-size: 0.75rem !important;
}
.MuiFormControl-root {
margin-bottom: 8px !important;
}
pre {
font-size: 0.75rem !important;
padding: 8px !important;
}
.api-description {
font-size: 0.75rem !important;
padding: 8px !important;
margin: 4px 0 8px !important;
}
}
/* 新增日志卡片样式 */
.log-card {
margin-top: 1rem;
transition: all 0.3s ease;
}
.log-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0.5rem 1rem;
cursor: pointer;
}
.log-content {
padding: 1rem;
max-height: 300px;
overflow-y: auto;
}
.log-item {
border-left: 3px solid #1976d2;
margin-bottom: 0.5rem;
padding: 0.5rem;
background: #f8f9fa;
}
/* 优化响应式布局 */
@media (max-width: 600px) {
body {
font-size: 16px;
font-size: 14px;
}
.MuiContainer-root {
padding: 12px !important;
padding: 0.5rem !important;
}
.MuiPaper-root {
padding: 16px !important;
margin-bottom: 16px !important;
padding: 0.75rem !important;
}
/* 标题样式 */
.MuiTypography-h4 {
font-size: 1.75rem !important;
margin-bottom: 0.5rem !important;
font-size: 1.5rem !important;
line-height: 1.3;
}
.MuiTypography-h6 {
font-size: 1.25rem !important;
font-size: 1.1rem !important;
}
/* 表单样式 */
.MuiFormControl-root {
margin-bottom: 0.75rem !important;
}
/* 标签页样式 */
.MuiTab-root {
min-height: 56px !important;
padding: 8px 16px !important;
font-size: 1rem !important;
font-size: 0.85rem !important;
min-width: unset !important;
padding: 0.5rem 0.75rem !important;
}
.MuiInputBase-input {
font-size: 1rem !important;
padding: 14px !important;
/* 输入框样式 */
.MuiInputBase-root {
font-size: 0.9rem !important;
}
.MuiButton-root {
padding: 12px 24px !important;
font-size: 1rem !important;
/* 其他元素缩放 */
.api-description {
font-size: 0.85rem !important;
padding: 0.75rem !important;
}
pre {
font-size: 0.8rem !important;
}
.backend-selector {
margin-top: 1.5rem;
padding: 1.25rem;
}
pre {
font-size: 0.9rem;
padding: 12px;
margin: 8px 0;
}
.api-description {
font-size: 0.95rem;
padding: 12px;
margin: 12px 0 !important;
}
/* 增强触摸区域 */
.MuiIconButton-root {
padding: 12px !important;
}
/* 改善表单间距 */
.MuiGrid-container {
gap: 16px;
}
/* 增加选择器高度 */
.MuiSelect-select {
padding: 14px !important;
}
/* 调整按钮大小和间距 */
.MuiButton-contained {
margin-top: 16px;
width: 100%;
height: 48px;
}
}
/* 添加暗色模式支持 */
@media (prefers-color-scheme: dark) {
body {
background-color: #121212;
color: #fff;
}
.MuiPaper-root {
background-color: #1e1e1e !important;
}
pre {
background-color: #2d2d2d;
color: #e0e0e0;
}
.api-description {
background-color: #2d2d2d;
border-left-color: #90caf9;
color: #e0e0e0;
}
footer {
background-color: #1e1e1e;
color: #888;
margin-top: 0.75rem;
padding: 0.75rem;
}
}
</style>
@ -248,7 +266,8 @@
Alert,
Menu,
IconButton,
Link
Link,
Collapse
} = MaterialUI;
// 创建主题
@ -262,9 +281,16 @@
];
// 通用表单组件
const DynamicForm = ({ formConfig, onSubmit }) => {
const DynamicForm = React.forwardRef(({ formConfig, onSubmit }, ref) => {
const [formData, setFormData] = React.useState({});
// 暴露更新表单数据的方法给父组件
React.useImperativeHandle(ref, () => ({
updateField: (fieldId, value) => {
handleChange(fieldId, value);
}
}));
const handleChange = (fieldId, value) => {
const keys = fieldId.split('.');
setFormData(prev => {
@ -340,7 +366,7 @@
</Grid>
</div>
);
};
});
function App() {
const [tabValue, setTabValue] = React.useState(0);
@ -372,6 +398,11 @@
const [snackbarOpen, setSnackbarOpen] = React.useState(false);
const [snackbarMessage, setSnackbarMessage] = React.useState('');
const [menuAnchorEl, setMenuAnchorEl] = React.useState(null);
const [logs, setLogs] = React.useState(
JSON.parse(localStorage.getItem('apiLogs') || '[]')
);
const [isLogExpanded, setIsLogExpanded] = React.useState(false);
const formRefs = React.useRef({});
// Cookie操作函数
function setCookie(name, value, days) {
@ -390,19 +421,76 @@
if (userId) setCookie('userId', userId, 7);
}, [userId]);
const handleApiCall = async (endpoint, method = 'GET', body = null) => {
const saveLog = (endpoint, request, response) => {
const newLog = {
timestamp: Date.now(),
endpoint,
request,
response,
date: new Date().toLocaleString()
};
const updatedLogs = [newLog, ...logs].slice(0, 50); // 只保留最近50条记录
setLogs(updatedLogs);
localStorage.setItem('apiLogs', JSON.stringify(updatedLogs));
};
const handleApiCall = async (endpoint, method = 'GET', formData = null, config) => {
try {
const options = {
method,
headers: { 'Content-Type': 'application/json' }
};
if (body) options.body = JSON.stringify(body);
let url = `${apiBase}${endpoint}`;
const res = await fetch(`${apiBase}${endpoint}`, options);
// 处理GET请求参数
if (method === 'GET' && config.queryParams) {
const params = new URLSearchParams();
config.queryParams.forEach(param => {
if (formData[param]) params.append(param, formData[param]);
});
url += `?${params.toString()}`;
}
// 处理POST请求体
if (method === 'POST') {
if (config.requestFormat === 'json') {
options.body = JSON.stringify(formData);
}
}
const res = await fetch(url, options);
const data = await res.json();
setResponse(JSON.stringify(data, null, 2));
// 保存日志
saveLog(endpoint, formData, data);
// 处理登录响应
if (config.endpoint === '/qr' && data.userId) {
setUserId(data.userId.toString());
setCookie('userId', data.userId.toString(), 7);
// 遍历所有表单配置更新包含userid/userId字段的表单
Object.entries(formConfigs).forEach(([key, formConfig]) => {
const userIdField = formConfig.fields.find(
field => field.id.toLowerCase().includes('userid')
);
if (userIdField && formRefs.current[key]) {
formRefs.current[key].updateField(userIdField.id, data.userId.toString());
}
});
}
// 根据状态设置提示消息
setSnackbarMessage(data.info || '操作成功');
setSnackbarOpen(true);
} catch (error) {
setResponse(`Error: ${error.message}`);
setSnackbarMessage(`错误: ${error.message}`);
setSnackbarOpen(true);
}
};
@ -468,7 +556,7 @@
))
);
setSnackbarMessage('后端URL已删除');
setSnackbarMessage('后端已删除');
setSnackbarOpen(true);
};
@ -558,11 +646,13 @@
tabValue === config.tab.index && (
<DynamicForm
key={key}
ref={el => formRefs.current[key] = el}
formConfig={config}
onSubmit={(data) => handleApiCall(
config.endpoint,
config.method,
config.method === 'POST' ? data : null
data,
config
)}
/>
)
@ -585,7 +675,7 @@
</Paper>
)}
{/* 后端选择器 */}
{/* 移动后端选择器到底部 */}
<Paper elevation={3} className="backend-selector">
<Typography variant="h6" gutterBottom>
后端设置
@ -642,7 +732,78 @@
</Button>
</FormControl>
</Paper>
{/* 日志卡片 */}
<Paper elevation={3} className="log-card">
<div
className="log-header"
onClick={() => setIsLogExpanded(!isLogExpanded)}
>
<Typography variant="h6">
📝 API调用日志
</Typography>
<IconButton size="small">
<span className="material-icons">
{isLogExpanded ? 'expand_less' : 'expand_more'}
</span>
</IconButton>
</div>
<Collapse in={isLogExpanded}>
<div className="log-content">
{logs.map((log, index) => (
<div key={index} className="log-item">
<Typography variant="subtitle2" gutterBottom>
{log.date} - {log.endpoint}
</Typography>
<Typography variant="body2" component="pre" style={{margin: 0}}>
请求: {JSON.stringify(log.request, null, 2)}
</Typography>
<Typography variant="body2" component="pre" style={{margin: 0}}>
响应: {JSON.stringify(log.response, null, 2)}
</Typography>
</div>
))}
</div>
</Collapse>
</Paper>
</Container>
{/* 添加自定义后端的对话框 */}
<Dialog open={isDialogOpen} onClose={handleDialogClose}>
<DialogTitle>添加自定义后端</DialogTitle>
<DialogContent>
<TextField
autoFocus
margin="dense"
label="后端名称"
fullWidth
value={newBackend.label}
onChange={(e) => setNewBackend(prev => ({...prev, label: e.target.value}))}
/>
<TextField
margin="dense"
label="后端地址"
fullWidth
value={newBackend.value}
onChange={(e) => setNewBackend(prev => ({...prev, value: e.target.value}))}
/>
</DialogContent>
<DialogActions>
<Button onClick={handleDialogClose}>取消</Button>
<Button onClick={handleSaveBackend} color="primary">保存</Button>
</DialogActions>
</Dialog>
{/* 提示消息 */}
<Snackbar
open={snackbarOpen}
autoHideDuration={3000}
onClose={handleSnackbarClose}
>
<Alert onClose={handleSnackbarClose} severity="success">
{snackbarMessage}
</Alert>
</Snackbar>
</ThemeProvider>
);
}