277 lines
11 KiB
HTML
277 lines
11 KiB
HTML
|
|
<!DOCTYPE html>
|
||
|
|
<html lang="en">
|
||
|
|
<head>
|
||
|
|
<meta charset="UTF-8">
|
||
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
|
|
<title>btl143</title>
|
||
|
|
<!-- <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
|
||
|
|
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
|
||
|
|
<script src="https://unpkg.com/element-ui/lib/index.js"></script>
|
||
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.0.1/socket.io.js"></script> -->
|
||
|
|
|
||
|
|
<link rel="stylesheet" href="static/index.css">
|
||
|
|
<script src="static/vue.js"></script>
|
||
|
|
<script src="static/index.js"></script>
|
||
|
|
<script src="static/socket.io.js"></script>
|
||
|
|
|
||
|
|
<style>
|
||
|
|
body {
|
||
|
|
font-family: Arial, sans-serif;
|
||
|
|
margin: 0;
|
||
|
|
padding: 0;
|
||
|
|
background-color: #f5f7fa;
|
||
|
|
}
|
||
|
|
.app-container {
|
||
|
|
padding: 20px;
|
||
|
|
max-width: 1200px;
|
||
|
|
margin: 0 auto;
|
||
|
|
}
|
||
|
|
.section-title {
|
||
|
|
margin-top: 30px;
|
||
|
|
margin-bottom: 20px;
|
||
|
|
color: #303133;
|
||
|
|
border-bottom: 1px solid #dcdfe6;
|
||
|
|
padding-bottom: 10px;
|
||
|
|
}
|
||
|
|
.button-group {
|
||
|
|
margin-bottom: 20px;
|
||
|
|
}
|
||
|
|
.config-form {
|
||
|
|
background-color: white;
|
||
|
|
padding: 20px;
|
||
|
|
border-radius: 4px;
|
||
|
|
box-shadow: 0 2px 12px 0 rgba(0,0,0,.1);
|
||
|
|
}
|
||
|
|
.log-container {
|
||
|
|
height: 400px;
|
||
|
|
overflow-y: auto;
|
||
|
|
background-color: white;
|
||
|
|
border-radius: 4px;
|
||
|
|
padding: 10px;
|
||
|
|
box-shadow: 0 2px 12px 0 rgba(0,0,0,.1);
|
||
|
|
}
|
||
|
|
.log-container1 {
|
||
|
|
height: 400px;
|
||
|
|
overflow-y: auto;
|
||
|
|
background-color: white;
|
||
|
|
border-radius: 4px;
|
||
|
|
padding: 10px;
|
||
|
|
box-shadow: 0 2px 12px 0 rgba(0,0,0,.1);
|
||
|
|
}
|
||
|
|
.log-entry {
|
||
|
|
margin-bottom: 5px;
|
||
|
|
font-family: monospace;
|
||
|
|
}
|
||
|
|
.log-info { color: #409EFF; }
|
||
|
|
.log-error { color: #F56C6C; }
|
||
|
|
.log-warning { color: #E6A23C; }
|
||
|
|
.log-debug { color: #909399; }
|
||
|
|
</style>
|
||
|
|
</head>
|
||
|
|
<body>
|
||
|
|
<div id="app">
|
||
|
|
<el-container class="app-container">
|
||
|
|
<el-main>
|
||
|
|
<h1 class="section-title">btl143 upper</h1>
|
||
|
|
|
||
|
|
<el-row :gutter="20" class="button-group">
|
||
|
|
<el-col :xs="24" :sm="8">
|
||
|
|
<el-button @click="startServer" type="success" style="width: 100%">开启 server</el-button>
|
||
|
|
</el-col>
|
||
|
|
<el-col :xs="24" :sm="8">
|
||
|
|
<el-button @click="stopServer" type="danger" style="width: 100%">关闭 server</el-button>
|
||
|
|
</el-col>
|
||
|
|
<el-col :xs="24" :sm="8">
|
||
|
|
<el-button @click="restartServer" type="warning" style="width: 100%">重启 server</el-button>
|
||
|
|
</el-col>
|
||
|
|
</el-row>
|
||
|
|
|
||
|
|
<el-row :gutter="20" class="button-group">
|
||
|
|
<el-col :xs="24" :sm="8">
|
||
|
|
<el-button @click="startTask" type="success" style="width: 100%">开启 task</el-button>
|
||
|
|
</el-col>
|
||
|
|
<el-col :xs="24" :sm="8">
|
||
|
|
<el-button @click="stopTask" type="danger" style="width: 100%">关闭 task</el-button>
|
||
|
|
</el-col>
|
||
|
|
<el-col :xs="24" :sm="8">
|
||
|
|
<el-button @click="restartTask" type="warning" style="width: 100%">重启 task</el-button>
|
||
|
|
</el-col>
|
||
|
|
</el-row>
|
||
|
|
|
||
|
|
<el-row :gutter="20" class="button-group">
|
||
|
|
<el-col :xs="24" :sm="8">
|
||
|
|
<el-button @click="showServerLog" type="success" style="width: 100%">
|
||
|
|
{{ showServerLogFlag ? '关闭' : '打开' }} server 日志
|
||
|
|
</el-button>
|
||
|
|
</el-col>
|
||
|
|
<el-col :xs="24" :sm="8">
|
||
|
|
|
||
|
|
</el-col>
|
||
|
|
<el-col :xs="24" :sm="8">
|
||
|
|
<el-button @click="skipTask" type="success" style="width: 100%">
|
||
|
|
强制跳转
|
||
|
|
</el-button>
|
||
|
|
</el-col>
|
||
|
|
</el-row>
|
||
|
|
|
||
|
|
<el-select v-model="selectedFile" placeholder="" @change="loadConfig" style="width: 100%; margin-bottom: 20px;">
|
||
|
|
<el-option
|
||
|
|
v-for="item in fileOptions"
|
||
|
|
:key="item"
|
||
|
|
:label="item"
|
||
|
|
:value="item">
|
||
|
|
</el-option>
|
||
|
|
</el-select>
|
||
|
|
|
||
|
|
<el-button v-if="showConfigForm" @click="toggleConfigForm" type="primary" style="margin-bottom: 20px;">
|
||
|
|
{{ showConfigForm ? '关闭' : '打开' }} 配置
|
||
|
|
</el-button>
|
||
|
|
|
||
|
|
<el-form v-if="showConfigForm && config" class="config-form">
|
||
|
|
<div v-for="(section, sectionName) in config" :key="sectionName">
|
||
|
|
<h3>{{ sectionName }}</h3>
|
||
|
|
<el-row :gutter="20">
|
||
|
|
<el-col v-for="(value, key) in section" :key="key" :xs="24" :sm="12" :md="8" :lg="6">
|
||
|
|
<el-form-item :label="key">
|
||
|
|
<el-switch
|
||
|
|
v-if="typeof value === 'boolean'"
|
||
|
|
v-model="config[sectionName][key]">
|
||
|
|
</el-switch>
|
||
|
|
<el-input-number
|
||
|
|
v-else-if="typeof value === 'number'"
|
||
|
|
v-model="config[sectionName][key]"
|
||
|
|
:controls="true"
|
||
|
|
:min="Number.MIN_SAFE_INTEGER"
|
||
|
|
:max="Number.MAX_SAFE_INTEGER"
|
||
|
|
:step="1"
|
||
|
|
style="width: 100%;">
|
||
|
|
</el-input-number>
|
||
|
|
<el-input
|
||
|
|
v-else
|
||
|
|
v-model="config[sectionName][key]">
|
||
|
|
</el-input>
|
||
|
|
</el-form-item>
|
||
|
|
</el-col>
|
||
|
|
</el-row>
|
||
|
|
</div>
|
||
|
|
<el-button @click="saveConfig" type="primary" style="margin-top: 20px;">保存配置</el-button>
|
||
|
|
</el-form>
|
||
|
|
|
||
|
|
<h2 class="section-title">Log Display</h2>
|
||
|
|
|
||
|
|
<div v-if="showServerLogFlag" class="log-container1" v-html="formatServerLog(ServerLog)"></div>
|
||
|
|
|
||
|
|
|
||
|
|
<div class="log-container">
|
||
|
|
<div v-for="logEntry in logs" :key="logEntry.id" :class="['log-entry', `log-${logEntry.level}`]">
|
||
|
|
[{{ logEntry.level.toUpperCase() }}] {{ logEntry.content }}
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</el-main>
|
||
|
|
</el-container>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<script>
|
||
|
|
new Vue({
|
||
|
|
el: '#app',
|
||
|
|
data: {
|
||
|
|
logs: [],
|
||
|
|
selectedFile: null,
|
||
|
|
showConfigForm: false,
|
||
|
|
fileOptions: [],
|
||
|
|
config: null,
|
||
|
|
files: {},
|
||
|
|
ServerLog: "",
|
||
|
|
showServerLogFlag: false,
|
||
|
|
timer: null
|
||
|
|
},
|
||
|
|
methods: {
|
||
|
|
loadConfig() {
|
||
|
|
this.config = this.files[this.selectedFile];
|
||
|
|
this.showConfigForm = true;
|
||
|
|
},
|
||
|
|
toggleConfigForm() {
|
||
|
|
this.showConfigForm = !this.showConfigForm;
|
||
|
|
},
|
||
|
|
startServer() {
|
||
|
|
this.socket.emit('operate', {type: 'operate_server', content: 'run'});
|
||
|
|
},
|
||
|
|
stopServer() {
|
||
|
|
this.socket.emit('operate', {type: 'operate_server', content: 'stop'});
|
||
|
|
},
|
||
|
|
restartServer() {
|
||
|
|
this.socket.emit('operate', {type: 'operate_server', content: 'restart'});
|
||
|
|
},
|
||
|
|
startTask() {
|
||
|
|
this.socket.emit('operate', {type: 'operate_task', content: 'run'});
|
||
|
|
},
|
||
|
|
stopTask() {
|
||
|
|
this.socket.emit('operate', {type: 'operate_task', content: 'stop'});
|
||
|
|
},
|
||
|
|
restartTask() {
|
||
|
|
this.socket.emit('operate', {type: 'operate_task', content: 'restart'});
|
||
|
|
},
|
||
|
|
saveConfig() {
|
||
|
|
console.log(this.config);
|
||
|
|
this.socket.emit('operate', {type: 'save_config', file_name: this.selectedFile, content: this.config});
|
||
|
|
},
|
||
|
|
addLog(log) {
|
||
|
|
this.logs.push({
|
||
|
|
level: log.level,
|
||
|
|
content: log.content
|
||
|
|
});
|
||
|
|
this.$nextTick(() => {
|
||
|
|
const container = document.querySelector('.log-container');
|
||
|
|
container.scrollTop = container.scrollHeight;
|
||
|
|
if (this.logs.length > 100) {
|
||
|
|
this.logs = this.logs.slice(-100);
|
||
|
|
}
|
||
|
|
});
|
||
|
|
},
|
||
|
|
showServerLog() {
|
||
|
|
if (this.showServerLogFlag == false)
|
||
|
|
{
|
||
|
|
this.timer = setInterval(() => {
|
||
|
|
this.socket.emit('operate', { type: 'show_server_log', content: '' });
|
||
|
|
}, 2000);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
clearInterval(this.timer);
|
||
|
|
this.timer = null;
|
||
|
|
}
|
||
|
|
this.showServerLogFlag = !this.showServerLogFlag;
|
||
|
|
},
|
||
|
|
formatServerLog(log) {
|
||
|
|
// 将换行符转换为 <br> 标签
|
||
|
|
return log.replace(/\n/g, '<br>');
|
||
|
|
},
|
||
|
|
skipTask() {
|
||
|
|
this.socket.emit('operate', { type: 'skip_task', content: '' });
|
||
|
|
}
|
||
|
|
},
|
||
|
|
mounted() {
|
||
|
|
this.socket = io('http://' + document.domain + ':5001');
|
||
|
|
this.socket.on('connect', () => {
|
||
|
|
console.log('Connected to server');
|
||
|
|
});
|
||
|
|
this.socket.on('log', (data) => {
|
||
|
|
this.addLog(data);
|
||
|
|
});
|
||
|
|
this.socket.on('config_data', (data) => {
|
||
|
|
if (data.type == 'config_data') {
|
||
|
|
this.files = data.content;
|
||
|
|
} else if (data.type == 'fileOptions') {
|
||
|
|
this.fileOptions = data.content;
|
||
|
|
}
|
||
|
|
});
|
||
|
|
this.socket.on('server_log', (data) => {
|
||
|
|
this.ServerLog = "";
|
||
|
|
this.ServerLog = data.content;
|
||
|
|
});
|
||
|
|
|
||
|
|
}
|
||
|
|
});
|
||
|
|
</script>
|
||
|
|
</body>
|
||
|
|
</html>
|