增加管理接口秘钥

This commit is contained in:
snltty
2024-04-29 14:18:38 +08:00
parent c6a1712f07
commit df2ed24dfe
195 changed files with 21135 additions and 515 deletions

View File

@@ -1,2 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" />
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Compile Update="MainForm.cs">
<SubType>Form</SubType>
</Compile>
</ItemGroup>
</Project>

View File

@@ -3,4 +3,9 @@
<PropertyGroup>
<_LastSelectedProfileId>D:\desktop\cmonitor\cmonitor.viewer.server.win\Properties\PublishProfiles\FolderProfile.pubxml</_LastSelectedProfileId>
</PropertyGroup>
<ItemGroup>
<Compile Update="MainForm.cs">
<SubType>Form</SubType>
</Compile>
</ItemGroup>
</Project>

23
cmonitor.web.client/.gitignore vendored Normal file
View File

@@ -0,0 +1,23 @@
.DS_Store
node_modules
/dist
# local env files
.env.local
.env.*.local
# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

View File

@@ -0,0 +1,19 @@
# cmonitor.web.client
## Project setup
```
npm install
```
### Compiles and hot-reloads for development
```
npm run serve
```
### Compiles and minifies for production
```
npm run build
```
### Customize configuration
See [Configuration Reference](https://cli.vuejs.org/config/).

View File

@@ -0,0 +1,5 @@
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset'
]
}

View File

@@ -0,0 +1,19 @@
{
"compilerOptions": {
"target": "es5",
"module": "esnext",
"baseUrl": "./",
"moduleResolution": "node",
"paths": {
"@/*": [
"src/*"
]
},
"lib": [
"esnext",
"dom",
"dom.iterable",
"scripthost"
]
}
}

18358
cmonitor.web.client/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,29 @@
{
"name": "cmonitor.web.client",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build"
},
"dependencies": {
"@element-plus/icons-vue": "^2.3.1",
"core-js": "^3.8.3",
"element-plus": "^2.7.1",
"vue": "^3.2.13",
"vue-router": "^4.0.3"
},
"devDependencies": {
"@vue/cli-plugin-babel": "~5.0.0",
"@vue/cli-plugin-router": "~5.0.0",
"@vue/cli-service": "~5.0.0",
"stylus": "^0.55.0",
"stylus-loader": "^6.1.0"
},
"browserslist": [
"> 1%",
"last 2 versions",
"not dead",
"not ie 11"
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View File

@@ -0,0 +1,17 @@
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>

View File

@@ -0,0 +1,38 @@
<template>
<div>
<div class="app-wrap flex flex-column flex-nowrap">
<div class="head"><Head></Head></div>
<div class="body flex-1">
<router-view/>
</div>
<div class="status">
<Status></Status>
</div>
</div>
</div>
</template>
<script>
import Head from './components/Head.vue'
import Status from './components/status/Index.vue'
import { provideGlobalData } from './provide';
export default{
components:{Head,Status},
setup(props) {
provideGlobalData();
}
}
</script>
<style lang="stylus" scoped>
.app-wrap{
box-sizing:border-box;
background-color:#fff;
border:1px solid #d0d7de;
width:80rem;
max-width : 80%;
height:90%;
position:absolute;
left:50%;
top:50%;
transform:translateX(-50%) translateY(-50%);
}
</style>

View File

@@ -0,0 +1,178 @@
import { ElMessage } from 'element-plus'
let requestId = 0, ws = null, wsUrl = '', index = 1, apiPassword = '';
//请求缓存,等待回调
const requests = {};
const queues = [];
export const websocketState = { connected: false, connecting: false };
const sendQueueMsg = () => {
if (queues.length > 0 && websocketState.connected && ws && ws.readyState == 1) {
try {
ws.send(queues.shift());
} catch (e) { }
}
setTimeout(sendQueueMsg, 1000 / 60);
}
//sendQueueMsg();
const sendTimeout = () => {
const time = Date.now();
for (let j in requests) {
const item = requests[j];
if (time - item.time > item.timeout) {
item.reject('超时~');
delete requests[j];
}
}
setTimeout(sendTimeout, 1000);
}
sendTimeout();
//发布订阅
export const pushListener = {
subs: {
},
add: function (type, callback) {
if (typeof callback == 'function') {
if (!this.subs[type]) {
this.subs[type] = [];
}
this.subs[type].push(callback);
}
},
remove(type, callback) {
let funcs = this.subs[type] || [];
for (let i = funcs.length - 1; i >= 0; i--) {
if (funcs[i] == callback) {
funcs.splice(i, 1);
}
}
},
push(type, data) {
let funcs = this.subs[type] || [];
for (let i = funcs.length - 1; i >= 0; i--) {
funcs[i](data);
}
}
}
//消息处理
const onWebsocketOpen = () => {
websocketState.connected = true;
websocketState.connecting = false;
pushListener.push(websocketStateChangeKey, websocketState.connected);
}
const onWebsocketClose = (e) => {
websocketState.connected = false;
websocketState.connecting = false;
pushListener.push(websocketStateChangeKey, websocketState.connected);
setTimeout(() => {
initWebsocket();
}, 1000);
}
export const onWebsocketMsg = (msg) => {
if (typeof msg.data != 'string') {
msg.data.arrayBuffer().then((res) => {
const length = new DataView(res).getInt8();
const reader = new FileReader();
reader.readAsText(msg.data.slice(4, 4 + length), 'utf8');
reader.onload = () => {
let json = JSON.parse(reader.result);
json.Content = {
Name: json.Content,
Img: msg.data.slice(4 + length, msg.data.length),
ArrayBuffer: res
};
pushMessage(json);
}
});
return;
}
let json = JSON.parse(msg.data);
pushMessage(json);
}
const pushMessage = (json) => {
let callback = requests[json.RequestId];
if (callback) {
if (json.Code == 0) {
callback.resolve(json.Content);
} else if (json.Code == 1) {
callback.reject(json.Content);
}
else if (json.Code == 255) {
callback.reject(json.Content);
if (!callback.errHandle) {
ElMessage.error(`${callback.path}:${json.Content}`);
}
} else {
pushListener.push(json.Path, json.Content);
}
delete requests[json.RequestId];
} else {
pushListener.push(json.Path, json.Content);
}
}
export const initWebsocket = (url = wsUrl, password = apiPassword) => {
apiPassword = password;
wsUrl = url;
if (websocketState.connecting) {
return;
}
if (ws != null) {
ws.close();
}
websocketState.connecting = true;
const protocol = password || 'snltty';
ws = new WebSocket(wsUrl, [protocol]);
ws.iddd = ++index;
ws.onopen = onWebsocketOpen;
ws.onclose = onWebsocketClose
ws.onmessage = onWebsocketMsg;
}
export const closeWebsocket = () => {
if (ws) {
ws.close();
}
}
//发送消息
export const sendWebsocketMsg = (path, msg = {}, errHandle = false, timeout = 15000) => {
return new Promise((resolve, reject) => {
let id = ++requestId;
try {
requests[id] = { resolve, reject, errHandle, path, time: Date.now(), timeout: timeout };
let str = JSON.stringify({
Path: path,
RequestId: id,
Content: typeof msg == 'string' ? msg : JSON.stringify(msg)
});
if (websocketState.connected && ws.readyState == 1) {
ws.send(str);
} else {
reject('网络错误~');
//queues.push(str);
}
} catch (e) {
console.log(e);
reject('网络错误~');
delete requests[id];
}
});
}
const websocketStateChangeKey = Symbol();
export const subWebsocketState = (callback) => {
pushListener.add(websocketStateChangeKey, callback);
}
export const subNotifyMsg = (path, callback) => {
pushListener.add(path, callback);
}
export const unsubNotifyMsg = (path, callback) => {
pushListener.remove(path, callback);
}

View File

@@ -0,0 +1,18 @@
import { sendWebsocketMsg } from './request'
export const getConfig = () => {
return sendWebsocketMsg('tunnel/config');
}
export const updateConfigSet = (data) => {
return sendWebsocketMsg('tunnel/configset', data);
}
export const updateConfigSetServers = (servers) => {
return sendWebsocketMsg('tunnel/configsetservers', servers);
}
export const getSignInfo = () => {
return sendWebsocketMsg('tunnel/signininfo');
}
export const updateSignInDel = (machineName) => {
return sendWebsocketMsg('tunnel/signindel', machineName);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View File

@@ -0,0 +1,372 @@
* {
margin: 0;
padding: 0;
list-style: none;
}
a {
text-decoration: none;
color: #6f9ccd;
}
:root {
--foot-menu-dropdown-color: #f5f5f5;
}
.flex {
display: flex;
display: -webkit-flex;
display: -ms-flex;
display: -o-flex;
flex-wrap: wrap;
}
.flex-nowrap {
flex-wrap: nowrap;
}
.flex-wrap {
flex-wrap: wrap;
}
.flex-column {
flex-direction: column;
}
.flex-row {
flex-direction: row;
}
.flex-1 {
-webkit-box-flex: 1;
-ms-flex-positive: 1;
flex: 1 1 0%;
}
.absolute {
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
}
.relative {
position: relative;
}
.h-100 {
height: 100%;
}
.w-100 {
width: 100%;
}
.t-c {
text-align: center;
}
.t-r {
text-align: right;
}
.t-l {
text-align: left !important;
}
.pdl-6 {
padding-left: .6rem;
}
.pdt-10 {
padding-top: 1rem;
}
.m-r-1 {
margin-right: 1rem;
}
table {
border-spacing: 0;
border-collapse: collapse;
}
html {
font-size: 10px;
/* background-color: #282c34; */
background-color: #f4f4f4;
}
body {
overflow: hidden;
}
span.split {
width: 0.6rem;
}
span.split-pad {
padding: 0 0.3rem;
}
span.split-pad10 {
padding: 0 1rem;
}
.middle {
vertical-align: middle;
}
.red {
color: red;
}
.scrollbar,
.scrollbar-1,
.scrollbar-4,
.scrollbar-10 {
overflow: auto;
}
.scrollbar-1::-webkit-scrollbar {
width: 0px;
height: 1px;
}
.scrollbar-1::-webkit-scrollbar-thumb {
background: rgba(0, 0, 0, 0.1);
border-radius: 10px;
}
.scrollbar::-webkit-scrollbar {
width: 1px;
height: 1px;
}
.scrollbar::-webkit-scrollbar-thumb {
background: rgba(0, 0, 0, 0.1);
border-radius: 10px;
}
.scrollbar-4::-webkit-scrollbar {
width: 4px;
height: 4px;
}
.scrollbar-4::-webkit-scrollbar-thumb {
background: rgba(0, 0, 0, 0.1);
border-radius: 10px;
}
.scrollbar-10::-webkit-scrollbar {
width: 10px;
height: 1px;
}
.scrollbar-10::-webkit-scrollbar-thumb {
background: rgba(0, 0, 0, 0.1);
border-radius: 10px;
}
:root {
--el-color-primary: var(--el-color-success) !important;
--el-color-primary-light-3: var(--el-color-success-light-3) !important;
--el-color-primary-light-5: var(--el-color-success-light-5) !important;
--el-color-primary-light-7: var(--el-color-success-light-7) !important;
--el-color-primary-light-8: var(--el-color-success-light-8) !important;
--el-color-primary-light-9: var(--el-color-success-light-9) !important;
--el-color-primary-dark-2: var(--el-color-success-dark-2) !important;
}
.el-table--scrollable-y .el-table__body-wrapper::-webkit-scrollbar {
background: #f5f5f5
}
.el-table--scrollable-y .el-table__body-wrapper::-webkit-scrollbar-thumb {
background: #ddd;
}
.el-collapse-item__header {
background-color: #fafafa !important;
border-left: 1px solid #EBEEF5;
border-right: 1px solid #EBEEF5;
padding: 0 2rem;
}
.el-collapse-item__content {
padding: 1rem;
border: 1px solid #EBEEF5;
border-bottom: 0;
}
.el-input.w-search .el-input__inner,
.el-input.w-search,
.el-select.w-search {
width: 10rem;
}
.el-form-item.w-search .el-form-item__label {
font-size: 1.2rem;
}
.table-search .el-form--inline .el-form-item {
margin-bottom: 0;
}
.el-dropdown {
font-size: 1.3rem;
}
.el-dropdown-menu__item {
font-size: 1.3rem;
}
.el-dropdown-menu__item a {
color: #333;
}
.el-input__inner:focus {
border-color: var(--main-color);
}
.el-date-editor.el-input.w-auto,
.el-date-editor.el-input__inner.w-auto {
width: auto;
}
.el-table .active-row {
background: rgba(0, 0, 0, 0.15);
}
.el-table .table-green-row {
background: rgba(0, 255, 0, 0.15);
}
.el-table .table-red-row {
background: rgba(255, 0, 0, 0.15);
}
.el-table .table-green-row td {
background: transparent !important;
}
.el-table .table-red-row td {
background: transparent !important;
}
.el-date-editor.el-input,
.el-date-editor.el-input__inner {
width: auto
}
.el-table .active-row td {
background: transparent !important;
}
.el-table--border th {
background-color: #fafafa;
}
.el-table--border,
.el-table--group,
.el-table-filter,
.el-table td,
.el-table th.is-leaf {
border-color: var(--main-border-color);
}
.el-pagination.is-background .el-pager li:not(.disabled).active {
background-color: var(--main-color);
}
.el-pagination.is-background .el-pager li:not(.disabled):hover {
color: var(--main-color);
}
.el-pagination .btn-next .el-icon,
.el-pagination .btn-prev .el-icon {
width: inherit;
}
.el-dialog {
max-width: 96%;
}
.el-dialog__body .el-form-item:last-child {
margin-bottom: 0;
}
.el-input-group__append,
.el-input-group__prepend {
padding: 0 4px !important;
background-color: transparent !important;
}
.el-checkbox__label .el-icon {
vertical-align: middle;
margin-top: -2px;
}
/* .el-input__inner:read-only {
background-color: #fafafa;
} */
.el-color-picker {
vertical-align: middle;
}
.el-color-picker__trigger {
border: 0 !important;
}
.el-color-picker__color {
border: 0 !important;
border-radius: 2px;
}
.el-color-picker__color-inner {
border-radius: 2px;
}
.el-message {
min-width: 10rem !important;
}
.card-header {
font-size: 1.4rem;
}
.forward-wrap .el-table--small.el-table .el-table__expanded-cell[class*=cell] {
padding: 20px 50px 20px 50px;
}
h3.title {
font-size: 1.6rem;
padding-bottom: .6rem;
color: #555;
}
.el-message-box {
max-width: 90%;
}
.el-select-dropdown__item {
padding-right: 2rem !important;
}
.el-form-item--default {
--font-size: 13px !important;
}
.el-input__inner {
font-size: 13px;
}
.el-dialog--center .el-dialog__body {
padding-top: 1rem !important;
padding-bottom: 1rem !important;
}

View File

@@ -0,0 +1,130 @@
<template>
<div>
<div class="head flex">
<div class="logo">
<router-link :to="{name:'Index'}">
<img src="../assets/logo.png" alt="">
</router-link>
</div>
<div class="menu">
<ul class="flex-1">
<li>
<router-link :to="{name:'Index'}">首页</router-link>
</li>
</ul>
</div>
</div>
<el-dialog class="options-center" title="管理接口" destroy-on-close v-model="showPort" center :show-close="false"
:close-on-click-modal="false" align-center width="200">
<div class="port-wrap t-c">
<div>
接口 : <el-input v-model="state.api" style="width:70%"></el-input>
</div>
<div class="pdt-10">
秘钥 : <el-input type="password" v-model="state.apipsd" style="width:70%"></el-input>
</div>
</div>
<template #footer>
<el-button type="success" @click="handleConnect" plain> </el-button>
</template>
</el-dialog>
</div>
</template>
<script>
import { computed, onMounted, reactive, watch } from 'vue';
import { initWebsocket, subWebsocketState } from '../apis/request'
import { getConfig,getSignInfo } from '../apis/tunnel'
import { useRoute } from 'vue-router';
import { injectGlobalData } from '../provide';
export default {
setup() {
const globalData = injectGlobalData();
const route = useRoute();
const state = reactive({
api: route.query.api ? `${window.location.hostname}:${route.query.api}` : (localStorage.getItem('api') || `${window.location.hostname}:1805`),
apipsd: route.query.apipsd ? `${route.query.apipsd}` : (localStorage.getItem('apipsd') || `snltty`),
showPort: false
});
localStorage.setItem('api', state.api);
localStorage.setItem('apipsd', state.apipsd);
const showPort = computed(() => globalData.value.connected == false && state.showPort);
const handleConnect = () => {
initWebsocket(`ws://${state.api}`,state.apipsd);
localStorage.setItem('api', state.api);
localStorage.setItem('apipsd', state.apipsd);
}
const _getConfig = ()=>{
getConfig().then((res)=>{
globalData.value.config.Common = res.Data.Common;
globalData.value.config.Client = res.Data.Client;
setTimeout(()=>{
_getConfig();
},1000);
}).catch((err)=>{
setTimeout(()=>{
_getConfig();
},1000);
});
}
const _getSignInfoInfo = ()=>{
getSignInfo().then((res)=>{
globalData.value.signin.Connected = res.Connected;
globalData.value.signin.Connecting = res.Connecting;
setTimeout(()=>{
_getSignInfoInfo();
},1000);
}).catch((err)=>{
setTimeout(()=>{
_getSignInfoInfo();
},1000);
});
}
onMounted(() => {
_getConfig();
_getSignInfoInfo();
handleConnect();
setTimeout(() => { state.showPort = true; }, 100);
subWebsocketState((state) => { if (state) globalData.value.updateFlag = Date.now(); });
});
return {
state, showPort, handleConnect
}
}
}
</script>
<style lang="stylus" scoped>
.head{
background-color:#f6f8fa;
border-bottom:1px solid #d0d7de;
box-shadow:1px 1px 4px rgba(0,0,0,0.05);
height:5rem;
line-height:5rem;
.logo{
padding:.5rem 0 0 1rem;
img{vertical-align:top;height:4rem;}
}
.menu{
padding-left:1rem;font-size:1.4rem;
li{box-sizing:border-box;padding:.5rem 0;margin-right:.5rem}
a{
display:block;
color:#333;
padding:0 1rem;
line-height:4rem
&:hover,&.router-link-active{
background-color:rgba(0,0,0,0.1);
font-weight:bold;
}
}
}
}
</style>

View File

@@ -0,0 +1,41 @@
<template>
<div class="status-api-wrap" :class="{connected:connected}">
<a href="javascript:;" @click="handleResetConnect">管理接口</a>
<span class="num">1</span>
</div>
</template>
<script>
import {computed} from 'vue'
import {useRoute,useRouter} from 'vue-router'
import {injectGlobalData} from '../../provide'
export default {
setup(props) {
const globalData = injectGlobalData();
const connected = computed(()=>globalData.value.connected);
const router = useRouter();
const route = useRoute();
const handleResetConnect = () => {
localStorage.setItem('api-client', '');
localStorage.setItem('apipsd-client', '');
router.push({name:route.name});
window.location.reload();
}
return {connected,handleResetConnect};
}
}
</script>
<style lang="stylus" scoped>
.status-api-wrap{
padding-right:2rem;
a{color:#333;}
span{border-radius:1rem;background-color:rgba(0,0,0,0.1);padding:0 .6rem;margin-left:.2rem}
&.connected {
a{color:green;font-weight:bold;}
span{background-color:green;color:#fff;}
}
}
</style>

View File

@@ -0,0 +1,34 @@
<template>
<div class="status-wrap flex">
<div class="copy"><a href="https://github.com/snltty/cmonitor" target="_blank">snltty©cmonitor v1.0.0</a></div>
<div class="flex-1"></div>
<div class="api"><Api></Api></div>
<div class="server"><Server></Server></div>
</div>
</template>
<script>
import Api from './Api.vue'
import Server from './Server.vue'
export default {
components:{Api,Server},
setup(props) {
}
}
</script>
<style lang="stylus" scoped>
.status-wrap{
border-top:1px solid #ddd;
background-color:#f5f5f5;
height:3rem;
line-height:3rem;
font-size:1.2rem;
color:#555;
.copy{
padding-left:.5rem;
a{color:#555;}
}
}
</style>

View File

@@ -0,0 +1,195 @@
<template>
<div class="status-server-wrap" :class="{connected:connected}">
<a href="javascript:;" @click="handleConfig">服务器 {{server}}</a>
<span class="num">{{serverLength}}</span>
</div>
<el-dialog v-model="state.show" title="登入设置" width="500">
<div>
<el-form :model="state.form" :rules="state.rules" label-width="6rem">
<el-form-item label="" label-width="0">
<el-col :span="12">
<el-form-item label="机器名" prop="name">
<el-input v-model="state.form.name" maxlength="12" show-word-limit />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="分组名" prop="groupid">
<el-input v-model="state.form.groupid" maxlength="32" show-word-limit />
</el-form-item>
</el-col>
</el-form-item>
<el-form-item label="" label-width="0">
<el-col :span="12">
<el-form-item label="服务器" prop="server">
<el-select v-model="state.form.server">
<template v-for="(item,index) in servers" :key="index">
<el-option :label="item.Name" :value="item.Host" >
<div class="flex">
<span>{{item.Name}}</span>
<span>{{item.Host}}</span>
<span class="pdl-6" @click.stop>
<el-popconfirm title="删除不可逆,确认吗?" @confirm.stop="handleDel(item)">
<template #reference>
<el-button size="small">删除</el-button>
</template>
</el-popconfirm>
</span>
</div>
</el-option>
</template>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<div class="pdl-6"><el-button @click="handleAdd">添加服务器</el-button></div>
</el-col>
</el-form-item>
</el-form>
</div>
<template #footer>
<div class="dialog-footer t-c">
<el-button @click="state.show = false" :loading="state.loading">取消</el-button>
<el-button type="primary" @click="handleSave" :loading="state.loading">确定保存</el-button>
</div>
</template>
</el-dialog>
<el-dialog v-model="state.showAdd" title="添加服务器" width="300">
<div>
<el-form :model="state.formAdd" :rules="state.rulesAdd" label-width="6rem">
<el-form-item label="名称" prop="name">
<el-input v-model="state.formAdd.name" maxlength="12" show-word-limit />
</el-form-item>
<el-form-item label="地址" prop="host">
<el-input v-model="state.formAdd.host" placeholder="ip/域名:端口" />
</el-form-item>
</el-form>
</div>
<template #footer>
<div class="dialog-footer t-c">
<el-button @click="state.showAdd = false" :loading="state.loading">取消</el-button>
<el-button type="primary" @click="handleSaveAdd" :loading="state.loading">确定保存</el-button>
</div>
</template>
</el-dialog>
</template>
<script>
import { updateConfigSet, updateConfigSetServers } from '@/apis/tunnel';
import { injectGlobalData } from '@/provide';
import { ElMessage } from 'element-plus';
import { computed, reactive } from 'vue';
export default {
setup(props) {
const globalData = injectGlobalData();
const connected = computed(()=>globalData.value.signin.Connected);
const connecting = computed(()=>globalData.value.signin.Connecting);
const server = computed(()=>globalData.value.config.Client.Server);
const servers = computed(()=>globalData.value.config.Client.Servers || []);
const serverLength = computed(()=>(globalData.value.config.Client.Servers||[]).length);
const state = reactive({
show:false,
loading:false,
form:{
name:globalData.value.config.Client.Name,
server:globalData.value.config.Client.Server,
groupid:globalData.value.config.Client.GroupId,
},
rules:{},
showAdd:false,
formAdd:{
name:'',
host:''
},
rulesAdd:{
name:[
{ required: true, message: '听填写', trigger: 'blur' },
],
host:[
{ required: true, message: '听填写', trigger: 'blur' },
]
},
});
const handleConfig = ()=>{
state.form.name = globalData.value.config.Client.Name;
state.form.server = globalData.value.config.Client.Server;
state.form.groupid = globalData.value.config.Client.GroupId;
state.show = true;
}
const handleSave = ()=>{
state.loading = true;
updateConfigSet(state.form).then(()=>{
state.loading = false;
state.show = false;
ElMessage.success('已操作');
globalData.value.updateFlag = Date.now();
}).catch((err)=>{
state.loading = false;
ElMessage.success('操作失败!');
});
}
const handleDel = (item)=>{
const servers = (globalData.value.config.Client.Servers || []).filter(c=>c.Host != item.Host || c.Name != item.Name);
state.loading = true;
updateConfigSetServers(servers).then(()=>{
state.loading = false;
ElMessage.success('已操作');
globalData.value.updateFlag = Date.now();
}).catch((err)=>{
state.loading = false;
ElMessage.success('操作失败!');
});
}
const handleAdd = ()=>{
state.showAdd = true;
state.formAdd.name = '';
state.formAdd.host = '';
}
const handleSaveAdd = ()=>{
const servers = globalData.value.config.Client.Servers || [];
const name = state.formAdd.name.replace(/^\s|\s$/g,'');
const host = state.formAdd.host.replace(/^\s|\s$/g,'');
if(servers.filter(c=>c.Host == host).length > 0 || servers.filter(c=>c.Name == name).length > 0){
ElMessage.error('已存在差不多相同的记录!');
return;
}
servers.push({Name:name,Host:host});
state.loading = true;
updateConfigSetServers(servers).then(()=>{
state.loading = false;
state.showAdd = false;
ElMessage.success('已操作');
globalData.value.updateFlag = Date.now();
}).catch((err)=>{
state.loading = false;
ElMessage.success('操作失败!');
});
}
return {
connected,connecting,server,servers,serverLength,state,handleConfig,handleSave,
handleDel,handleAdd,handleSaveAdd
}
}
}
</script>
<style lang="stylus" scoped>
.status-server-wrap{
padding-right:.5rem;
a{color:#333;}
span{border-radius:1rem;background-color:rgba(0,0,0,0.1);padding:0 .6rem; margin-left:.2rem}
&.connected {
a{color:green;font-weight:bold;}
span{background-color:green;color:#fff;}
}
}
</style>

View File

@@ -0,0 +1,23 @@
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
// import VConsole from 'vconsole';
// new VConsole();
const app = createApp(App);
import './assets/style.css'
import ElementPlus from 'element-plus';
import 'element-plus/dist/index.css'
import 'element-plus/theme-chalk/display.css'
import 'element-plus/theme-chalk/dark/css-vars.css'
import {
ChromeFilled,
} from '@element-plus/icons-vue'
app.component(ChromeFilled.name, ChromeFilled);
app.use(ElementPlus, { size: 'default' }).use(router).mount('#app');

View File

@@ -0,0 +1,23 @@
import { subWebsocketState } from "@/apis/request";
import { computed, inject, provide, ref } from "vue";
const globalDataSymbol = Symbol();
export const provideGlobalData = () => {
const globalData = ref({
//已连接
connected: false,
updateFlag: false,
config: { Common: {}, Client: {} },
signin: { Connected: false, Connecting: false }
});
subWebsocketState((state) => {
globalData.value.connected = state;
});
provide(globalDataSymbol, globalData);
return globalData;
}
export const injectGlobalData = () => {
return inject(globalDataSymbol);
}

View File

@@ -0,0 +1,15 @@
import { createRouter, createWebHashHistory } from 'vue-router'
const routes = [
{
path: '/',
name: 'Index',
component: () => import('../views/Index.vue')
}
]
const router = createRouter({
history: createWebHashHistory(),
routes
})
export default router

View File

@@ -0,0 +1,10 @@
<template>
<div class="home"></div>
</template>
<script>
export default {
name: 'Index',
components: {}
}
</script>

View File

@@ -0,0 +1,10 @@
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
productionSourceMap: process.env.NODE_ENV === 'production' ? false : true,
outputDir: '../public/extends/web-client',
transpileDependencies: true,
publicPath: './',
devServer: {
port: 8081
}
})

View File

@@ -1,8 +1,8 @@
import { sendWebsocketMsg } from './request'
export const notifyUpdate = (speed, msg, star1, star2, star3) => {
export const notifyUpdate = (groupid, speed, msg, star1, star2, star3) => {
return sendWebsocketMsg('notify/update', {
speed, msg, star1, star2, star3
groupid, speed, msg, star1, star2, star3
});
}

View File

@@ -1,6 +1,6 @@
import { ElMessage } from 'element-plus'
let requestId = 0, ws = null, wsUrl = '', index = 1;
let requestId = 0, ws = null, wsUrl = '', index = 1, apiPassword = '';
//请求缓存,等待回调
const requests = {};
const queues = [];
@@ -115,7 +115,8 @@ const pushMessage = (json) => {
pushListener.push(json.Path, json.Content);
}
}
export const initWebsocket = (url = wsUrl) => {
export const initWebsocket = (url = wsUrl, password = apiPassword) => {
apiPassword = password;
wsUrl = url;
if (websocketState.connecting) {
return;
@@ -124,7 +125,8 @@ export const initWebsocket = (url = wsUrl) => {
ws.close();
}
websocketState.connecting = true;
ws = new WebSocket(wsUrl);
const protocol = password || 'snltty';
ws = new WebSocket(wsUrl, [protocol]);
ws.iddd = ++index;
ws.onopen = onWebsocketOpen;
ws.onclose = onWebsocketClose
@@ -154,6 +156,7 @@ export const sendWebsocketMsg = (path, msg = {}, errHandle = false, timeout = 15
//queues.push(str);
}
} catch (e) {
console.log(e);
reject('网络错误~');
delete requests[id];
}

View File

@@ -1,7 +1,7 @@
import { sendWebsocketMsg } from './request'
export const getList = () => {
return sendWebsocketMsg('signin/list');
export const getList = (groupid) => {
return sendWebsocketMsg('signin/list', groupid);
}
export const getConfig = () => {
return sendWebsocketMsg('signin/config');

View File

@@ -15,7 +15,15 @@
<el-dialog class="options-center" title="管理接口" destroy-on-close v-model="showPort" center :show-close="false"
:close-on-click-modal="false" align-center width="70%">
<div class="port-wrap t-c">
<el-input v-model="state.api" style="width:auto"></el-input>
<div>
接口 : <el-input v-model="state.api" style="width:70%"></el-input>
</div>
<div style="padding-top:1rem ;">
秘钥 : <el-input type="password" v-model="state.apipsd" style="width:70%"></el-input>
</div>
<div style="padding-top:1rem ;">
分组 : <el-input v-model="state.groupid" style="width:70%"></el-input>
</div>
</div>
<template #footer>
<el-button type="success" @click="handleConnect" plain> </el-button>
@@ -28,6 +36,7 @@
import { computed, onMounted, reactive, watch } from 'vue';
import { initWebsocket, subWebsocketState } from '../apis/request'
import { getRules, addName } from '../apis/rule'
import { getConfig } from '../apis/signin'
import { useRoute } from 'vue-router';
import { injectGlobalData } from './provide';
export default {
@@ -38,23 +47,36 @@ export default {
const state = reactive({
api: route.query.api ? `${window.location.hostname}:${route.query.api}` : (localStorage.getItem('api') || `${window.location.hostname}:1801`),
apipsd: route.query.apipsd ? `${route.query.apipsd}` : (localStorage.getItem('apipsd') || `snltty`),
groupid: route.query.groupid ? `${route.query.groupid}` : (localStorage.getItem('groupid') || `snltty`),
usernames: [],
username: globalData.value.username || localStorage.getItem('username') || '',
showPort: false
});
localStorage.setItem('api', state.api);
localStorage.setItem('apipsd', state.apipsd);
localStorage.setItem('groupid', state.groupid);
globalData.value.username = state.username;
globalData.value.groupid = state.groupid;
const showSelectUsername = computed(() => !!!globalData.value.username && globalData.value.connected);
const showPort = computed(() => globalData.value.connected == false && state.showPort);
watch(() => globalData.value.updateRuleFlag, () => {
_getRules();
_getConfig();
});
watch(() => globalData.value.updateDeviceFlag, () => {
_getRules();
_getConfig();
});
const _getConfig = ()=>{
getConfig().then((res)=>{
globalData.value.config.Common = res.Data.Common;
globalData.value.config.Server = res.Data.Server;
}).catch((err)=>{});
}
const _getRules = () => {
getRules().then((res) => {
@@ -68,13 +90,17 @@ export default {
}).catch(() => { });
}
const handleConnect = () => {
//initWebsocket(`ws://hk.cmonitor.snltty.com:1801`);
initWebsocket(`ws://${state.api}`);
//initWebsocket(`ws://hk.cmonitor.snltty.com:1801`,state.apipsd);
initWebsocket(`ws://${state.api}`,state.apipsd);
localStorage.setItem('api', state.api);
localStorage.setItem('apipsd', state.apipsd);
localStorage.setItem('groupid', state.groupid);
}
const handleUsername = () => {
globalData.value.username = state.username || '';
globalData.value.groupid = state.groupid || '';
localStorage.setItem('username', globalData.value.username);
localStorage.setItem('groupid', globalData.value.groupid);
document.title = `班长-${globalData.value.username}`
}
const handleChange = (value) => {
@@ -90,6 +116,8 @@ export default {
handleConnect();
_getRules();
_getConfig();
setTimeout(() => { state.showPort = true; }, 100);
subWebsocketState((state) => { if (state) globalData.value.updateRuleFlag = Date.now(); });
@@ -103,22 +131,4 @@ export default {
</script>
<style lang="stylus" scoped>
.head-wrap {
text-align: center;
padding: 0.5rem 0;
line-height: 4rem;
border-bottom: 1px solid #ddd;
background-color: #f0f0f0;
font-size: 1.5rem;
font-weight: bold;
z-index: 999;
position: relative;
box-shadow: 1px 1px 4px rgba(0, 0, 0, 0.075);
}
img {
height: 4rem;
vertical-align: middle;
margin-right: 0.6rem;
}
</style>

View File

@@ -8,19 +8,6 @@
<div class="items flex-1 relative scrollbar-1">
<Items></Items>
</div>
<!-- <div class="active-device flex flex-column" v-if="globalData.pc">
<div class="flex-1 prev">
<div class="prev-inner">
<h3>{{globalData.currentDevice.MachineName}}</h3>
<div class="inner">
<canvas id="prev-canvas" width="1920" height="1080"></canvas>
</div>
</div>
</div>
</div> -->
</div>
<div class="foot" v-if="!globalData.pc">
<div class="foot-options">
@@ -42,15 +29,19 @@ import Items from './wraps/Items.vue'
import Head from './wraps/Head.vue'
import { providePluginState } from './provide'
import { injectGlobalData } from '../provide'
import { computed } from 'vue'
export default {
components: { Items, FootMenu, FootOptions, Head },
setup() {
const globalData = injectGlobalData();
const plugins = computed(()=>globalData.value.config.Common.Plugins||[]);
const files = require.context('./plugins/', true, /index\.js/);
const pluginSettings = files.keys().map(c => files(c).default);
const pluginState = pluginSettings.reduce((data, item, index) => {
const _pluginSettings = files.keys().map(c => files(c).default);
const pluginSettings = computed(()=>_pluginSettings.filter(c=>plugins.value.length == 0 || plugins.value.indexOf(c.pluginName)>=0));
const pluginState = pluginSettings.value.reduce((data, item, index) => {
if (item.state) {
data = Object.assign(data, item.state);
}
@@ -59,7 +50,8 @@ export default {
const state = providePluginState(pluginState);
const indexFiles = require.context('./plugins/', true, /Index\.vue/);
const indexModules = indexFiles.keys().map(c => indexFiles(c).default);
const _indexModules = indexFiles.keys().map(c => indexFiles(c).default);
const indexModules = computed(()=>_indexModules.filter(c=>plugins.value.length == 0 || plugins.value.indexOf(c.pluginName)>=0));
return {
indexModules, globalData
@@ -69,35 +61,6 @@ export default {
</script>
<style lang="stylus" scoped>
// @media (min-width: 768px) {
// .active-device {
// // width: calc(100% - 41rem) !important;
// }
// .items {
// padding: 1rem 1rem 0 1rem !important;
// height: auto;
// width: 80.6rem;
// // padding: 1rem 0 !important;
// box-sizing: border-box;
// // border-right: 1px solid #999;
// // background-color: rgba(255, 255, 255, 0.3);
// display: flex;
// display: -ms-flex;
// display: -o-flex;
// flex-wrap: wrap;
// justify-content: space-between;
// }
// .foot {
// display: none;
// }
// }
// @media (min-width: 768px) {
// .items {
// max-width: 39rem;
// }
// }
.device-list-wrap {
.content {
position: relative;

View File

@@ -12,6 +12,7 @@
<script>
import { injectPluginState } from '../../provide'
export default {
pluginName:'cmonitor.plugin.active.',
props: ['data'],
setup(props) {

View File

@@ -34,6 +34,7 @@ import { activeDisallow } from '@/apis/active'
import { injectGlobalData } from '@/views/provide';
import { injectPluginState } from '../../provide';
export default {
pluginName:'cmonitor.plugin.active.',
props: ['modelValue'],
emits: ['update:modelValue'],
components: { CheckBoxWrap },

View File

@@ -11,6 +11,7 @@
import { injectPluginState } from '../../provide';
export default {
sort: 1,
pluginName:'cmonitor.plugin.active.',
setup() {
const pluginState = injectPluginState();

View File

@@ -9,6 +9,7 @@
import { injectGlobalData } from '@/views/provide';
import { injectPluginState } from '../../provide';
export default {
pluginName:'cmonitor.plugin.active.',
setup() {
const pluginState = injectPluginState();

View File

@@ -17,6 +17,7 @@ import ChooseDig from './ChooseDig.vue'
import { injectPluginState } from '../../provide'
export default {
components: { ActiveTimes, Windows, ChooseDig, AddWindow, ActiveWindows },
pluginName:'cmonitor.plugin.active.',
setup() {
const pluginState = injectPluginState();
return {

View File

@@ -24,6 +24,7 @@ import CheckBoxWrap from '../../boxs/CheckBoxWrap.vue'
import { injectGlobalData } from '@/views/provide';
export default {
label: '窗口',
pluginName:'cmonitor.plugin.active.',
components: { CheckBoxWrap },
setup(props, { emit }) {

View File

@@ -24,6 +24,7 @@ import { injectPluginState } from '../../provide';
import { activeKill } from '@/apis/active';
export default {
props: ['data'],
pluginName:'cmonitor.plugin.active.',
setup(props, { emit }) {
const pluginState = injectPluginState();

View File

@@ -1,4 +1,5 @@
export default {
pluginName: 'cmonitor.plugin.active.',
field() {
return {
ActiveWindow: {

View File

@@ -11,6 +11,7 @@
<script>
import { injectPluginState } from '../../provide'
export default {
pluginName:'cmonitor.plugin.command.',
props: ['data'],
setup(props) {

View File

@@ -28,6 +28,7 @@ import PrevBoxWrap from '../../boxs/PrevBoxWrap.vue'
import { injectPluginState } from '../../provide';
import { injectGlobalData } from '@/views/provide';
export default {
pluginName:'cmonitor.plugin.command.',
props: ['modelValue'],
emits: ['update:modelValue'],
components: { CheckBoxWrap, PrevBoxWrap },

View File

@@ -11,6 +11,7 @@
<script>
import { injectPluginState } from '../../provide'
export default {
pluginName:'cmonitor.plugin.command.',
setup() {
const pluginState = injectPluginState();

View File

@@ -8,6 +8,7 @@
import { injectGlobalData } from '@/views/provide';
import { injectPluginState } from '../../provide'
export default {
pluginName:'cmonitor.plugin.command.',
setup() {
const pluginState = injectPluginState();

View File

@@ -10,6 +10,7 @@ import { injectPluginState } from '../../provide'
import ChooseDig from './ChooseDig.vue'
import Term from './Term.vue'
export default {
pluginName:'cmonitor.plugin.command.',
components: { ChooseDig, Term },
setup() {
const pluginState = injectPluginState();

View File

@@ -1,4 +1,5 @@
export default {
pluginName: 'cmonitor.plugin.command.',
field() {
return {
Command: {

View File

@@ -34,6 +34,7 @@ import { ElMessage } from 'element-plus';
import { injectGlobalData } from '@/views/provide';
export default {
pluginName:'cmonitor.plugin.device.',
props: ['modelValue'],
emits: ['update:modelValue'],
components: { CheckBoxWrap },

View File

@@ -10,6 +10,7 @@
<script>
import { injectPluginState } from '../../provide'
export default {
pluginName:'cmonitor.plugin.device.',
sort: 0,
setup() {

View File

@@ -8,6 +8,7 @@
import { injectPluginState } from '../../provide';
import ChooseDig from './ChooseDig.vue'
export default {
pluginName:'cmonitor.plugin.device.',
components: { ChooseDig },
setup() {
const pluginState = injectPluginState();

View File

@@ -1,4 +1,5 @@
export default {
pluginName: 'cmonitor.plugin.device.',
state: {
device: {
showDevices: false

View File

@@ -10,6 +10,7 @@
<script>
import { injectPluginState } from '../../provide'
export default {
pluginName:'cmonitor.plugin.hijack.',
props: ['data'],
setup(props) {

View File

@@ -38,6 +38,7 @@ import { setRules } from '../../../../apis/hijack'
import { injectGlobalData } from '@/views/provide';
import { injectPluginState } from '../../provide';
export default {
pluginName:'cmonitor.plugin.hijack.',
props: ['modelValue', 'items'],
emits: ['update:modelValue'],
components: { CheckBoxWrap },
@@ -51,20 +52,7 @@ export default {
const usePublic = publicUser.value && globalData.value.username != publicUserName;
const state = reactive({
show: props.modelValue,
items: computed(() => {
const devices = pluginState.value.hijack.devices;
let ids1 = devices.reduce((arr, value) => {
arr.push(...value.Hijack.RuleIds1);
return arr;
}, []);
let ids2 = devices.reduce((arr, value) => {
arr.push(...value.Hijack.RuleIds2);
return arr;
}, []);
state.currentPrivate = state.privateRules.filter(c => ids1.indexOf(c.Name) >= 0);
state.currentPublic = state.publicRules.filter(c => ids2.indexOf(c.Name) >= 0);
return devices;
}),
items:[],
privateRules: computed(() => user.value ? user.value.Processs || [] : []),
publicRules: computed(() => usePublic ? publicUser.value.Processs || [] : []),
loading: false,
@@ -72,6 +60,7 @@ export default {
currentPublic: [],
domainKill: false
});
watch(() => state.show, (val) => {
if (!val) {
setTimeout(() => {
@@ -161,11 +150,26 @@ export default {
const parseDomainKill = () => {
state.domainKill = pluginState.value.hijack.devices.filter(c => c.Hijack.DomainKill === true).length > 0;
}
const parseItems = (devices)=>{
let ids1 = devices.reduce((arr, value) => {
arr.push(...value.Hijack.RuleIds1);
return arr;
}, []);
let ids2 = devices.reduce((arr, value) => {
arr.push(...value.Hijack.RuleIds2);
return arr;
}, []);
state.currentPrivate = state.privateRules.filter(c => ids1.indexOf(c.Name) >= 0);
state.currentPublic = state.publicRules.filter(c => ids2.indexOf(c.Name) >= 0);
state.items = devices;
}
const handleDevicesChange = (devices) => {
parseDomainKill();
parseItems(devices);
}
onMounted(() => {
parseDomainKill();
parseItems( pluginState.value.hijack.devices);
});
return {

View File

@@ -23,6 +23,7 @@
<script>
import { injectPluginState } from '@/views/device/provide'
export default {
pluginName:'cmonitor.plugin.hijack.',
sort: 2,
setup() {

View File

@@ -12,6 +12,7 @@ import ChooseDig from './ChooseDig.vue'
import RuleSetting from './rules/Index.vue'
import ProcessSetting from './process/Index.vue'
export default {
pluginName:'cmonitor.plugin.hijack.',
components: { ChooseDig, RuleSetting, ProcessSetting },
setup() {
const pluginState = injectPluginState();

View File

@@ -22,6 +22,7 @@ import { computed, getCurrentInstance, inject, onMounted, watch,nextTick } from
import CheckBoxWrap from '../../boxs/CheckBoxWrap.vue'
import { injectGlobalData } from '@/views/provide';
export default {
pluginName:'cmonitor.plugin.hijack.',
label: '网络',
components: { CheckBoxWrap },
setup(props, { emit }) {

View File

@@ -17,6 +17,7 @@
<script>
export default {
pluginName:'cmonitor.plugin.hijack.',
props: ['data'],
setup(props) {

View File

@@ -1,5 +1,6 @@
import { injectGlobalData } from "@/views/provide";
export default {
pluginName: 'cmonitor.plugin.hijack.',
field() {
return {
Hijack: {

View File

@@ -9,6 +9,7 @@
<script>
import { injectPluginState } from '../../provide'
export default {
pluginName:'cmonitor.plugin.keyboard.',
props: ['data'],
setup(props) {

View File

@@ -13,6 +13,7 @@ import { ElMessage, ElMessageBox } from 'element-plus';
import { injectPluginState } from '../../provide'
import { ctrlAltDelete } from '@/apis/keyboard';
export default {
pluginName:'cmonitor.plugin.keyboard.',
setup() {
const pluginState = injectPluginState();

View File

@@ -8,6 +8,7 @@
import { injectPluginState } from '../../provide'
import KeyBoard from './KeyBoard.vue'
export default {
pluginName:'cmonitor.plugin.keyboard.',
components: { KeyBoard },
setup() {
const pluginState = injectPluginState();

View File

@@ -24,6 +24,7 @@ import { computed, onMounted, reactive } from 'vue'
import { injectPluginState } from '../../provide';
import { keyboard } from '@/apis/keyboard';
export default {
pluginName:'cmonitor.plugin.keyboard.',
setup() {
const pluginState = injectPluginState();

View File

@@ -1,4 +1,5 @@
export default {
pluginName: 'cmonitor.plugin.keyboard.',
field() {
return {
Keyboard: {

View File

@@ -17,6 +17,7 @@
<script>
import { injectPluginState } from '../../provide'
export default {
pluginName:'cmonitor.plugin.light.',
props: ['data'],
setup(props) {

View File

@@ -8,6 +8,7 @@
import { injectGlobalData } from '@/views/provide';
import { injectPluginState } from '../../provide';
export default {
pluginName:'cmonitor.plugin.light.',
setup() {
const pluginState = injectPluginState();

View File

@@ -10,6 +10,7 @@ import { injectPluginState } from '../../provide';
import Light from './Light.vue'
import LightSingle from './LightSingle.vue'
export default {
pluginName:'cmonitor.plugin.light.',
components: { Light, LightSingle },
setup() {
const pluginState = injectPluginState();

View File

@@ -50,6 +50,7 @@ import { setLight } from '../../../../apis/light'
import { injectGlobalData } from '@/views/provide';
import { injectPluginState } from '../../provide';
export default {
pluginName:'cmonitor.plugin.light.',
props: ['modelValue'],
emits: ['update:modelValue'],
components: { CheckBoxWrap, PrevBoxWrap },

View File

@@ -17,6 +17,7 @@ import { setLight } from '../../../../apis/light'
import { injectGlobalData } from '@/views/provide';
import { injectPluginState } from '../../provide';
export default {
pluginName:'cmonitor.plugin.light.',
props: ['modelValue', 'items'],
emits: ['update:modelValue'],
components: {},

View File

@@ -1,6 +1,7 @@
import { injectGlobalData } from "@/views/provide";
export default {
pluginName: 'cmonitor.plugin.light.',
field() {
return {
Light: {

View File

@@ -18,6 +18,7 @@ import { ElMessage, ElMessageBox } from 'element-plus';
import { injectPluginState } from '../../provide'
import { llockScreen, lockSystem } from '../../../../apis/llock'
export default {
pluginName:'cmonitor.plugin.llock.',
setup() {
const pluginState = injectPluginState();

View File

@@ -9,6 +9,7 @@ import { llockScreen } from '@/apis/llock';
import { injectPluginState } from '../../provide'
import { ElMessage, ElMessageBox } from 'element-plus';
export default {
pluginName:'cmonitor.plugin.llock.',
sort: 2,
props: ['data'],
setup(props) {

View File

@@ -1,4 +1,5 @@
export default {
pluginName: 'cmonitor.plugin.llock.',
field() {
return {
LLock: {

View File

@@ -9,6 +9,7 @@
<script>
import { injectPluginState } from '../../provide'
export default {
pluginName:'cmonitor.plugin.message.',
props: ['data'],
setup(props) {
const pluginState = injectPluginState();

View File

@@ -54,6 +54,7 @@ import { play } from '@/apis/volume'
import pako from 'pako';
export default {
pluginName:'cmonitor.plugin.message.',
props: ['modelValue'],
emits: ['update:modelValue'],
components: { CheckBoxWrap, PrevBoxWrap },

View File

@@ -9,6 +9,7 @@
import { injectGlobalData } from '@/views/provide';
import { injectPluginState } from '../../provide';
export default {
pluginName:'cmonitor.plugin.message.',
setup() {
const pluginState = injectPluginState();

View File

@@ -8,6 +8,7 @@
import { injectPluginState } from '../../provide'
import ChooseDig from './ChooseDig.vue'
export default {
pluginName:'cmonitor.plugin.message.',
components: { ChooseDig },
setup() {

View File

@@ -1,4 +1,5 @@
export default {
pluginName: 'cmonitor.plugin.message.',
state: {
message: {
showMessage: false,

View File

@@ -35,6 +35,7 @@ import { injectPluginState } from '../../provide';
import { useModes } from '../../../../apis/modes';
export default {
pluginName:'cmonitor.plugin.modes.',
props: ['modelValue'],
emits: ['update:modelValue'],
components: { CheckBoxWrap },

View File

@@ -10,6 +10,7 @@
<script>
import { injectPluginState } from '../../provide'
export default {
pluginName:'cmonitor.plugin.modes.',
sort: 0,
setup() {

View File

@@ -8,6 +8,7 @@
import { injectGlobalData } from '@/views/provide';
import { injectPluginState } from '../../provide';
export default {
pluginName:'cmonitor.plugin.modes.',
setup() {
const pluginState = injectPluginState();

View File

@@ -10,6 +10,7 @@ import { injectPluginState } from '../../provide';
import ChooseDig from './ChooseDig.vue'
import SettingDig from './SettingDig.vue'
export default {
pluginName:'cmonitor.plugin.modes.',
components: { ChooseDig, SettingDig },
setup() {
const pluginState = injectPluginState();

View File

@@ -42,6 +42,7 @@ import { injectGlobalData } from '@/views/provide';
import { updateModes } from '../../../../apis/modes';
export default {
pluginName:'cmonitor.plugin.modes.',
props: ['modelValue'],
emits: ['update:modelValue'],
components: {},

View File

@@ -1,4 +1,5 @@
export default {
pluginName: 'cmonitor.plugin.modes.',
field() {
return {

View File

@@ -6,6 +6,7 @@
<script>
export default {
pluginName:'cmonitor.plugin.report.',
sort: -1,
props: ['data'],
setup(props) {

View File

@@ -2,6 +2,7 @@ import { subNotifyMsg } from '@/apis/request';
import { reportPing, reportUpdate } from '../../../../apis/report'
import { injectGlobalData } from '@/views/provide';
export default {
pluginName: 'cmonitor.plugin.report.',
field() {
return {
Report: {

View File

@@ -14,6 +14,7 @@ import { injectPluginState } from '../../provide'
import { screenDisplay } from '../../../../apis/display'
import { injectGlobalData } from '@/views/provide';
export default {
pluginName:'cmonitor.plugin.screen.',
setup() {
const pluginState = injectPluginState();

View File

@@ -5,6 +5,7 @@
<script>
export default {
pluginName:'cmonitor.plugin.screen.',
components: {},
setup() {

View File

@@ -2,6 +2,7 @@ import { injectGlobalData } from '@/views/provide';
import { screenClip, screenUpdateFull, screenUpdateRegion } from '../../../../apis/screen'
import { subNotifyMsg } from '@/apis/request';
export default {
pluginName: 'cmonitor.plugin.screen.',
field() {
return {
Screen: {

View File

@@ -6,6 +6,7 @@
<script>
import { injectPluginState } from '../../provide';
export default {
pluginName:'cmonitor.plugin.share.',
components: {},
setup() {
const pluginState = injectPluginState();

View File

@@ -46,10 +46,13 @@ import { reactive } from 'vue'
import { shareUpdate } from '@/apis/share'
import { notifyUpdate } from '@/apis/notify'
import { ElMessage } from 'element-plus';
import { injectGlobalData } from '@/views/provide';
export default {
pluginName:'cmonitor.plugin.share.',
props: ['data'],
setup(props) {
const globalData = injectGlobalData();
const state = reactive({
loading: false
});
@@ -85,7 +88,7 @@ export default {
if (res) {
ElMessage.success('操作成功!');
if (value.notify) {
notifyUpdate(2, props.data.Share.UserName.Value, value.star1, value.star2, value.star3);
notifyUpdate(globalData.value.groupid,2, props.data.Share.UserName.Value, value.star1, value.star2, value.star3);
}
} else {
ElMessage.error('操作失败!');

View File

@@ -4,6 +4,7 @@
<script>
export default {
pluginName:'cmonitor.plugin.share.',
props: ['data'],
setup(props) {

View File

@@ -1,4 +1,5 @@
export default {
pluginName: 'cmonitor.plugin.share.',
field() {
return {
Share: {

View File

@@ -15,6 +15,7 @@ import { injectPluginState } from '@/views/device/provide';
import SnatchTemplate from './template/Template.vue'
import SnatchUse from './use/Use.vue'
export default {
pluginName:'cmonitor.plugin.snatch.',
components: { SnatchTemplate, SnatchUse },
setup() {

View File

@@ -1,4 +1,5 @@
export default {
pluginName: 'cmonitor.plugin.snatch.',
field() {
return {
};

View File

@@ -12,6 +12,7 @@
<script>
import { injectPluginState } from '../../provide'
export default {
pluginName:'cmonitor.plugin.system.',
props: ['data'],
setup(props) {

View File

@@ -19,6 +19,7 @@ import { injectPluginState } from '../../provide'
import { exec } from '@/apis/command';
import { injectGlobalData } from '@/views/provide';
export default {
pluginName:'cmonitor.plugin.system.',
setup() {
const pluginState = injectPluginState();

View File

@@ -8,6 +8,7 @@
import { injectPluginState } from '../../provide'
import SystemOptions from './SystemOptions.vue'
export default {
pluginName:'cmonitor.plugin.system.',
components: { SystemOptions },
setup() {
const pluginState = injectPluginState();

View File

@@ -24,6 +24,7 @@ import { reactive } from '@vue/reactivity';
import { getCurrentInstance, inject, onMounted, watch } from '@vue/runtime-core';
import { injectGlobalData } from '@/views/provide';
export default {
pluginName:'cmonitor.plugin.system.',
label: '系统选项',
setup(props, { emit }) {

View File

@@ -16,6 +16,7 @@ import { ElMessage, ElMessageBox } from 'element-plus';
import { computed } from 'vue';
import { updateRegistryOptions } from '@/apis/system';
export default {
pluginName:'cmonitor.plugin.system.',
sort: 4,
props: ['data'],
setup(props) {

View File

@@ -44,6 +44,7 @@ import { injectGlobalData } from '@/views/provide';
import { updateRegistryOptions } from '@/apis/system';
import { ElMessage } from 'element-plus';
export default {
pluginName:'cmonitor.plugin.system.',
props: ['modelValue'],
emits: ['update:modelValue'],
components: { CheckBoxWrap, PrevBoxWrap },

View File

@@ -1,4 +1,5 @@
export default {
pluginName: 'cmonitor.plugin.system.',
field() {
return {
System: {

View File

@@ -25,6 +25,7 @@ import { injectPluginState } from '../../provide'
import { injectGlobalData } from '@/views/provide';
import { viewerUpdate } from '@/apis/viewer';
export default {
pluginName:'cmonitor.plugin.viewer.',
setup() {
const pluginState = injectPluginState();

View File

@@ -8,6 +8,7 @@ import { onMounted, watch } from 'vue';
import { injectPluginState } from '../../provide'
import { injectGlobalData } from '@/views/provide';
export default {
pluginName:'cmonitor.plugin.viewer.',
components: {},
setup() {

View File

@@ -21,6 +21,7 @@ import { ElMessage } from 'element-plus';
import { injectPluginState } from '../../provide';
import { viewerUpdate } from '../../../../apis/viewer';
export default {
pluginName:'cmonitor.plugin.viewer.',
props: ['data'],
setup(props) {

Some files were not shown because too many files have changed in this diff Show More