大更新,太多了,具体进游戏查看详细更新内容
反正很多
This commit is contained in:
100
Server/JsonEdit/README.md
Normal file
100
Server/JsonEdit/README.md
Normal file
@@ -0,0 +1,100 @@
|
||||
# JSON 批量编辑器
|
||||
|
||||
一个简洁强大的JSON编辑工具,专门用于批量添加键值对到JSON文件中的所有对象。
|
||||
|
||||
## 🚀 功能特点
|
||||
|
||||
- **批量添加属性**: 一键为JSON中所有对象添加新的键值对
|
||||
- **智能类型识别**: 自动识别并转换数据类型
|
||||
- **支持所有JSON数据类型**: 字符串、数字、布尔值、对象、数组、null
|
||||
- **文件上传**: 支持JSON文件拖拽上传
|
||||
- **即时下载**: 编辑完成后立即下载修改后的JSON文件
|
||||
- **无需服务器**: 纯前端实现,直接在浏览器中运行
|
||||
|
||||
## 📋 支持的数据类型
|
||||
|
||||
| 类型 | 输入示例 | 转换结果 |
|
||||
|------|----------|----------|
|
||||
| 字符串 | `hello world` | `"hello world"` |
|
||||
| 整数 | `123` | `123` |
|
||||
| 小数 | `3.14` | `3.14` |
|
||||
| 布尔值 | `true` 或 `false` | `true` 或 `false` |
|
||||
| 空值 | `null` | `null` |
|
||||
| 对象 | `{"key": "value"}` | `{"key": "value"}` |
|
||||
| 数组 | `[1, 2, 3]` | `[1, 2, 3]` |
|
||||
| 空字符串 | *(留空)* | `""` |
|
||||
|
||||
## 🎯 使用方法
|
||||
|
||||
### 1. 加载JSON数据
|
||||
- **方法一**: 点击"上传JSON文件"按钮选择文件
|
||||
- **方法二**: 直接在编辑器中粘贴JSON数据
|
||||
- **方法三**: 点击"加载示例数据"使用预设数据
|
||||
|
||||
### 2. 批量添加属性
|
||||
1. 在"键名"字段输入要添加的属性名,如: `能否购买`
|
||||
2. 在"键值"字段输入属性值,如: `true`
|
||||
3. 点击"批量添加到所有对象"按钮
|
||||
4. 系统会自动为JSON中的每个对象添加该属性
|
||||
|
||||
### 3. 下载结果
|
||||
点击"下载修改后的JSON"按钮保存编辑后的文件
|
||||
|
||||
## 💡 使用示例
|
||||
|
||||
### 原始JSON:
|
||||
```json
|
||||
{
|
||||
"小麦": {
|
||||
"花费": 120,
|
||||
"收益": 100,
|
||||
"品质": "普通"
|
||||
},
|
||||
"稻谷": {
|
||||
"花费": 100,
|
||||
"收益": 120,
|
||||
"品质": "普通"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 添加属性: 键名=`能否购买`, 键值=`true`
|
||||
|
||||
### 结果JSON:
|
||||
```json
|
||||
{
|
||||
"小麦": {
|
||||
"花费": 120,
|
||||
"收益": 100,
|
||||
"品质": "普通",
|
||||
"能否购买": true
|
||||
},
|
||||
"稻谷": {
|
||||
"花费": 100,
|
||||
"收益": 120,
|
||||
"品质": "普通",
|
||||
"能否购买": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 🔧 快速开始
|
||||
|
||||
1. 直接在浏览器中打开 `templates/json_editor.html` 文件
|
||||
2. 无需安装任何依赖或服务器
|
||||
3. 开始使用批量编辑功能
|
||||
|
||||
## ⚠️ 注意事项
|
||||
|
||||
- 工具会递归处理嵌套对象,为所有找到的对象添加指定属性
|
||||
- 数组元素如果是对象,也会被添加属性
|
||||
- 确保JSON格式正确,否则无法处理
|
||||
- 修改前建议备份原始文件
|
||||
|
||||
## 🎨 界面说明
|
||||
|
||||
- **左侧边栏**: 文件操作、批量编辑功能、快速示例
|
||||
- **右侧编辑区**: JSON数据显示和编辑
|
||||
- **智能提示**: 实时显示操作结果和错误信息
|
||||
|
||||
这个工具特别适合游戏开发、配置文件管理等需要批量修改JSON数据的场景。
|
||||
65
Server/JsonEdit/example_formats.md
Normal file
65
Server/JsonEdit/example_formats.md
Normal file
@@ -0,0 +1,65 @@
|
||||
# JSON格式化示例
|
||||
|
||||
以下展示三种不同的JSON格式化效果:
|
||||
|
||||
## 原始数据
|
||||
```json
|
||||
{"小麦":{"花费":120,"收益":100,"品质":"普通"},"稻谷":{"花费":100,"收益":120,"品质":"普通"}}
|
||||
```
|
||||
|
||||
## 1. 标准格式化(2空格缩进)
|
||||
```json
|
||||
{
|
||||
"小麦": {
|
||||
"花费": 120,
|
||||
"收益": 100,
|
||||
"品质": "普通"
|
||||
},
|
||||
"稻谷": {
|
||||
"花费": 100,
|
||||
"收益": 120,
|
||||
"品质": "普通"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 2. 最小化(压缩)
|
||||
```json
|
||||
{"小麦":{"花费":120,"收益":100,"品质":"普通"},"稻谷":{"花费":100,"收益":120,"品质":"普通"}}
|
||||
```
|
||||
|
||||
## 3. 一行化(一个对象一行)
|
||||
```json
|
||||
{
|
||||
"小麦": {"花费":120,"收益":100,"品质":"普通"},
|
||||
"稻谷": {"花费":100,"收益":120,"品质":"普通"}
|
||||
}
|
||||
```
|
||||
|
||||
## 使用场景
|
||||
|
||||
- **标准格式化**: 适合阅读和编辑,开发时使用
|
||||
- **最小化**: 适合网络传输,节省带宽
|
||||
- **一行化**: 适合比较不同对象,每行一个对象便于查看差异
|
||||
|
||||
## 批量添加属性示例
|
||||
|
||||
添加键名: `能否购买`, 键值: `true`
|
||||
|
||||
### 结果:
|
||||
```json
|
||||
{
|
||||
"小麦": {
|
||||
"花费": 120,
|
||||
"收益": 100,
|
||||
"品质": "普通",
|
||||
"能否购买": true
|
||||
},
|
||||
"稻谷": {
|
||||
"花费": 100,
|
||||
"收益": 120,
|
||||
"品质": "普通",
|
||||
"能否购买": true
|
||||
}
|
||||
}
|
||||
```
|
||||
267
Server/JsonEdit/json_editor.py
Normal file
267
Server/JsonEdit/json_editor.py
Normal file
@@ -0,0 +1,267 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from flask import Flask, request, jsonify, render_template, send_file
|
||||
import json
|
||||
import os
|
||||
from datetime import datetime
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
class JSONFormatter:
|
||||
"""JSON格式化工具类"""
|
||||
|
||||
@staticmethod
|
||||
def format_standard(data, indent=2):
|
||||
"""标准格式化 - 带缩进的可读格式"""
|
||||
return json.dumps(data, ensure_ascii=False, indent=indent)
|
||||
|
||||
@staticmethod
|
||||
def minify(data):
|
||||
"""最小化 - 压缩去除空格"""
|
||||
return json.dumps(data, ensure_ascii=False, separators=(',', ':'))
|
||||
|
||||
@staticmethod
|
||||
def one_line_per_object(data):
|
||||
"""一行化 - 每个对象/元素占一行"""
|
||||
if isinstance(data, list):
|
||||
# 如果是数组,每个元素占一行
|
||||
lines = ['[']
|
||||
for i, item in enumerate(data):
|
||||
comma = ',' if i < len(data) - 1 else ''
|
||||
lines.append(f' {json.dumps(item, ensure_ascii=False)}{comma}')
|
||||
lines.append(']')
|
||||
return '\n'.join(lines)
|
||||
|
||||
elif isinstance(data, dict):
|
||||
# 如果是对象,每个键值对占一行
|
||||
lines = ['{']
|
||||
keys = list(data.keys())
|
||||
for i, key in enumerate(keys):
|
||||
comma = ',' if i < len(keys) - 1 else ''
|
||||
value_str = json.dumps(data[key], ensure_ascii=False)
|
||||
lines.append(f' {json.dumps(key, ensure_ascii=False)}: {value_str}{comma}')
|
||||
lines.append('}')
|
||||
return '\n'.join(lines)
|
||||
|
||||
else:
|
||||
# 基本类型直接返回
|
||||
return json.dumps(data, ensure_ascii=False)
|
||||
|
||||
@app.route('/')
|
||||
def index():
|
||||
"""主页"""
|
||||
return render_template('json_editor.html')
|
||||
|
||||
@app.route('/api/format', methods=['POST'])
|
||||
def format_json():
|
||||
"""JSON格式化API"""
|
||||
try:
|
||||
data = request.get_json()
|
||||
content = data.get('content', '')
|
||||
format_type = data.get('format_type', 'standard') # standard, minify, oneline
|
||||
|
||||
if not content.strip():
|
||||
return jsonify({'success': False, 'message': '请提供JSON内容'})
|
||||
|
||||
# 解析JSON
|
||||
try:
|
||||
json_data = json.loads(content)
|
||||
except json.JSONDecodeError as e:
|
||||
return jsonify({'success': False, 'message': f'JSON格式错误: {str(e)}'})
|
||||
|
||||
# 根据类型格式化
|
||||
formatter = JSONFormatter()
|
||||
|
||||
if format_type == 'standard':
|
||||
formatted = formatter.format_standard(json_data)
|
||||
message = 'JSON标准格式化完成'
|
||||
elif format_type == 'minify':
|
||||
formatted = formatter.minify(json_data)
|
||||
message = 'JSON最小化完成'
|
||||
elif format_type == 'oneline':
|
||||
formatted = formatter.one_line_per_object(json_data)
|
||||
message = 'JSON一行化格式完成'
|
||||
else:
|
||||
return jsonify({'success': False, 'message': '不支持的格式化类型'})
|
||||
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'message': message,
|
||||
'formatted': formatted,
|
||||
'original_length': len(content),
|
||||
'formatted_length': len(formatted)
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
return jsonify({'success': False, 'message': f'处理错误: {str(e)}'})
|
||||
|
||||
@app.route('/api/batch_add', methods=['POST'])
|
||||
def batch_add_property():
|
||||
"""批量添加属性API"""
|
||||
try:
|
||||
data = request.get_json()
|
||||
content = data.get('content', '')
|
||||
key_name = data.get('key_name', '')
|
||||
key_value = data.get('key_value', '')
|
||||
|
||||
if not content.strip():
|
||||
return jsonify({'success': False, 'message': '请提供JSON内容'})
|
||||
|
||||
if not key_name.strip():
|
||||
return jsonify({'success': False, 'message': '请提供键名'})
|
||||
|
||||
# 解析JSON
|
||||
try:
|
||||
json_data = json.loads(content)
|
||||
except json.JSONDecodeError as e:
|
||||
return jsonify({'success': False, 'message': f'JSON格式错误: {str(e)}'})
|
||||
|
||||
# 智能解析键值
|
||||
parsed_value = parse_value(key_value)
|
||||
|
||||
# 批量添加属性
|
||||
count = add_property_to_all_objects(json_data, key_name, parsed_value)
|
||||
|
||||
# 格式化输出
|
||||
formatted = JSONFormatter.format_standard(json_data)
|
||||
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'message': f'成功为 {count} 个对象添加了属性 "{key_name}": {json.dumps(parsed_value, ensure_ascii=False)}',
|
||||
'formatted': formatted,
|
||||
'count': count
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
return jsonify({'success': False, 'message': f'处理错误: {str(e)}'})
|
||||
|
||||
def parse_value(value_str):
|
||||
"""智能解析值的类型"""
|
||||
if value_str == '':
|
||||
return ''
|
||||
|
||||
# null
|
||||
if value_str.lower() == 'null':
|
||||
return None
|
||||
|
||||
# boolean
|
||||
if value_str.lower() == 'true':
|
||||
return True
|
||||
if value_str.lower() == 'false':
|
||||
return False
|
||||
|
||||
# number
|
||||
try:
|
||||
if '.' in value_str:
|
||||
return float(value_str)
|
||||
else:
|
||||
return int(value_str)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
# JSON object or array
|
||||
if (value_str.startswith('{') and value_str.endswith('}')) or \
|
||||
(value_str.startswith('[') and value_str.endswith(']')):
|
||||
try:
|
||||
return json.loads(value_str)
|
||||
except json.JSONDecodeError:
|
||||
pass
|
||||
|
||||
# string
|
||||
return value_str
|
||||
|
||||
def add_property_to_all_objects(obj, key, value):
|
||||
"""递归为所有对象添加属性"""
|
||||
count = 0
|
||||
|
||||
def traverse(current):
|
||||
nonlocal count
|
||||
if isinstance(current, dict):
|
||||
current[key] = value
|
||||
count += 1
|
||||
# 继续递归处理嵌套对象
|
||||
for val in current.values():
|
||||
if isinstance(val, (dict, list)) and val != current:
|
||||
traverse(val)
|
||||
elif isinstance(current, list):
|
||||
for item in current:
|
||||
traverse(item)
|
||||
|
||||
traverse(obj)
|
||||
return count
|
||||
|
||||
@app.route('/api/validate', methods=['POST'])
|
||||
def validate_json():
|
||||
"""JSON验证API"""
|
||||
try:
|
||||
data = request.get_json()
|
||||
content = data.get('content', '')
|
||||
|
||||
if not content.strip():
|
||||
return jsonify({'success': False, 'message': '请提供JSON内容'})
|
||||
|
||||
try:
|
||||
json_data = json.loads(content)
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'message': 'JSON格式正确 ✓',
|
||||
'valid': True
|
||||
})
|
||||
except json.JSONDecodeError as e:
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'message': f'JSON格式错误: {str(e)}',
|
||||
'valid': False,
|
||||
'error': str(e)
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
return jsonify({'success': False, 'message': f'验证错误: {str(e)}'})
|
||||
|
||||
@app.route('/api/download', methods=['POST'])
|
||||
def download_json():
|
||||
"""下载JSON文件"""
|
||||
try:
|
||||
data = request.get_json()
|
||||
content = data.get('content', '')
|
||||
format_type = data.get('format_type', 'standard')
|
||||
|
||||
if not content.strip():
|
||||
return jsonify({'success': False, 'message': '没有可下载的内容'})
|
||||
|
||||
# 验证JSON格式
|
||||
try:
|
||||
json_data = json.loads(content)
|
||||
except json.JSONDecodeError as e:
|
||||
return jsonify({'success': False, 'message': f'JSON格式错误: {str(e)}'})
|
||||
|
||||
# 格式化
|
||||
formatter = JSONFormatter()
|
||||
if format_type == 'minify':
|
||||
formatted_content = formatter.minify(json_data)
|
||||
elif format_type == 'oneline':
|
||||
formatted_content = formatter.one_line_per_object(json_data)
|
||||
else:
|
||||
formatted_content = formatter.format_standard(json_data)
|
||||
|
||||
# 生成文件名
|
||||
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
||||
filename = f"edited_json_{format_type}_{timestamp}.json"
|
||||
|
||||
# 创建临时文件
|
||||
temp_file = f"temp_{filename}"
|
||||
with open(temp_file, 'w', encoding='utf-8') as f:
|
||||
f.write(formatted_content)
|
||||
|
||||
return send_file(temp_file, as_attachment=True, download_name=filename)
|
||||
|
||||
except Exception as e:
|
||||
return jsonify({'success': False, 'message': f'下载错误: {str(e)}'})
|
||||
|
||||
if __name__ == '__main__':
|
||||
# 确保templates目录存在
|
||||
os.makedirs('templates', exist_ok=True)
|
||||
|
||||
# 运行应用
|
||||
app.run(debug=True, host='0.0.0.0', port=5000)
|
||||
2
Server/JsonEdit/requirements.txt
Normal file
2
Server/JsonEdit/requirements.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
Flask==2.3.3
|
||||
Werkzeug==2.3.7
|
||||
627
Server/JsonEdit/templates/json_editor.html
Normal file
627
Server/JsonEdit/templates/json_editor.html
Normal file
@@ -0,0 +1,627 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>简易JSON编辑器 - 批量添加键值</title>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||
background: #f5f5f5;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
background: white;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.header {
|
||||
background: #4a90e2;
|
||||
color: white;
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.main-content {
|
||||
display: grid;
|
||||
grid-template-columns: 300px 1fr;
|
||||
gap: 0;
|
||||
min-height: 600px;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
background: #f8f9fa;
|
||||
border-right: 1px solid #dee2e6;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.editor-area {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.section {
|
||||
background: white;
|
||||
border: 1px solid #dee2e6;
|
||||
border-radius: 5px;
|
||||
padding: 15px;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.section h3 {
|
||||
margin-bottom: 15px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.btn {
|
||||
background: #4a90e2;
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 10px 20px;
|
||||
border-radius: 5px;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
margin: 5px 5px 5px 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background: #357abd;
|
||||
}
|
||||
|
||||
.btn-success {
|
||||
background: #28a745;
|
||||
}
|
||||
|
||||
.btn-success:hover {
|
||||
background: #218838;
|
||||
}
|
||||
|
||||
.input-group {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.input-group label {
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
font-weight: 500;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.input-group input {
|
||||
width: 100%;
|
||||
padding: 8px 12px;
|
||||
border: 1px solid #dee2e6;
|
||||
border-radius: 5px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.input-group input:focus {
|
||||
outline: none;
|
||||
border-color: #4a90e2;
|
||||
}
|
||||
|
||||
#jsonEditor {
|
||||
width: 100%;
|
||||
height: 500px;
|
||||
border: 1px solid #dee2e6;
|
||||
border-radius: 5px;
|
||||
padding: 15px;
|
||||
font-family: 'Courier New', monospace;
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
#jsonEditor:focus {
|
||||
outline: none;
|
||||
border-color: #4a90e2;
|
||||
}
|
||||
|
||||
.file-upload {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.file-upload input[type=file] {
|
||||
position: absolute;
|
||||
left: -9999px;
|
||||
}
|
||||
|
||||
.alert {
|
||||
padding: 10px 15px;
|
||||
margin-bottom: 15px;
|
||||
border-radius: 5px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.alert-success {
|
||||
background: #d4edda;
|
||||
color: #155724;
|
||||
border: 1px solid #c3e6cb;
|
||||
}
|
||||
|
||||
.alert-error {
|
||||
background: #f8d7da;
|
||||
color: #721c24;
|
||||
border: 1px solid #f5c6cb;
|
||||
}
|
||||
|
||||
.alert-info {
|
||||
background: #d1ecf1;
|
||||
color: #0c5460;
|
||||
border: 1px solid #bee5eb;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.main-content {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<h1>🔧 JSON批量编辑器</h1>
|
||||
<p>批量添加键值对到JSON文件</p>
|
||||
</div>
|
||||
|
||||
<div class="main-content">
|
||||
<!-- 侧边栏 -->
|
||||
<div class="sidebar">
|
||||
<!-- 文件操作 -->
|
||||
<div class="section">
|
||||
<h3>📁 文件操作</h3>
|
||||
<div class="file-upload btn">
|
||||
<input type="file" id="fileInput" accept=".json" />
|
||||
上传JSON文件
|
||||
</div>
|
||||
<button class="btn btn-success" onclick="downloadJSON()">
|
||||
下载修改后的JSON
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 批量添加键值 -->
|
||||
<div class="section">
|
||||
<h3>⚡ 批量添加键值</h3>
|
||||
<div class="input-group">
|
||||
<label for="keyName">键名:</label>
|
||||
<input type="text" id="keyName" placeholder="例: 能否购买" />
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<label for="keyValue">键值:</label>
|
||||
<input type="text" id="keyValue" placeholder="支持多种类型,见下方说明" />
|
||||
</div>
|
||||
<button class="btn btn-success" onclick="batchAddProperty()">
|
||||
批量添加到所有对象
|
||||
</button>
|
||||
|
||||
<div style="margin-top: 15px; padding: 10px; background: #f8f9fa; border-radius: 5px; font-size: 12px;">
|
||||
<strong>支持的数据类型:</strong><br>
|
||||
• 字符串: hello world<br>
|
||||
• 数字: 123 或 3.14<br>
|
||||
• 布尔值: true 或 false<br>
|
||||
• 空值: null<br>
|
||||
• 对象: {"key": "value"}<br>
|
||||
• 数组: [1, 2, 3]<br>
|
||||
<small style="color: #666;">系统会自动识别并转换数据类型</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 快速示例 -->
|
||||
<div class="section">
|
||||
<h3>📝 快速示例</h3>
|
||||
<button class="btn" onclick="loadSampleJSON()">
|
||||
加载示例数据
|
||||
</button>
|
||||
|
||||
<div style="margin-top: 15px;">
|
||||
<strong style="font-size: 12px;">快速填入示例键值:</strong><br>
|
||||
<button class="btn" style="font-size: 11px; padding: 5px 10px; margin: 2px;" onclick="fillExample('能否购买', 'true')">
|
||||
布尔值示例
|
||||
</button>
|
||||
<button class="btn" style="font-size: 11px; padding: 5px 10px; margin: 2px;" onclick="fillExample('价格', '150')">
|
||||
数字示例
|
||||
</button>
|
||||
<button class="btn" style="font-size: 11px; padding: 5px 10px; margin: 2px;" onclick="fillExample('备注', '新增属性')">
|
||||
字符串示例
|
||||
</button>
|
||||
<button class="btn" style="font-size: 11px; padding: 5px 10px; margin: 2px;" onclick="fillExample('tags', '["新", "热门"]')">
|
||||
数组示例
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- JSON格式化操作 -->
|
||||
<div class="section">
|
||||
<h3>🔧 格式化操作</h3>
|
||||
<button class="btn" onclick="formatJSONStandard()">
|
||||
标准格式化
|
||||
</button>
|
||||
<button class="btn btn-success" onclick="minifyJSON()">
|
||||
最小化(压缩)
|
||||
</button>
|
||||
<button class="btn" style="background: #17a2b8;" onclick="oneLinePerObject()">
|
||||
一行化(一个对象一行)
|
||||
</button>
|
||||
<button class="btn" style="background: #6f42c1; color: white;" onclick="validateJSON()">
|
||||
验证JSON格式
|
||||
</button>
|
||||
|
||||
<div style="margin-top: 15px; padding: 10px; background: #f8f9fa; border-radius: 5px; font-size: 12px;">
|
||||
<strong>格式化说明:</strong><br>
|
||||
• <strong>标准格式化</strong>: 2空格缩进,易于阅读<br>
|
||||
• <strong>最小化</strong>: 去除空格,节省空间<br>
|
||||
• <strong>一行化</strong>: 每个对象占一行,便于比较<br>
|
||||
• <strong>验证格式</strong>: 检查JSON语法是否正确<br>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 编辑区域 -->
|
||||
<div class="editor-area">
|
||||
<!-- 消息区域 -->
|
||||
<div id="messageArea"></div>
|
||||
|
||||
<!-- JSON编辑器 -->
|
||||
<textarea id="jsonEditor" placeholder="在此输入或上传JSON数据..."></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// 初始化
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
document.getElementById('fileInput').addEventListener('change', handleFileUpload);
|
||||
});
|
||||
|
||||
// 显示消息
|
||||
function showMessage(message, type = 'success') {
|
||||
const messageArea = document.getElementById('messageArea');
|
||||
let alertClass = 'alert-success';
|
||||
|
||||
if (type === 'error') {
|
||||
alertClass = 'alert-error';
|
||||
} else if (type === 'info') {
|
||||
alertClass = 'alert-info';
|
||||
}
|
||||
|
||||
messageArea.innerHTML = `
|
||||
<div class="alert ${alertClass}">
|
||||
${message}
|
||||
</div>
|
||||
`;
|
||||
|
||||
setTimeout(() => {
|
||||
messageArea.innerHTML = '';
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
// 加载示例JSON
|
||||
function loadSampleJSON() {
|
||||
const sampleJSON = {
|
||||
"测试作物": {
|
||||
"花费": 1,
|
||||
"生长时间": 3,
|
||||
"收益": 9999,
|
||||
"品质": "普通"
|
||||
},
|
||||
"小麦": {
|
||||
"花费": 120,
|
||||
"生长时间": 120,
|
||||
"收益": 100,
|
||||
"品质": "普通"
|
||||
},
|
||||
"稻谷": {
|
||||
"花费": 100,
|
||||
"生长时间": 240,
|
||||
"收益": 120,
|
||||
"品质": "普通"
|
||||
}
|
||||
};
|
||||
|
||||
document.getElementById('jsonEditor').value = JSON.stringify(sampleJSON, null, 2);
|
||||
showMessage('示例数据已加载');
|
||||
}
|
||||
|
||||
// 快速填入示例键值对
|
||||
function fillExample(keyName, keyValue) {
|
||||
document.getElementById('keyName').value = keyName;
|
||||
document.getElementById('keyValue').value = keyValue;
|
||||
showMessage(`已填入示例: ${keyName} = ${keyValue}`, 'info');
|
||||
}
|
||||
|
||||
// 文件上传处理
|
||||
function handleFileUpload(event) {
|
||||
const file = event.target.files[0];
|
||||
if (!file) return;
|
||||
|
||||
if (!file.name.toLowerCase().endsWith('.json')) {
|
||||
showMessage('请选择JSON文件', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
const reader = new FileReader();
|
||||
reader.onload = function(e) {
|
||||
try {
|
||||
const content = e.target.result;
|
||||
JSON.parse(content); // 验证JSON格式
|
||||
document.getElementById('jsonEditor').value = content;
|
||||
showMessage('文件上传成功');
|
||||
} catch (error) {
|
||||
showMessage('JSON格式错误: ' + error.message, 'error');
|
||||
}
|
||||
};
|
||||
reader.readAsText(file);
|
||||
|
||||
// 清空文件输入
|
||||
event.target.value = '';
|
||||
}
|
||||
|
||||
// 批量添加属性
|
||||
function batchAddProperty() {
|
||||
const keyName = document.getElementById('keyName').value.trim();
|
||||
const keyValue = document.getElementById('keyValue').value.trim();
|
||||
const jsonContent = document.getElementById('jsonEditor').value.trim();
|
||||
|
||||
if (!keyName) {
|
||||
showMessage('请输入键名', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!jsonContent) {
|
||||
showMessage('请输入或上传JSON数据', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
let jsonData = JSON.parse(jsonContent);
|
||||
|
||||
// 智能类型转换
|
||||
let processedValue = parseValue(keyValue);
|
||||
|
||||
// 批量添加属性
|
||||
const result = addPropertyToAllObjects(jsonData, keyName, processedValue);
|
||||
|
||||
if (result.count > 0) {
|
||||
document.getElementById('jsonEditor').value = JSON.stringify(jsonData, null, 2);
|
||||
showMessage(`成功为 ${result.count} 个对象添加了属性 "${keyName}": ${JSON.stringify(processedValue)}`);
|
||||
} else {
|
||||
showMessage('未找到可添加属性的对象', 'info');
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
showMessage('JSON格式错误: ' + error.message, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
// 智能解析值的类型
|
||||
function parseValue(value) {
|
||||
// 如果输入为空,返回空字符串
|
||||
if (value === '') {
|
||||
return '';
|
||||
}
|
||||
|
||||
// 尝试解析为null
|
||||
if (value.toLowerCase() === 'null') {
|
||||
return null;
|
||||
}
|
||||
|
||||
// 尝试解析为undefined(虽然JSON不支持,但转为null)
|
||||
if (value.toLowerCase() === 'undefined') {
|
||||
return null;
|
||||
}
|
||||
|
||||
// 尝试解析为布尔值
|
||||
if (value.toLowerCase() === 'true') {
|
||||
return true;
|
||||
}
|
||||
if (value.toLowerCase() === 'false') {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 尝试解析为数字
|
||||
if (!isNaN(value) && !isNaN(parseFloat(value))) {
|
||||
// 检查是否为整数
|
||||
if (Number.isInteger(parseFloat(value))) {
|
||||
return parseInt(value, 10);
|
||||
} else {
|
||||
return parseFloat(value);
|
||||
}
|
||||
}
|
||||
|
||||
// 尝试解析为JSON对象或数组
|
||||
if ((value.startsWith('{') && value.endsWith('}')) ||
|
||||
(value.startsWith('[') && value.endsWith(']'))) {
|
||||
try {
|
||||
return JSON.parse(value);
|
||||
} catch (e) {
|
||||
// 如果解析失败,当作字符串处理
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
// 默认当作字符串处理
|
||||
return value;
|
||||
}
|
||||
|
||||
// 递归为所有对象添加属性
|
||||
function addPropertyToAllObjects(obj, key, value) {
|
||||
let count = 0;
|
||||
|
||||
function traverse(current) {
|
||||
if (typeof current === 'object' && current !== null) {
|
||||
if (Array.isArray(current)) {
|
||||
// 处理数组
|
||||
current.forEach(item => traverse(item));
|
||||
} else {
|
||||
// 处理对象
|
||||
current[key] = value;
|
||||
count++;
|
||||
|
||||
// 继续递归处理嵌套对象
|
||||
Object.values(current).forEach(val => {
|
||||
if (typeof val === 'object' && val !== null && val !== current) {
|
||||
traverse(val);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
traverse(obj);
|
||||
return { count };
|
||||
}
|
||||
|
||||
// 下载JSON
|
||||
function downloadJSON() {
|
||||
const content = document.getElementById('jsonEditor').value.trim();
|
||||
|
||||
if (!content) {
|
||||
showMessage('没有可下载的内容', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// 验证JSON格式
|
||||
JSON.parse(content);
|
||||
|
||||
const blob = new Blob([content], { type: 'application/json' });
|
||||
const url = URL.createObjectURL(blob);
|
||||
const link = document.createElement('a');
|
||||
link.href = url;
|
||||
link.download = `edited_json_${new Date().getTime()}.json`;
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
URL.revokeObjectURL(url);
|
||||
|
||||
showMessage('JSON文件下载成功');
|
||||
} catch (error) {
|
||||
showMessage('JSON格式错误,无法下载: ' + error.message, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
// 标准格式化JSON
|
||||
function formatJSONStandard() {
|
||||
const content = document.getElementById('jsonEditor').value.trim();
|
||||
|
||||
if (!content) {
|
||||
showMessage('请输入JSON数据', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const jsonData = JSON.parse(content);
|
||||
const formatted = JSON.stringify(jsonData, null, 2);
|
||||
document.getElementById('jsonEditor').value = formatted;
|
||||
showMessage('JSON标准格式化完成');
|
||||
} catch (error) {
|
||||
showMessage('JSON格式错误: ' + error.message, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
// 最小化JSON(压缩)
|
||||
function minifyJSON() {
|
||||
const content = document.getElementById('jsonEditor').value.trim();
|
||||
|
||||
if (!content) {
|
||||
showMessage('请输入JSON数据', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const jsonData = JSON.parse(content);
|
||||
const minified = JSON.stringify(jsonData);
|
||||
document.getElementById('jsonEditor').value = minified;
|
||||
showMessage('JSON最小化完成');
|
||||
} catch (error) {
|
||||
showMessage('JSON格式错误: ' + error.message, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
// 一行化格式(一个对象一行)
|
||||
function oneLinePerObject() {
|
||||
const content = document.getElementById('jsonEditor').value.trim();
|
||||
|
||||
if (!content) {
|
||||
showMessage('请输入JSON数据', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const jsonData = JSON.parse(content);
|
||||
let formatted = '';
|
||||
|
||||
if (Array.isArray(jsonData)) {
|
||||
// 如果是数组,每个元素占一行
|
||||
formatted = '[\n';
|
||||
jsonData.forEach((item, index) => {
|
||||
formatted += ' ' + JSON.stringify(item);
|
||||
if (index < jsonData.length - 1) {
|
||||
formatted += ',';
|
||||
}
|
||||
formatted += '\n';
|
||||
});
|
||||
formatted += ']';
|
||||
} else if (typeof jsonData === 'object' && jsonData !== null) {
|
||||
// 如果是对象,每个键值对占一行
|
||||
formatted = '{\n';
|
||||
const keys = Object.keys(jsonData);
|
||||
keys.forEach((key, index) => {
|
||||
formatted += ' ' + JSON.stringify(key) + ': ' + JSON.stringify(jsonData[key]);
|
||||
if (index < keys.length - 1) {
|
||||
formatted += ',';
|
||||
}
|
||||
formatted += '\n';
|
||||
});
|
||||
formatted += '}';
|
||||
} else {
|
||||
// 基本类型直接输出
|
||||
formatted = JSON.stringify(jsonData);
|
||||
}
|
||||
|
||||
document.getElementById('jsonEditor').value = formatted;
|
||||
showMessage('JSON一行化格式完成');
|
||||
} catch (error) {
|
||||
showMessage('JSON格式错误: ' + error.message, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
// 验证JSON格式
|
||||
function validateJSON() {
|
||||
const content = document.getElementById('jsonEditor').value.trim();
|
||||
|
||||
if (!content) {
|
||||
showMessage('请输入JSON数据', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
JSON.parse(content);
|
||||
showMessage('JSON格式验证通过');
|
||||
} catch (error) {
|
||||
showMessage('JSON格式错误: ' + error.message, 'error');
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user