This commit is contained in:
snltty
2025-11-08 18:05:13 +08:00
parent c1d75ff8f0
commit c69e2f7f75
38 changed files with 890 additions and 769 deletions

View File

@@ -14,7 +14,7 @@ slug: /install/ikuai
![](./img/ikuai-ssh1.jpg)
先下载 <a href="/update-20241130.bin" target="_blank">update-20241130.bin</a><a href="https://www.ikuaios.com:555/i/%E5%8E%86%E5%8F%B2%E5%9B%BA%E4%BB%B6" target="_blank">iKuai-3.7.16</a>如果ikuai版本不是`3.7.16`,还需要先升级为`3.7.16`
先下载 <a href="/update-20241130.bin" target="_blank">update-20241130.bin</a><a href="/iKuai-3.7.16-base.bin" target="_blank">iKuai-3.7.16</a>如果ikuai版本不是`3.7.16`,还需要先升级为`3.7.16`
然后依次上传`iKuai-3.7.16-base.bin`升级,重启,再上传`update-20241130.bin`升级,重启

Binary file not shown.

View File

@@ -1,19 +1,30 @@
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import i18n from './lang';
const app = createApp(App);
import i18n from './lang';
app.use(i18n);
import './assets/style.css'
import router from './router'
app.use(router);
import AccessShow from './views/components/accesss/AccessShow.vue';
app.component('AccessShow', AccessShow);
import AccessBoolean from './views/components/accesss/AccessBoolean.vue';
app.component('AccessBoolean', AccessBoolean);
import PhoneShow from './views/components/global/PhoneShow.vue';
app.component('PhoneShow', PhoneShow);
import PcShow from './views/components/global/PcShow.vue';
app.component('PcShow', PcShow);
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'
app.use(ElementPlus, { size: 'default' });
app.use(ElementPlus, { size: 'default' }).use(router).mount('#app');
app.mount('#app');
app.directive('trim', {
@@ -46,12 +57,10 @@ app.directive('trim', {
}
});
const ignoreErrors = [
"ResizeObserver loop completed with undelivered notifications",
"ResizeObserver loop limit exceeded"
];
window.addEventListener('error', e => {
let errorMsg = e.message;
ignoreErrors.forEach(m => {

View File

@@ -0,0 +1,25 @@
<template>
<slot :values="values"></slot>
</template>
<script>
import { injectGlobalData } from '@/provide';
import { computed } from 'vue';
export default {
props: ['value'],
setup (props) {
const globalData = injectGlobalData();
const values = computed(()=>props.value.split(',').reduce((json,item,index)=>{
json[item] = globalData.value.hasAccess(item);
return json;
},{}) );
return {values}
}
}
</script>
<style lang="stylus" scoped>
</style>

View File

@@ -0,0 +1,21 @@
<template>
<slot v-if="show"></slot>
</template>
<script>
import { injectGlobalData } from '@/provide';
import { computed } from 'vue';
export default {
props:['value'],
setup (props) {
const globalData = injectGlobalData();
const show = computed(()=>props.value.split(',').filter(c=>globalData.value.hasAccess(c)).length > 0 );
return {show}
}
}
</script>
<style lang="stylus" scoped>
</style>

View File

@@ -62,14 +62,16 @@
<el-table-column label="操作" width="54">
<template #default="scope">
<div>
<el-popconfirm v-if="hasTunnelRemove" confirm-button-text="确认" cancel-button-text="取消"
title="确定关闭此连接?" @confirm="handleDel(scope.row)">
<template #reference>
<el-button type="danger" size="small"><el-icon>
<Delete />
</el-icon></el-button>
</template>
</el-popconfirm>
<AccessShow value="TunnelRemove">
<el-popconfirm confirm-button-text="确认" cancel-button-text="取消"
title="确定关闭此连接?" @confirm="handleDel(scope.row)">
<template #reference>
<el-button type="danger" size="small"><el-icon>
<Delete />
</el-icon></el-button>
</template>
</el-popconfirm>
</AccessShow>
</div>
</template>
</el-table-column>
@@ -149,7 +151,6 @@ export default {
const { t } = useI18n();
const globalData = injectGlobalData();
const hasTunnelRemove = computed(() => globalData.value.hasAccess('TunnelRemove'));
const connections = useConnections();
const forwardConnections = useForwardConnections();
@@ -187,10 +188,6 @@ export default {
}
});
const handleDel = (row) => {
if (!hasTunnelRemove.value) {
ElMessage.success('无权限');
return;
}
row.removeFunc(row.RemoteMachineId).then(() => {
ElMessage.success(t('common.oper'));
}).catch(() => { });
@@ -246,7 +243,7 @@ export default {
})
return {
state, handleDel, hasTunnelRemove,handlep2p, handleNode, handleConnect
state, handleDel,handlep2p, handleNode, handleConnect
}
}
}

View File

@@ -34,12 +34,10 @@
</el-table-column>
</template>
<script>
import { computed, ref } from 'vue';
import { ref } from 'vue';
import {Search} from '@element-plus/icons-vue'
import UpdaterBtn from '../updater/UpdaterBtn.vue';
import DeviceName from './DeviceName.vue';
import { injectGlobalData } from '@/provide';
import { ElMessage } from 'element-plus';
import { useI18n } from 'vue-i18n';
export default {
@@ -48,15 +46,9 @@ export default {
setup(props,{emit}) {
const t = useI18n();
const globalData = injectGlobalData();
const hasExternal = computed(()=>globalData.value.hasAccess('ExternalShow'));
const name = ref(sessionStorage.getItem('search-name') || '');
const handleExternal = (row)=>{
if(!hasExternal.value) {
ElMessage.success(t('common.access'));
return;
}
row.showip=!row.showip;
}
const handleRefresh = ()=>{

View File

@@ -1,18 +1,22 @@
<template>
<div>
<a href="javascript:;" @click="handleEdit" title="此客户端的设备名" class="a-line">
<strong class="gateway" :class="{green:item.Connected}">{{item.MachineName || 'null' }}</strong>
</a>
<strong class="self gateway" v-if="item.isSelf">(<el-icon size="16"><StarFilled /></el-icon>)</strong>
<template v-if="tuntap.list[item.MachineId] && tuntap.list[item.MachineId].systems">
<template v-for="system in tuntap.list[item.MachineId].systems">
<span :title="tuntap.list[item.MachineId].SystemInfo">
<img class="system" :src="`./${system}.svg`" />
</span>
</template>
<AccessBoolean value="RenameSelf,RenameOther">
<template #default="{values}">
<div>
<a href="javascript:;" @click="handleEdit(values)" title="此客户端的设备名" class="a-line">
<strong class="gateway" :class="{green:item.Connected}">{{item.MachineName || 'null' }}</strong>
</a>
<strong class="self gateway" v-if="item.isSelf">(<el-icon size="16"><StarFilled /></el-icon>)</strong>
<template v-if="tuntap.list[item.MachineId] && tuntap.list[item.MachineId].systems">
<template v-for="system in tuntap.list[item.MachineId].systems">
<span :title="tuntap.list[item.MachineId].SystemInfo">
<img class="system" :src="`./${system}.svg`" />
</span>
</template>
</template>
</div>
</template>
</div>
</AccessBoolean>
</template>
<script>
@@ -31,20 +35,18 @@ export default {
const tuntap = useTuntap();
const globalData = injectGlobalData();
const hasRenameSelf = computed(()=>globalData.value.hasAccess('RenameSelf'));
const hasRenameOther = computed(()=>globalData.value.hasAccess('RenameOther'));
const machineId = computed(() => globalData.value.config.Client.Id);
const handleEdit = ()=>{
const handleEdit = (access)=>{
if(!props.config){
return;
}
if(machineId.value === props.item.MachineId){
if(!hasRenameSelf.value){
if(!access.RenameSelf){
ElMessage.success('无权限');
return;
}
}else{
if(!hasRenameOther.value){
if(!access.RenameOther){
ElMessage.success('无权限');
return;
}
@@ -55,7 +57,8 @@ export default {
return {
item:computed(()=>props.item),tuntap,handleEdit,accessLength:globalData.value.config.Client
item:computed(()=>props.item),
tuntap,handleEdit
}
}
}

View File

@@ -5,7 +5,9 @@
<a href="javascript:;" @click="state.showModes = true" class="mgr-1 delay a-line" :class="{red:state.nodes.length==0,green:state.nodes.length>0}">
{{$t('server.sforwardNodes')}} : {{state.nodes.length}}
</a>
<WhiteList type="SForward" prefix="sfp->" v-if="state.super && hasWhiteList"></WhiteList>
<AccessShow value="WhiteList">
<WhiteList type="SForward" prefix="sfp->" v-if="state.super"></WhiteList>
</AccessShow>
<Nodes v-if="state.showModes" v-model="state.showModes" :data="state.nodes"></Nodes>
<!-- <Status type="SForward"></Status> -->
</div>
@@ -26,7 +28,6 @@ export default {
setup(props) {
const {t} = useI18n();
const globalData = injectGlobalData();
const hasWhiteList = computed(()=>globalData.value.hasAccess('WhiteList'));
const state = reactive({
super:computed(()=>globalData.value.signin.Super),
type:props.type,
@@ -55,7 +56,7 @@ export default {
clearTimeout(state.timer);
});
return {globalData,state,hasWhiteList}
return {globalData,state}
}
}
</script>

View File

@@ -2,32 +2,23 @@
<el-table-column prop="forward" :label="forward.show?$t('home.forward'):''" >
<template #default="scope">
<template v-if="forward.show && scope.row.Connected">
<template v-if="scope.row.isSelf && (hasForwardShowSelf || hasForwardSelf)">
<div class="nowrap">
<ConnectionShow :data="connections.list[scope.row.MachineId]" :row="scope.row" transitionId="forward"></ConnectionShow>
<a href="javascript:;" :class="{green:forward.list[scope.row.MachineId]>0 }" @click="handleEdit(scope.row.MachineId,scope.row.MachineName)">
<span :class="{gateway:forward.list[scope.row.MachineId]>0}">{{$t('home.forwardPort')}}({{forward.list[scope.row.MachineId]>99 ? '99+' : forward.list[scope.row.MachineId]}})</span>
</a>
</div>
<div class="nowrap">
<a href="javascript:;" :class="{green:sforward.list[scope.row.MachineId]>0}" @click="handleSEdit(scope.row.MachineId,scope.row.MachineName)">
<span :class="{gateway:sforward.list[scope.row.MachineId]>0 }">{{$t('home.forwardServer')}}({{sforward.list[scope.row.MachineId]>99 ? '99+' : sforward.list[scope.row.MachineId]}})</span>
</a>
</div>
</template>
<template v-else-if="hasForwardShowOther || hasForwardOther">
<div class="nowrap">
<ConnectionShow :data="connections.list[scope.row.MachineId]" :row="scope.row" transitionId="forward"></ConnectionShow>
<a href="javascript:;" :class="{green:forward.list[scope.row.MachineId]>0}" @click="handleEdit(scope.row.MachineId,scope.row.MachineName)">
<span :class="{gateway:forward.list[scope.row.MachineId]>0}">{{$t('home.forwardPort')}}({{forward.list[scope.row.MachineId]>99 ? '99+' : forward.list[scope.row.MachineId]}})</span>
</a>
</div>
<div class="nowrap">
<a href="javascript:;" :class="{green:sforward.list[scope.row.MachineId]>0}" @click="handleSEdit(scope.row.MachineId,scope.row.MachineName)">
<span :class="{gateway:sforward.list[scope.row.MachineId]>0 }">{{$t('home.forwardServer')}}({{sforward.list[scope.row.MachineId]>99 ? '99+' : sforward.list[scope.row.MachineId]}})</span>
</a>
</div>
</template>
<AccessBoolean value="ForwardOther,ForwardSelf">
<template #default="{values}">
<template v-if="values.ForwardOther || (values.ForwardSelf && scope.row.isSelf)">
<div class="nowrap">
<ConnectionShow :data="connections.list[scope.row.MachineId]" :row="scope.row" transitionId="forward"></ConnectionShow>
<a href="javascript:;" :class="{green:forward.list[scope.row.MachineId]>0}" @click="handleEdit(scope.row.MachineId,scope.row.MachineName,values)">
<span :class="{gateway:forward.list[scope.row.MachineId]>0}">{{$t('home.forwardPort')}}({{forward.list[scope.row.MachineId]>99 ? '99+' : forward.list[scope.row.MachineId]}})</span>
</a>
</div>
<div class="nowrap">
<a href="javascript:;" :class="{green:sforward.list[scope.row.MachineId]>0}" @click="handleSEdit(scope.row.MachineId,scope.row.MachineName,values)">
<span :class="{gateway:sforward.list[scope.row.MachineId]>0 }">{{$t('home.forwardServer')}}({{sforward.list[scope.row.MachineId]>99 ? '99+' : sforward.list[scope.row.MachineId]}})</span>
</a>
</div>
</template>
</template>
</AccessBoolean>
</template>
</template>
</el-table-column>
@@ -50,20 +41,16 @@ export default {
const sforward = useSforward()
const globalData = injectGlobalData();
const machineId = computed(() => globalData.value.config.Client.Id);
const hasForwardShowSelf = computed(()=>globalData.value.hasAccess('ForwardShowSelf'));
const hasForwardShowOther = computed(()=>globalData.value.hasAccess('ForwardShowOther'));
const hasForwardSelf = computed(()=>globalData.value.hasAccess('ForwardSelf'));
const hasForwardOther = computed(()=>globalData.value.hasAccess('ForwardOther'));
const connections = useForwardConnections();
const handleEdit = (_machineId,_machineName)=>{
const handleEdit = (_machineId,_machineName,access)=>{
if(machineId.value === _machineId){
if(!hasForwardSelf.value){
if(!access.ForwardSelf){
ElMessage.success('无权限');
return;
}
}else{
if(!hasForwardOther.value){
if(!access.ForwardOther){
ElMessage.success('无权限');
return;
}
@@ -72,14 +59,14 @@ export default {
forward.value.machineName = _machineName;
forward.value.showEdit = true;
}
const handleSEdit = (_machineId,_machineName)=>{
const handleSEdit = (_machineId,_machineName,access)=>{
if(machineId.value === _machineId){
if(!hasForwardSelf.value){
if(!access.ForwardSelf){
ElMessage.success('无权限');
return;
}
}else{
if(!hasForwardOther.value){
if(!access.ForwardOther){
ElMessage.success('无权限');
return;
}
@@ -93,7 +80,7 @@ export default {
}
return {
forward,sforward,hasForwardShowSelf,hasForwardShowOther,connections, handleEdit,handleSEdit,handleForwardRefresh
forward,sforward,connections, handleEdit,handleSEdit,handleForwardRefresh
}
}
}

View File

@@ -0,0 +1,21 @@
<template>
<slot v-if="show"></slot>
</template>
<script>
import { injectGlobalData } from '@/provide';
import { computed } from 'vue';
export default {
setup () {
const globalData = injectGlobalData();
const show = computed(()=>globalData.value.isPhone == false);
return {show}
}
}
</script>
<style lang="stylus" scoped>
</style>

View File

@@ -0,0 +1,21 @@
<template>
<slot v-if="show"></slot>
</template>
<script>
import { injectGlobalData } from '@/provide';
import { computed } from 'vue';
export default {
props:['value'],
setup (props) {
const globalData = injectGlobalData();
const show = computed(()=>globalData.value.isPhone);
return {show}
}
}
</script>
<style lang="stylus" scoped>
</style>

View File

@@ -31,8 +31,7 @@
</template>
<template v-else>
<a href="javascript:;" class="a-line" @click="handleEdit(scope.row, 'Password')">
<template v-if="globalData.isPhone"><span>***</span></template>
<template v-else><span>{{ scope.row.Password.replace(/.{1}/g,'*') }}</span></template>
<template><span>***</span></template>
</a>
</template>
</template>

View File

@@ -6,10 +6,12 @@
<el-icon class="right"><ArrowDown /></el-icon>
</span>
<template #dropdown>
<el-dropdown-menu v-if="hasGroup">
<el-dropdown-item v-for="item in state.groups" @click="handleGroupChange(item.Id)">{{item.Name || '未知'}}</el-dropdown-item>
<el-dropdown-item @click="state.showGroups = true">{{$t('status.group')}}</el-dropdown-item>
</el-dropdown-menu>
<AccessShow value="Group">
<el-dropdown-menu>
<el-dropdown-item v-for="item in state.groups" @click="handleGroupChange(item.Id)">{{item.Name || '未知'}}</el-dropdown-item>
<el-dropdown-item @click="state.showGroups = true">{{$t('status.group')}}</el-dropdown-item>
</el-dropdown-menu>
</AccessShow>
</template>
</el-dropdown>
<Groups v-if="state.showGroups" v-model="state.showGroups"></Groups>
@@ -28,7 +30,6 @@ export default {
setup(props) {
const { t } = useI18n();
const globalData = injectGlobalData();
const hasGroup = computed(()=>globalData.value.hasAccess('Group'));
const state = reactive({
loading: false,
connected: computed(() => globalData.value.signin.Connected),
@@ -66,7 +67,7 @@ export default {
});
}
return {
config:props.config,hasGroup, state,handleGroupChange
config:props.config,state,handleGroupChange
}
}
}

View File

@@ -1,45 +1,67 @@
<template>
<el-table-column :label="$t('home.oper')" fixed="right" width="75">
<template #default="scope">
<el-dropdown size="small" >
<div class="dropdown">
<span>{{$t('home.oper')}}</span>
<el-icon class="el-icon--right">
<ArrowDown />
</el-icon>
</div>
<template #dropdown>
<el-dropdown-menu>
<template v-if="scope.row.Connected">
<el-dropdown-item v-if="scope.row.showReboot && hasReboot" @click="handleExit(scope.row.MachineId,scope.row.MachineName)"><el-icon><SwitchButton /></el-icon>{{$t('home.reboot')}}</el-dropdown-item>
<el-dropdown-item v-if="handleShowAccess(scope.row,accessList[scope.row.MachineId] || '0')" @click="handleAccess(scope.row)"><el-icon><Flag /></el-icon>{{$t('home.access')}}</el-dropdown-item>
<el-dropdown-item v-if="scope.row.isSelf && hasApiPassword" @click="handleApiPassword(scope.row)"><el-icon><HelpFilled /></el-icon>{{$t('home.managerApi')}}</el-dropdown-item>
<el-dropdown-item v-else-if="hasApiPasswordOther" @click="handleApiPassword(scope.row)"><el-icon><HelpFilled /></el-icon> {{$t('home.managerApi')}}</el-dropdown-item>
<el-dropdown-item @click="handleStopwatch(scope.row.MachineId,scope.row.MachineName)"><el-icon><Platform /></el-icon>{{$t('home.messenger',[scope.row.MachineName])}}</el-dropdown-item>
<el-dropdown-item @click="handleStopwatch('',$t('home.server'))"><el-icon><Platform /></el-icon>{{$t('home.messengerServer')}}</el-dropdown-item>
<el-dropdown-item @click="handleRoutes(scope.row.MachineId,scope.row.MachineName)"><el-icon><Paperclip /></el-icon>{{$t('home.tuntapRoute')}}</el-dropdown-item>
<el-dropdown-item v-if="scope.row.isSelf && hasFirewallSelf" @click="handleFirewall(scope.row.MachineId,scope.row.MachineName)"><el-icon><CircleCheck /></el-icon>{{$t('home.firewall')}}</el-dropdown-item>
<el-dropdown-item v-else-if="hasFirewallOther" @click="handleFirewall(scope.row.MachineId,scope.row.MachineName)"><el-icon><CircleCheck /></el-icon>{{$t('home.firewall')}}</el-dropdown-item>
<el-dropdown-item v-if="scope.row.isSelf && hasWakeupSelf" @click="handleWakeup(scope.row.MachineId,scope.row.MachineName)"><el-icon><VideoPlay /></el-icon>{{$t('home.wakeup')}}</el-dropdown-item>
<el-dropdown-item v-else-if="hasWakeupOther" @click="handleWakeup(scope.row.MachineId,scope.row.MachineName)"><el-icon><VideoPlay /></el-icon>{{$t('home.wakeup')}}</el-dropdown-item>
<el-dropdown-item v-if="hasTransport" @click="handleTransport(scope.row.MachineId,scope.row.MachineName)"><el-icon><Orange /></el-icon>{{$t('home.protocol')}}</el-dropdown-item>
<el-dropdown-item v-if="scope.row.isSelf && hasActionSelf" @click="handleAction(scope.row.MachineId,scope.row.MachineName)"><el-icon><Lock /></el-icon>{{$t('home.action')}}</el-dropdown-item>
<el-dropdown-item v-else-if="hasActionOther" @click="handleAction(scope.row.MachineId,scope.row.MachineName)"><el-icon><Lock /></el-icon>{{$t('home.action')}}</el-dropdown-item>
<el-dropdown-item v-if="scope.row.isSelf && hasFlow" @click="handleFlow(scope.row.MachineId,scope.row.MachineName)"><el-icon><Histogram /></el-icon>{{$t('home.flowStatis')}}</el-dropdown-item>
<el-dropdown-item v-else-if="hasFlow" @click="handleFlow(scope.row.MachineId,scope.row.MachineName)"><el-icon><Histogram /></el-icon>{{$t('home.flowStatis')}}</el-dropdown-item>
<AccessBoolean value="Access">
<template #default="{values}">
<el-table-column :label="$t('home.oper')" fixed="right" width="75">
<template #default="scope">
<el-dropdown size="small" >
<div class="dropdown">
<span>{{$t('home.oper')}}</span>
<el-icon class="el-icon--right">
<ArrowDown />
</el-icon>
</div>
<template #dropdown>
<el-dropdown-menu>
<template v-if="scope.row.Connected">
<AccessShow value="Reboot">
<el-dropdown-item v-if="scope.row.showReboot" @click="handleExit(scope.row.MachineId,scope.row.MachineName)"><el-icon><SwitchButton /></el-icon>{{$t('home.reboot')}}</el-dropdown-item>
</AccessShow>
<el-dropdown-item v-if="handleShowAccess(scope.row,accessList[scope.row.MachineId] || '0',values)" @click="handleAccess(scope.row)"><el-icon><Flag /></el-icon>{{$t('home.access')}}</el-dropdown-item>
<AccessShow value="ApiPassword">
<el-dropdown-item v-if="scope.row.isSelf" @click="handleApiPassword(scope.row)"><el-icon><HelpFilled /></el-icon>{{$t('home.managerApi')}}</el-dropdown-item>
</AccessShow>
<AccessShow value="ApiPasswordOther">
<el-dropdown-item v-if="scope.row.isSelf==false" @click="handleApiPassword(scope.row)"><el-icon><HelpFilled /></el-icon> {{$t('home.managerApi')}}</el-dropdown-item>
</AccessShow>
<el-dropdown-item @click="handleStopwatch(scope.row.MachineId,scope.row.MachineName)"><el-icon><Platform /></el-icon>{{$t('home.messenger',[scope.row.MachineName])}}</el-dropdown-item>
<el-dropdown-item @click="handleStopwatch('',$t('home.server'))"><el-icon><Platform /></el-icon>{{$t('home.messengerServer')}}</el-dropdown-item>
<el-dropdown-item @click="handleRoutes(scope.row.MachineId,scope.row.MachineName)"><el-icon><Paperclip /></el-icon>{{$t('home.tuntapRoute')}}</el-dropdown-item>
<AccessShow value="FirewallSelf">
<el-dropdown-item v-if="scope.row.isSelf" @click="handleFirewall(scope.row.MachineId,scope.row.MachineName)"><el-icon><CircleCheck /></el-icon>{{$t('home.firewall')}}</el-dropdown-item>
</AccessShow>
<AccessShow value="FirewallOther">
<el-dropdown-item v-if="scope.row.isSelf==false" @click="handleFirewall(scope.row.MachineId,scope.row.MachineName)"><el-icon><CircleCheck /></el-icon>{{$t('home.firewall')}}</el-dropdown-item>
</AccessShow>
<AccessShow value="WakeupSelf">
<el-dropdown-item v-if="scope.row.isSelf" @click="handleWakeup(scope.row.MachineId,scope.row.MachineName)"><el-icon><VideoPlay /></el-icon>{{$t('home.wakeup')}}</el-dropdown-item>
</AccessShow>
<AccessShow value="WakeupOther">
<el-dropdown-item v-if="scope.row.isSelf==false" @click="handleWakeup(scope.row.MachineId,scope.row.MachineName)"><el-icon><VideoPlay /></el-icon>{{$t('home.wakeup')}}</el-dropdown-item>
</AccessShow>
<AccessShow value="Transport">
<el-dropdown-item @click="handleTransport(scope.row.MachineId,scope.row.MachineName)"><el-icon><Orange /></el-icon>{{$t('home.protocol')}}</el-dropdown-item>
</AccessShow>
<AccessShow value="ActionSelf">
<el-dropdown-item v-if="scope.row.isSelf" @click="handleAction(scope.row.MachineId,scope.row.MachineName)"><el-icon><Lock /></el-icon>{{$t('home.action')}}</el-dropdown-item>
</AccessShow>
<AccessShow value="ActionOther">
<el-dropdown-item v-if="scope.row.isSelf==false" @click="handleAction(scope.row.MachineId,scope.row.MachineName)"><el-icon><Lock /></el-icon>{{$t('home.action')}}</el-dropdown-item>
</AccessShow>
<AccessShow value="Flow">
<el-dropdown-item @click="handleFlow(scope.row.MachineId,scope.row.MachineName)"><el-icon><Histogram /></el-icon>{{$t('home.flowStatis')}}</el-dropdown-item>
</AccessShow>
</template>
<AccessShow value="Remove">
<el-dropdown-item v-if="scope.row.showDel" @click="handleDel(scope.row.MachineId,scope.row.MachineName)"><el-icon><Delete /></el-icon> {{$t('home.delete')}}</el-dropdown-item>
</AccessShow>
</el-dropdown-menu>
</template>
<el-dropdown-item v-if="scope.row.showDel && hasRemove" @click="handleDel(scope.row.MachineId,scope.row.MachineName)"><el-icon><Delete /></el-icon> {{$t('home.delete')}}</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</template>
</el-dropdown>
</el-table-column>
</template>
</el-table-column>
</AccessBoolean>
</template>
<script>
@@ -67,27 +89,8 @@ export default {
const devices = useDevice();
const allAccess = useAccess();
const myAccess = computed(()=>globalData.value.config.Client.AccessBits);
const hasAccess = computed(()=>globalData.value.hasAccess('Access'));
const accessList = computed(()=>allAccess.value.list);
const hasReboot = computed(()=>globalData.value.hasAccess('Reboot'));
const hasRemove = computed(()=>globalData.value.hasAccess('Remove'));
const hasApiPassword = computed(()=>globalData.value.hasAccess('SetApiPassword'));
const hasApiPasswordOther = computed(()=>globalData.value.hasAccess('SetApiPasswordOther'));
const hasFirewallSelf = computed(()=>globalData.value.hasAccess('FirewallSelf'));
const hasFirewallOther = computed(()=>globalData.value.hasAccess('FirewallOther'));
const hasWakeupSelf = computed(()=>globalData.value.hasAccess('WakeupSelf'));
const hasWakeupOther = computed(()=>globalData.value.hasAccess('WakeupOther'));
const hasTransport = computed(()=>globalData.value.hasAccess('Transport'));
const hasActionSelf = computed(()=>globalData.value.hasAccess('Action'));
const hasActionOther = computed(()=>globalData.value.hasAccess('ActionOther'));
const hasFlow = computed(()=>globalData.value.hasAccess('Flow'));
const flow = useFlow();
const oper = useOper();
@@ -114,11 +117,11 @@ export default {
}).catch(() => {});
}
const handleShowAccess = (row,rowAccess)=>{
const handleShowAccess = (row,rowAccess,access)=>{
let maxLength = Math.max(myAccess.value.length,rowAccess.length);
let myValue = myAccess.value.padEnd(maxLength,'0').split('');
let rowValue = rowAccess.padEnd(maxLength,'0').split('');
return row.showAccess && hasAccess.value
return row.showAccess && access.Access
&& myValue.map((v,i)=>{
return (rowValue[i] == '1' && v == '1') || rowValue[i] == '0';
}).filter(c=>c).length > 0;
@@ -182,10 +185,10 @@ export default {
oper.value.showFlow = true;
}
return {accessList,handleDel,handleExit,hasReboot,hasRemove,hasAccess,handleShowAccess,handleAccess,
hasApiPassword,hasApiPasswordOther,handleApiPassword,handleStopwatch,handleRoutes,
hasFirewallSelf,hasFirewallOther,handleFirewall,hasWakeupSelf,hasWakeupOther,handleWakeup,
hasTransport,handleTransport,hasActionSelf,hasActionOther,handleAction,hasFlow,handleFlow
return {accessList,handleDel,handleExit,handleShowAccess,handleAccess,
handleApiPassword,handleStopwatch,handleRoutes,
handleFirewall,handleWakeup,
handleTransport,handleAction,handleFlow
}
}
}

View File

@@ -1,50 +1,54 @@
<template>
<div>
<div class="flex">
<div class="flex-1">
<ConnectionShow :data="connections.list[item.MachineId]" :row="item" transitionId="socks5"></ConnectionShow>
<a href="javascript:;" class="a-line" @click="handleSocks5Port(socks5.list[item.MachineId])" title="此设备的socks5代理">
<template v-if="socks5.list[item.MachineId].SetupError">
<strong class="red" :title="socks5.list[item.MachineId].SetupError">
socks5://*:{{ socks5.list[item.MachineId].Port }}
</strong>
</template>
<template v-else>
<template v-if="item.Connected &&socks5.list[item.MachineId].running">
<strong class="green gateway">socks5://*:{{ socks5.list[item.MachineId].Port }}</strong>
</template>
<template v-else>
<span>socks5://*:{{ socks5.list[item.MachineId].Port }}</span>
</template>
</template>
</a>
</div>
<template v-if="socks5.list[item.MachineId].loading">
<div>
<el-icon size="14" class="loading"><Loading /></el-icon>
</div>
</template>
<template v-else>
<el-switch :model-value="item.Connected && socks5.list[item.MachineId].running" :loading="socks5.list[item.MachineId].loading" disabled @click="handleSocks5(socks5.list[item.MachineId])" size="small" inline-prompt active-text="😀" inactive-text="😣" >
</el-switch>
</template>
</div>
<div>
<AccessBoolean value="Socks5ChangeSelf,Socks5ChangeOther,Socks5StatusSelf,Socks5StatusOther">
<template #default="{values}">
<div>
<template v-for="(item1,index) in socks5.list[item.MachineId].Lans" :key="index">
<template v-if="item1.Disabled">
<div class="flex disable" title="已禁用">{{ item1.IP }} / {{ item1.PrefixLength }}</div>
</template>
<template v-else-if="item1.Exists">
<div class="flex yellow" title="与其它设备填写IP、或本机局域网IP有冲突">{{ item1.IP }} / {{ item1.PrefixLength }}</div>
<div class="flex">
<div class="flex-1">
<ConnectionShow :data="connections.list[item.MachineId]" :row="item" transitionId="socks5"></ConnectionShow>
<a href="javascript:;" class="a-line" @click="handleSocks5Port(socks5.list[item.MachineId],values)" title="此设备的socks5代理">
<template v-if="socks5.list[item.MachineId].SetupError">
<strong class="red" :title="socks5.list[item.MachineId].SetupError">
socks5://*:{{ socks5.list[item.MachineId].Port }}
</strong>
</template>
<template v-else>
<template v-if="item.Connected &&socks5.list[item.MachineId].running">
<strong class="green gateway">socks5://*:{{ socks5.list[item.MachineId].Port }}</strong>
</template>
<template v-else>
<span>socks5://*:{{ socks5.list[item.MachineId].Port }}</span>
</template>
</template>
</a>
</div>
<template v-if="socks5.list[item.MachineId].loading">
<div>
<el-icon size="14" class="loading"><Loading /></el-icon>
</div>
</template>
<template v-else>
<div class="flex green" title="正常使用" :class="{green:item.Connected &&socks5.list[item.MachineId].running}">{{ item1.IP }} / {{ item1.PrefixLength }}</div>
<el-switch :model-value="item.Connected && socks5.list[item.MachineId].running" :loading="socks5.list[item.MachineId].loading" disabled @click="handleSocks5(socks5.list[item.MachineId],values)" size="small" inline-prompt active-text="😀" inactive-text="😣" >
</el-switch>
</template>
</template>
</div>
<div>
<div>
<template v-for="(item1,index) in socks5.list[item.MachineId].Lans" :key="index">
<template v-if="item1.Disabled">
<div class="flex disable" title="已禁用">{{ item1.IP }} / {{ item1.PrefixLength }}</div>
</template>
<template v-else-if="item1.Exists">
<div class="flex yellow" title="与其它设备填写IP、或本机局域网IP有冲突">{{ item1.IP }} / {{ item1.PrefixLength }}</div>
</template>
<template v-else>
<div class="flex green" title="正常使用" :class="{green:item.Connected &&socks5.list[item.MachineId].running}">{{ item1.IP }} / {{ item1.PrefixLength }}</div>
</template>
</template>
</div>
</div>
</div>
</div>
</div>
</template>
</AccessBoolean>
</template>
<script>
@@ -65,23 +69,19 @@ export default {
const socks5 = useSocks5();
const globalData = injectGlobalData();
const machineId = computed(() => globalData.value.config.Client.Id);
const hasSocks5ChangeSelf = computed(()=>globalData.value.hasAccess('Socks5ChangeSelf'));
const hasSocks5ChangeOther = computed(()=>globalData.value.hasAccess('Socks5ChangeOther'));
const hasSocks5StatusSelf = computed(()=>globalData.value.hasAccess('Socks5StatusSelf'));
const hasSocks5StatusOther = computed(()=>globalData.value.hasAccess('Socks5StatusOther'));
const connections = useSocks5Connections();
const handleSocks5 = (socks5) => {
const handleSocks5 = (socks5,access) => {
if(!props.config){
return;
}
if(machineId.value === socks5.MachineId){
if(!hasSocks5StatusSelf.value){
if(!access.Socks5StatusSelf){
ElMessage.success('无权限');
return;
}
}else{
if(!hasSocks5StatusOther.value){
if(!access.Socks5StatusOther){
ElMessage.success('无权限');
return;
}
@@ -95,17 +95,17 @@ export default {
ElMessage.error('操作失败!');
})
}
const handleSocks5Port = (socks5) => {
const handleSocks5Port = (socks5,access) => {
if(!props.config && machineId.value != socks5.MachineId){
return;
}
if(machineId.value === socks5.MachineId){
if(!hasSocks5ChangeSelf.value){
if(!access.Socks5ChangeSelf){
ElMessage.success('无权限');
return;
}
}else{
if(!hasSocks5ChangeOther.value){
if(!access.Socks5ChangeOther){
ElMessage.success('无权限');
return;
}

View File

@@ -1,88 +1,92 @@
<template>
<div v-if="config && hasExport" class="status-export-wrap">
<a href="javascript:;" :title="$t('status.export')" @click="state.show = true">
<el-icon size="16"><Share /></el-icon>
<span v-if="globalData.isPc">{{$t('status.export')}}</span>
</a>
<el-dialog class="options-center" :title="$t('status.export')" destroy-on-close v-model="state.show" center width="580" top="1vh">
<div class="port-wrap">
<div class="text">
{{$t('status.exportText')}}
</div>
<div class="body">
<el-card shadow="never">
<template #header>
<div class="card-header">
<div>
<el-row>
<el-col :span="12"><el-checkbox :disabled="onlyNode" v-model="state.single" :label="$t('status.exportSingle')" /></el-col>
<el-col :span="12">
<div class="flex flex-nowrap">
<span style="width: 11rem;">{{$t('status.exportName')}} : </span><el-input v-trim :disabled="!state.single" v-model="state.name" maxlength="32" show-word-limit></el-input>
</div>
</el-col>
</el-row>
<AccessShow value="Export">
<div v-if="config" class="status-export-wrap">
<a href="javascript:;" :title="$t('status.export')" @click="state.show = true">
<el-icon size="16"><Share /></el-icon>
<PcShow>
<span>{{$t('status.export')}}</span>
</PcShow>
</a>
<el-dialog class="options-center" :title="$t('status.export')" destroy-on-close v-model="state.show" center width="580" top="1vh">
<div class="port-wrap">
<div class="text">
{{$t('status.exportText')}}
</div>
<div class="body">
<el-card shadow="never">
<template #header>
<div class="card-header">
<div>
<el-row>
<el-col :span="12"><el-checkbox :disabled="onlyNode" v-model="state.single" :label="$t('status.exportSingle')" /></el-col>
<el-col :span="12">
<div class="flex flex-nowrap">
<span style="width: 11rem;">{{$t('status.exportName')}} : </span><el-input v-trim :disabled="!state.single" v-model="state.name" maxlength="32" show-word-limit></el-input>
</div>
</el-col>
</el-row>
</div>
<div>
<el-row>
<el-col :span="12">
<div class="flex flex-nowrap mgt-1">
<span style="width: 11rem;">{{$t('status.exportWebport')}} : </span><el-input v-trim :disabled="onlyNode" v-model="state.webport"></el-input>
</div>
</el-col>
<el-col :span="12">
<div class="flex flex-nowrap mgt-1">
<span style="width: 11rem;">{{$t('status.exportApiPassword')}} : </span><el-input v-trim type="password" show-password :disabled="onlyNode" v-model="state.apipassword" maxlength="36" show-word-limit></el-input>
</div>
</el-col>
</el-row>
</div>
<div>
<el-row>
<el-col :xs="12" :sm="8"><el-checkbox v-model="state.relay" :label="$t('status.exportRelay')" /></el-col>
<el-col :xs="12" :sm="8"><el-checkbox v-model="state.updater" :label="$t('status.exportUpdater')" /></el-col>
<el-col :xs="12" :sm="8"><el-checkbox v-model="state.group" :label="$t('status.exportGroup')" /></el-col>
<el-col :xs="12" :sm="8"><el-checkbox v-model="state.server" :label="$t('status.exportServer')" /></el-col>
<el-col :xs="12" :sm="8"><el-checkbox v-model="state.super" :label="$t('status.exportSuper')" /></el-col>
<el-col :xs="12" :sm="8"><el-checkbox v-model="state.tunnel" :label="$t('status.exportTunnel')" /></el-col>
</el-row>
</div>
</div>
<div>
<el-row>
<el-col :span="12">
<div class="flex flex-nowrap mgt-1">
<span style="width: 11rem;">{{$t('status.exportWebport')}} : </span><el-input v-trim :disabled="onlyNode" v-model="state.webport"></el-input>
</div>
</el-col>
<el-col :span="12">
<div class="flex flex-nowrap mgt-1">
<span style="width: 11rem;">{{$t('status.exportApiPassword')}} : </span><el-input v-trim type="password" show-password :disabled="onlyNode" v-model="state.apipassword" maxlength="36" show-word-limit></el-input>
</div>
</el-col>
</el-row>
</div>
<div>
<el-row>
<el-col :xs="12" :sm="8"><el-checkbox v-model="state.relay" :label="$t('status.exportRelay')" /></el-col>
<el-col :xs="12" :sm="8"><el-checkbox v-model="state.updater" :label="$t('status.exportUpdater')" /></el-col>
<el-col :xs="12" :sm="8"><el-checkbox v-model="state.group" :label="$t('status.exportGroup')" /></el-col>
<el-col :xs="12" :sm="8"><el-checkbox v-model="state.server" :label="$t('status.exportServer')" /></el-col>
<el-col :xs="12" :sm="8"><el-checkbox v-model="state.super" :label="$t('status.exportSuper')" /></el-col>
<el-col :xs="12" :sm="8"><el-checkbox v-model="state.tunnel" :label="$t('status.exportTunnel')" /></el-col>
</el-row>
</div>
</div>
</template>
<Access ref="accessDom" :machineid="machineId" :height="30"></Access>
</el-card>
</template>
<Access ref="accessDom" :machineid="machineId" :height="30"></Access>
</el-card>
</div>
</div>
</div>
<template #footer>
<el-button plain @click="state.show = false" :loading="state.loading">{{$t('common.cancel') }}</el-button>
<el-button type="default" plain @click="handleExport" :loading="state.loading">{{$t('status.exportDownload') }}</el-button>
<el-button type="info" plain @click="handleCopy" :loading="state.loading">{{$t('status.exportCopy') }}</el-button>
<el-button type="success" plain @click="handleSave" :loading="state.loading">{{$t('status.exportSave') }}</el-button>
</template>
</el-dialog>
<el-dialog class="options-center" :title="$t('status.export')" destroy-on-close v-model="state.showCopy" center width="580" top="1vh">
<div class="port-wrap">
<el-input v-trim v-model="state.copyContent" type="textarea" :rows="10" resize="none" readonly></el-input>
</div>
<template #footer>
<el-button plain @click="copyToClipboard">{{$t('status.exportCopy') }}</el-button>
</template>
</el-dialog>
<el-dialog class="options-center" :title="$t('status.export')" destroy-on-close v-model="state.showSave" center width="300" top="1vh">
<div class="port-wrap">
<div>
<el-input v-trim v-model="state.saveServer" readonly></el-input>
<template #footer>
<el-button plain @click="state.show = false" :loading="state.loading">{{$t('common.cancel') }}</el-button>
<el-button type="default" plain @click="handleExport" :loading="state.loading">{{$t('status.exportDownload') }}</el-button>
<el-button type="info" plain @click="handleCopy" :loading="state.loading">{{$t('status.exportCopy') }}</el-button>
<el-button type="success" plain @click="handleSave" :loading="state.loading">{{$t('status.exportSave') }}</el-button>
</template>
</el-dialog>
<el-dialog class="options-center" :title="$t('status.export')" destroy-on-close v-model="state.showCopy" center width="580" top="1vh">
<div class="port-wrap">
<el-input v-trim v-model="state.copyContent" type="textarea" :rows="10" resize="none" readonly></el-input>
</div>
<div style="margin-top:1rem">
<el-input v-trim v-model="state.saveContent" readonly></el-input>
<template #footer>
<el-button plain @click="copyToClipboard">{{$t('status.exportCopy') }}</el-button>
</template>
</el-dialog>
<el-dialog class="options-center" :title="$t('status.export')" destroy-on-close v-model="state.showSave" center width="300" top="1vh">
<div class="port-wrap">
<div>
<el-input v-trim v-model="state.saveServer" readonly></el-input>
</div>
<div style="margin-top:1rem">
<el-input v-trim v-model="state.saveContent" readonly></el-input>
</div>
</div>
</div>
<template #footer>
<el-button plain @click="copySaveToClipboard">{{$t('status.exportCopy') }}</el-button>
</template>
</el-dialog>
</div>
<template #footer>
<el-button plain @click="copySaveToClipboard">{{$t('status.exportCopy') }}</el-button>
</template>
</el-dialog>
</div>
</AccessShow>
</template>
<script>
import { computed, reactive, ref } from 'vue';
@@ -99,7 +103,6 @@ export default {
const { t } = useI18n();
const globalData = injectGlobalData();
const hasExport = computed(()=>globalData.value.hasAccess('Export'));
const onlyNode = computed(()=>globalData.value.config.Client.OnlyNode);
const machineId = computed(()=>globalData.value.config.Client.Id);
const state = reactive({
@@ -128,10 +131,6 @@ export default {
const getJson = ()=>{
if(!hasExport.value){
ElMessage.success('无权限');
return;
}
const access = accessDom.value.getValue();
const json = {
access:access[0],
@@ -260,7 +259,7 @@ export default {
}
}
return {globalData,config:props.config,onlyNode,hasExport,machineId, state,accessDom,
return {globalData,config:props.config,onlyNode,machineId, state,accessDom,
handleSave,handleExport,handleCopy,copyToClipboard,copySaveToClipboard};
}
}

View File

@@ -7,13 +7,17 @@
<span>{{$t('status.support')}}</span>
</a>
<a href="javascript:;">©linker {{ self.Version }}</a>
<a v-if="globalData.isPc" href="https://github.com/snltty/linker" target="_blank">Github</a>
<a v-if="globalData.isPc" href="https://linker.snltty.com" target="_blank">{{$t('status.website')}}</a>
<a v-if="globalData.isPc" href="https://linker-doc.snltty.com" target="_blank">{{$t('status.doc')}}</a>
<PcShow>
<a href="https://github.com/snltty/linker" target="_blank">Github</a>
<a href="https://linker.snltty.com" target="_blank">{{$t('status.website')}}</a>
<a href="https://linker-doc.snltty.com" target="_blank">{{$t('status.doc')}}</a>
</PcShow>
</div>
<div class="flex-1"></div>
<div class="export"><Export :config="config"></Export></div>
<div class="api" v-if="globalData.isPc"><Api :config="config"></Api></div>
<PcShow>
<div class="api"><Api :config="config"></Api></div>
</PcShow>
<div class="server"><Server :config="config"></Server></div>
<el-dialog v-model="state.showPay" :title="$t('status.support')" width="80%">
@@ -35,7 +39,7 @@
</div>
</template>
<script>
import { computed, reactive, ref } from 'vue';
import { computed, reactive } from 'vue';
import Api from './Api.vue'
import Server from './server/Index.vue'
import Export from './Export.vue'
@@ -52,7 +56,7 @@ export default {
showPay:false
});
return {
globalData,state,config:props.config,self
state,config:props.config,self
}
}
}

View File

@@ -2,30 +2,28 @@
<div class="status-server-wrap">
<Groups :config="config"></Groups>
<ServerVersion :config="config"></ServerVersion>
<Flow v-if="config && hasFlow" :config="config"></Flow>
<AccessShow value="Flow">
<Flow v-if="config" :config="config"></Flow>
</AccessShow>
</div>
</template>
<script>
import { computed, reactive } from 'vue';
import { reactive } from 'vue';
import Groups from '../../groups/Index.vue';
import Flow from './Flow.vue';
import ServerVersion from './Version.vue';
import { injectGlobalData } from '@/provide';
export default {
components:{Groups,Flow,ServerVersion},
props:['config'],
setup(props) {
const globalData = injectGlobalData();
const hasFlow = computed(()=>globalData.value.hasAccess('Flow'));
const state = reactive({
show: false,
loading: false
});
return {
config:props.config,hasFlow, state
config:props.config,state
}
}
}

View File

@@ -1,26 +1,30 @@
<template>
<a href="javascript:;" @click="handleUpdate" class="download" :title="updateText()" :class="updateColor()">
<span>{{state.version}}</span>
<template v-if="updaterServer.Version">
<template v-if="updaterServer.Status == 1">
<el-icon size="14" class="loading"><Loading /></el-icon>
</template>
<template v-else-if="updaterServer.Status == 2">
<el-icon size="14"><Download /></el-icon>
</template>
<template v-else-if="updaterServer.Status == 3 || updaterServer.Status == 5">
<el-icon size="14" class="loading"><Loading /></el-icon>
<span class="progress" v-if="updaterServer.Length ==0">0%</span>
<span class="progress" v-else>{{parseInt(updaterServer.Current/updaterServer.Length*100)}}%</span>
</template>
<template v-else-if="updaterServer.Status == 6">
<el-icon size="14" class="yellow"><CircleCheck /></el-icon>
</template>
<AccessBoolean value="UpdateServer">
<template #default="{values}">
<a href="javascript:;" @click="handleUpdate(values)" class="download" :title="updateText()" :class="updateColor()">
<span>{{state.version}}</span>
<template v-if="updaterServer.Version">
<template v-if="updaterServer.Status == 1">
<el-icon size="14" class="loading"><Loading /></el-icon>
</template>
<template v-else-if="updaterServer.Status == 2">
<el-icon size="14"><Download /></el-icon>
</template>
<template v-else-if="updaterServer.Status == 3 || updaterServer.Status == 5">
<el-icon size="14" class="loading"><Loading /></el-icon>
<span class="progress" v-if="updaterServer.Length ==0">0%</span>
<span class="progress" v-else>{{parseInt(updaterServer.Current/updaterServer.Length*100)}}%</span>
</template>
<template v-else-if="updaterServer.Status == 6">
<el-icon size="14" class="yellow"><CircleCheck /></el-icon>
</template>
</template>
<template v-else>
<el-icon size="14"><Download /></el-icon>
</template>
</a>
</template>
<template v-else>
<el-icon size="14"><Download /></el-icon>
</template>
</a>
</AccessBoolean>
</template>
<script>
import { injectGlobalData } from '@/provide';
@@ -37,7 +41,6 @@ export default {
const { t } = useI18n();
const globalData = injectGlobalData();
const hasUpdateServer = computed(()=>globalData.value.hasAccess('UpdateServer'));
const updaterServer = ref({Version: '', Status: 0, Length: 0, Current: 0,Msg:[],DateTime:''});
const state = reactive({
@@ -86,8 +89,8 @@ export default {
const updateColor = ()=>{
return state.version != updaterServer.value.Version ? 'yellow' :'green'
}
const handleUpdate = ()=>{
if(!props.config || !hasUpdateServer.value){
const handleUpdate = (access)=>{
if(!props.config || !access.UpdateServer){
return;
}
//未检测,检测中,下载中,解压中

View File

@@ -1,31 +1,35 @@
<template>
<div>
<slot>
<el-button class="btn" size="small" @click="handleShowSync"><el-icon><Share /></el-icon></el-button>
</slot>
<el-dialog class="options-center" :title="$t('server.sync')" destroy-on-close v-model="state.showNames" width="54rem" top="2vh">
<AccessBoolean value="Sync">
<template #default="{values}">
<div>
<div class="t-c">
{{ `${$t('server.sync')}${$t(`server.async${state.name}`)}${$t('server.asyncText')}` }}
</div>
<el-transfer class="src-tranfer mgt-1"
v-model="state.srcIdValues"
filterable
:filter-method="srcFilterMethod"
:data="state.srcIds"
:titles="[$t('firewall.unselect'), $t('firewall.selected')]"
:props="{
key: 'MachineId',
label: 'MachineName',
}"
/>
<div class="t-c w-100 mgt-1">
<el-button @click="state.showNames = false">{{$t('common.cancel')}}</el-button>
<el-button type="primary" @click="handleConfirm">{{$t('common.confirm')}}</el-button>
<slot>
<el-button class="btn" size="small" @click="handleShowSync(values)"><el-icon><Share /></el-icon></el-button>
</slot>
<el-dialog class="options-center" :title="$t('server.sync')" destroy-on-close v-model="state.showNames" width="54rem" top="2vh">
<div>
<div class="t-c">
{{ `${$t('server.sync')}${$t(`server.async${state.name}`)}${$t('server.asyncText')}` }}
</div>
<el-transfer class="src-tranfer mgt-1"
v-model="state.srcIdValues"
filterable
:filter-method="srcFilterMethod"
:data="state.srcIds"
:titles="[$t('firewall.unselect'), $t('firewall.selected')]"
:props="{
key: 'MachineId',
label: 'MachineName',
}"
/>
<div class="t-c w-100 mgt-1">
<el-button @click="state.showNames = false">{{$t('common.cancel')}}</el-button>
<el-button type="primary" @click="handleConfirm">{{$t('common.confirm')}}</el-button>
</div>
</div>
</el-dialog>
</div>
</el-dialog>
</div>
</template>
</AccessBoolean>
</template>
<script>
@@ -42,7 +46,6 @@ export default {
setup (props) {
const { t } = useI18n();
const globalData = injectGlobalData();
const hasSync = computed(()=>globalData.value.hasAccess('Sync'));
const state = reactive({
name:props.name,
loading:false,
@@ -60,8 +63,8 @@ export default {
state.showNames = false;
});
}
const handleShowSync = ()=>{
if(!hasSync.value){
const handleShowSync = (access)=>{
if(!access.Sync){
ElMessage.success(t('common.access'));
return;
}

View File

@@ -1,43 +1,47 @@
<template>
<el-table-column prop="tunnel" :label="$t('home.tunnel')" width="86">
<template #default="scope">
<template v-if="tunnel.list[scope.row.MachineId]">
<div>
<template v-if="tunnel.list[scope.row.MachineId].Net.CountryCode">
<img
:title="`${tunnel.list[scope.row.MachineId].Net.CountryCode}、${tunnel.list[scope.row.MachineId].Net.City}`"
class="system"
:src="`https://unpkg.com/flag-icons@7.2.3/flags/4x3/${tunnel.list[scope.row.MachineId].Net.CountryCode.toLowerCase()}.svg`" />
<AccessBoolean value="TunnelChangeSelf,TunnelChangeOther">
<template #default="{values}">
<el-table-column prop="tunnel" :label="$t('home.tunnel')" width="86">
<template #default="scope">
<template v-if="tunnel.list[scope.row.MachineId]">
<div>
<template v-if="tunnel.list[scope.row.MachineId].Net.CountryCode">
<img
:title="`${tunnel.list[scope.row.MachineId].Net.CountryCode}、${tunnel.list[scope.row.MachineId].Net.City}`"
class="system"
:src="`https://unpkg.com/flag-icons@7.2.3/flags/4x3/${tunnel.list[scope.row.MachineId].Net.CountryCode.toLowerCase()}.svg`" />
</template>
<template v-else>
<img title="?" class="system" src="/system.svg" />
</template>
<template v-if="tunnel.list[scope.row.MachineId].Net.Isp">
<img
:title="`${tunnel.list[scope.row.MachineId].Net.Isp}`"
class="system" :src="netImg(tunnel.list[scope.row.MachineId].Net)" />
</template>
<template v-else>
<img title="?" class="system" src="/system.svg" />
</template>
<template v-if="tunnel.list[scope.row.MachineId].Net.Nat">
<span class="nat" :title="tunnel.list[scope.row.MachineId].Net.Nat">{{ natMap[tunnel.list[scope.row.MachineId].Net.Nat] }}</span>
</template>
<template v-else>
<img title="?" class="system" src="/system.svg" />
</template>
</div>
<div class="flex">
<a href="javascript:;" class="a-line"
:class="{yellow:tunnel.list[scope.row.MachineId].NeedReboot}"
:title="$t('home.holeText')"
@click="handleTunnel(tunnel.list[scope.row.MachineId],scope.row,values)">
<span>{{$t('home.jump')}}:{{tunnel.list[scope.row.MachineId].RouteLevel}}+{{tunnel.list[scope.row.MachineId].RouteLevelPlus}}</span>
</a>
</div>
</template>
<template v-else>
<img title="?" class="system" src="/system.svg" />
</template>
<template v-if="tunnel.list[scope.row.MachineId].Net.Isp">
<img
:title="`${tunnel.list[scope.row.MachineId].Net.Isp}`"
class="system" :src="netImg(tunnel.list[scope.row.MachineId].Net)" />
</template>
<template v-else>
<img title="?" class="system" src="/system.svg" />
</template>
<template v-if="tunnel.list[scope.row.MachineId].Net.Nat">
<span class="nat" :title="tunnel.list[scope.row.MachineId].Net.Nat">{{ natMap[tunnel.list[scope.row.MachineId].Net.Nat] }}</span>
</template>
<template v-else>
<img title="?" class="system" src="/system.svg" />
</template>
</div>
<div class="flex">
<a href="javascript:;" class="a-line"
:class="{yellow:tunnel.list[scope.row.MachineId].NeedReboot}"
:title="$t('home.holeText')"
@click="handleTunnel(tunnel.list[scope.row.MachineId],scope.row)">
<span>{{$t('home.jump')}}:{{tunnel.list[scope.row.MachineId].RouteLevel}}+{{tunnel.list[scope.row.MachineId].RouteLevelPlus}}</span>
</a>
</div>
</template>
</template>
</el-table-column>
</template>
</el-table-column>
</AccessBoolean>
</template>
<script>
import { useTunnel } from './tunnel';
@@ -54,8 +58,6 @@ export default {
const t = useI18n();
const globalData = injectGlobalData();
const machineId = computed(() => globalData.value.config.Client.Id);
const hasTunnelChangeSelf = computed(()=>globalData.value.hasAccess('TunnelChangeSelf'));
const hasTunnelChangeOther = computed(()=>globalData.value.hasAccess('TunnelChangeOther'));
const tunnel = useTunnel();
const connections = useConnections();
@@ -108,14 +110,14 @@ export default {
return length;
};
const handleTunnel = (_tunnel,row) => {
const handleTunnel = (_tunnel,row,access) => {
if(machineId.value === _tunnel.MachineId){
if(!hasTunnelChangeSelf.value){
if(!access.TunnelChangeSelf){
ElMessage.success(t('common.access'));
return;
}
}else{
if(!hasTunnelChangeOther.value){
if(!access.TunnelChangeOther){
ElMessage.success(t('common.access'));
return;
}

View File

@@ -25,21 +25,22 @@
<p><span class="label">IP数量</span><span class="value">{{ state.values.Count }}</span></p>
</div>
</el-form-item>
<el-form-item label="" prop="Btns" v-if="hasLease">
<div>
<el-button @click="state.show = false">取消</el-button>
<el-button type="primary" @click="handleSave">确认</el-button>
</div>
</el-form-item>
<AccessShow value="Lease">
<el-form-item label="" prop="Btns">
<div>
<el-button @click="state.show = false">取消</el-button>
<el-button type="primary" @click="handleSave">确认</el-button>
</div>
</el-form-item>
</AccessShow>
</el-form>
</div>
</el-dialog>
</template>
<script>
import {getNetwork,addNetwork,calcNetwork } from '@/apis/tuntap';
import { injectGlobalData } from '@/provide';
import { ElMessage } from 'element-plus';
import { computed, onMounted, reactive, ref, watch } from 'vue';
import { onMounted, reactive, ref, watch } from 'vue';
import { Delete, Plus } from '@element-plus/icons-vue'
export default {
props: ['modelValue'],
@@ -47,9 +48,6 @@ export default {
components: {Delete,Plus},
setup(props, { emit }) {
const globalData = injectGlobalData();
const hasLease = computed(()=>globalData.value.hasAccess('Lease'));
const ruleFormRef = ref(null);
const state = reactive({
show: true,
@@ -123,7 +121,7 @@ export default {
})
return {
state,hasLease, ruleFormRef, handleSave,handlePrefixLengthChange,handleClear
state,ruleFormRef, handleSave,handlePrefixLengthChange,handleClear
}
}
}

View File

@@ -1,77 +1,81 @@
<template>
<div>
<div class="flex">
<div class="flex-1">
<ConnectionShow :data="connections.list[item.MachineId]" :row="item" transitionId="tuntap"></ConnectionShow>
<a href="javascript:;" class="a-line" @click="handleTuntapIP(tuntap.list[item.MachineId])" title="虚拟网卡IP">
<template v-if="item.Connected">
<template v-if="tuntap.list[item.MachineId].SetupError">
<strong class="red" :title="`setup ${tuntap.list[item.MachineId].SetupError}`">{{ tuntap.list[item.MachineId].IP }}</strong>
</template>
<template v-else-if="tuntap.list[item.MachineId].Exists">
<strong class="red" title="IP存在冲突请使用新IP">{{ tuntap.list[item.MachineId].IP }}</strong>
</template>
<template v-else-if="tuntap.list[item.MachineId].Available == false">
<strong class="disable" title="IP不生效可能是设备不在线">{{ tuntap.list[item.MachineId].IP }}</strong>
</template>
<template v-else-if="tuntap.list[item.MachineId].NatError">
<strong class="yellow" :title="`nat ${tuntap.list[item.MachineId].NatError}`">{{ tuntap.list[item.MachineId].IP }}</strong>
</template>
<template v-else-if="tuntap.list[item.MachineId].AppNat && tuntap.list[item.MachineId].running">
<strong class="app-nat" :title="`虚拟网卡IP\r\n应用层DNAT`">{{ tuntap.list[item.MachineId].IP }}</strong>
</template>
<template v-else-if="tuntap.list[item.MachineId].running">
<strong class="green gateway" :title="`虚拟网卡IP\r\n系统NAT`">{{ tuntap.list[item.MachineId].IP }}</strong>
</template>
<template v-else>
<strong>{{ tuntap.list[item.MachineId].IP }}</strong>
</template>
<AccessBoolean value="TuntapChangeSelf,TuntapChangeOther,TuntapStatusSelf,TuntapStatusOther">
<template #default="{values}">
<div>
<div class="flex">
<div class="flex-1">
<ConnectionShow :data="connections.list[item.MachineId]" :row="item" transitionId="tuntap"></ConnectionShow>
<a href="javascript:;" class="a-line" @click="handleTuntapIP(tuntap.list[item.MachineId],values)" title="虚拟网卡IP">
<template v-if="item.Connected">
<template v-if="tuntap.list[item.MachineId].SetupError">
<strong class="red" :title="`setup ${tuntap.list[item.MachineId].SetupError}`">{{ tuntap.list[item.MachineId].IP }}</strong>
</template>
<template v-else-if="tuntap.list[item.MachineId].Exists">
<strong class="red" title="IP存在冲突请使用新IP">{{ tuntap.list[item.MachineId].IP }}</strong>
</template>
<template v-else-if="tuntap.list[item.MachineId].Available == false">
<strong class="disable" title="IP不生效可能是设备不在线">{{ tuntap.list[item.MachineId].IP }}</strong>
</template>
<template v-else-if="tuntap.list[item.MachineId].NatError">
<strong class="yellow" :title="`nat ${tuntap.list[item.MachineId].NatError}`">{{ tuntap.list[item.MachineId].IP }}</strong>
</template>
<template v-else-if="tuntap.list[item.MachineId].AppNat && tuntap.list[item.MachineId].running">
<strong class="app-nat" :title="`虚拟网卡IP\r\n应用层DNAT`">{{ tuntap.list[item.MachineId].IP }}</strong>
</template>
<template v-else-if="tuntap.list[item.MachineId].running">
<strong class="green gateway" :title="`虚拟网卡IP\r\n系统NAT`">{{ tuntap.list[item.MachineId].IP }}</strong>
</template>
<template v-else>
<strong>{{ tuntap.list[item.MachineId].IP }}</strong>
</template>
</template>
<template v-else>
<strong class="disable" title="IP不生效可能是设备不在线">{{ tuntap.list[item.MachineId].IP }}</strong>
</template>
</a>
</div>
<template v-if="tuntap.list[item.MachineId].loading">
<div>
<el-icon size="14" class="loading"><Loading /></el-icon>
</div>
</template>
<template v-else>
<strong class="disable" title="IP不生效可能是设备不在线">{{ tuntap.list[item.MachineId].IP }}</strong>
<el-switch :model-value="item.Connected && tuntap.list[item.MachineId].running" :loading="tuntap.list[item.MachineId].loading" disabled @click="handleTuntap(tuntap.list[item.MachineId],values)" size="small" inline-prompt active-text="😀" inactive-text="😣" >
</el-switch>
</template>
</a>
</div>
<template v-if="tuntap.list[item.MachineId].loading">
<div>
<el-icon size="14" class="loading"><Loading /></el-icon>
</div>
</template>
<template v-else>
<el-switch :model-value="item.Connected && tuntap.list[item.MachineId].running" :loading="tuntap.list[item.MachineId].loading" disabled @click="handleTuntap(tuntap.list[item.MachineId])" size="small" inline-prompt active-text="😀" inactive-text="😣" >
</el-switch>
</template>
</div>
<div>
<div>
<template v-for="(item1,index) in tuntap.list[item.MachineId].Lans" :key="index">
<template v-if="tuntap.list[item.MachineId].Available == false">
<div class="flex disable" title="IP不生效可能是设备不在线">{{ item1.IP }} / {{ item1.PrefixLength }}</div>
<div>
<div>
<template v-for="(item1,index) in tuntap.list[item.MachineId].Lans" :key="index">
<template v-if="tuntap.list[item.MachineId].Available == false">
<div class="flex disable" title="IP不生效可能是设备不在线">{{ item1.IP }} / {{ item1.PrefixLength }}</div>
</template>
<template v-else-if="item1.Disabled">
<div class="flex disable" title="已禁用">{{ item1.IP }} / {{ item1.PrefixLength }}</div>
</template>
<template v-else-if="item1.Exists">
<div class="flex yellow" title="与其它设备填写IP、或本机局域网IP有冲突、或与本机外网IP一致">{{ item1.IP }} / {{ item1.PrefixLength }}</div>
</template>
<template v-else>
<div class="flex green" title="正常使用">{{ item1.IP }} / {{ item1.PrefixLength }}</div>
</template>
</template>
</div>
<template v-if="tuntap.list[item.MachineId].Any">
<div class="any green"><el-icon><Share /></el-icon></div>
</template>
<template v-else-if="item1.Disabled">
<div class="flex disable" title="已禁用">{{ item1.IP }} / {{ item1.PrefixLength }}</div>
<template v-if="showDelay">
<template v-if="tuntap.list[item.MachineId].Delay>=0 && tuntap.list[item.MachineId].Delay<=100">
<div class="delay green">{{ tuntap.list[item.MachineId].Delay }}ms</div>
</template>
<template>
<div class="delay yellow">{{ tuntap.list[item.MachineId].Delay }}ms</div>
</template>
</template>
<template v-else-if="item1.Exists">
<div class="flex yellow" title="与其它设备填写IP、或本机局域网IP有冲突、或与本机外网IP一致">{{ item1.IP }} / {{ item1.PrefixLength }}</div>
</template>
<template v-else>
<div class="flex green" title="正常使用">{{ item1.IP }} / {{ item1.PrefixLength }}</div>
</template>
</template>
</div>
</div>
<template v-if="tuntap.list[item.MachineId].Any">
<div class="any green"><el-icon><Share /></el-icon></div>
</template>
<template v-if="showDelay">
<template v-if="tuntap.list[item.MachineId].Delay>=0 && tuntap.list[item.MachineId].Delay<=100">
<div class="delay green">{{ tuntap.list[item.MachineId].Delay }}ms</div>
</template>
<template>
<div class="delay yellow">{{ tuntap.list[item.MachineId].Delay }}ms</div>
</template>
</template>
</div>
</div>
</template>
</AccessBoolean>
</template>
<script>
@@ -91,25 +95,21 @@ export default {
const tuntap = useTuntap();
const globalData = injectGlobalData();
const machineId = computed(() => globalData.value.config.Client.Id);
const hasTuntapChangeSelf = computed(()=>globalData.value.hasAccess('TuntapChangeSelf'));
const hasTuntapChangeOther = computed(()=>globalData.value.hasAccess('TuntapChangeOther'));
const hasTuntapStatusSelf = computed(()=>globalData.value.hasAccess('TuntapStatusSelf'));
const hasTuntapStatusOther = computed(()=>globalData.value.hasAccess('TuntapStatusOther'));
const connections = useTuntapConnections();
const showDelay = computed(()=>((globalData.value.config.Running.Tuntap || {Switch:0}).Switch & 2) == 2);
const handleTuntap = (_tuntap) => {
const handleTuntap = (_tuntap,access) => {
if(!props.config){
return;
}
if(machineId.value === _tuntap.MachineId){
if(!hasTuntapStatusSelf.value){
if(!access.TuntapStatusSelf){
ElMessage.success('无权限');
return;
}
}else{
if(!hasTuntapStatusOther.value){
if(!access.TuntapStatusOther){
ElMessage.success('无权限');
return;
}
@@ -124,18 +124,18 @@ export default {
ElMessage.error('操作失败!');
})
}
const handleTuntapIP = (_tuntap) => {
const handleTuntapIP = (_tuntap,access) => {
if(!props.config && machineId.value != _tuntap.MachineId){
ElMessage.success('无权限');
return;
}
if(machineId.value === _tuntap.MachineId){
if(!hasTuntapChangeSelf.value){
if(!access.TuntapChangeSelf){
ElMessage.success('无权限');
return;
}
}else{
if(!hasTuntapChangeOther.value){
if(!access.TuntapChangeOther){
ElMessage.success('无权限');
return;
}

View File

@@ -1,29 +1,33 @@
<template>
<a href="javascript:;" class="download" @click="handleUpdate()" :title="updaterText" :class="updaterColor">
<span>
<span>{{item.Version}}</span>
<template v-if="updater.list[item.MachineId]">
<template v-if="updater.list[item.MachineId].Status == 1">
<el-icon size="14" class="loading"><Loading /></el-icon>
</template>
<template v-else-if="updater.list[item.MachineId].Status == 2">
<el-icon size="14"><Download /></el-icon>
</template>
<template v-else-if="updater.list[item.MachineId].Status == 3 || updater.list[item.MachineId].Status == 5">
<el-icon size="14" class="loading"><Loading /></el-icon>
<span class="progress" v-if="updater.list[item.MachineId].Length ==0">0%</span>
<span class="progress" v-else>{{parseInt(updater.list[item.MachineId].Current/updater.list[item.MachineId].Length*100)}}%</span>
</template>
<template v-else-if="updater.list[item.MachineId].Status == 6">
<el-icon size="14" class="yellow"><CircleCheck /></el-icon>
</template>
</template>
<template v-else>
<el-icon size="14"><Download /></el-icon>
</template>
</span>
</a>
<a href="javascript:;" class="download" title="检查更新" @click="handleCheck"><el-icon><Refresh /></el-icon></a>
<AccessBoolean value="UpdateSelf,UpdateOther">
<template #default="{values}">
<a href="javascript:;" class="download" @click="handleUpdate(values)" :title="updaterText" :class="updaterColor">
<span>
<span>{{item.Version}}</span>
<template v-if="updater.list[item.MachineId]">
<template v-if="updater.list[item.MachineId].Status == 1">
<el-icon size="14" class="loading"><Loading /></el-icon>
</template>
<template v-else-if="updater.list[item.MachineId].Status == 2">
<el-icon size="14"><Download /></el-icon>
</template>
<template v-else-if="updater.list[item.MachineId].Status == 3 || updater.list[item.MachineId].Status == 5">
<el-icon size="14" class="loading"><Loading /></el-icon>
<span class="progress" v-if="updater.list[item.MachineId].Length ==0">0%</span>
<span class="progress" v-else>{{parseInt(updater.list[item.MachineId].Current/updater.list[item.MachineId].Length*100)}}%</span>
</template>
<template v-else-if="updater.list[item.MachineId].Status == 6">
<el-icon size="14" class="yellow"><CircleCheck /></el-icon>
</template>
</template>
<template v-else>
<el-icon size="14"><Download /></el-icon>
</template>
</span>
</a>
<a href="javascript:;" class="download" title="检查更新" @click="handleCheck"><el-icon><Refresh /></el-icon></a>
</template>
</AccessBoolean>
</template>
<script>
@@ -40,8 +44,6 @@ export default {
setup (props) {
const globalData = injectGlobalData();
const hasUpdateSelf = computed(()=>globalData.value.hasAccess('UpdateSelf'));
const hasUpdateOther = computed(()=>globalData.value.hasAccess('UpdateOther'));
const updater = useUpdater();
const serverVersion = computed(()=>globalData.value.signin.Version);
const updaterVersion = computed(()=>updater.value.current.Version);
@@ -70,16 +72,16 @@ export default {
: updater.value.list[props.item.MachineId] && updaterVersion.value != props.item.Version
? 'yellow' :'green'
})
const handleUpdate = ()=>{
const handleUpdate = (access)=>{
updater.value.device = props.item;
if(!props.config){
return;
}
if(!hasUpdateSelf.value){
if(!access.UpdateSelf){
ElMessage.error('无权限');
return;
}
if(props.item.MachineId != globalData.value.self.MachineId && !hasUpdateOther.value){
if(props.item.MachineId != globalData.value.self.MachineId && !access.UpdateOther){
ElMessage.error('无权限');
return;
}

View File

@@ -1,32 +1,35 @@
<template>
<el-dialog class="options-center" title="更新" destroy-on-close v-model="state.show" width="40rem" top="2vh">
<div class="updater-wrap t-c">
<div class="t-l">
<ul>
<li v-for="item in state.msg">{{ item }}</li>
</ul>
</div>
<div class="flex mgt-1">
<el-row class="w-100">
<el-col :span="10">
<el-select v-model="state.type" size="large">
<el-option v-for="item in state.types" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</el-col>
<el-col :span="4">
->
</el-col>
<el-col :span="10">
<el-select v-model="state.version" size="large" filterable allow-create default-first-option>
<el-option v-for="item in state.versions" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</el-col>
</el-row>
</div>
<div class="mgt-1 t-c">
<el-button type="success" @click="handleUpdate" plain> </el-button>
</div>
<AccessBoolean value="UpdateSelf,UpdateOther">
<template #default="{values}">
<div class="t-l">
<ul>
<li v-for="item in state.msg">{{ item }}</li>
</ul>
</div>
<div class="flex mgt-1">
<el-row class="w-100">
<el-col :span="10">
<el-select v-model="state.type" size="large">
<el-option v-for="item in getTypes(values)" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</el-col>
<el-col :span="4">
->
</el-col>
<el-col :span="10">
<el-select v-model="state.version" size="large" filterable allow-create default-first-option>
<el-option v-for="item in state.versions" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</el-col>
</el-row>
</div>
<div class="mgt-1 t-c">
<el-button type="success" @click="handleUpdate(values)" plain> </el-button>
</div>
</template>
</AccessBoolean>
</div>
</el-dialog>
</template>
@@ -43,26 +46,18 @@ export default {
setup (props,{emit}) {
const globalData = injectGlobalData();
const hasUpdateSelf = computed(()=>globalData.value.hasAccess('UpdateSelf'));
const hasUpdateOther = computed(()=>globalData.value.hasAccess('UpdateOther'));
const updater = useUpdater();
const serverVersion = computed(()=>globalData.value.signin.Version);
const updaterVersion = computed(()=>updater.value.current.Version);
const types = [
{label:`仅【${updater.value.device.MachineName}`,value:updater.value.device.MachineId},
hasUpdateOther.value ? {label:`本组所有`,value:'g-all'} : {},
hasUpdateOther.value ? {label:`本服务器所有`,value:'s-all'} : {},
].filter(c=>c.value);
const versions = [
{label:`${updaterVersion.value}【最新版本】`,value:updaterVersion.value},
{label:`${serverVersion.value}【服务器版本】`,value:serverVersion.value},
].filter(c=>c.value);
const state = reactive({
show: true,
type:types[0] || '',
type:'',
version:versions[0] || '',
types:types,
versions:versions,
msg:[]
});
@@ -74,7 +69,19 @@ export default {
}, 300);
}
});
const handleUpdate = ()=>{
const getTypes = (access)=>{
const types = [
{label:`仅【${updater.value.device.MachineName}`,value:updater.value.device.MachineId},
access.UpdateOther.value ? {label:`本组所有`,value:'g-all'} : {},
access.UpdateOther.value ? {label:`本服务器所有`,value:'s-all'} : {},
].filter(c=>c.value);
if(!state.type){
state.type = types[0] || '';
}
return types;
}
const handleUpdate = (access)=>{
const data = {
MachineId:updater.value.device.MachineId,
Version:state.version.value || state.version,
@@ -97,7 +104,7 @@ export default {
});
return {
state,updater,handleUpdate
state,getTypes,updater,handleUpdate
}
}
}

View File

@@ -16,7 +16,6 @@
<Install></Install>
</div>
</div>
</template>
<script>

View File

@@ -8,7 +8,9 @@
<div class="flex">
<el-input v-trim style="width:20rem;" v-model="state.list.Host" @blur="handleSave" />
<Sync class="mgl-1" name="SignInServer"></Sync>
<span class="mgl-1" v-if="globalData.isPc">{{$t('server.messengerText')}}</span>
<PcShow>
<span class="mgl-1">{{$t('server.messengerText')}}</span>
</PcShow>
</div>
</el-form-item>
<el-form-item :label="`${$t('server.messengerAddr')}1`">
@@ -28,19 +30,14 @@
<el-input v-trim :class="{success:state.super,error:state.super==false}" style="width:20rem;" type="password" show-password maxlength="36" v-model="state.list.SuperPassword" @blur="handleSave" />
</div>
</el-form-item>
<!-- <el-form-item :label="$t('server.messenger')" v-if="state.super && hasWhiteList">
<div>
<div class="flex">
<WhiteList type="SignIn"></WhiteList>
</div>
</div>
</el-form-item> -->
<el-form-item></el-form-item>
<el-form-item :label="$t('server.messengerUserId')">
<div class="flex">
<el-input v-trim style="width:20rem;" type="password" show-password maxlength="36" v-model="state.list.UserId" @blur="handleSave" />
<Sync class="mgl-1" name="SignInUserId"></Sync>
<span class="mgl-1" v-if="globalData.isPc">{{$t('server.messengerUserIdText')}}</span>
<PcShow>
<span class="mgl-1">{{$t('server.messengerUserIdText')}}</span>
</PcShow>
</div>
</el-form-item>
<el-form-item></el-form-item>
@@ -74,7 +71,6 @@ export default {
setup(props) {
const {t} = useI18n();
const globalData = injectGlobalData();
const hasWhiteList = computed(()=>globalData.value.hasAccess('WhiteList'));
const state = reactive({
list:globalData.value.config.Client.Server,
height: computed(()=>globalData.value.height-90),
@@ -99,7 +95,7 @@ export default {
handleCheckKey();
});
return {globalData,state,hasWhiteList,handleSave}
return {globalData,state,handleSave}
}
}
</script>

View File

@@ -1,21 +1,16 @@
<template>
<div class="servers-wrap scrollbar" >
<Config v-if="hasConfig"></Config>
<AccessShow value="Config">
<Config></Config>
</AccessShow>
</div>
</template>
<script>
import { computed, reactive } from 'vue';
import { injectGlobalData } from '@/provide';
import Config from './Config.vue';
export default {
components:{Config},
setup(props) {
const globalData = injectGlobalData();
const hasConfig = computed(()=>globalData.value.hasAccess('Config'))
const state = reactive({});
return {
state,hasConfig
}
return {}
}
}
</script>

View File

@@ -1,12 +1,13 @@
<template>
<div class="image" v-if="globalData.isPc">
<a href="javascript:;" @click="handleBg"><el-icon><PictureRounded /></el-icon></a>
<input type="file" id="file-input">
</div>
<PcShow>
<div class="image">
<a href="javascript:;" @click="handleBg"><el-icon><PictureRounded /></el-icon></a>
<input type="file" id="file-input">
</div>
</PcShow>
</template>
<script>
import { injectGlobalData } from '@/provide';
import {PictureRounded} from '@element-plus/icons-vue'
import { ElMessageBox } from 'element-plus';
import { onMounted } from 'vue';
@@ -15,7 +16,6 @@ export default {
props:['name'],
setup(props) {
const globalData = injectGlobalData();
const key = `bg-${props.name}`;
const handleBg = ()=>{
@@ -67,7 +67,7 @@ export default {
})
return {
globalData,handleBg
handleBg
}
}
}

View File

@@ -1,24 +1,25 @@
<template>
<div class="locale" v-if="globalData.isPc">
<el-dropdown>
<span class="el-dropdown-link">
{{localeOptions[locale]}}
<el-icon>
<ArrowDown />
</el-icon>
</span>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item v-for="(item,index) in localeOptions" @click="handleLocale(index)">{{item}}</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
<PcShow>
<div class="locale">
<el-dropdown>
<span class="el-dropdown-link">
{{localeOptions[locale]}}
<el-icon>
<ArrowDown />
</el-icon>
</span>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item v-for="(item,index) in localeOptions" @click="handleLocale(index)">{{item}}</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
</PcShow>
</template>
<script>
import {ArrowDown} from '@element-plus/icons-vue'
import { injectGlobalData } from '@/provide';
import { computed, ref} from 'vue';
import { LOCALE_OPTIONS } from '@/lang'
import useLocale from '@/lang/provide'
@@ -26,7 +27,6 @@ export default {
components:{ArrowDown},
setup() {
const globalData = injectGlobalData();
const localeOptions = ref(LOCALE_OPTIONS);
const { changeLocale, currentLocale } = useLocale()
const locale = computed({
@@ -41,7 +41,6 @@ export default {
locale.value =index;
}
return {
globalData,
localeOptions,locale,handleLocale
}
}

View File

@@ -1,91 +1,131 @@
<template>
<div class="menu flex-1">
<ul class="flex" v-if="globalData.isPc">
<li>
<router-link :to="{name:'FullIndex'}"><img src="@/assets/shouye.svg"/><span>{{$t('head.home')}}</span></router-link>
</li>
<li v-if="hasConfig">
<router-link :to="{name:'FullServers'}"><img src="@/assets/fuwuqi.svg"/><span>{{$t('head.server')}}</span></router-link>
</li>
<li v-if="hasTransport">
<router-link :to="{name:'FullTransport'}"><img src="@/assets/dadong.svg"/><span>{{$t('head.protocol')}}</span></router-link>
</li>
<li v-if="hasAction">
<router-link :to="{name:'FullAction'}"><img src="@/assets/login.svg"/><span>{{$t('head.action')}}</span></router-link>
</li>
<li v-if="hasFirewall">
<router-link :to="{name:'FullFirewall'}"><img src="@/assets/anquan.svg"/><span>{{$t('head.firewall')}}</span></router-link>
</li>
<li v-if="hasWakeupSelf">
<router-link :to="{name:'FullWakeup'}"><img src="@/assets/qidong.svg"/><span>{{$t('head.wakeup')}}</span></router-link>
</li>
<li v-if="hasLogger">
<router-link :to="{name:'FullLogger'}"><img src="@/assets/rizhi.svg"/><span>{{$t('head.logger')}}</span></router-link>
</li>
</ul>
<ul class="flex" v-else>
<li v-if="route.name == 'FullIndex'">
<router-link :to="{name:'FullIndex'}"><img src="@/assets/shouye.svg"/><span>{{$t('head.home')}}</span></router-link>
</li>
<li v-if="hasConfig && route.name == 'FullServers'">
<router-link :to="{name:'FullServers'}"><img src="@/assets/fuwuqi.svg"/><span>{{$t('head.server')}}</span></router-link>
</li>
<li v-if="hasTransport && route.name == 'FullTransport'">
<router-link :to="{name:'FullTransport'}"><img src="@/assets/dadong.svg"/><span>{{$t('head.protocol')}}</span></router-link>
</li>
<li v-if="hasAction && route.name == 'FullAction'">
<router-link :to="{name:'FullAction'}"><img src="@/assets/login.svg"/><span>{{$t('head.action')}}</span></router-link>
</li>
<li v-if="hasFirewall && route.name == 'FullFirewall'">
<router-link :to="{name:'FullFirewall'}"><img src="@/assets/anquan.svg"/><span>{{$t('head.firewall')}}</span></router-link>
</li>
<li v-if="hasWakeupSelf && route.name == 'FullWakeup'">
<router-link :to="{name:'FullWakeup'}"><img src="@/assets/qidong.svg"/><span>{{$t('head.wakeup')}}</span></router-link>
</li>
<li v-if="hasLogger && route.name == 'FullLogger'">
<router-link :to="{name:'FullLogger'}"><img src="@/assets/rizhi.svg"/> <span>{{$t('head.logger')}}</span></router-link>
</li>
<li>
<a href="javascript:void(0);" @click="refresh"><img src="@/assets/shuaxin2.svg"/><span>{{$t('head.refresh')}}</span></a>
</li>
</ul>
</div>
<div class="select" v-if="globalData.isPhone">
<el-dropdown>
<span class="el-dropdown-link"><el-icon><Operation /></el-icon></span>
<template #dropdown>
<el-dropdown-menu class="select-menu">
<el-dropdown-item>
<router-link :to="{name:'FullIndex'}"><img src="@/assets/shouye.svg" height="20" style="vertical-align: text-top;"/> {{$t('head.home')}}</router-link>
</el-dropdown-item>
<el-dropdown-item v-if="hasConfig">
<router-link :to="{name:'FullServers'}"><img src="@/assets/fuwuqi.svg" height="20" style="vertical-align: text-top;"/> {{$t('head.server')}}</router-link>
</el-dropdown-item>
<el-dropdown-item v-if="hasTransport">
<router-link :to="{name:'FullTransport'}"><img src="@/assets/dadong.svg" height="20" style="vertical-align: text-top;"/> {{$t('head.protocol')}}</router-link>
</el-dropdown-item>
<el-dropdown-item v-if="hasAction">
<router-link :to="{name:'FullAction'}"><img src="@/assets/login.svg" height="20" style="vertical-align: text-top;"/> {{$t('head.action')}}</router-link>
</el-dropdown-item>
<el-dropdown-item v-if="hasFirewall">
<router-link :to="{name:'FullFirewall'}"><img src="@/assets/anquan.svg" height="20" style="vertical-align: text-top;"/> {{$t('head.firewall')}}</router-link>
</el-dropdown-item>
<el-dropdown-item v-if="hasWakeupSelf">
<router-link :to="{name:'FullWakeup'}"><img src="@/assets/qidong.svg" height="20" style="vertical-align: text-top;"/> {{$t('head.wakeup')}}</router-link>
</el-dropdown-item>
<el-dropdown-item v-if="hasLogger">
<router-link :to="{name:'FullLogger'}"><img src="@/assets/rizhi.svg" height="20" style="vertical-align: text-top;"/> {{$t('head.logger')}}</router-link>
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
<PcShow>
<ul class="flex">
<li>
<router-link :to="{name:'FullIndex'}"><img src="@/assets/shouye.svg"/><span>{{$t('head.home')}}</span></router-link>
</li>
<AccessShow value="Config">
<li>
<router-link :to="{name:'FullServers'}"><img src="@/assets/fuwuqi.svg"/><span>{{$t('head.server')}}</span></router-link>
</li>
</AccessShow>
<AccessShow value="Transport">
<li>
<router-link :to="{name:'FullTransport'}"><img src="@/assets/dadong.svg"/><span>{{$t('head.protocol')}}</span></router-link>
</li>
</AccessShow>
<AccessShow value="Action">
<li>
<router-link :to="{name:'FullAction'}"><img src="@/assets/login.svg"/><span>{{$t('head.action')}}</span></router-link>
</li>
</AccessShow>
<AccessShow value="FirewallSelf">
<li>
<router-link :to="{name:'FullFirewall'}"><img src="@/assets/anquan.svg"/><span>{{$t('head.firewall')}}</span></router-link>
</li>
</AccessShow>
<AccessShow value="WakeupSelf">
<li>
<router-link :to="{name:'FullWakeup'}"><img src="@/assets/qidong.svg"/><span>{{$t('head.wakeup')}}</span></router-link>
</li>
</AccessShow>
<AccessShow value="LoggerShow">
<li>
<router-link :to="{name:'FullLogger'}"><img src="@/assets/rizhi.svg"/><span>{{$t('head.logger')}}</span></router-link>
</li>
</AccessShow>
</ul>
</PcShow>
<PhoneShow>
<ul class="flex">
<li v-if="route.name == 'FullIndex'">
<router-link :to="{name:'FullIndex'}"><img src="@/assets/shouye.svg"/><span>{{$t('head.home')}}</span></router-link>
</li>
<AccessShow value="Config">
<li v-if="route.name == 'FullServers'">
<router-link :to="{name:'FullServers'}"><img src="@/assets/fuwuqi.svg"/><span>{{$t('head.server')}}</span></router-link>
</li>
</AccessShow>
<AccessShow value="Transport">
<li v-if="route.name == 'FullTransport'">
<router-link :to="{name:'FullTransport'}"><img src="@/assets/dadong.svg"/><span>{{$t('head.protocol')}}</span></router-link>
</li>
</AccessShow>
<AccessShow value="Action">
<li v-if="route.name == 'FullAction'">
<router-link :to="{name:'FullAction'}"><img src="@/assets/login.svg"/><span>{{$t('head.action')}}</span></router-link>
</li>
</AccessShow>
<AccessShow value="FirewallSelf">
<li v-if="route.name == 'FullFirewall'">
<router-link :to="{name:'FullFirewall'}"><img src="@/assets/anquan.svg"/><span>{{$t('head.firewall')}}</span></router-link>
</li>
</AccessShow>
<AccessShow value="WakeupSelf">
<li v-if="route.name == 'FullWakeup'">
<router-link :to="{name:'FullWakeup'}"><img src="@/assets/qidong.svg"/><span>{{$t('head.wakeup')}}</span></router-link>
</li>
</AccessShow>
<AccessShow value="LoggerShow">
<li v-if="route.name == 'FullLogger'">
<router-link :to="{name:'FullLogger'}"><img src="@/assets/rizhi.svg"/> <span>{{$t('head.logger')}}</span></router-link>
</li>
</AccessShow>
<li>
<a href="javascript:void(0);" @click="refresh"><img src="@/assets/shuaxin2.svg"/><span>{{$t('head.refresh')}}</span></a>
</li>
</ul>
</PhoneShow>
</div>
<PhoneShow>
<div class="select">
<el-dropdown>
<span class="el-dropdown-link"><el-icon><Operation /></el-icon></span>
<template #dropdown>
<el-dropdown-menu class="select-menu">
<el-dropdown-item>
<router-link :to="{name:'FullIndex'}"><img src="@/assets/shouye.svg" height="20" style="vertical-align: text-top;"/> {{$t('head.home')}}</router-link>
</el-dropdown-item>
<AccessShow value="Config">
<el-dropdown-item>
<router-link :to="{name:'FullServers'}"><img src="@/assets/fuwuqi.svg" height="20" style="vertical-align: text-top;"/> {{$t('head.server')}}</router-link>
</el-dropdown-item>
</AccessShow>
<AccessShow value="Transport">
<el-dropdown-item>
<router-link :to="{name:'FullTransport'}"><img src="@/assets/dadong.svg" height="20" style="vertical-align: text-top;"/> {{$t('head.protocol')}}</router-link>
</el-dropdown-item>
</AccessShow>
<AccessShow value="Action">
<el-dropdown-item>
<router-link :to="{name:'FullAction'}"><img src="@/assets/login.svg" height="20" style="vertical-align: text-top;"/> {{$t('head.action')}}</router-link>
</el-dropdown-item>
</AccessShow>
<AccessShow value="FirewallSelf">
<el-dropdown-item>
<router-link :to="{name:'FullFirewall'}"><img src="@/assets/anquan.svg" height="20" style="vertical-align: text-top;"/> {{$t('head.firewall')}}</router-link>
</el-dropdown-item>
</AccessShow>
<AccessShow value="WakeupSelf">
<el-dropdown-item>
<router-link :to="{name:'FullWakeup'}"><img src="@/assets/qidong.svg" height="20" style="vertical-align: text-top;"/> {{$t('head.wakeup')}}</router-link>
</el-dropdown-item>
</AccessShow>
<AccessShow value="LoggerShow">
<el-dropdown-item>
<router-link :to="{name:'FullLogger'}"><img src="@/assets/rizhi.svg" height="20" style="vertical-align: text-top;"/> {{$t('head.logger')}}</router-link>
</el-dropdown-item>
</AccessShow>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
</PhoneShow>
</template>
<script>
import {Operation,ArrowDown} from '@element-plus/icons-vue'
import { injectGlobalData } from '@/provide';
import { computed} from 'vue';
import Background from './Background.vue';
import Theme from './Theme.vue';
import { useRoute } from 'vue-router';
@@ -94,20 +134,12 @@ export default {
setup() {
const route = useRoute();
const globalData = injectGlobalData();
const hasConfig = computed(()=>globalData.value.hasAccess('Config'));
const hasLogger = computed(()=>globalData.value.hasAccess('LoggerShow'));
const hasTransport = computed(()=>globalData.value.hasAccess('Transport'));
const hasAction = computed(()=>globalData.value.hasAccess('Action'));
const hasFirewall = computed(()=>globalData.value.hasAccess('FirewallSelf'));
const hasWakeupSelf = computed(()=>globalData.value.hasAccess('WakeupSelf'));
const refresh = () => {
window.location.reload();
}
return {
route,globalData,hasConfig,
hasLogger,hasTransport,hasAction,hasFirewall,hasWakeupSelf,refresh
route,refresh
}
}
}

View File

@@ -1,19 +1,19 @@
<template>
<div class="image" v-if="globalData.isPc">
<a href="javascript:;" @click="changeMode('light')" v-if="state.mode == 'dark'"><el-icon><Moon /></el-icon></a>
<a href="javascript:;" @click="changeMode('dark')" v-else><el-icon><Sunny /></el-icon></a>
</div>
<PcShow>
<div class="image">
<a href="javascript:;" @click="changeMode('light')" v-if="state.mode == 'dark'"><el-icon><Moon /></el-icon></a>
<a href="javascript:;" @click="changeMode('dark')" v-else><el-icon><Sunny /></el-icon></a>
</div>
</PcShow>
</template>
<script>
import { injectGlobalData } from '@/provide';
import {Moon,Sunny} from '@element-plus/icons-vue'
import { onMounted, reactive } from 'vue';
export default {
components:{Moon,Sunny},
setup () {
const globalData = injectGlobalData();
const isSystemDarkMode = window.matchMedia('(prefers-color-scheme: dark)').matches;
const isSystemLightMode = window.matchMedia('(prefers-color-scheme: light)').matches;
const cacheMode = localStorage.getItem('theme-mode') || (isSystemDarkMode?'dark':'light');
@@ -33,7 +33,7 @@ export default {
setMode();
})
return {globalData,state,changeMode}
return {state,changeMode}
}
}
</script>

View File

@@ -10,20 +10,23 @@
</el-col>
</el-row>
</el-form-item>
<el-form-item label="" label-width="0" v-if="globalData.isPc">
<el-row class="w-100">
<el-col :sm="12" :xs="24" v-if="globalData.isPc">
<el-form-item label="管理端口" prop="web">
<el-input v-trim v-model="state.form.web" />
</el-form-item>
</el-col>
<el-col :sm="12" :xs="24">
<el-form-item label="管理密码" prop="password">
<el-input v-trim type="password" v-model="state.form.password" show-password maxlength="36" show-word-limit/>
</el-form-item>
</el-col>
</el-row>
</el-form-item>
<PcShow>
<el-form-item label="" label-width="0">
<el-row class="w-100">
<el-col :sm="12" :xs="24">
<el-form-item label="管理端口" prop="web">
<el-input v-trim v-model="state.form.web" />
</el-form-item>
</el-col>
<el-col :sm="12" :xs="24">
<el-form-item label="管理密码" prop="password">
<el-input v-trim type="password" v-model="state.form.password" show-password maxlength="36" show-word-limit/>
</el-form-item>
</el-col>
</el-row>
</el-form-item>
</PcShow>
<el-form-item label="" label-width="0">
<el-row class="w-100">
<el-col :sm="12" :xs="24">
@@ -160,7 +163,7 @@ export default {
}
})
return { state,globalData, handleValidate, formDom };
return { state,handleValidate, formDom };
}
}
</script>

View File

@@ -1,7 +1,9 @@
<template>
<div class="t-c">
<el-checkbox v-model="state.form.client" label="作为客户端" />
<el-checkbox v-model="state.form.server" label="作为服务端" v-if="globalData.isPc" />
<PcShow>
<el-checkbox v-model="state.form.server" label="作为服务端"/>
</PcShow>
</div>
</template>

View File

@@ -42,10 +42,7 @@ export default {
const globalData = injectGlobalData();
const state = reactive({
steps:computed(()=>['选择模式',
globalData.value.isPc ? '服务端' : '',
'客户端',
'完成'])
steps:computed(()=>['选择模式', globalData.value.isPc ? '服务端' : '','客户端','完成'])
});
const currentDom = ref(null);
@@ -78,7 +75,7 @@ export default {
})
}
return { state,globalData,currentDom,step,handlePrev,handleNext,handleSave};
return { state,currentDom,step,handlePrev,handleNext,handleSave};
}
}
</script>

View File

@@ -1,51 +1,55 @@
<template>
<div class="logger-setting-wrap flex flex-column h-100" ref="wrap">
<el-tabs type="border-card" class="w-100">
<el-tab-pane :label="$t('logger.list')" v-if="hasLogger">
<div class="inner">
<div class="head flex">
<div>
<el-select v-model="state.type" @change="loadData" size="small" class="mgr-1" style="width: 6rem;">
<el-option :value="-1" label="all"></el-option>
<el-option :value="0" label="debug"></el-option>
<el-option :value="1" label="info"></el-option>
<el-option :value="2" label="warning"></el-option>
<el-option :value="3" label="error"></el-option>
<el-option :value="4" label="fatal"></el-option>
</el-select>
<AccessShow value="LoggerShow">
<el-tab-pane :label="$t('logger.list')">
<div class="inner">
<div class="head flex">
<div>
<el-select v-model="state.type" @change="loadData" size="small" class="mgr-1" style="width: 6rem;">
<el-option :value="-1" label="all"></el-option>
<el-option :value="0" label="debug"></el-option>
<el-option :value="1" label="info"></el-option>
<el-option :value="2" label="warning"></el-option>
<el-option :value="3" label="error"></el-option>
<el-option :value="4" label="fatal"></el-option>
</el-select>
</div>
<el-button type="warning" size="small" :loading="state.loading" @click="clearData">{{$t('logger.clear')}}</el-button>
<el-button size="small" :loading="state.loading" @click="loadData">{{$t('logger.refresh')}}</el-button>
<span class="flex-1"></span>
</div>
<el-button type="warning" size="small" :loading="state.loading" @click="clearData">{{$t('logger.clear')}}</el-button>
<el-button size="small" :loading="state.loading" @click="loadData">{{$t('logger.refresh')}}</el-button>
<span class="flex-1"></span>
</div>
<div class="body flex-1 relative">
<el-table stripe border :data="state.page.List" size="small" :height="`${state.height}px`" width="100%" @row-click="handleRowClick" :row-class-name="tableRowClassName">
<el-table-column type="index" width="50" />
<el-table-column prop="Type" :label="$t('logger.level')" width="80">
<template #default="scope">
<span>{{state.types[scope.row.Type]}} </span>
</template>
</el-table-column>
<el-table-column prop="Time" :label="$t('logger.time')" width="160"></el-table-column>
<el-table-column prop="content" :label="$t('logger.content')"></el-table-column>
</el-table>
</div>
<div class="pages t-c">
<div class="page-wrap">
<el-pagination small :total="state.page.Count"
v-model:currentPage="state.page.Page" :page-size="state.page.Size"
:pager-count="globalData.isPc?7:3"
:layout="globalData.isPc?'total,prev, pager, next':'prev, pager, next'"
@current-change="handlePageChange" background
>
</el-pagination>
<div class="body flex-1 relative">
<el-table stripe border :data="state.page.List" size="small" :height="`${state.height}px`" width="100%" @row-click="handleRowClick" :row-class-name="tableRowClassName">
<el-table-column type="index" width="50" />
<el-table-column prop="Type" :label="$t('logger.level')" width="80">
<template #default="scope">
<span>{{state.types[scope.row.Type]}} </span>
</template>
</el-table-column>
<el-table-column prop="Time" :label="$t('logger.time')" width="160"></el-table-column>
<el-table-column prop="content" :label="$t('logger.content')"></el-table-column>
</el-table>
</div>
<div class="pages t-c">
<div class="page-wrap">
<el-pagination small :total="state.page.Count"
v-model:currentPage="state.page.Page" :page-size="state.page.Size"
:pager-count="globalData.isPc?7:3"
:layout="globalData.isPc?'total,prev, pager, next':'prev, pager, next'"
@current-change="handlePageChange" background
>
</el-pagination>
</div>
</div>
</div>
</div>
</el-tab-pane>
<el-tab-pane :label="$t('common.setting')" v-if="hasLoggerLevel">
<Setting></Setting>
</el-tab-pane>
</el-tab-pane>
</AccessShow>
<AccessShow value="LoggerLevel">
<el-tab-pane :label="$t('common.setting')">
<Setting></Setting>
</el-tab-pane>
</AccessShow>
</el-tabs>
</div>
<el-dialog class="options-center" title="" destroy-on-close v-model="state.show" width="98%" top="2vh">
@@ -66,8 +70,6 @@ export default {
components: { Setting },
setup() {
const globalData = injectGlobalData();
const hasLogger = computed(()=>globalData.value.hasAccess('LoggerShow'));
const hasLoggerLevel = computed(()=>globalData.value.hasAccess('LoggerLevel'));
const wrap = ref(null);
const state = reactive({
loading: true,
@@ -125,7 +127,7 @@ export default {
});
return {
globalData,hasLogger,hasLoggerLevel,wrap,state, loadData, clearData, tableRowClassName, handleRowClick,handlePageChange
globalData,wrap,state, loadData, clearData, tableRowClassName, handleRowClick,handlePageChange
}
}
}

View File

@@ -1,5 +1,5 @@
v1.9.6
2025-11-08 00:05:36
2025-11-08 18:05:11
1. 一些累计更新一些BUG修复
2. 优化客户端数据同步,减少服务器流量
3. 去除cdkey改为发电解锁中继速度