This commit is contained in:
尹舟 2025-08-20 17:59:26 +08:00
parent 48e5220ec5
commit c7ec0cea6c
10 changed files with 18674 additions and 87 deletions

View File

@ -2,3 +2,4 @@
.idea/
.deploy/
logs/
.git/

View File

@ -1,22 +1,31 @@
from flask import Flask, render_template, request, jsonify,send_file
from flask import Flask, render_template, request, jsonify, send_file, send_from_directory
from utils.sql_parse import parse_create_table_sql
from utils.log import Log
app = Flask(__name__)
log = Log().getlog()
@app.route('/css/<path:filename>')
def css_files(filename):
return send_from_directory('templates/css', filename)
@app.route('/')
def index():
return send_file('templates/index.html')
@app.route('/a')
def index_a():
return render_template('a.html')
@app.route('/b')
def index_b():
return render_template('b.html')
@app.route('/convert', methods=['POST'])
def convert_sql():
sql_input = request.form['sql']
@ -39,6 +48,55 @@ def convert_sql():
log.info("SQL result: %s", result)
return jsonify(result)
@app.route('/convert1', methods=['POST'])
def convert_sql1():
createTableDDL = request.form['sql']
if createTableDDL.strip() == '':
return jsonify({
'parsed_result': "请在上面输入框输入hologres建表语句",
'message': 'SQL processed.'
})
log.info("SQL Input: %s", createTableDDL)
try:
parsed_result = ''
createTableDDL = createTableDDL.split('CREATE')[1].split('with (')[0]
createTableDDL = 'CREATE' + createTableDDL
print(createTableDDL)
createTableDDL = createTableDDL.replace('public.', '').replace('integer', 'int')
createTableDDL = createTableDDL.replace('timestamp with time zone', 'DATETIME').replace('text', 'VARCHAR(64)')
createTableDDL = createTableDDL.replace(',PRIMARY KEY', 'UNIQUE KEY')
createTableDDL = createTableDDL.replace('numeric(10,2)', 'DECIMAL(10,2)')
createTableDDL = createTableDDL.replace('numeric(10,4)', 'DECIMAL(10,4)')
createTableDDL = createTableDDL.split('\n')
createTableDDL = [(i + '\n').strip() for i in createTableDDL]
UNIQUE_str = ''
UNIQUE_key = ''
for i in createTableDDL:
if i.startswith('UNIQUE'):
# 获取字符()里面的字符串
UNIQUE_key = i.replace('UNIQUE KEY (', '').replace(")", "")
UNIQUE_str += i
else:
if i:
parsed_result += i + '\n'
UNIQUE_str += f' DISTRIBUTED BY HASH ({UNIQUE_key}) BUCKETS 32;'
parsed_result += UNIQUE_str
result = {
'parsed_result': parsed_result,
'message': 'SQL processed successfully.'
}
except Exception as e:
result = {'error': f'请检查输入sql:\n\n {str(e)}'}
log.info("SQL result: %s", result)
print(result)
return jsonify(result)
if __name__ == '__main__':
# 指定host和port这里使用0.0.0.0可以让服务器被外部访问
app.run(host='0.0.0.0', port=8778, debug=True)

View File

@ -1,90 +1,318 @@
<!DOCTYPE html>
<html lang="en">
<html lang="zh-Hans">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>SQL Processor</title>
<title>SQL 处理器</title>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<link rel="stylesheet" href="/css/codemirror.min.css">
<link rel="stylesheet" href="/css/theme/monokai.min.css">
<script src="/css/codemirror.min.js"></script>
<script src="/css/sql.min.js"></script>
<style>
body { font: 1rem 'Roboto', Arial, sans-serif; margin: 0; padding: 0; background: #f5f5f5; color: #333; }
.container { max-width: 1200px; margin: 0 auto; padding: 1rem; }
header { text-align: center; padding: 1rem 0; background: #fff; border-radius: 10px; box-shadow: 0 4px 6px rgba(0,0,0,0.1); margin-bottom: 1rem; }
h1 { font-size: 2.5rem; color: #4a90e2; margin: 0; font-weight: 500; }
form, .output-box { background: #fff; padding: 1rem; border-radius: 10px; box-shadow: 0 4px 6px rgba(0,0,0,0.1); }
textarea, input[type="text"] { width: 100%; padding: 0.6rem; margin-bottom: 1rem; font: inherit; border: 1px solid #ddd; border-radius: 6px; background: #f9f9f9; resize: none; }
textarea { height: 200px; }
button { display: inline-block; background: #4a90e2; color: #fff; border: none; border-radius: 6px; padding: 0.75rem 1.5rem; font: 600 1rem 'Roboto'; cursor: pointer; transition: background 0.3s ease; }
button:hover { background: #357ab8; }
.output-box { margin-bottom: 1rem; border: 1px solid #ddd; border-radius: 6px; background: #f9f9f9; }
.error { color: #dc3545; background: #ffebee; padding: 0.6rem; border-radius: 6px; }
.success { color: #28a745; background: #d4edda; padding: 0.6rem; border-radius: 6px; }
:root {
--primary-color: #4a90e2;
--hover-color: #2c78c8;
--bg-color: #f0f2f5;
--border-color: #ddd;
--success-color: #28a745;
--error-color: #dc3545;
--warning-color: #ffc107;
}
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 20px;
background-color: var(--bg-color);
}
h1 {
font-size: 2.5rem;
color: var(--primary-color);
margin: 0 0 20px;
font-weight: 500;
}
.container {
margin-bottom: 20px;
background: white;
padding: 15px;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.CodeMirror {
height: 300px;
border: 1px solid var(--border-color);
border-radius: 6px;
resize: vertical;
}
.buttons {
margin: 15px 0;
display: flex;
gap: 10px;
flex-wrap: wrap;
}
button {
background: var(--primary-color);
color: #fff;
border: none;
border-radius: 6px;
padding: 0.75rem 1.5rem;
font: 600 1rem 'Roboto', sans-serif;
cursor: pointer;
transition: background 0.3s ease;
}
button:hover {
background: var(--hover-color);
}
button:disabled {
background: #cccccc;
cursor: not-allowed;
}
.status-message {
font-size: 0.9em;
margin-top: 10px;
min-height: 1.2em;
padding: 8px;
border-radius: 4px;
/*设置高度*/
overflow: hidden;
overflow-y: auto;
word-wrap: break-word;
overflow-wrap: break-word;
word-break: break-all;
/*设置宽度*/
max-width: 100%;
}
.status-success {
background: #e8f5e9;
color: var(--success-color);
}
.status-error {
background: #ffebee;
color: var(--error-color);
}
.status-warning {
background: #fff3e0;
color: var(--warning-color);
}
.status-info {
background: #e3f2fd;
color: var(--primary-color);
}
</style>
</head>
<body>
<div class="container">
<div id="app">
<!-- 基本结构:图片作为超链接内容 -->
<a href="/" >
<img src="https://yinzhou.oss-cn-shanghai.aliyuncs.com/image/bianmu.png" width="50" height="50">
<a href="/">
<img src="https://yinzhou.oss-cn-shanghai.aliyuncs.com/image/bianmu.png" width="50" height="50">
</a>
<a href="/a" >
<img src="https://yinzhou.oss-cn-shanghai.aliyuncs.com/image/buoumao.png" width="50" height="50">
<a href="/a">
<img src="https://yinzhou.oss-cn-shanghai.aliyuncs.com/image/buoumao.png" width="50" height="50">
</a>
<a href="/b" >
<img src="https://yinzhou.oss-cn-shanghai.aliyuncs.com/image/chaiquan.png" width="50" height="50">
<a href="/">
<img src="https://yinzhou.oss-cn-shanghai.aliyuncs.com/image/chaiquan.png" width="50" height="50">
</a>
<header><h1>SQL格式化工具</h1></header>
<form id="sqlForm">
<textarea id="sqlInput" placeholder="Enter your SQL here..."></textarea>
<label for="hologresConnection">Hologres Connection Info:</label>
<input type="text" id="hologresConnection" name="hologresConnection" value="hgprecn-cn-i7m2ssubq004-cn-hangzhou-internal.hologres.aliyuncs.com:80" placeholder="Enter Hologres connection info...">
<button type="submit">Convert</button>
</form>
<div id="resultArea" class="output-box" style="display: none;"></div>
<header><h1>转odps外部表 SQL格式化工具</h1></header>
<div class="container">
<h2>输入 SQL</h2>
<div ref="sqlInput"></div>
</div>
<div class="buttons">
<button @click="clearInput" title="清空输入框">清空</button>
<button @click="formatSQL" :disabled="isProcessing">格式化</button>
<button @click="copyToClipboard">复制</button>
<button @click="insertSample" title="插入示例语句">示例</button>
</div>
<div class="status-message" :class="statusClass">{{ statusMessage }}</div>
<div class="container">
<h2>输出 SQL</h2>
<div ref="sqlOutput"></div>
</div>
</div>
<script>
document.getElementById('sqlForm').addEventListener('submit', async (e) => {
e.preventDefault();
const resultArea = document.getElementById('resultArea');
resultArea.style.display = 'block';
resultArea.querySelector('.output-box')?.remove();
const {createApp, ref, onMounted, computed} = Vue;
const sql = encodeURIComponent(document.getElementById('sqlInput').value);
const connection = encodeURIComponent(document.getElementById('hologresConnection').value);
const API_CONFIG = {
ENDPOINT: '/convert',
DEFAULT_HEADERS: {
'Content-Type': 'application/x-www-form-urlencoded'
},
DEFAULT_SQL: "SELECT * FROM table WHERE condition;",
SAMPLE_SQL: "SELECT * FROM users WHERE age > 18;"
};
try {
const response = await fetch('/convert', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: `sql=${sql}&hologresConnection=${connection}`
});
const data = await response.json();
if (data.error) {
const div = document.createElement('div');
div.className = 'output-box error';
div.textContent = data.error;
resultArea.appendChild(div);
} else {
const div = document.createElement('div');
div.className = 'output-box success';
const textarea = document.createElement('textarea');
textarea.readOnly = true;
textarea.value = data.parsed_result || '请检查输入建表语句';
div.appendChild(textarea);
const messageP = document.createElement('p');
messageP.textContent = data.message;
div.appendChild(messageP);
resultArea.appendChild(div);
const createEditorConfig = (readOnly = false) => ({
mode: "sql",
lineNumbers: true,
theme: "monokai",
readOnly,
extraKeys: {"Ctrl-Space": "autocomplete"},
hintOptions: {
completeSingle: false,
tables: {
users: ["id", "name", "age"],
products: ["id", "name", "price"]
}
} catch (error) {
console.error('Error:', error);
const errorDiv = document.createElement('div');
errorDiv.className = 'output-box error';
errorDiv.textContent = 'An unexpected error occurred. Please try again.';
resultArea.appendChild(errorDiv);
}
});
createApp({
setup() {
const sqlInput = ref(null);
const sqlOutput = ref(null);
const isProcessing = ref(false);
const statusMessage = ref('');
const statusType = ref('');
let editorInput = null;
let editorOutput = null;
const outputContent = computed(() => {
return editorOutput ? editorOutput.getValue().trim() : '';
});
const statusClass = computed(() => {
// 控制台打印
console.log(`1Status: ${statusType.value} - ${statusMessage.value}`);
return statusType.value ? `status-${statusType.value}` : '';
});
const setStatus = (message, type = 'info', timeout = 10000) => {
statusMessage.value = message;
statusType.value = type;
if (timeout) {
setTimeout(() => {
statusMessage.value = '';
statusType.value = '';
}, timeout);
}
};
onMounted(() => {
if (sqlInput.value && sqlOutput.value) {
editorInput = CodeMirror(sqlInput.value, {
...createEditorConfig(),
value: API_CONFIG.DEFAULT_SQL
});
editorOutput = CodeMirror(sqlOutput.value, {
...createEditorConfig(true),
value: "默认输出内容" // 给输出框一个默认值
});
}
});
const insertSample = () => {
editorInput.setValue(API_CONFIG.SAMPLE_SQL);
setStatus('示例语句已插入', 'success');
};
const clearInput = () => {
editorInput.setValue('');
setStatus('输入已清空', 'info');
};
const formatSQL = async () => {
const inputSQL = editorInput.getValue().trim();
if (!inputSQL) {
setStatus('请输入要格式化的SQL内容', 'warning');
return;
}
try {
isProcessing.value = true;
setStatus('正在格式化SQL...', 'info', 0);
const startTime = Date.now();
const response = await fetch(API_CONFIG.ENDPOINT, {
method: 'POST',
headers: API_CONFIG.DEFAULT_HEADERS,
body: `sql=${encodeURIComponent(inputSQL)}`
});
const duration = Date.now() - startTime;
if (!response.ok) {
throw new Error(`请求失败: ${response.status} ${response.statusText}`);
}
const data = await response.json();
if (!data.parsed_result) {
throw new Error('服务器返回空结果');
}
editorOutput.setValue(data.parsed_result);
setStatus(`格式化成功 (${duration}ms)`, 'success');
} catch (error) {
console.error('格式化错误:', error);
editorOutput.setValue('');
setStatus(`格式化失败: ${error.message}`, 'error');
} finally {
isProcessing.value = false;
}
};
const copyToClipboard = async () => {
try {
const content = editorOutput.getValue().trim();
if (!content) {
setStatus('无内容可复制', 'warning');
return;
}
try {
await navigator.clipboard.writeText(content);
setStatus('内容已复制到剪贴板', 'success');
} catch (err) {
// 回退到传统复制方式
const textarea = document.createElement('textarea');
textarea.value = content;
document.body.appendChild(textarea);
textarea.select();
const success = document.execCommand('copy');
document.body.removeChild(textarea);
if (!success) throw new Error('传统复制方式失败');
setStatus('内容已复制(传统方式)', 'success');
}
} catch (error) {
console.error('复制失败:', error);
setStatus(`复制失败: ${error.message}`, 'error');
}
};
return {
sqlInput,
sqlOutput,
isProcessing,
statusMessage,
statusClass,
outputContent,
insertSample,
clearInput,
formatSQL,
copyToClipboard
};
}
}).mount('#app');
</script>
</body>
</html>

View File

@ -4,10 +4,10 @@
<meta charset="UTF-8">
<title>SQL 处理器</title>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.2/codemirror.min.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.2/theme/monokai.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.2/codemirror.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.2/mode/sql/sql.min.js"></script>
<link rel="stylesheet" href="/css/codemirror.min.css">
<link rel="stylesheet" href="/css/theme/monokai.min.css">
<script src="/css/codemirror.min.js"></script>
<script src="/css/mode/sql/sql.min.js"></script>
<style>
:root {
--primary-color: #4a90e2;
@ -75,7 +75,41 @@
cursor: not-allowed;
}
.status-message {
font-size: 0.9em;
margin-top: 10px;
min-height: 1.2em;
padding: 8px;
border-radius: 4px;
/*设置高度*/
overflow: hidden;
overflow-y: auto;
word-wrap: break-word;
overflow-wrap: break-word;
word-break: break-all;
/*设置宽度*/
max-width: 100%;
}
.status-success {
background: #e8f5e9;
color: var(--success-color);
}
.status-error {
background: #ffebee;
color: var(--error-color);
}
.status-warning {
background: #fff3e0;
color: var(--warning-color);
}
.status-info {
background: #e3f2fd;
color: var(--primary-color);
}
</style>
</head>
<body>
@ -87,9 +121,8 @@
<a href="/a">
<img src="https://yinzhou.oss-cn-shanghai.aliyuncs.com/image/buoumao.png" width="50" height="50">
</a>
<a href="/b">
<img src="https://yinzhou.oss-cn-shanghai.aliyuncs.com/image/chaiquan.png" width="50"
height="50">
<a href="/">
<img src="https://yinzhou.oss-cn-shanghai.aliyuncs.com/image/chaiquan.png" width="50" height="50">
</a>
<header><h1>SQL格式化工具</h1></header>
@ -99,11 +132,14 @@
</div>
<div class="buttons">
<button @click="insertSample" title="插入示例语句">示例</button>
<button @click="clearInput" title="清空输入框">清空</button>
<button @click="formatSQL" :disabled="isProcessing">格式化</button>
<button @click="copyToClipboard">复制</button>
<button @click="insertSample" title="插入示例语句">示例</button>
</div>
<div class="status-message" :class="statusClass">{{ statusMessage }}</div>
<div class="container">
<h2>输出 SQL</h2>
<div ref="sqlOutput"></div>
@ -114,7 +150,7 @@
const {createApp, ref, onMounted, computed} = Vue;
const API_CONFIG = {
ENDPOINT: 'http://10.23.0.209:8778/convert',
ENDPOINT: '/convert',
DEFAULT_HEADERS: {
'Content-Type': 'application/x-www-form-urlencoded'
},
@ -142,6 +178,8 @@
const sqlInput = ref(null);
const sqlOutput = ref(null);
const isProcessing = ref(false);
const statusMessage = ref('');
const statusType = ref('');
let editorInput = null;
let editorOutput = null;
@ -149,6 +187,24 @@
return editorOutput ? editorOutput.getValue().trim() : '';
});
const statusClass = computed(() => {
// 控制台打印
console.log(`1Status: ${statusType.value} - ${statusMessage.value}`);
return statusType.value ? `status-${statusType.value}` : '';
});
const setStatus = (message, type = 'info', timeout = 10000) => {
statusMessage.value = message;
statusType.value = type;
if (timeout) {
setTimeout(() => {
statusMessage.value = '';
statusType.value = '';
}, timeout);
}
};
onMounted(() => {
if (sqlInput.value && sqlOutput.value) {
editorInput = CodeMirror(sqlInput.value, {
@ -165,20 +221,25 @@
const insertSample = () => {
editorInput.setValue(API_CONFIG.SAMPLE_SQL);
setStatus('示例语句已插入', 'success');
};
const clearInput = () => {
editorInput.setValue('');
setStatus('输入已清空', 'info');
};
const formatSQL = async () => {
const inputSQL = editorInput.getValue().trim();
if (!inputSQL) {
setStatus('请输入要格式化的SQL内容', 'warning');
return;
}
try {
isProcessing.value = true;
setStatus('正在格式化SQL...', 'info', 0);
const startTime = Date.now();
const response = await fetch(API_CONFIG.ENDPOINT, {
method: 'POST',
@ -198,9 +259,11 @@
}
editorOutput.setValue(data.parsed_result);
setStatus(`格式化成功 (${duration}ms)`, 'success');
} catch (error) {
console.error('格式化错误:', error);
editorOutput.setValue('');
setStatus(`格式化失败: ${error.message}`, 'error');
} finally {
isProcessing.value = false;
}
@ -210,11 +273,13 @@
try {
const content = editorOutput.getValue().trim();
if (!content) {
setStatus('无内容可复制', 'warning');
return;
}
try {
await navigator.clipboard.writeText(content);
setStatus('内容已复制到剪贴板', 'success');
} catch (err) {
// 回退到传统复制方式
const textarea = document.createElement('textarea');
@ -226,9 +291,11 @@
document.body.removeChild(textarea);
if (!success) throw new Error('传统复制方式失败');
setStatus('内容已复制(传统方式)', 'success');
}
} catch (error) {
console.error('复制失败:', error);
setStatus(`复制失败: ${error.message}`, 'error');
}
};
@ -236,6 +303,8 @@
sqlInput,
sqlOutput,
isProcessing,
statusMessage,
statusClass,
outputContent,
insertSample,
clearInput,

1
templates/css/codemirror.min.css vendored Normal file

File diff suppressed because one or more lines are too long

1
templates/css/codemirror.min.js vendored Normal file

File diff suppressed because one or more lines are too long

1
templates/css/monokai.min.css vendored Normal file
View File

@ -0,0 +1 @@
.cm-s-monokai.CodeMirror{background:#272822;color:#f8f8f2}.cm-s-monokai div.CodeMirror-selected{background:#49483e}.cm-s-monokai .CodeMirror-line::selection,.cm-s-monokai .CodeMirror-line>span::selection,.cm-s-monokai .CodeMirror-line>span>span::selection{background:rgba(73,72,62,.99)}.cm-s-monokai .CodeMirror-line::-moz-selection,.cm-s-monokai .CodeMirror-line>span::-moz-selection,.cm-s-monokai .CodeMirror-line>span>span::-moz-selection{background:rgba(73,72,62,.99)}.cm-s-monokai .CodeMirror-gutters{background:#272822;border-right:0}.cm-s-monokai .CodeMirror-guttermarker{color:#fff}.cm-s-monokai .CodeMirror-guttermarker-subtle{color:#d0d0d0}.cm-s-monokai .CodeMirror-linenumber{color:#d0d0d0}.cm-s-monokai .CodeMirror-cursor{border-left:1px solid #f8f8f0}.cm-s-monokai span.cm-comment{color:#75715e}.cm-s-monokai span.cm-atom{color:#ae81ff}.cm-s-monokai span.cm-number{color:#ae81ff}.cm-s-monokai span.cm-comment.cm-attribute{color:#97b757}.cm-s-monokai span.cm-comment.cm-def{color:#bc9262}.cm-s-monokai span.cm-comment.cm-tag{color:#bc6283}.cm-s-monokai span.cm-comment.cm-type{color:#5998a6}.cm-s-monokai span.cm-attribute,.cm-s-monokai span.cm-property{color:#a6e22e}.cm-s-monokai span.cm-keyword{color:#f92672}.cm-s-monokai span.cm-builtin{color:#66d9ef}.cm-s-monokai span.cm-string{color:#e6db74}.cm-s-monokai span.cm-variable{color:#f8f8f2}.cm-s-monokai span.cm-variable-2{color:#9effff}.cm-s-monokai span.cm-type,.cm-s-monokai span.cm-variable-3{color:#66d9ef}.cm-s-monokai span.cm-def{color:#fd971f}.cm-s-monokai span.cm-bracket{color:#f8f8f2}.cm-s-monokai span.cm-tag{color:#f92672}.cm-s-monokai span.cm-header{color:#ae81ff}.cm-s-monokai span.cm-link{color:#ae81ff}.cm-s-monokai span.cm-error{background:#f92672;color:#f8f8f0}.cm-s-monokai .CodeMirror-activeline-background{background:#373831}.cm-s-monokai .CodeMirror-matchingbracket{text-decoration:underline;color:#fff!important}

1
templates/css/sql.min.js vendored Normal file

File diff suppressed because one or more lines are too long

18227
templates/css/vue.global.js Normal file

File diff suppressed because it is too large Load Diff

View File

@ -4,10 +4,10 @@
<meta charset="UTF-8">
<title>SQL 处理器</title>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.2/codemirror.min.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.2/theme/monokai.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.2/codemirror.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.2/mode/sql/sql.min.js"></script>
<link rel="stylesheet" href="/css/codemirror.min.css">
<link rel="stylesheet" href="/css/monokai.min.css">
<script src="/css/codemirror.min.js"></script>
<script src="/css/sql.min.js"></script>
<style>
:root {
--primary-color: #4a90e2;
@ -118,13 +118,13 @@
<a href="/">
<img src="https://yinzhou.oss-cn-shanghai.aliyuncs.com/image/bianmu.png" width="50" height="50">
</a>
<a href="/">
<a href="/a">
<img src="https://yinzhou.oss-cn-shanghai.aliyuncs.com/image/buoumao.png" width="50" height="50">
</a>
<a href="/">
<img src="https://yinzhou.oss-cn-shanghai.aliyuncs.com/image/chaiquan.png" width="50" height="50">
</a>
<header><h1>SQL格式化工具</h1></header>
<header><h1>转doirs SQL格式化工具</h1></header>
<div class="container">
<h2>输入 SQL</h2>
@ -150,7 +150,7 @@
const {createApp, ref, onMounted, computed} = Vue;
const API_CONFIG = {
ENDPOINT: '/convert',
ENDPOINT: '/convert1',
DEFAULT_HEADERS: {
'Content-Type': 'application/x-www-form-urlencoded'
},