优化页面

This commit is contained in:
lj124 2026-04-17 20:42:21 +08:00
parent 146b071737
commit 47032dd19d
7 changed files with 1980 additions and 1624 deletions

41
package-lock.json generated
View File

@ -23,7 +23,8 @@
"vue": "^3.3.11", "vue": "^3.3.11",
"vue-cookies": "^1.8.3", "vue-cookies": "^1.8.3",
"vue-qr": "^4.0.9", "vue-qr": "^4.0.9",
"vue-router": "^4.2.5" "vue-router": "^4.2.5",
"vue-virtual-scroller": "^2.0.0-beta.8"
}, },
"devDependencies": { "devDependencies": {
"@vitejs/plugin-vue": "^4.6.2", "@vitejs/plugin-vue": "^4.6.2",
@ -1687,6 +1688,12 @@
"node": ">=10" "node": ">=10"
} }
}, },
"node_modules/mitt": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/mitt/-/mitt-2.1.0.tgz",
"integrity": "sha512-ILj2TpLiysu2wkBbWjAmww7TkZb65aiQO+DkVdUTBpBXq+MHYiETENkKFMtsJZX1Lf4pe4QOrTSjIfUwN5lRdg==",
"license": "MIT"
},
"node_modules/mpd-parser": { "node_modules/mpd-parser": {
"version": "1.3.0", "version": "1.3.0",
"resolved": "https://registry.npmjs.org/mpd-parser/-/mpd-parser-1.3.0.tgz", "resolved": "https://registry.npmjs.org/mpd-parser/-/mpd-parser-1.3.0.tgz",
@ -2269,6 +2276,15 @@
"resolved": "https://registry.npmjs.org/vue-cookies/-/vue-cookies-1.8.3.tgz", "resolved": "https://registry.npmjs.org/vue-cookies/-/vue-cookies-1.8.3.tgz",
"integrity": "sha512-VBRsyRMVdahBgFfh389TMHPmDdr4URDJNMk4FKSCfuNITs7+jitBDhwyL4RJd3WUsfOYNNjPAkfbehyH9AFuoA==" "integrity": "sha512-VBRsyRMVdahBgFfh389TMHPmDdr4URDJNMk4FKSCfuNITs7+jitBDhwyL4RJd3WUsfOYNNjPAkfbehyH9AFuoA=="
}, },
"node_modules/vue-observe-visibility": {
"version": "2.0.0-alpha.1",
"resolved": "https://registry.npmjs.org/vue-observe-visibility/-/vue-observe-visibility-2.0.0-alpha.1.tgz",
"integrity": "sha512-flFbp/gs9pZniXR6fans8smv1kDScJ8RS7rEpMjhVabiKeq7Qz3D9+eGsypncjfIyyU84saU88XZ0zjbD6Gq/g==",
"license": "MIT",
"peerDependencies": {
"vue": "^3.0.0"
}
},
"node_modules/vue-qr": { "node_modules/vue-qr": {
"version": "4.0.9", "version": "4.0.9",
"resolved": "https://registry.npmjs.org/vue-qr/-/vue-qr-4.0.9.tgz", "resolved": "https://registry.npmjs.org/vue-qr/-/vue-qr-4.0.9.tgz",
@ -2280,6 +2296,15 @@
"string-split-by": "^1.0.0" "string-split-by": "^1.0.0"
} }
}, },
"node_modules/vue-resize": {
"version": "2.0.0-alpha.1",
"resolved": "https://registry.npmjs.org/vue-resize/-/vue-resize-2.0.0-alpha.1.tgz",
"integrity": "sha512-7+iqOueLU7uc9NrMfrzbG8hwMqchfVfSzpVlCMeJQe4pyibqyoifDNbKTZvwxZKDvGkB+PdFeKvnGZMoEb8esg==",
"license": "MIT",
"peerDependencies": {
"vue": "^3.0.0"
}
},
"node_modules/vue-router": { "node_modules/vue-router": {
"version": "4.2.5", "version": "4.2.5",
"resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.2.5.tgz", "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.2.5.tgz",
@ -2294,6 +2319,20 @@
"vue": "^3.2.0" "vue": "^3.2.0"
} }
}, },
"node_modules/vue-virtual-scroller": {
"version": "2.0.0-beta.8",
"resolved": "https://registry.npmjs.org/vue-virtual-scroller/-/vue-virtual-scroller-2.0.0-beta.8.tgz",
"integrity": "sha512-b8/f5NQ5nIEBRTNi6GcPItE4s7kxNHw2AIHLtDp+2QvqdTjVN0FgONwX9cr53jWRgnu+HRLPaWDOR2JPI5MTfQ==",
"license": "MIT",
"dependencies": {
"mitt": "^2.1.0",
"vue-observe-visibility": "^2.0.0-alpha.1",
"vue-resize": "^2.0.0-alpha.1"
},
"peerDependencies": {
"vue": "^3.2.0"
}
},
"node_modules/which-module": { "node_modules/which-module": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz",

View File

@ -24,7 +24,8 @@
"vue": "^3.3.11", "vue": "^3.3.11",
"vue-cookies": "^1.8.3", "vue-cookies": "^1.8.3",
"vue-qr": "^4.0.9", "vue-qr": "^4.0.9",
"vue-router": "^4.2.5" "vue-router": "^4.2.5",
"vue-virtual-scroller": "^2.0.0-beta.8"
}, },
"devDependencies": { "devDependencies": {
"@vitejs/plugin-vue": "^4.6.2", "@vitejs/plugin-vue": "^4.6.2",

View File

@ -1,6 +1,7 @@
<script> <script>
import axios from "axios"; import axios from "axios";
import { inject } from "vue"; import { ElMessage } from "element-plus";
import { Refresh, Plus, Edit, Delete, View } from "@element-plus/icons-vue";
import { getCIDLogListService } from "@/api/cid.js"; import { getCIDLogListService } from "@/api/cid.js";
import { runCIDService } from "@/api/cid.js"; import { runCIDService } from "@/api/cid.js";
import { addCIDService } from "@/api/cid.js"; import { addCIDService } from "@/api/cid.js";
@ -8,8 +9,14 @@ import { deleteCIDService } from "@/api/cid.js";
import { updateCIDService } from "@/api/cid.js"; import { updateCIDService } from "@/api/cid.js";
import router from "@/router/index.js"; import router from "@/router/index.js";
export default { export default {
components: {
Refresh,
Plus,
Edit,
Delete,
View
},
data() { data() {
return { return {
ip: "", ip: "",
@ -32,6 +39,7 @@ export default {
script: "", script: "",
end: "", end: "",
error: "", error: "",
RunTime: ""
}, },
}; };
}, },
@ -50,9 +58,9 @@ export default {
try { try {
this.tokenData.id = parseInt(this.tokenData.id); this.tokenData.id = parseInt(this.tokenData.id);
result = await getCIDLogListService(this.tokenData); result = await getCIDLogListService(this.tokenData);
this.loading = false;
} catch (e) { } catch (e) {
console.log(e); console.log(e);
} finally {
this.loading = false; this.loading = false;
} }
let data = result.data; let data = result.data;
@ -62,8 +70,7 @@ export default {
this.tableData = data; this.tableData = data;
for(let i = 0;i<this.tableData.length;i++) { for(let i = 0;i<this.tableData.length;i++) {
this.tableData[i].UpdatedAt = this.formattedTime(this.tableData[i].UpdatedAt); this.tableData[i].UpdatedAt = this.formattedTime(this.tableData[i].UpdatedAt);
this.tableData[i].CreatedAt = this.formattedTime(this.tableData[i].CreatedAt) this.tableData[i].CreatedAt = this.formattedTime(this.tableData[i].CreatedAt);
//console.log('this.ConfigFileList:',this.ConfigFileList);
} }
this.handleCurrentChange(1); this.handleCurrentChange(1);
}, },
@ -83,6 +90,7 @@ export default {
}, },
handleSizeChange(val) { handleSizeChange(val) {
this.pageSize = val; this.pageSize = val;
this.handleCurrentChange(this.currentPage);
}, },
handleCurrentChange(val) { handleCurrentChange(val) {
this.currentPage = val; this.currentPage = val;
@ -104,9 +112,9 @@ export default {
try { try {
var d_re = await runCIDService(run_data); var d_re = await runCIDService(run_data);
if (d_re.code == 0) { if (d_re.code == 0) {
alert("操作成功"); ElMessage.success("操作成功");
} else { } else {
alert("操作失败"); ElMessage.error("操作失败");
} }
} catch (e) { } catch (e) {
console.log(e); console.log(e);
@ -122,11 +130,10 @@ export default {
try { try {
var d_re = await deleteCIDService(delete_data); var d_re = await deleteCIDService(delete_data);
if (d_re.code == 0) { if (d_re.code == 0) {
alert("删除成功"); ElMessage.success("删除成功");
// this.getCIDLogList();
this.getDeviceList();
} else { } else {
alert("操作失败"); ElMessage.error("操作失败");
} }
} catch (e) { } catch (e) {
console.log(e); console.log(e);
@ -134,12 +141,6 @@ export default {
}, },
async updateButtonLogCID(index) { async updateButtonLogCID(index) {
this.updateDialogVisible = true; this.updateDialogVisible = true;
// var id = this.tableData[index].ID;
// this.updateForm.create_time = this.tableData[index].CreatedAt;
// this.updateForm.script = this.tableData[index].Script;
// this.updateForm.end = this.tableData[index].Log;
// this.updateForm.error = this.tableData[index].Error;
// this.updateForm.RunTime = this.tableData[index].RunTime;
var id = this.currentPageData[index].ID; var id = this.currentPageData[index].ID;
this.updateForm.create_time = this.currentPageData[index].CreatedAt; this.updateForm.create_time = this.currentPageData[index].CreatedAt;
this.updateForm.script = this.currentPageData[index].Script; this.updateForm.script = this.currentPageData[index].Script;
@ -152,7 +153,6 @@ export default {
const response = await axios.get("https://ipinfo.io/json"); const response = await axios.get("https://ipinfo.io/json");
this.ip = response.data.ip; this.ip = response.data.ip;
localStorage.setItem("ip", this.ip); localStorage.setItem("ip", this.ip);
//console.log(response);
} catch (error) { } catch (error) {
console.error(error); console.error(error);
} }
@ -182,7 +182,6 @@ export default {
if (localStorage.getItem("token") === null) { if (localStorage.getItem("token") === null) {
router.push("/login"); router.push("/login");
} }
// console.log("mounted");
this.getIpClient(); this.getIpClient();
this.getCIDLogList(); this.getCIDLogList();
}, },
@ -190,133 +189,76 @@ export default {
</script> </script>
<template> <template>
<div> <div class="page-container">
<el-container style="min-height: calc(100vh - 40px); background: #fff; border-radius: 4px;"> <el-card class="page-card" shadow="never">
<el-header style="font-size: 40px; background-color: rgb(238, 241, 246)" <template #header>
>集成部署项目日志{{ tokenData.id }}</el-header <div class="card-header">
> <div class="header-left">
<el-container> <span class="page-title">集成部署项目日志 {{ tokenData.id }}</span>
<el-main> </div>
<!-- 表单 --> <div class="header-actions">
<el-form :inline="true" :model="tokenData" class="demo-form-inline"> <el-button @click="getCIDLogList()" :icon="Refresh">
<el-form-item> 刷新
<el-button </el-button>
class="el-button--danger" </div>
type="primary" </div>
@click="getCIDLogList()"
:disabled="loading"
>刷新</el-button
>
</el-form-item>
<el-form-item>
<el-dialog
v-model="updateDialogVisible"
title="查看集成项目日志"
width="50%"
:before-close="handleClose"
>
<!-- 内容主体区域 -->
<el-form
ref="addFormRef"
:model="updateForm"
:rules="updateFormRules"
label-width="70px"
>
<el-form-item label="创建时间" prop="create_time">
<el-input
v-model="updateForm.create_time"
autocomplete="on"
style="width: 600px"
></el-input>
</el-form-item>
<el-col>
<el-form-item label="执行时间" prop="run_time">
<el-input
v-model="updateForm.RunTime"
autocomplete="on"
style="width: 100px"
></el-input>
</el-form-item>
</el-col>
<el-form-item label="脚本内容" prop="script">
<el-input type="textarea" v-model="updateForm.script" style="width: 700px" :autosize="{ minRows: 4, maxRows: 8 }" />
</el-form-item>
<el-form-item label="执行结果" prop="end">
<el-input type="textarea" v-model="updateForm.end" style="width: 700px" :autosize="{ minRows: 4, maxRows: 8 }" />
</el-form-item>
<el-col>
<el-form-item label="错误内容" prop="error">
<el-input type="textarea" v-model="updateForm.error" style="width: 700px" :autosize="{ minRows: 4, maxRows: 8 }" />
</el-form-item>
</el-col>
</el-form>
<!-- 底部区域 -->
<template #footer>
<span class="dialog-footer">
<el-button @click="updateDialogVisible = false"
>关闭</el-button
>
</span>
</template> </template>
</el-dialog>
</el-form-item>
</el-form>
<!-- 表格 :row-style="this.tableRowClassName"--> <div class="table-wrapper">
<el-table <el-table
:data="currentPageData" :data="currentPageData"
width="100%" style="width: 100%"
v-loading="loading" v-loading="loading"
element-loading-text="数据加载中..." element-loading-text="数据加载中..."
element-loading-background="rgba(240, 242, 245, 0.8)"
stripe
:row-class-name="tableRowClassName"
> >
:row-style="this.tableRowClassName" <el-table-column prop="ID" label="ID" width="80"></el-table-column>
<el-table-column prop="ID" label="id" width="80"></el-table-column>
<el-table-column <el-table-column
prop="CreatedAt" prop="CreatedAt"
label="创建时间" label="创建时间"
min-width="160"
show-overflow-tooltip show-overflow-tooltip
width="200"
></el-table-column> ></el-table-column>
<el-table-column <el-table-column
prop="Script" prop="Script"
label="执行脚本" label="执行脚本"
width="180" min-width="180"
show-overflow-tooltip show-overflow-tooltip
></el-table-column> ></el-table-column>
<el-table-column <el-table-column
prop="Log" prop="Log"
label="运行日志" label="运行日志"
width="180" min-width="180"
show-overflow-tooltip show-overflow-tooltip
></el-table-column> ></el-table-column>
<el-table-column <el-table-column
prop="Error" prop="Error"
label="错误信息" label="错误信息"
width="250" min-width="250"
show-overflow-tooltip
></el-table-column> ></el-table-column>
<el-table-column <el-table-column
prop="RunTime" prop="RunTime"
label="运行时间(s)" label="运行时间(s)"
width="80" width="100"
></el-table-column> ></el-table-column>
<el-table-column label="操作" width="350"> <el-table-column label="操作" width="120" fixed="right">
<template #default="scope"> <template #default="scope">
<el-button <el-button
type="primary" type="primary"
size="mini" size="small"
@click.prevent="updateButtonLogCID(scope.$index)" @click.prevent="updateButtonLogCID(scope.$index)"
>详情</el-button :icon="View"
> >
<!-- <el-button type="danger" size="mini">删除</el-button> --> 详情
</el-button>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
<br />
<!-- 分页条 --> <div class="pagination-wrapper">
<el-pagination <el-pagination
@size-change="handleSizeChange" @size-change="handleSizeChange"
@current-change="handleCurrentChange" @current-change="handleCurrentChange"
@ -324,15 +266,148 @@ export default {
:page-sizes="[10, 20, 50, 100]" :page-sizes="[10, 20, 50, 100]"
:page-size="pageSize" :page-size="pageSize"
layout="total, sizes, prev, pager, next, jumper" layout="total, sizes, prev, pager, next, jumper"
:total="tableData.length"> :total="tableData.length"
>
</el-pagination> </el-pagination>
</el-main> </div>
</el-container> </div>
</el-container> </el-card>
<!-- 查看日志对话框 -->
<el-dialog
v-model="updateDialogVisible"
title="查看集成项目日志"
width="70%"
:close-on-click-modal="false"
top="5vh"
>
<el-form
ref="addFormRef"
:model="updateForm"
label-width="100px"
class="form-dialog"
>
<el-row gutter="20">
<el-col :span="12">
<el-form-item label="创建时间">
<el-input
v-model="updateForm.create_time"
autocomplete="on"
disabled
></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="执行时间">
<el-input
v-model="updateForm.RunTime"
autocomplete="on"
disabled
></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-form-item label="脚本内容">
<el-input type="textarea" v-model="updateForm.script" :rows="4" disabled></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-form-item label="执行结果">
<el-input type="textarea" v-model="updateForm.end" :rows="4" disabled></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-form-item label="错误内容">
<el-input type="textarea" v-model="updateForm.error" :rows="4" disabled></el-input>
</el-form-item>
</el-col>
</el-row>
</el-form>
<!-- 底部区域 -->
<template #footer>
<div class="dialog-footer">
<el-button @click="updateDialogVisible = false">关闭</el-button>
</div> </div>
</template> </template>
<style> </el-dialog>
.blueRowbg { </div>
background: "#488aff"; </template>
<style scoped>
.page-container {
width: 100%;
height: 100%;
}
.page-card {
height: 100%;
display: flex;
flex-direction: column;
border: none;
border-radius: 8px;
}
.page-card :deep(.el-card__body) {
flex: 1;
overflow: hidden;
padding: 20px;
display: flex;
flex-direction: column;
}
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
}
.header-left {
display: flex;
align-items: center;
}
.page-title {
font-size: 18px;
font-weight: 600;
color: #303133;
}
.header-actions {
display: flex;
align-items: center;
gap: 12px;
}
.table-wrapper {
flex: 1;
overflow: auto;
display: flex;
flex-direction: column;
}
.table-wrapper :deep(.el-table) {
border-radius: 4px;
}
.pagination-wrapper {
margin-top: 16px;
display: flex;
justify-content: flex-end;
}
.form-dialog {
padding: 10px 0;
}
.dialog-footer {
display: flex;
justify-content: flex-end;
gap: 12px;
} }
</style> </style>

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +1,8 @@
<script> <script>
import router from "@/router/index.js"; import router from "@/router/index.js";
import { autoResizerProps, ElMessage } from "element-plus"; import { ElMessage } from "element-plus";
import CryptoJS from "crypto-js"; import CryptoJS from "crypto-js";
import { Refresh, Plus, Edit, Delete, Document } from "@element-plus/icons-vue";
import { getConfigFileListService } from "@/api/file.js"; import { getConfigFileListService } from "@/api/file.js";
import { addConfigFileService } from "@/api/file.js"; import { addConfigFileService } from "@/api/file.js";
@ -10,6 +10,13 @@ import { deleteConfigFileService } from "@/api/file.js";
import { updateConfigFileService } from "@/api/file.js"; import { updateConfigFileService } from "@/api/file.js";
export default { export default {
components: {
Refresh,
Plus,
Edit,
Delete,
Document
},
data() { data() {
return { return {
ip: "", ip: "",
@ -22,13 +29,13 @@ export default {
ConfigFileCurrentPageData: [], ConfigFileCurrentPageData: [],
pageSize: 10, pageSize: 10,
currentPage: 1, currentPage: 1,
upload_file: null, // upload_file: null,
file_md5: "", //md5 file_md5: "",
addForm: { addForm: {
file_name: "", file_name: "",
file_path: "", file_path: "",
}, },
loading: false, // loading: false,
server_list: [ server_list: [
{ label: "js.ljsea.top", value: "js.ljsea.top" }, { label: "js.ljsea.top", value: "js.ljsea.top" },
{ label: "tx.ljsea.top", value: "tx.ljsea.top" }, { label: "tx.ljsea.top", value: "tx.ljsea.top" },
@ -36,7 +43,6 @@ export default {
{ label: "as.ljsea.top", value: "as.ljsea.top" }, { label: "as.ljsea.top", value: "as.ljsea.top" },
{ label: 'al.ljsea.top', value: "al.ljsea.top" } { label: 'al.ljsea.top', value: "al.ljsea.top" }
], ],
role: "", role: "",
tokenData: { tokenData: {
token: localStorage.getItem("token"), token: localStorage.getItem("token"),
@ -50,14 +56,11 @@ export default {
}; };
}, },
// methods
//
methods: { methods: {
async getConfigFileList() { async getConfigFileList() {
this.loading = true; this.loading = true;
let result = {}; let result = {};
try { try {
//search_id
let req = { let req = {
token: this.tokenData.token, token: this.tokenData.token,
type: "all", type: "all",
@ -67,7 +70,6 @@ export default {
if (data !== undefined && data !== null) { if (data !== undefined && data !== null) {
this.tableData = data; this.tableData = data;
} }
} catch (e) { } catch (e) {
console.log(e); console.log(e);
ElMessage.error("获取文件列表失败"); ElMessage.error("获取文件列表失败");
@ -76,8 +78,7 @@ export default {
} }
for(let i = 0;i<this.tableData.length;i++) { for(let i = 0;i<this.tableData.length;i++) {
this.tableData[i].UpdatedAt = this.formattedTime(this.tableData[i].UpdatedAt); this.tableData[i].UpdatedAt = this.formattedTime(this.tableData[i].UpdatedAt);
this.tableData[i].CreatedAt = this.formattedTime(this.tableData[i].CreatedAt) this.tableData[i].CreatedAt = this.formattedTime(this.tableData[i].CreatedAt);
//console.log('this.ConfigFileList:',this.ConfigFileList);
} }
this.currentPageData(); this.currentPageData();
}, },
@ -103,6 +104,10 @@ export default {
ElMessage.success("添加成功"); ElMessage.success("添加成功");
this.getConfigFileList(); this.getConfigFileList();
this.addConfigFileVisible = false; this.addConfigFileVisible = false;
this.addForm = {
file_name: "",
file_path: "",
};
} else { } else {
ElMessage.error("添加失败"); ElMessage.error("添加失败");
} }
@ -114,7 +119,6 @@ export default {
} }
}, },
async deleteConfigFile(index) { async deleteConfigFile(index) {
//
let isDelete = confirm("是否删除?"); let isDelete = confirm("是否删除?");
if (!isDelete) { if (!isDelete) {
return; return;
@ -156,33 +160,6 @@ export default {
this.ConfigFileUpdateForm = data[0]; this.ConfigFileUpdateForm = data[0];
this.updateDialogVisible = true; this.updateDialogVisible = true;
}, },
handleAvatarFileUpload(e) {
this.avatar_file = e.target.files[0];
//
if (!this.avatar_file.type.startsWith("image/")) {
ElMessage.error("请选择图片文件");
this.avatar_file = null;
return;
}
this.uploadAvatarFile();
},
readFileAndCalculateMD5() {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = (event) => {
const wordArray = CryptoJS.lib.WordArray.create(event.target.result);
const md5Hash = CryptoJS.MD5(wordArray);
const md5Str = md5Hash.toString(CryptoJS.enc.Hex);
//console.log("onload: " + md5Str);
this.file_md5 = md5Str;
resolve(md5Str);
};
reader.onerror = (error) => {
reject(error);
};
reader.readAsArrayBuffer(this.avatar_file);
});
},
formattedTime(isoTime) { formattedTime(isoTime) {
const date = new Date(isoTime); const date = new Date(isoTime);
const year = date.getFullYear(); const year = date.getFullYear();
@ -194,51 +171,6 @@ export default {
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`; return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
}, },
async uploadFile() {
if (this.avatar_file == null) {
alert("请先选择要上传的文件");
return;
}
try {
let result = {};
this.file_md5 = await this.readFileAndCalculateMD5(this.avatar_file);
//console.log("md5:",this.file_md5);
let md5_result = await GetFileInfoByMd5Service({
md5: this.file_md5,
token: this.tokenData.token,
type: 1,
});
if (md5_result.code === 0) {
result = md5_result;
} else {
let formData = new FormData();
formData.append("file", this.avatar_file);
//console.log("add file: " + this.file);
formData.append("upload_type", "1");
formData.append("md5", this.file_md5);
formData.append("auth_type", "public");
//console.log("formData:",formData);
result = await UploadFileService(formData, this.tokenData.token);
if (result.code !== 0) {
ElMessage.error("上传文件失败,请稍后再试");
return;
}
}
let resp_data = result.data;
//console.log("resp:",resp_data);
let url = "https://gep.ljsea.top/tool/file/" + resp_data.FileStoreName;
this.UserUpdateForm.avatar = url;
//
await this.updateUserInfo();
} catch (error) {
ElMessage.error("上传文件时出现网络错误,请稍后再试");
console.error(error);
}
},
async updateConfigFileInfo() { async updateConfigFileInfo() {
this.loading = true; this.loading = true;
let result = {}; let result = {};
@ -248,9 +180,6 @@ export default {
id: this.ConfigFileUpdateForm.id, id: this.ConfigFileUpdateForm.id,
content: this.ConfigFileUpdateForm.content, content: this.ConfigFileUpdateForm.content,
}; };
for (var key in this.UserUpdateForm) {
req[key] = this.UserUpdateForm[key];
}
result = await updateConfigFileService(req); result = await updateConfigFileService(req);
if (result.code === 0) { if (result.code === 0) {
ElMessage.success("更新成功"); ElMessage.success("更新成功");
@ -265,7 +194,6 @@ export default {
this.loading = false; this.loading = false;
} }
}, },
onSubmit() { onSubmit() {
getConfigFileList(); getConfigFileList();
}, },
@ -276,32 +204,19 @@ export default {
); );
}, },
handleSizeChange(val) { handleSizeChange(val) {
//console.log(` ${val} `);
this.pageSize = val; this.pageSize = val;
this.currentPageData(); this.currentPageData();
}, },
handleCurrentChange(val) { handleCurrentChange(val) {
//console.log(`: ${val}`);
this.currentPage = val; this.currentPage = val;
this.currentPageData(); this.currentPageData();
}, },
async displayMyInfo() {
await this.getMyUserInfo(this.tokenData.user_id);
this.updateDialogVisible = true;
},
async displayUserInfo(id) {
await this.getMyUserInfo(id);
this.updateDialogVisible = true;
},
handleMenuSelect(val) { handleMenuSelect(val) {
router.push(val); router.push(val);
}, },
toVideoList() { toVideoList() {
router.push("/videoList"); router.push("/videoList");
}, },
//
tableRowClassName({ row, rowIndex }) { tableRowClassName({ row, rowIndex }) {
if (row.human === 1) { if (row.human === 1) {
return { return {
@ -313,153 +228,107 @@ export default {
}, },
}, },
//
//
async mounted() { async mounted() {
let now = new Date(); let now = new Date();
if (localStorage.getItem("token") === null) { if (localStorage.getItem("token") === null) {
router.push("/login"); router.push("/login");
} }
await this.getConfigFileList(); await this.getConfigFileList();
//await this.getMyUserInfo(localStorage.getItem("userId"));
}, },
}; };
</script> </script>
<template> <template>
<div> <div class="page-container">
<el-container style="min-height: calc(100vh - 40px); background: #fff; border-radius: 4px;"> <el-card class="page-card" shadow="never">
<el-header style="font-size: 28px; font-weight: 500; background-color: #f5f7fa; display: flex; align-items: center; padding: 0 20px; border-bottom: 1px solid #e4e7ed;" <template #header>
>配置文件管理</el-header <div class="card-header">
> <div class="header-left">
<el-container> <span class="page-title">配置文件管理</span>
<el-main> </div>
<el-form :inline="true" :model="tokenData" class="demo-form-inline"> <div class="header-actions">
<el-form-item>
<el-dialog
v-model="updateDialogVisible"
title="编辑配置文件"
width="70%"
:before-close="handleClose"
top="3vh"
:close-on-click-modal="false"
>
<!-- 内容主体区域 -->
<el-form
ref="updateFormRef"
:model="ConfigFileUpdateForm"
:rules="UserUpdateFormRules"
label-width="90px"
>
<!-- row -->
<el-row gutter="20">
<el-col :span="12">
<el-form-item label="ID">
<el-input
v-model="ConfigFileUpdateForm.id"
disabled
></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="文件名称">
<el-input
v-model="ConfigFileUpdateForm.file_name"
disabled
></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-form-item label="文件路径">
<el-input
v-model="ConfigFileUpdateForm.file_path"
disabled
></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-form-item label="文件内容" prop="device_status">
<el-input
type="textarea"
v-model="ConfigFileUpdateForm.content"
style="font-family: 'Consolas', 'Monaco', monospace; font-size: 14px; line-height: 1.6; min-height: 650px; width: 800px;"
:autosize="{ minRows: 20, maxRows: 60 }"
/>
</el-form-item>
</el-col>
</el-row>
</el-form>
<!-- 底部区域 -->
<template #footer>
<span class="dialog-footer">
<el-button @click="updateDialogVisible = false"
>取消</el-button
>
<el-button type="primary" @click="updateConfigFileInfo()"
>确定</el-button
>
</span>
</template>
</el-dialog>
</el-form-item>
<!-- 表单 -->
<el-form :inline="true" :model="tokenData" class="demo-form-inline">
<el-form-item>
<el-button
type="primary"
@click="getConfigFileList()"
>刷新列表</el-button
>
</el-form-item>
<el-form-item>
<el-button
type="success"
@click="addConfigFileV()"
>添加配置文件</el-button
>
</el-form-item>
<!-- 选择服务器 -->
<el-form-item>
<el-select <el-select
v-model="tokenData.server" v-model="tokenData.server"
filterable allow-create filterable
allow-create
@change="handleServerChange" @change="handleServerChange"
style="width: 200px;"
placeholder="选择服务器"
> >
<el-option v-for="item in server_list" :key="item.value" :label="item.label" :value="item.value"></el-option> <el-option v-for="item in server_list" :key="item.value" :label="item.label" :value="item.value"></el-option>
</el-select> </el-select>
</el-form-item> <el-button type="primary" @click="addConfigFileV()" :icon="Plus">
</el-form> 添加配置文件
</el-form> </el-button>
<el-button @click="getConfigFileList()" :icon="Refresh">
刷新列表
</el-button>
</div>
</div>
</template>
<div class="table-wrapper">
<el-table
:data="ConfigFileCurrentPageData"
style="width: 100%"
v-loading="loading"
element-loading-text="加载中..."
element-loading-background="rgba(240, 242, 245, 0.8)"
stripe
:row-class-name="tableRowClassName"
>
<el-table-column prop="ID" label="ID" width="80"></el-table-column>
<el-table-column prop="FileName" label="文件名称" min-width="150"></el-table-column>
<el-table-column prop="FilePath" label="文件路径" min-width="200" show-overflow-tooltip></el-table-column>
<el-table-column prop="CreatedAt" label="创建时间" min-width="160"></el-table-column>
<el-table-column prop="UpdatedAt" label="上次更新" min-width="160"></el-table-column>
<el-table-column prop="AuthID" label="创建用户ID" width="120"></el-table-column>
<el-table-column label="操作" width="200" fixed="right">
<template #default="scope">
<el-button type="primary" size="small" @click.prevent="updateConfigFile(scope.$index)" :icon="Edit">
编辑
</el-button>
<el-button type="danger" size="small" @click.prevent="deleteConfigFile(scope.$index)" :icon="Delete">
删除
</el-button>
</template>
</el-table-column>
</el-table>
<div class="pagination-wrapper">
<el-pagination
background
layout="total,sizes, prev, pager, next, jumper"
:page-sizes="[10, 20, 50, 100]"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:total="tableData.length"
></el-pagination>
</div>
</div>
</el-card>
<el-dialog <el-dialog
v-model="addConfigFileVisible" v-model="addConfigFileVisible"
title="添加配置文件" title="添加配置文件"
width="600px" width="500px"
:before-close="handleClose" :close-on-click-modal="false"
top="15vh" top="15vh"
> >
<!-- 内容主体区域 -->
<el-form <el-form
ref="addFormRef" ref="addFormRef"
:model="addForm" :model="addForm"
:rules="addFormRules"
label-width="90px" label-width="90px"
style="padding: 20px 10px;" class="form-dialog"
> >
<el-form-item label="文件名称" prop="file_name"> <el-form-item label="文件名称">
<el-input <el-input
v-model="addForm.file_name" v-model="addForm.file_name"
autocomplete="on" autocomplete="on"
placeholder="请输入文件名称" placeholder="请输入文件名称"
></el-input> ></el-input>
</el-form-item> </el-form-item>
<el-form-item label="文件路径" prop="file_path"> <el-form-item label="文件路径">
<el-input <el-input
v-model="addForm.file_path" v-model="addForm.file_path"
autocomplete="on" autocomplete="on"
@ -467,90 +336,138 @@ export default {
></el-input> ></el-input>
</el-form-item> </el-form-item>
</el-form> </el-form>
<!-- 底部区域 -->
<template #footer> <template #footer>
<span class="dialog-footer"> <div class="dialog-footer">
<el-button @click="addConfigFileVisible = false" <el-button @click="addConfigFileVisible = false">取消</el-button>
>取消</el-button <el-button type="primary" @click="addConfigFile()">确定</el-button>
> </div>
<el-button type="primary" @click="addConfigFile()"
>确定</el-button
>
</span>
</template> </template>
</el-dialog> </el-dialog>
<!-- 表格 :row-style="this.tableRowClassName"--> <el-dialog
<el-table v-model="updateDialogVisible"
:data="ConfigFileCurrentPageData" title="编辑配置文件"
width="100%" width="70%"
v-loading="loading" top="3vh"
element-loading-text="加载中..." :close-on-click-modal="false"
element-loading-background="rgba(240, 242, 245, 0.8)"
border
stripe
style="margin-top: 20px;"
> >
:row-style="this.tableRowClassName" <el-form
<el-table-column prop="ID" label="id" width="80"></el-table-column> ref="updateFormRef"
<el-table-column :model="ConfigFileUpdateForm"
prop="FileName" label-width="90px"
label="文件名称" class="form-dialog"
width="120"
></el-table-column>
<el-table-column
prop="FilePath"
label="文件路径"
width="180"
></el-table-column>
<el-table-column
prop="CreatedAt"
label="创建时间"
width="160"
></el-table-column>
<el-table-column
prop="UpdatedAt"
label="上次更新"
width="160"
></el-table-column>
<el-table-column
prop="AuthID"
label="创建用户ID"
width="100"
></el-table-column>
<el-table-column label="操作" width="200">
<template #default="scope">
<el-button
type="primary"
size="mini"
@click.prevent="updateConfigFile(scope.$index)"
>编辑</el-button
> >
<el-button <el-row gutter="20">
type="primary" <el-col :span="12">
size="mini" <el-form-item label="ID">
@click.prevent="deleteConfigFile(scope.$index)" <el-input v-model="ConfigFileUpdateForm.id" disabled></el-input>
>删除</el-button </el-form-item>
> </el-col>
</template> <el-col :span="12">
</el-table-column> <el-form-item label="文件名称">
</el-table> <el-input v-model="ConfigFileUpdateForm.file_name" disabled></el-input>
<!-- 分页条 --> </el-form-item>
<!-- Pagination 分页 --> </el-col>
<el-pagination </el-row>
background <el-row>
layout="total,sizes, prev, pager, next, jumper" <el-col :span="24">
@size-change="handleSizeChange" <el-form-item label="文件路径">
@current-change="handleCurrentChange" <el-input v-model="ConfigFileUpdateForm.file_path" disabled></el-input>
:total="10" </el-form-item>
></el-pagination> </el-col>
</el-main> </el-row>
</el-container> <el-row>
</el-container> <el-col :span="24">
<el-form-item label="文件内容">
<el-input
type="textarea"
v-model="ConfigFileUpdateForm.content"
style="font-family: 'Consolas', 'Monaco', monospace; font-size: 14px; line-height: 1.6;"
:autosize="{ minRows: 20, maxRows: 40 }"
/>
</el-form-item>
</el-col>
</el-row>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button @click="updateDialogVisible = false">取消</el-button>
<el-button type="primary" @click="updateConfigFileInfo()">确定</el-button>
</div> </div>
</template> </template>
</el-dialog>
</div>
</template>
<style scoped> <style scoped>
.blueRowbg { .page-container {
background: "#488aff"; width: 100%;
height: 100%;
}
.page-card {
height: 100%;
display: flex;
flex-direction: column;
border: none;
border-radius: 8px;
}
.page-card :deep(.el-card__body) {
flex: 1;
overflow: hidden;
padding: 20px;
display: flex;
flex-direction: column;
}
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
}
.header-left {
display: flex;
align-items: center;
}
.page-title {
font-size: 18px;
font-weight: 600;
color: #303133;
}
.header-actions {
display: flex;
align-items: center;
gap: 12px;
}
.table-wrapper {
flex: 1;
overflow: auto;
display: flex;
flex-direction: column;
}
.table-wrapper :deep(.el-table) {
border-radius: 4px;
}
.pagination-wrapper {
margin-top: 16px;
display: flex;
justify-content: flex-end;
}
.form-dialog {
padding: 10px 0;
}
.dialog-footer {
display: flex;
justify-content: flex-end;
gap: 12px;
} }
</style> </style>

View File

@ -1,82 +1,75 @@
<template> <template>
<div style="padding: 10px; margin-bottom: 50px"> <div class="page-container">
<el-button <el-card class="page-card" shadow="never">
type="primary" <template #header>
size="mini" <div class="card-header">
@click.prevent="handleMenuSelect('/User')" <div class="header-left">
>用户</el-button <span class="page-title">聊天窗口 - {{ chatUser }}</span>
>
<el-row v-loading="loading" element-loading-text="正在连接....">
<el-col :span="16">
<div
style="
width: 800px;
margin: 0 auto;
background-color: white;
border-radius: 5px;
box-shadow: 0 0 10px #ccc;
"
>
<div style="text-align: center; line-height: 50px">
{{ chatUser }}
</div> </div>
<div <div class="header-actions">
style="height: 350px; overflow: auto; border-top: 1px solid #ccc" <el-button type="primary" size="small" @click.prevent="handleMenuSelect('/user')" :icon="User">
v-html="content" 返回用户列表
></div> </el-button>
<div style="height: 200px">
<textarea
v-model="text"
style="
height: 160px;
width: 100%;
padding: 20px;
border: none;
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
outline: none;
"
></textarea>
<div style="text-align: right; padding-right: 10px">
<el-button type="primary" size="mini" @click="send"
>发送</el-button
>
</div> </div>
</div> </div>
</div>
</el-col>
</el-row>
</div>
</template> </template>
<div class="chat-container" v-loading="loading" element-loading-text="正在连接...">
<div class="chat-header">
<div class="chat-user-info">
<el-avatar size="small" :src="circleUrl" style="margin-right: 8px;"></el-avatar>
<span class="chat-user-name">{{ chatUser }}</span>
</div>
</div>
<div class="chat-messages" v-html="content"></div>
<div class="chat-input-area">
<el-input
v-model="text"
type="textarea"
:rows="4"
placeholder="请输入消息..."
resize="none"
></el-input>
<div class="chat-actions">
<el-button type="primary" @click="send">
发送
</el-button>
</div>
</div>
</div>
</el-card>
</div>
</template>
<script> <script>
import { ref, onMounted, inject, onUnmounted } from "vue"; import { ref, onMounted, onUnmounted } from "vue";
import { User } from "@element-plus/icons-vue";
import { getImKeyService } from "@/api/im.js"; import { getImKeyService } from "@/api/im.js";
import router from "@/router/index.js"; import router from "@/router/index.js";
import * as crypto from "crypto";
import CryptoJS from "crypto-js"; import CryptoJS from "crypto-js";
import { ElLoading } from "element-plus";
import { ElMessage } from 'element-plus'; import { ElMessage } from 'element-plus';
import Cookies from "js-cookie";
export default { export default {
components: {
User
},
data() { data() {
return { return {
circleUrl: circleUrl: "https://cube.elemecdn.com/3/7c/3ea6beec64369c2642b92c6726f1epng.png",
"https://cube.elemecdn.com/3/7c/3ea6beec64369c2642b92c6726f1epng.png", chatUser: "",
user: {},
isCollapse: false,
users: [{ username: "admin" }, { username: "zhang" }],
chatUser: "2002",
text: "", text: "",
messages: [], messages: [],
session: "", session: "",
loading: ref(true), loading: true,
imKey: "testimkey", imKey: "testimkey",
socket: null, socket: null,
content: "", content: "",
to_user_id: 0, to_user_id: 0,
to_user_name: "", to_user_name: "",
cnt: 0, cnt: 0,
intervalId: null, timerId: null, // ID
tokenData: { tokenData: {
token: localStorage.getItem("token"), token: localStorage.getItem("token"),
ip: localStorage.getItem("ip"), ip: localStorage.getItem("ip"),
@ -84,31 +77,27 @@ export default {
username: localStorage.getItem("username"), username: localStorage.getItem("username"),
to_user_id: this.to_user_id, to_user_id: this.to_user_id,
}, },
intervalId: ref(null),
timerId: null, // ID
}; };
}, },
methods: { methods: {
async send() { async send() {
if (!this.text) { if (!this.text) {
this.$message({ type: "warning", message: "请输入内容" }); ElMessage({ type: "warning", message: "请输入内容" });
} else { } else {
if (typeof WebSocket == "undefined") { if (typeof WebSocket == "undefined") {
console.log("您的浏览器不支持WebSocket"); console.log("您的浏览器不支持WebSocket");
ElMessage.error("您的浏览器不支持WebSocket");
} else { } else {
var aesEnc = await this.aesEncrypt(this.text, this.imKey, this.imKey); var aesEnc = await this.aesEncrypt(this.text, this.imKey, this.imKey);
let data = let data = {
'{"type":"msg","data":"' + type: "msg",
aesEnc + data: aesEnc,
'","to_user_id":' + to_user_id: this.to_user_id,
this.to_user_id + from_user_id: this.tokenData.userId,
',"from_user_id":' + session: this.session
this.tokenData.userId + };
',"session":"' + this.socket.send(JSON.stringify(data)); // json
this.session + this.messages.push(data);
'"}';
this.socket.send(data); // json
this.messages.push(JSON.parse(data));
// //
this.createContent(null, this.tokenData.username, this.text); this.createContent(null, this.tokenData.username, this.text);
this.text = ""; this.text = "";
@ -143,11 +132,7 @@ export default {
if (this.cnt > 10) { if (this.cnt > 10) {
// //
this.stopInterval(); this.stopInterval();
//alert(""); ElMessage.error("连接失败,请重试!");
ElMessage({
message: "连接失败,请重试!",
type: "error",
})
router.push("/user"); router.push("/user");
} }
return; return;
@ -164,7 +149,7 @@ export default {
data.expire data.expire
); );
this.session = data.im_session; this.session = data.im_session;
this.loading=false this.loading = false;
// //
this.stopInterval(); this.stopInterval();
this.connectWebSocket(); this.connectWebSocket();
@ -173,7 +158,6 @@ export default {
if (this.cnt > 30) { if (this.cnt > 30) {
// //
this.stopInterval(); this.stopInterval();
//confirm("");
ElMessage.error("连接失败,请重试!"); ElMessage.error("连接失败,请重试!");
router.push("/user"); router.push("/user");
} }
@ -188,36 +172,40 @@ export default {
// //
if (nowUser) { if (nowUser) {
// nowUser 绿 // nowUser 绿
html = html = `
'<div class="el-row" style="padding: 5px 0">\n' + <div class="message-row message-row-right">
' <div class="el-col el-col-22" style="text-align: right; padding-right: 10px">\n' + <div class="message-content message-content-right">
' <div class="tip left">' + ${text}
text + </div>
"</div>\n" + <div class="message-avatar">
" </div>\n" + <img src="${this.circleUrl}" alt="Avatar">
' <div class="el-col el-col-2">\n' + </div>
' <span class="el-avatar el-avatar--circle" style="height: 40px; width: 40px; line-height: 40px;">\n' + </div>
' <img src="https://cube.elemecdn.com/3/7c/3ea6beec64369c2642b92c6726f1epng.png" style="object-fit: cover;">\n' + `;
" </span>\n" +
" </div>\n" +
"</div>";
} else if (remoteUser) { } else if (remoteUser) {
// remoteUser // remoteUser
html = html = `
'<div class="el-row" style="padding: 5px 0">\n' + <div class="message-row message-row-left">
' <div class="el-col el-col-2" style="text-align: right">\n' + <div class="message-avatar">
' <span class="el-avatar el-avatar--circle" style="height: 40px; width: 40px; line-height: 40px;">\n' + <img src="${this.circleUrl}" alt="Avatar">
' <img src="https://cube.elemecdn.com/3/7c/3ea6beec64369c2642b92c6726f1epng.png" style="object-fit: cover;">\n' + </div>
" </span>\n" + <div class="message-content message-content-left">
" </div>\n" + ${text}
' <div class="el-col el-col-22" style="text-align: left; padding-left: 10px">\n' + </div>
' <div class="tip right">' + </div>
text + `;
"</div>\n" +
" </div>\n" +
"</div>";
} }
this.content += html; this.content += html;
//
this.scrollToBottom();
},
scrollToBottom() {
setTimeout(() => {
const chatMessages = document.querySelector('.chat-messages');
if (chatMessages) {
chatMessages.scrollTop = chatMessages.scrollHeight;
}
}, 100);
}, },
aesEncrypt(text, password, iv) { aesEncrypt(text, password, iv) {
// CryptoJS使WordArrayBufferIVWordArray // CryptoJS使WordArrayBufferIVWordArray
@ -246,9 +234,6 @@ export default {
const ivData = CryptoJS.enc.Utf8.parse(iv); const ivData = CryptoJS.enc.Utf8.parse(iv);
// Base64 // Base64
// CryptoJS.enc.Base64.parse WordArrayBase64
// Base64使 CryptoJS.enc.Base64.parse(CryptoJS.enc.Base64.stringify(someWordArray))
// 使encryptedDataBase64
try { try {
const decrypted = CryptoJS.AES.decrypt(encryptedData, key, { const decrypted = CryptoJS.AES.decrypt(encryptedData, key, {
iv: ivData, iv: ivData,
@ -275,6 +260,7 @@ export default {
let _this = this; let _this = this;
if (typeof WebSocket == "undefined") { if (typeof WebSocket == "undefined") {
console.log("浏览器不支持WebSocket"); console.log("浏览器不支持WebSocket");
ElMessage.error("浏览器不支持WebSocket");
} else { } else {
console.log("浏览器支持WebSocket"); console.log("浏览器支持WebSocket");
let socketUrl = let socketUrl =
@ -283,7 +269,6 @@ export default {
"&token=" + "&token=" +
this.tokenData.token; this.tokenData.token;
// console.log("socketUrl:", socketUrl);
if (this.socket != null) { if (this.socket != null) {
this.socket.close(); this.socket.close();
this.socket = null; this.socket = null;
@ -292,31 +277,22 @@ export default {
this.socket = new WebSocket(socketUrl); this.socket = new WebSocket(socketUrl);
// //
this.socket.onopen = function () { this.socket.onopen = function () {
this.loading=false _this.loading = false;
//alert(""); ElMessage.success("连接成功");
ElMessage({
message: "连接成功",
type: "success",
})
}; };
this.socket.onerror = (error) => { this.socket.onerror = (error) => {
console.error("WebSocket Error:", error); console.error("WebSocket Error:", error);
_this.loading = false;
ElMessage.error("连接出错");
}; };
// //
this.socket.onclose = function () { this.socket.onclose = function () {
//alert("!"); ElMessage.error("连接已关闭");
ElMessage({
message: "连接已关闭",
type: "error",
})
router.push("/user"); router.push("/user");
}; };
// //
this.socket.onmessage = async function (msg) { this.socket.onmessage = async function (msg) {
//console.log("====" + msg.data); let data = JSON.parse(msg.data); // json
let data = JSON.parse(msg.data); // json
//console.log("====" + data);
// json
if (data.type == "msg") { // if (data.type == "msg") { //
data.data = await _this.decryptAES( data.data = await _this.decryptAES(
data.data, data.data,
@ -324,15 +300,10 @@ export default {
_this.imKey _this.imKey
); );
_this.messages.push(data); _this.messages.push(data);
//console.log("====" + msg.data);
// //
_this.createContent(_this.to_user_name, null, data.data); _this.createContent(_this.to_user_name, null, data.data);
} else if (data.type == "offline") { } else if (data.type == "offline") {
//alert("线"); ElMessage.error("对方已下线");
ElMessage({
message: "对方已下线",
type: "error",
})
_this.socket.close(); _this.socket.close();
router.push("/user"); router.push("/user");
} }
@ -344,38 +315,191 @@ export default {
mounted() { mounted() {
this.to_user_id = localStorage.getItem("to_user_id"); this.to_user_id = localStorage.getItem("to_user_id");
this.to_user_name = localStorage.getItem("to_user_name"); this.to_user_name = localStorage.getItem("to_user_name");
this.chatUser = this.to_user_name; this.chatUser = this.to_user_name || "未知用户";
//console.log("to_user_id:", this.to_user_id, this.to_user_name);
this.startInterval(); this.startInterval();
//setTimeout(() => this.loading=false, 3000);
//this.connectWebSocket();
}, },
// , // ,
onUnmounted() { onUnmounted() {
this.stopInterval(); this.stopInterval();
if (this.socket) {
this.socket.close(); this.socket.close();
}
this.loading = false; this.loading = false;
}, },
}; };
</script> </script>
<style>
.tip { <style scoped>
color: white; .page-container {
text-align: center; width: 100%;
border-radius: 10px; height: 100%;
font-family: sans-serif;
padding: 10px;
width: auto;
display: inline-block !important;
display: inline;
} }
.right {
background-color: deepskyblue; .page-card {
height: 100%;
display: flex;
flex-direction: column;
border: none;
border-radius: 8px;
} }
.left {
background-color: forestgreen; .page-card :deep(.el-card__body) {
flex: 1;
overflow: hidden;
padding: 20px;
display: flex;
flex-direction: column;
}
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
}
.header-left {
display: flex;
align-items: center;
}
.page-title {
font-size: 18px;
font-weight: 600;
color: #303133;
}
.header-actions {
display: flex;
align-items: center;
gap: 12px;
}
.chat-container {
flex: 1;
display: flex;
flex-direction: column;
background: #f5f7fa;
border-radius: 8px;
overflow: hidden;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
}
.chat-header {
background: #ffffff;
padding: 16px 20px;
border-bottom: 1px solid #e4e7ed;
display: flex;
align-items: center;
}
.chat-user-info {
display: flex;
align-items: center;
}
.chat-user-name {
font-size: 16px;
font-weight: 500;
color: #303133;
}
.chat-messages {
flex: 1;
padding: 20px;
overflow-y: auto;
display: flex;
flex-direction: column;
gap: 16px;
}
.message-row {
display: flex;
align-items: flex-end;
gap: 12px;
}
.message-row-left {
justify-content: flex-start;
}
.message-row-right {
justify-content: flex-end;
}
.message-avatar {
width: 36px;
height: 36px;
border-radius: 50%;
overflow: hidden;
flex-shrink: 0;
}
.message-avatar img {
width: 100%;
height: 100%;
object-fit: cover;
}
.message-content {
max-width: 70%;
padding: 10px 14px;
border-radius: 18px;
word-wrap: break-word;
line-height: 1.4;
}
.message-content-left {
background: #ffffff;
border-bottom-left-radius: 4px;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
}
.message-content-right {
background: #409eff;
color: #ffffff;
border-bottom-right-radius: 4px;
box-shadow: 0 1px 2px rgba(64, 158, 255, 0.3);
}
.chat-input-area {
background: #ffffff;
padding: 16px;
border-top: 1px solid #e4e7ed;
display: flex;
flex-direction: column;
gap: 12px;
}
.chat-input-area :deep(.el-textarea) {
width: 100%;
}
.chat-input-area :deep(.el-textarea__inner) {
border-radius: 8px;
resize: none;
}
.chat-actions {
display: flex;
justify-content: flex-end;
}
/* 滚动条样式 */
.chat-messages::-webkit-scrollbar {
width: 6px;
}
.chat-messages::-webkit-scrollbar-track {
background: #f1f1f1;
border-radius: 3px;
}
.chat-messages::-webkit-scrollbar-thumb {
background: #c1c1c1;
border-radius: 3px;
}
.chat-messages::-webkit-scrollbar-thumb:hover {
background: #a8a8a8;
} }
</style> </style>

View File

@ -1,7 +1,7 @@
<script> <script>
import router from "@/router/index.js"; import router from "@/router/index.js";
import { ElMessage } from "element-plus"; import { ElMessage } from "element-plus";
import { Refresh, Plus, Edit, Delete, Monitor, Operation } from "@element-plus/icons-vue";
import { getConfigShellListService } from "@/api/shell.js"; import { getConfigShellListService } from "@/api/shell.js";
import { addConfigShellService } from "@/api/shell.js"; import { addConfigShellService } from "@/api/shell.js";
@ -12,6 +12,14 @@ import { UpdateMonitorDeviceInfoService } from "@/api/tool.js";
import { DelMonitorDeviceInfoService } from "@/api/tool.js"; import { DelMonitorDeviceInfoService } from "@/api/tool.js";
export default { export default {
components: {
Refresh,
Plus,
Edit,
Delete,
Monitor,
Operation
},
data() { data() {
return { return {
ip: "", ip: "",
@ -26,8 +34,8 @@ export default {
ConfigFileCurrentPageData: [], ConfigFileCurrentPageData: [],
pageSize: 10, pageSize: 10,
currentPage: 1, currentPage: 1,
upload_file: null, // upload_file: null,
file_md5: "", //md5 file_md5: "",
addForm: { addForm: {
shell_name: "", shell_name: "",
shel_content: "", shel_content: "",
@ -36,7 +44,6 @@ export default {
serverList: [ serverList: [
{ label: "家里服务器", value: "home_server" }, { label: "家里服务器", value: "home_server" },
{ label: "腾讯服务器", value: "tx_vp_server" }, { label: "腾讯服务器", value: "tx_vp_server" },
// { label: "", value: "aliyun_vp_server" },
{ label:"azure服务器", value:"azure_vp_server" }, { label:"azure服务器", value:"azure_vp_server" },
{ label: '阿里云成都服务器', value: "aliyun_chengdu_vp_server"} { label: '阿里云成都服务器', value: "aliyun_chengdu_vp_server"}
], ],
@ -44,7 +51,6 @@ export default {
monitor_add_update_visible: false, monitor_add_update_visible: false,
monitor_update_add: {}, monitor_update_add: {},
role: "", role: "",
tokenData: { tokenData: {
token: localStorage.getItem("token"), token: localStorage.getItem("token"),
@ -58,14 +64,11 @@ export default {
}; };
}, },
// methods
//
methods: { methods: {
async getConfigFileList() { async getConfigFileList() {
let result = {}; let result = {};
this.loading = true; this.loading = true;
try { try {
//search_id
let req = { let req = {
token: this.tokenData.token, token: this.tokenData.token,
type: "all", type: "all",
@ -82,10 +85,8 @@ export default {
} }
for(let i = 0;i<this.tableData.length;i++) { for(let i = 0;i<this.tableData.length;i++) {
this.tableData[i].UpdatedAt = this.formattedTime(this.tableData[i].UpdatedAt); this.tableData[i].UpdatedAt = this.formattedTime(this.tableData[i].UpdatedAt);
this.tableData[i].CreatedAt = this.formattedTime(this.tableData[i].CreatedAt) this.tableData[i].CreatedAt = this.formattedTime(this.tableData[i].CreatedAt);
//console.log('this.ConfigFileList:',this.ConfigFileList);
} }
this.currentPageData(); this.currentPageData();
}, },
addConfigFileV() { addConfigFileV() {
@ -110,8 +111,12 @@ export default {
ElMessage.success("添加成功"); ElMessage.success("添加成功");
this.getConfigFileList(); this.getConfigFileList();
this.addConfigFileVisible = false; this.addConfigFileVisible = false;
this.addForm = {
shell_name: "",
shell_content: "",
server: ""
};
} else { } else {
//alert("");
ElMessage.error("添加失败"); ElMessage.error("添加失败");
} }
} catch (e) { } catch (e) {
@ -121,10 +126,6 @@ export default {
async updateConfigShellInfo() { async updateConfigShellInfo() {
let result = {}; let result = {};
try { try {
let d={}
// for (var key in this.ConfigShellUpdateForm) {
// d[key] = this.ConfigShellUpdateForm[key];
// }
let req = { let req = {
token: this.tokenData.token, token: this.tokenData.token,
shells: [{"id":this.ConfigShellUpdateForm.ID,"shell_result":this.ConfigShellUpdateForm.ShellResult,"status":this.ConfigShellUpdateForm.Status}], shells: [{"id":this.ConfigShellUpdateForm.ID,"shell_result":this.ConfigShellUpdateForm.ShellResult,"status":this.ConfigShellUpdateForm.Status}],
@ -141,7 +142,6 @@ export default {
} }
}, },
async deleteConfigFile(index) { async deleteConfigFile(index) {
//
let isDelete = confirm("是否删除?"); let isDelete = confirm("是否删除?");
if (!isDelete) { if (!isDelete) {
return; return;
@ -153,7 +153,6 @@ export default {
token: this.tokenData.token, token: this.tokenData.token,
shells: [{"id":this.ConfigFileCurrentPageData[index].ID}], shells: [{"id":this.ConfigFileCurrentPageData[index].ID}],
}; };
console.log("req:", req);
result = await deleteConfigShellService(req); result = await deleteConfigShellService(req);
if (result.code == 0) { if (result.code == 0) {
ElMessage.success("删除成功"); ElMessage.success("删除成功");
@ -177,16 +176,7 @@ export default {
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`; return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
}, },
async updateConfigShell(index) { async updateConfigShell(index) {
//console.log("index:", index);
let cf = this.ConfigFileCurrentPageData[index]; let cf = this.ConfigFileCurrentPageData[index];
// console.log("cf:", cf);
// let req = {
// token: this.tokenData.token,
// id: cf.ID,
// type: "one",
// };
// let result = await getConfigShellListService(req);
// let data = result.data;
this.ConfigShellUpdateForm = cf; this.ConfigShellUpdateForm = cf;
this.updateDialogVisible = true; this.updateDialogVisible = true;
}, },
@ -201,9 +191,7 @@ export default {
this.addForm.server = cf.Server; this.addForm.server = cf.Server;
await this.addConfigFile(); await this.addConfigFile();
}, },
onSubmit() { onSubmit() {
getConfigFileList(); getConfigFileList();
}, },
@ -214,31 +202,13 @@ export default {
); );
}, },
handleSizeChange(val) { handleSizeChange(val) {
//console.log(` ${val} `);
this.pageSize = val; this.pageSize = val;
this.currentPageData(); this.currentPageData();
}, },
handleCurrentChange(val) { handleCurrentChange(val) {
//console.log(`: ${val}`);
this.currentPage = val; this.currentPage = val;
this.currentPageData(); this.currentPageData();
}, },
async displayMyInfo() {
await this.getMyUserInfo(this.tokenData.user_id);
this.updateDialogVisible = true;
},
async displayUserInfo(id) {
await this.getMyUserInfo(id);
this.updateDialogVisible = true;
},
handleMenuSelect(val) {
router.push(val);
},
toVideoList() {
router.push("/videoList");
},
async getMonitorDeviceList(){ async getMonitorDeviceList(){
try { try {
let req = { let req = {
@ -248,8 +218,7 @@ export default {
let result = await GetMonitorDeviceInfoService(req); let result = await GetMonitorDeviceInfoService(req);
if (result.code === 0) { if (result.code === 0) {
this.monitor_list = result.data; this.monitor_list = result.data;
console.log("monitor_list:", this.monitor_list); this.dialogVisible = true;
this.dialogVisible = true; //
} else { } else {
ElMessage.error("获取设备列表失败"); ElMessage.error("获取设备列表失败");
} }
@ -259,9 +228,8 @@ export default {
}, },
updateMonitorShow(index) { updateMonitorShow(index) {
this.monitor_add_update_visible = true; this.monitor_add_update_visible = true;
this.monitor_update_add = { ...this.monitor_list[index] }; // this.monitor_update_add = { ...this.monitor_list[index] };
}, },
//
async addUpdateMonitor(){ async addUpdateMonitor(){
let req = { let req = {
"token": this.tokenData.token, "token": this.tokenData.token,
@ -276,12 +244,10 @@ export default {
} else { } else {
ElMessage.error("设备信息更新失败"); ElMessage.error("设备信息更新失败");
} }
}catch (e) { }catch (e) {
console.log(e); console.log(e);
} }
}, },
async DelMonitor(index) { async DelMonitor(index) {
let isDelete = confirm("是否删除?"); let isDelete = confirm("是否删除?");
if (!isDelete) { if (!isDelete) {
@ -292,7 +258,6 @@ export default {
devices: [this.monitor_list[index]], devices: [this.monitor_list[index]],
}; };
try { try {
let result = await DelMonitorDeviceInfoService(req); let result = await DelMonitorDeviceInfoService(req);
if (result.code === 0) { if (result.code === 0) {
ElMessage.success("设备删除成功"); ElMessage.success("设备删除成功");
@ -304,420 +269,327 @@ export default {
console.log(e); console.log(e);
} }
}, },
//
tableRowClassName({ row, rowIndex }) { tableRowClassName({ row, rowIndex }) {
switch (row.Status) { switch (row.Status) {
case 0: case 0:
return 'rgba(243, 243, 248, 0.1)'; // return 'rgba(243, 243, 248, 0.1)';
case 1: case 1:
return 'rgba(0, 0, 255, 0.5)'; // return 'rgba(0, 0, 255, 0.5)';
case 2: case 2:
return 'rgba(0, 0, 255, 0.9)'; // return 'rgba(0, 0, 255, 0.9)';
default: default:
return 'transparent'; // return 'transparent';
} }
}, },
}, },
//
//
async mounted() { async mounted() {
let now = new Date(); let now = new Date();
if (localStorage.getItem("token") === null) { if (localStorage.getItem("token") === null) {
router.push("/login"); router.push("/login");
} }
await this.getConfigFileList(); await this.getConfigFileList();
//await this.getMyUserInfo(localStorage.getItem("userId"));
}, },
}; };
</script> </script>
<template> <template>
<div> <div class="page-container">
<el-container style="min-height: calc(100vh - 40px); background: #fff; border-radius: 4px;"> <el-card class="page-card" shadow="never">
<el-header style="font-size: 40px; background-color: rgb(238, 241, 246)" <template #header>
>命令分发</el-header <div class="card-header">
> <div class="header-left">
<el-container> <span class="page-title">命令分发</span>
<el-main> </div>
<el-form :inline="true" :model="tokenData" class="demo-form-inline"> <div class="header-actions">
<el-form-item> <el-button type="primary" @click="addConfigFileV()" :icon="Plus">
创建命令
</el-button>
<el-button type="primary" @click="getMonitorDeviceList()" :icon="Monitor">
设备监控
</el-button>
<el-button @click="getConfigFileList()" :icon="Refresh">
刷新
</el-button>
</div>
</div>
</template>
<div class="table-wrapper">
<el-table :data="ConfigFileCurrentPageData" style="width: 100%" v-loading="loading"
element-loading-text="加载中..."
element-loading-background="rgba(240, 242, 245, 0.8)"
stripe
:row-class-name="tableRowClassName">
<el-table-column prop="ID" label="ID" width="80"></el-table-column>
<el-table-column prop="ShellName" label="命令名称" min-width="150" show-overflow-tooltip></el-table-column>
<el-table-column prop="ShellContent" label="命令内容" min-width="200" show-overflow-tooltip></el-table-column>
<el-table-column prop="Status" label="状态" width="100">
<template #default="scope">
<el-tag :type="scope.row.Status === 0 ? 'info' : scope.row.Status === 1 ? 'warning' : 'success'">
{{ scope.row.Status === 0 ? '待执行' : scope.row.Status === 1 ? '执行中' : '已完成' }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="CreatedAt" label="创建时间" min-width="160"></el-table-column>
<el-table-column prop="UpdatedAt" label="更新时间" min-width="160"></el-table-column>
<el-table-column label="操作" width="250" fixed="right">
<template #default="scope">
<el-button type="primary" size="small" @click.prevent="updateConfigShell(scope.$index)" :icon="Edit">
编辑
</el-button>
<el-button type="danger" size="small" @click.prevent="deleteConfigFile(scope.$index)" :icon="Delete">
删除
</el-button>
<el-button type="success" size="small" @click.prevent="createAgain(scope.$index)" :icon="Operation">
再次执行
</el-button>
</template>
</el-table-column>
</el-table>
<div class="pagination-wrapper">
<el-pagination
background
layout="total,sizes, prev, pager, next, jumper"
:page-sizes="[10, 20, 50, 100]"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:total="tableData.length"
></el-pagination>
</div>
</div>
</el-card>
<!-- 编辑命令对话框 -->
<el-dialog <el-dialog
v-model="updateDialogVisible" v-model="updateDialogVisible"
title="编辑配置" title="编辑配置"
width="60%" width="60%"
:before-close="handleClose" :close-on-click-modal="false"
top="5vh"
> >
<!-- 内容主体区域 -->
<el-form <el-form
ref="updateFormRef" ref="updateFormRef"
:model="ConfigShellUpdateForm" :model="ConfigShellUpdateForm"
:rules="UserUpdateFormRules" :rules="UserUpdateFormRules"
label-width="70px" label-width="80px"
class="form-dialog"
> >
<!-- row --> <el-row gutter="20">
<el-row>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="ID"> <el-form-item label="ID">
<el-input <el-input v-model="ConfigShellUpdateForm.ID" disabled></el-input>
v-model="ConfigShellUpdateForm.ID"
disabled
></el-input>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="名称"> <el-form-item label="名称">
<el-input <el-input v-model="ConfigShellUpdateForm.ShellName" disabled></el-input>
v-model="ConfigShellUpdateForm.ShellName"
disabled
></el-input>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="32"> </el-row>
<el-row>
<el-col :span="24">
<el-form-item label="内容"> <el-form-item label="内容">
<el-input <el-input v-model="ConfigShellUpdateForm.ShellContent" disabled type="textarea" :rows="3"></el-input>
v-model="ConfigShellUpdateForm.ShellContent"
disabled
type="textarea"
style="width: 512px"
></el-input>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col> </el-row>
<el-form-item label="运行结果" prop="shell_result"> <el-row>
<el-input <el-col :span="24">
type="textarea" <el-form-item label="运行结果">
v-model="ConfigShellUpdateForm.ShellResult" <el-input type="textarea" v-model="ConfigShellUpdateForm.ShellResult" :rows="6"></el-input>
style="width: 600px"
:autosize="{ minRows: 4, maxRows: 8 }"
/>
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
</el-form> </el-form>
<!-- 底部区域 -->
<template #footer> <template #footer>
<span class="dialog-footer"> <div class="dialog-footer">
<el-button @click="updateDialogVisible = false" <el-button @click="updateDialogVisible = false">取消</el-button>
>取消</el-button <el-button type="primary" @click="updateConfigShellInfo()">确定</el-button>
> </div>
<el-button type="primary" @click="updateConfigShellInfo()"
>确定</el-button
>
</span>
</template> </template>
</el-dialog> </el-dialog>
</el-form-item>
<!-- 表单 -->
<el-form :inline="true" :model="tokenData" class="demo-form-inline">
<el-form-item>
<el-button
class="el-button--danger"
type="primary"
:disabled="loading"
@click="getConfigFileList()"
>查询</el-button
>
</el-form-item>
<el-form-item>
<el-button
class="el-button--danger"
type="primary"
@click="addConfigFileV()"
>创建命令</el-button
>
</el-form-item>
<el-form-item>
<el-button
class="el-button--danger"
type="primary"
@click="getMonitorDeviceList()"
>设备监控</el-button
>
</el-form-item>
</el-form>
</el-form>
<!-- 创建命令对话框 -->
<el-dialog <el-dialog
v-model="addConfigFileVisible" v-model="addConfigFileVisible"
title="创建命令" title="创建命令"
width="50%" width="50%"
:before-close="handleClose" :close-on-click-modal="false"
top="5vh"
> >
<!-- 内容主体区域 -->
<el-form <el-form
ref="addFormRef" ref="addFormRef"
:model="addForm" :model="addForm"
:rules="addFormRules" :rules="addFormRules"
label-width="70px" label-width="80px"
class="form-dialog"
> >
<el-row> <el-form-item label="名称">
<el-form-item label="名称" prop="shell_name"> <el-input v-model="addForm.shell_name" placeholder="请输入命令名称"></el-input>
<el-input
v-model="addForm.shell_name"
autocomplete="on"
></el-input>
</el-form-item> </el-form-item>
</el-row> <el-form-item label="内容">
<el-row> <el-input type="textarea" v-model="addForm.shell_content" placeholder="请输入命令内容" :rows="4"></el-input>
<el-form-item label="内容" prop="file_path">
<el-input
type="textarea"
v-model="addForm.shell_content"
autocomplete="on"
style="width: 600px"
:autosize="{ minRows: 4, maxRows: 8 }"
></el-input>
</el-form-item> </el-form-item>
</el-row> <el-form-item label="服务器">
<el-row> <el-select v-model="addForm.server" filterable allow-create placeholder="选择服务器">
<el-form-item label="服务器" prop="server"> <el-option v-for="item in serverList" :key="item.value" :label="item.label" :value="item.value"></el-option>
<el-select v-model="addForm.server" filterable allow-create>
<el-option
v-for="item in serverList"
:key="item.value"
:label="item.label"
:value="item.value"
></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
</el-row>
</el-form> </el-form>
<!-- 底部区域 -->
<template #footer> <template #footer>
<span class="dialog-footer"> <div class="dialog-footer">
<el-button @click="addConfigFileVisible = false" <el-button @click="addConfigFileVisible = false">取消</el-button>
>取消</el-button <el-button type="primary" @click="addConfigFile()">确定</el-button>
> </div>
<el-button type="primary" @click="addConfigFile()"
>确定</el-button
>
</span>
</template> </template>
</el-dialog> </el-dialog>
<!-- 设备监控对话框 -->
<el-dialog
v-model="dialogVisible"
title="设备状态监控"
width="70%"
@close="handleClose"
top="5vh"
>
<el-button type="primary" @click="monitor_add_update_visible = true" style="margin-bottom: 16px;">
添加设备
</el-button>
<el-table :data="monitor_list" stripe style="width: 100%">
<el-table-column prop="id" label="设备" width="150"></el-table-column>
<el-table-column prop="status" label="状态" width="150">
<template #default="scope">
<el-tag :type="scope.row.status === '1' ? 'success' : 'danger'">
{{ scope.row.status === '1' ? '在线' : '离线' }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="expire" label="过期时间" width="150"></el-table-column>
<el-table-column label="操作" width="180" fixed="right">
<template #default="scope">
<el-button type="primary" size="small" @click.prevent="updateMonitorShow(scope.$index)" :icon="Edit">
编辑
</el-button>
<el-button type="danger" size="small" @click.prevent="DelMonitor(scope.$index)" :icon="Delete">
删除
</el-button>
</template>
</el-table-column>
</el-table>
<template #footer>
<el-button @click="dialogVisible = false">关闭</el-button>
</template>
</el-dialog>
<!-- 添加/编辑设备监控对话框 -->
<el-dialog <el-dialog
v-model="monitor_add_update_visible" v-model="monitor_add_update_visible"
title="编辑监控" title="添加/编辑设备监控"
width="50%" width="50%"
@close="handleClose"> @close="handleClose"
top="5vh"
>
<el-form <el-form
ref="monitorUpdateFormRef" ref="monitorUpdateFormRef"
:model="monitor_update_add" :model="monitor_update_add"
:rules="UserUpdateFormRules" :rules="UserUpdateFormRules"
label-width="70px" label-width="80px"
class="form-dialog"
> >
<el-form-item label="设备">
<el-row> <el-input v-model="monitor_update_add.id" placeholder="设备ID"></el-input>
<el-form-item label="设备" prop="id">
<el-input
v-model="monitor_update_add.id"
></el-input>
</el-form-item> </el-form-item>
</el-row> <el-form-item label="状态">
<el-row>
<el-form-item label="状态" prop="status">
<el-select v-model="monitor_update_add.status"> <el-select v-model="monitor_update_add.status">
<el-option label="在线" value="1"></el-option> <el-option label="在线" value="1"></el-option>
<el-option label="离线" value="0"></el-option> <el-option label="离线" value="0"></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
</el-row> <el-form-item label="过期时间">
<el-row> <el-input v-model="monitor_update_add.expire" placeholder="过期时间" oninput="this.value = this.value.replace(/[^0-9]/g, '')"></el-input>
<el-form-item label="过期时间" prop="expire">
<el-input
v-model="monitor_update_add.expire"
oninput="this.value = this.value.replace(/[^0-9]/g, '')"
></el-input>
</el-form-item> </el-form-item>
</el-row>
</el-form> </el-form>
<!-- 底部区域 -->
<template #footer> <template #footer>
<div class="dialog-footer">
<span class="dialog-footer"> <el-button @click="monitor_add_update_visible = false">取消</el-button>
<el-button @click="monitor_add_update_visible = false" <el-button type="primary" @click="addUpdateMonitor()">确定</el-button>
>取消</el-button
>
<el-button type="primary" @click="addUpdateMonitor()"
>确定</el-button
>
</span>
</template>
</el-dialog>
<el-dialog
v-model="dialogVisible"
title="设备状态监控"
width="50%"
@close="handleClose"
>
<el-button type="primary" @click="monitor_add_update_visible = true">添加</el-button>
<el-table
:data="monitor_list"
stripe
width="90%"
fit
>
<el-table-column prop="id" label="设备" width="150"></el-table-column>
<el-table-column prop="status" label="状态" width="150">
<template #default="scope">
<el-tag
:type="scope.row.status === '1' ? 'success' : 'danger'"
>{{ scope.row.status === "1" ? '在线' : '离线' }}</el-tag
>
</template>
</el-table-column>
<el-table-column prop="expire" label="过期时间" width="150">
</el-table-column>
<el-table-column label="操作" width="270">
<template #default="scope">
<el-button
type="primary"
size="mini"
@click.prevent="updateMonitorShow(scope.$index)"
>编辑</el-button
>
<el-button
type="primary"
size="mini"
@click.prevent="DelMonitor(scope.$index)"
>删除</el-button
>
</template>
</el-table-column>
</el-table>
<template #footer>
<el-button @click="dialogVisible = false">取消</el-button>
</template>
</el-dialog>
<!-- 表格 :row-style="this.tableRowClassName"-->
<el-table :data="ConfigFileCurrentPageData" width="100%" v-loading="loading">
:row-style="tableRowClassName"
<el-table-column prop="ID" label="id" width="80"></el-table-column>
<el-table-column
prop="ShellName"
label="命令名称"
width="120"
></el-table-column>
<el-table-column
prop="ShellContent"
label="命令内容"
show-overflow-tooltip
width="120"
></el-table-column>
<el-table-column
prop="Status"
label="状态"
width="100"
>
<template #default="scope">
<el-tag
v-if="scope.row.Status === 0"
>任务提交</el-tag
>
<el-tag
v-if="scope.row.Status === 1"
type="warning"
>正在运行</el-tag>
<el-tag
v-if="scope.row.Status === 2"
type="success"
>执行成功</el-tag>
<el-tag
v-if="scope.row.Status === 3"
type="danger"
>执行出错</el-tag>
</template>
</el-table-column>
<el-table-column
prop="ShellRuntime"
label="SR"
width="50"
>
<template #default="scope">
<!-- 转为秒两位小数-->
{{ Math.round(scope.row.ShellRuntime * 100) / 100 }}
</template>
</el-table-column>
<el-table-column
prop="ShellDuration"
label="SD"
width="50"
>
<template #default="scope">
<!-- 转为秒两位小数-->
{{ Math.round(scope.row.ShellDuration * 100) / 100 }}
</template>
</el-table-column>
<el-table-column
prop="Server"
label="服务器"
width="100"
></el-table-column>
<el-table-column
prop="CreatedAt"
label="创建时间"
width="160"
></el-table-column>
<el-table-column
prop="UpdatedAt"
label="上次更新"
width="160"
></el-table-column>
<!-- <el-table-column
prop="AuthID"
label="创建用户ID"
width="40"
></el-table-column> -->
<el-table-column label="操作" width="270">
<template #default="scope">
<el-button
type="primary"
size="mini"
@click.prevent="updateConfigShell(scope.$index)"
>编辑</el-button
>
<el-button
type="primary"
size="mini"
@click.prevent="deleteConfigFile(scope.$index)"
>删除</el-button
>
<el-button
type="primary"
size="mini"
@click.prevent="createAgain(scope.$index)"
>再次执行</el-button
>
</template>
</el-table-column>
</el-table>
<!-- 分页条 -->
<!-- Pagination 分页 -->
<el-pagination
background
layout="total,sizes, prev, pager, next, jumper"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:total="tableData.length"
></el-pagination>
</el-main>
</el-container>
</el-container>
</div> </div>
</template> </template>
<style> </el-dialog>
.blueRowbg { </div>
background: "#488aff"; </template>
<style scoped>
.page-container {
width: 100%;
height: 100%;
}
.page-card {
height: 100%;
display: flex;
flex-direction: column;
border: none;
border-radius: 8px;
}
.page-card :deep(.el-card__body) {
flex: 1;
overflow: hidden;
padding: 20px;
display: flex;
flex-direction: column;
}
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
}
.header-left {
display: flex;
align-items: center;
}
.page-title {
font-size: 18px;
font-weight: 600;
color: #303133;
}
.header-actions {
display: flex;
align-items: center;
gap: 12px;
}
.table-wrapper {
flex: 1;
overflow: auto;
display: flex;
flex-direction: column;
}
.table-wrapper :deep(.el-table) {
border-radius: 4px;
}
.pagination-wrapper {
margin-top: 16px;
display: flex;
justify-content: flex-end;
}
.form-dialog {
padding: 10px 0;
}
.dialog-footer {
display: flex;
justify-content: flex-end;
gap: 12px;
} }
</style> </style>