diff --git a/config/label.json b/config/label.json
index 0bdcad9..e9f9195 100644
--- a/config/label.json
+++ b/config/label.json
@@ -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",
diff --git a/favicon.png b/favicon.png
new file mode 100644
index 0000000..8b6ba7a
Binary files /dev/null and b/favicon.png differ
diff --git a/index.html b/index.html
index 163274a..7a8f114 100644
--- a/index.html
+++ b/index.html
@@ -1,35 +1,11 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
TsumugiBoshi|纺星
-
-
-
-
+
-
+
@@ -39,16 +15,15 @@
-
-
+
+
@@ -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 @@
);
- };
+ });
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 && (
formRefs.current[key] = el}
formConfig={config}
onSubmit={(data) => handleApiCall(
config.endpoint,
config.method,
- config.method === 'POST' ? data : null
+ data,
+ config
)}
/>
)
@@ -585,7 +675,7 @@
)}
- {/* 后端选择器 */}
+ {/* 移动后端选择器到底部 */}
后端设置
@@ -642,7 +732,78 @@
+
+ {/* 日志卡片 */}
+
+ setIsLogExpanded(!isLogExpanded)}
+ >
+
+ 📝 API调用日志
+
+
+
+ {isLogExpanded ? 'expand_less' : 'expand_more'}
+
+
+
+
+
+ {logs.map((log, index) => (
+
+
+ {log.date} - {log.endpoint}
+
+
+ 请求: {JSON.stringify(log.request, null, 2)}
+
+
+ 响应: {JSON.stringify(log.response, null, 2)}
+
+
+ ))}
+
+
+
+
+ {/* 添加自定义后端的对话框 */}
+
+
+ {/* 提示消息 */}
+
+
+ {snackbarMessage}
+
+
);
}