mirror of
https://github.com/Zhuym07/Tsumugiboshi.git
synced 2025-07-06 17:54:46 +08:00
更新label.json,添加查询参数和请求格式以支持新的API需求
This commit is contained in:
parent
40ade5bcdb
commit
4922677215
@ -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
BIN
favicon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 20 KiB |
399
index.html
399
index.html
@ -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>
|
||||
);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user