Commit 82a090d9 by wuchao

客户端监控管理、客户端密管

parent ee17f5e4
import request from '@/utils/request'
/**
* 显示客户端参数
*
* @param projcetId 项目ID
* @returns 客户端参数信息
*/
export function showClientParams(projcetId) {
return request({
url: '/key/client/showClientParams?projectid=' + projcetId,
method: 'get'
})
}
/**
* 保存客户端参数
*
* @param {any} data - 需要保存的客户端参数数据
* @returns {Promise} - 返回Promise对象,用于处理异步请求结果
*/
export function saveClientParams(data) {
return request({
url: '/key/client/saveClientParams',
method: 'post',
data: data
})
}
\ No newline at end of file
import request from '@/utils/request'
export function ipsList(data) {
return request({
url: '/jar_socket_controller/ipsList',
method: 'post',
data: data
})
}
export function ipsSave(data) {
return request({
url: '/jar_socket_controller/ipsSave',
method: 'post',
data: data
})
}
export function list(data) {
return request({
url: '/jar_socket_controller/list',
method: 'post',
data: data
})
}
export function changeLog(data) {
return request({
url: '/jar_socket_controller/changeLog',
method: 'post',
data: data
})
}
export function deleteLog(data) {
return request({
url: '/jar_socket_controller/delete',
method: 'post',
data: data
})
}
......@@ -93,6 +93,18 @@ export const constantRoutes = [
component: () => import('@/views/ruleConfig/Dictionary/index'),
hidden: true
},
{
// 客户端密管
path: '/classification/DensetuArea',
component: () => import('@/views/classification/DensetuArea/index'),
hidden: true
},
{
// 客户端监控管理
path: '/classification/MonitorManagement',
component: () => import('@/views/classification/MonitorManagement/index'),
hidden: true
},
// {
// // 项目管理
// path: '/projectManage',
......
<script setup name="DensetuArea">
import { ref, toRefs, reactive, getCurrentInstance, proxyRefs, onMounted } from 'vue'
import { Lock } from '@element-plus/icons-vue'
import { changeRoute } from '@/utils/switchRoute'
import { useRouter } from 'vue-router'
import { showClientParams, saveClientParams } from '@/api/classification/densetuArea.js'
const router = useRouter()
const { proxy } = getCurrentInstance()
const projectId = ref('')
const form = ref({
"id": null,
"projectid": null,
"keylocation": null, // 密钥存放位置 1:缓存 2:文件
"encdeclocation": null // 加解密计算位置 0:客户端 1:服务端
})
const currentForm = ref({
"keylocation": null, // 密钥存放位置 1:缓存 2:文件
"encdeclocation": null // 加解密计算位置 0:客户端 1:服务端
})
const edit = ref(false)
onMounted(()=>{
sessionStorage.setItem('projectId', 'fda50ea9-b7fa-4fe4-b368-eebeffded6b6')
projectId.value = sessionStorage.getItem('projectId')
console.log('projectId',projectId.value)
showClientParamsMethod()
})
/**
* 获取客户端参数
*
* 从服务器获取配置,并将结果设置到表单中
*/
function showClientParamsMethod() {
console.log('获取配置')
showClientParams(projectId.value).then((res) => {
form.value.id = res.data.id ? res.data.id : null
form.value.projectid = projectId.value
form.value.keylocation = res.data.keylocation ? res.data.keylocation : '1'
form.value.encdeclocation = res.data.encdeclocation ? res.data.encdeclocation : '0'
currentForm.value.keylocation = res.data.keylocation ? res.data.keylocation : '1'
currentForm.value.encdeclocation = res.data.encdeclocation ? res.data.encdeclocation : '0'
})
}
/**
* 保存客户端参数的处理函数
*/
function handlerSaveClientParams() {
saveClientParams(form.value).then((res) => {
console.log('保存配置',res)
showClientParamsMethod()
})
}
/**
* 处理取消事件
*
* 当用户点击取消按钮时,调用此函数。
* 该函数将编辑状态重置为 false,并将表单中的 keylocation 和 encdeclocation 字段
* 更新为当前表单的对应字段值。
*/
function handlerCancle() {
edit.value = false
form.value.keylocation = currentForm.value.keylocation
form.value.encdeclocation = currentForm.value.encdeclocation
}
function pageProjectManage() {
changeRoute()
router.push({
path: '/project/Project'
})
}
defineExpose({
// handleRedInk,
// handleVoid
})
</script>
<template>
<div class="app-container scroller">
<PageTitle :back="true" @back="pageProjectManage" >
<template #title>
返回项目管理
</template>
</PageTitle>
<div class="app-container__body">
<div class="flex-container content-container">
<div class="secondtitle">
<el-icon :size="30" color="#2c9ef7"><Lock /></el-icon>
<span>客户端密管</span>
</div>
<div class="thirdtitle">
<span></span>
<span>客户端密管设置区域:</span>
</div>
<el-form :model="form" label-width="auto" style="max-width: 600px;margin-left: 100px;margin-top: 30px;">
<el-form-item label="密钥存放位置">
<el-select v-model="form.keylocation" placeholder="请选择密钥存放位置" :disabled="!edit">
<el-option label="缓存" value="1" />
<el-option label="文件" value="2" />
</el-select>
</el-form-item>
<el-form-item label="加解密计算位置">
<el-select v-model="form.encdeclocation" placeholder="请选择加解密计算位置" :disabled="!edit">
<el-option label="客户端" value="0" />
<el-option label="服务端" value="1" />
</el-select>
</el-form-item>
<el-form-item label=" ">
<el-button
type="primary"
v-if="!edit"
@click="edit = true">
编辑
</el-button>
<el-button
type="primary"
v-if="edit"
@click="edit = true">
取消
</el-button>
<el-button
type="primary"
v-if="edit"
@click="handlerSaveClientParams">
保存配置
</el-button>
</el-form-item>
</el-form>
</div>
</div>
</div>
</template>
<style lang="scss" scoped>
.secondtitle {
display: flex;
align-items: center;
color: #2c9ef7;
font-size: 16px;
}
.thirdtitle {
display: flex;
align-items: center;
color: #2c9ef7;
font-weight: bolder;
font-size: 18px;
margin-top: 30px;
}
.thirdtitle > span:nth-child(1) {
display: inline-block;
width: 5px;
height: 20px;
font-weight: bolder;
margin-right: 5px;
background-color: #2c9ef7;
}
</style>
++ "b/src/views/classification/DensetuArea/\345\256\242\346\210\267\347\253\257\345\257\206\347\256\241"
<script setup name="DensetuArea">
import { ref, toRefs, reactive, getCurrentInstance, proxyRefs, onMounted } from 'vue'
import { Notification, CirclePlus, CircleClose } from '@element-plus/icons-vue'
import { changeRoute } from '@/utils/switchRoute'
import { useRouter } from 'vue-router'
import { ipsList, ipsSave, list, deleteLog } from '@/api/classification/monitorManagement.js'
import changeLog from './model/changeLog.vue'
import errorLog from './model/errorLog.vue'
const router = useRouter()
const { proxy } = getCurrentInstance()
const projectId = ref('')
const ipList = ref([])
const currentIpList = ref([])
const dataList = ref([])
const editIp = ref(false)
const totalCount = ref(0)
const timer = ref(null)
const queryParams = ref({
"currentpage": 1,
"pageSize": 10
})
// ipList内容格式
// {
// "content": "2.2.2.2/255.255.255.255" 或 "3.3.3.3",
// "isEquals": 1, // 1: 包含,0:等于
// }
/**
* 处理输入事件,限制只能输入0-255的整数
* @param {String} value - 输入框当前值(来自$event)
* @param {Object} obj - 当前绑定的对象
* @param {String} key - 对象中对应的字段名
*/
const handleInput = (value, obj, key) => {
// 1. 过滤非数字字符
let processed = value.replace(/[^0-9]/g, '');
// 2. 限制长度不超过3位
if (processed.length > 3) {
processed = processed.slice(0, 3);
}
// 3. 处理数值范围(输入过程中超过255则修正)
if (processed) {
const num = parseInt(processed, 10);
if (num > 255) {
processed = '255';
}
}
// 4. 去除前置多余的0(如"00"→"0","012"→"12")
if (processed.length > 1 && processed.startsWith('0')) {
processed = processed.replace(/^0+/, '0');
}
// 直接更新当前对象的字段值
obj[key] = processed;
};
function listMethod() {
const postData = {
"projectid": projectId.value,
"clientIp": "",
"clientPort": "",
"syncStatus": "-1",
"isForbidden": "-1",
...queryParams.value
}
list(postData).then((res) => {
dataList.value = res.data
totalCount.value = res.totalCount
})
}
/**
* 获取客户端参数
*
* 从服务器获取配置,并将结果设置到表单中
*/
function ipsListMethod() {
console.log('获取配置')
ipsList({projectId: projectId.value}).then((res) => {
let data = res.data
if(data && data.length > 0) {
data.forEach(item => {
if(item.isEquals == '1') {
let content = item.content.split('/')
let left = content[0].split('.')
let right = content[1].split('.')
item['ip1'] = left[0]
item['ip2'] = left[1]
item['ip3'] = left[2]
item['ip4'] = left[3]
item['ip5'] = right[0]
item['ip6'] = right[1]
item['ip7'] = right[2]
item['ip8'] = right[3]
} else {
let left = item.content.split('.')
item['ip1'] = left[0]
item['ip2'] = left[1]
item['ip3'] = left[2]
item['ip4'] = left[3]
item['ip5'] = ''
item['ip6'] = ''
item['ip7'] = ''
item['ip8'] = ''
}
})
} else {
data = [{
ip1: '0',
ip2: '0',
ip3: '0',
ip4: '0',
ip5: '255',
ip6: '255',
ip7: '255',
ip8: '255',
isEquals: '1',
content: '0.0.0.0/255.255.255.255',
}]
}
console.log('获取配置成功', data)
ipList.value = data
currentIpList.value = JSON.parse(JSON.stringify(ipList.value))
})
}
/**
* 向IP列表中添加一个新的IP对象
*/
function handlerAddIp() {
ipList.value.push({
ip1: '',
ip2: '',
ip3: '',
ip4: '',
ip5: '',
ip6: '',
ip7: '',
ip8: '',
isEquals: '0',
content: '',
})
}
/**
* 处理IP地址保存的函数
*/
function handlerIpsSave() {
let msg = null
ipList.value.forEach(item =>{
if(item.isEquals == '1' && (!item.ip1 || !item.ip2 || !item.ip3 || !item.ip4 || !item.ip5 || !item.ip6 || !item.ip7 || !item.ip8)) {
msg = '请填写完整IP信息!'
} else if(item.isEquals == '0' && (!item.ip1 || !item.ip2 || !item.ip3 || !item.ip4) ) {
msg = '请填写完整IP信息!'
}
})
if(msg) {
proxy.$message.error(msg)
return false
}
let ips = []
ipList.value.forEach(item => {
if (item.isEquals == '1') {
ips.push({
content: item.ip1 + '.' + item.ip2 + '.' + item.ip3 + '.' + item.ip4 + '/' + item.ip5 + '.' + item.ip6 + '.' + item.ip7 + '.' + item.ip8,
isEquals: '1',
type: '1',
})
} else if (item.isEquals == '0') {
ips.push({
content: item.ip1 + '.' + item.ip2 + '.' + item.ip3 + '.' + item.ip4,
isEquals: '0',
type: '1',
})
}
})
console.log('保存的IP列表', ips)
ipsSave({projectId: projectId.value, ips}).then((res) => {
proxy.$message.success('保存成功')
editIp.value = false
ipsListMethod()
})
}
function handlerRemoveIp(index) {
ipList.value.splice(index, 1)
if (ipList.value.length == 0) {
handlerAddIp()
}
}
/**
* 处理取消事件
*
* 当用户点击取消按钮时,调用此函数。
* 该函数将编辑状态重置为 false,并将表单中的 keylocation 和 encdeclocation 字段
* 更新为当前表单的对应字段值。
*/
function handlerCancle() {
edit.value = false
form.value.keylocation = currentForm.value.keylocation
form.value.encdeclocation = currentForm.value.encdeclocation
}
/**
* 处理取消事件
* 当用户点击取消按钮时,调用此函数。
* 该函数将编辑状态重置为 false,并将表单中的 keylocation 和 encdeclocation 字段
* 更新为当前表单的对应字段值。
*/
function handlerCancel() {
editIp.value = false
ipList.value = JSON.parse(JSON.stringify(currentIpList.value))
}
function handleDelete(row) {
proxy.$modal.confirm('删除后无法恢复,是否确认删除此客户端?').then(function () {
return deleteLog({clientId: row.id})
}).then(() => {
listMethod()
proxy.$modal.msgSuccess("删除成功")
}).catch(() => {})
}
function handleChange(row) {
console.log('点击变更记录')
proxy.$refs.changeLogRef?.show(row.id)
}
function handlerError(row) {
proxy.$refs.errorLogRef?.show(row)
}
function pageProjectManage() {
changeRoute()
router.push({
path: '/project/Project'
})
}
defineExpose({
// handleRedInk,
// handleVoid
})
onMounted(()=>{
// sessionStorage.setItem('projectId', 'fda50ea9-b7fa-4fe4-b368-eebeffded6b6')
sessionStorage.setItem('projectId', 'df345570-d044-47b3-a2c6-0ff265f89b80')
projectId.value = sessionStorage.getItem('projectId')
ipsListMethod()
listMethod()
startTimer()
})
// 启动定时器
const startTimer = () => {
// 10秒后开始每10秒执行一次(10000毫秒 = 10秒)
timer.value = setInterval(listMethod, 2000);
};
// 停止定时器
const stopTimer = () => {
if (timer.value) {
clearInterval(timer.value);
timer.value = null;
}
};
// 组件卸载时清除定时器(防止内存泄漏)
onUnmounted(() => {
stopTimer();
});
</script>
<template>
<div class="app-container scroller">
<PageTitle :back="true" @back="pageProjectManage" >
<template #title>
返回项目管理
</template>
</PageTitle>
<div class="app-container__body">
<div class="flex-container content-container">
<div class="secondtitle">
<el-icon :size="30" color="#2c9ef7"><Notification /></el-icon>
<span>客户端监控管理</span>
</div>
<el-card style="margin-top: 30px;">
<div class="thirdtitle">
<span></span>
<span>客户端白名单设置区域:</span>
</div>
<el-form label-width="208">
<el-form-item label="可访问IP白名单">
<el-row class="line" v-if="!editIp" style="margin-top: 0px;">
<span v-for="(item, index) in ipList" style="width: 100%;">
<span v-if="index > 0"></span>
{{ item.content }}
</span>
</el-row>
<el-row v-if="editIp">
<div v-for="(item, index) in ipList" style="width: 100%;" >
<div class="line">
<el-select v-model="item.isEquals" placeholder="请选择" class="putsec">
<el-option label="等于" value="0" />
<el-option label="包含" value="1" />
</el-select>
<el-input v-model="item.ip1" class="putnum" @input="handleInput($event, item, 'ip1')" :maxlength="3"></el-input>
<span>.</span>
<el-input v-model="item.ip2" class="putnum" @input="handleInput($event, item, 'ip2')" :maxlength="3"></el-input>
<span>.</span>
<el-input v-model="item.ip3" class="putnum" @input="handleInput($event, item, 'ip3')" :maxlength="3"></el-input>
<span>.</span>
<el-input v-model="item.ip4" class="putnum" @input="handleInput($event, item, 'ip4')" :maxlength="3"></el-input>
<span v-if="item.isEquals == '1'"></span>
<el-input v-model="item.ip5" class="putnum" @input="handleInput($event, item, 'ip5')" :maxlength="3" v-if="item.isEquals == '1'"></el-input>
<span v-if="item.isEquals == '1'">.</span>
<el-input v-model="item.ip6" class="putnum" @input="handleInput($event, item, 'ip6')" :maxlength="3" v-if="item.isEquals == '1'"></el-input>
<span v-if="item.isEquals == '1'">.</span>
<el-input v-model="item.ip7" class="putnum" @input="handleInput($event, item, 'ip7')" :maxlength="3" v-if="item.isEquals == '1'"></el-input>
<span v-if="item.isEquals == '1'">.</span>
<el-input v-model="item.ip8" class="putnum" @input="handleInput($event, item, 'ip8')" :maxlength="3" v-if="item.isEquals == '1'"></el-input>
<el-button type="primary" :icon="CirclePlus" circle @click="handlerAddIp" v-if="index == 0"/>
<el-button type="danger" :icon="CircleClose" circle @click="handlerRemoveIp(index)" v-if="index > 0"/>
</div>
</div>
</el-row>
</el-form-item>
<el-form-item label=" ">
<el-button
type="primary"
v-if="!editIp"
@click="editIp = true">
编辑
</el-button>
<el-button
type="info"
v-if="editIp"
@click="handlerCancel">
取消
</el-button>
<el-button
type="primary"
@click="handlerIpsSave"
v-if="editIp">
保存配置
</el-button>
</el-form-item>
</el-form>
</el-card>
<el-card style="margin-top: 30px;">
<div class="thirdtitle">
<span></span>
<span>客户端列表区域:</span>
</div>
<el-table :data="dataList" border style="width: 100%">
<el-table-column label="序号" align="center" width="60" type="index">
<template #default="scope">
<span>{{ scope.$index + 1 }}</span>
</template>
</el-table-column>
<el-table-column prop="client_ip" label="客户端IP" align="center" width="100"/>
<el-table-column prop="client_port" label="端口号" align="center" width="70"/>
<el-table-column prop="client_status" label="同步状态" align="center" width="80">
<template #default="{ row }">
<span v-if="row.client_status == '1'">未同步</span>
<span v-if="row.client_status == '2'">同步中</span>
<span v-if="row.client_status == '3'" style="color: green;">成功</span>
<span v-if="row.client_status == '4'" style="color: red;">失败</span>
</template>
</el-table-column>
<el-table-column prop="create_time" label="创建时间" align="center" width="100"/>
<el-table-column prop="last_opt_time" label="更新时间" align="center" width="100"/>
<el-table-column prop="databaseUrl" label="数据库URL" align="left" />
<el-table-column prop="insname" label="是否可访问" align="center" width="100">
<span >未判断出来</span>
</el-table-column>
<el-table-column prop="insname" label="操作" align="center" width="300">
<template #default="{ row }">
<el-button type="text" size="small" @click="handleChange(row)">变更记录</el-button>
<el-button type="text" size="small" @click="handlerError(row)">错误日志</el-button>
<el-button type="text" size="small" @click="handleDelete(row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<pagination
v-show="totalCount > 0"
:total="totalCount"
v-model:page="queryParams.currentpage"
v-model:limit="queryParams.pageSize"
@pagination="listMethod"
/>
</el-card>
</div>
</div>
<!-- 变更记录 -->
<changeLog ref="changeLogRef"/>
<!-- 错误日志 -->
<errorLog ref="errorLogRef"/>
</div>
</template>
<style lang="scss" scoped>
.secondtitle {
display: flex;
align-items: center;
color: #2c9ef7;
font-size: 16px;
font-weight: bolder;
}
.thirdtitle {
display: flex;
align-items: center;
color: #2c9ef7;
font-weight: bolder;
font-size: 18px;
}
.thirdtitle > span:nth-child(1) {
display: inline-block;
width: 5px;
height: 20px;
font-weight: bolder;
margin-right: 5px;
background-color: #2c9ef7;
}
.line {
display: flex;
align-items: center;
margin-top: 20px;
}
.putnum {
width: 60px;
text-align: center;
margin-left: 5px;
margin-right: 5px;
}
.putsec {
width: 100px;
margin-right: 10px;
}
</style>
<template>
<el-dialog
v-model="dialogVisible"
:title="'变更记录'"
width="80%">
<el-table :data="dataList" border style="width: 100%">
<el-table-column label="序号" width="60" type="index">
<template #default="scope">
<span>{{ scope.$index + 1 }}</span>
</template>
</el-table-column>
<el-table-column prop="create_time" label="变更时间" align="center" width="120"/>
<el-table-column prop="rule_str" label="变更规则" align="center" />
</el-table>
<pagination
v-show="total > 0"
:total="total"
v-model:page="queryParams.currentpage"
v-model:limit="queryParams.pageSize"
@pagination="changeLogMethod"
/>
<template #footer>
<div class="dialog-footer">
<el-button @click="handlerClose">关 闭</el-button>
</div>
</template>
</el-dialog>
</template>
<script setup>
import { ref, reactive } from 'vue';
import { ElMessage } from 'element-plus';
import { changeLog } from '@/api/classification/monitorManagement.js'
const props = defineProps({
hideComponent: {
type: Array,
default: () => [],
}
})
const dialogVisible = ref(false);
const currentStep = ref(1);
const desensitizationDialogVisible = ref(false);
const currentField = ref({});
const dataList = ref([]);
const queryParams = ref({
"currentpage": 1,
"pageSize": 10,
'clientId': ''
})
const total = ref(0)
function changeLogMethod() {
changeLog(queryParams.value).then(res => {
dataList.value = res.data
total.value = res.totalCount
})
}
function show(clientId) {
queryParams.value.clientId = clientId;
queryParams.value.currentpage = 1;
changeLogMethod()
dialogVisible.value = true;
}
function handlerClose() {
dialogVisible.value = false;
}
// 关键:通过defineExpose暴露方法,供父组件调用
defineExpose({
show
});
</script>
<style scoped lang="scss">
.step-content {
min-height: 400px;
}
.version-select {
margin-bottom: 20px;
}
.field-selection {
display: flex;
height: 400px;
}
.tree-container {
width: 250px;
height: 400px;
overflow-y: auto;
padding-right: 10px;
}
.table-container {
flex: 1;
height: 100%;
overflow-y: auto;
}
.dialog-footer {
display: flex;
justify-content: flex-end;
}
.el-divider {
height: 100%;
margin: 0 10px;
}
.flex-container {
display: flex;
}
.align-center {
align-items: center;
}
.justify-between {
justify-content: space-between;
}
.flex1 {
flex: 1;
}
.version-select-content {
margin-left: 15px;
}
.pagination {
background: #fff;
padding: 15px 20px;
border-radius: 4px;
display: flex;
justify-content: space-between;
align-items: center;
.pagination-info {
color: #666;
font-size: 14px;
}
}
</style>
\ No newline at end of file
<template>
<el-dialog
v-model="dialogVisible"
:title="'变更记录'"
width="80%">
<el-row style="min-height: 300px;background-color: #000000;color:#FFFFFF;padding: 10px;">
{{ errorObj.create_time }} Error | {{ errorObj.clientError }}
</el-row>
<template #footer>
<div class="dialog-footer">
<el-button @click="handlerClose">关 闭</el-button>
</div>
</template>
</el-dialog>
</template>
<script setup>
import { ref, reactive } from 'vue';
const dialogVisible = ref(false);
const errorObj = ref({})
function show(obj) {
errorObj.value = obj;
dialogVisible.value = true;
}
function handlerClose() {
dialogVisible.value = false;
}
// 关键:通过defineExpose暴露方法,供父组件调用
defineExpose({
show
});
</script>
<style scoped lang="scss">
.step-content {
min-height: 400px;
}
.version-select {
margin-bottom: 20px;
}
.field-selection {
display: flex;
height: 400px;
}
.tree-container {
width: 250px;
height: 400px;
overflow-y: auto;
padding-right: 10px;
}
.table-container {
flex: 1;
height: 100%;
overflow-y: auto;
}
.dialog-footer {
display: flex;
justify-content: flex-end;
}
.el-divider {
height: 100%;
margin: 0 10px;
}
.flex-container {
display: flex;
}
.align-center {
align-items: center;
}
.justify-between {
justify-content: space-between;
}
.flex1 {
flex: 1;
}
.version-select-content {
margin-left: 15px;
}
.pagination {
background: #fff;
padding: 15px 20px;
border-radius: 4px;
display: flex;
justify-content: space-between;
align-items: center;
.pagination-info {
color: #666;
font-size: 14px;
}
}
</style>
\ No newline at end of file
++ "b/src/views/classification/MonitorManagement/\345\256\242\346\210\267\347\253\257\347\233\221\346\216\247\347\256\241\347\220\206"
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论