diff --git a/napcat.webui/src/pages/NetWork.vue b/napcat.webui/src/pages/NetWork.vue index 26d2c144..0d92910e 100644 --- a/napcat.webui/src/pages/NetWork.vue +++ b/napcat.webui/src/pages/NetWork.vue @@ -11,15 +11,14 @@ - 添加配置 + 添加配置
- + @@ -27,71 +26,51 @@
-
+
- +
- +
- + {{ item.host }}:{{ item.port }} - +
- + {{ item.url }}
- +
{{ showToken ? item.token : '******' }} - - + +
@@ -108,60 +87,36 @@ - + - - {{ item.debug ? '开启' : '关闭' }} + + {{ item.debug ? '开启' : '关闭' }} - - - {{ item.enableWebsocket ? '启用' : '禁用' }} + + + {{ item.enableWebsocket ? '启用' : '禁用' }} - - - {{ item.enableCors ? '开启' : '关闭' }} + + + {{ item.enableCors ? '开启' : '关闭' }} - - - {{ item.reportSelfMessage ? '开启' : '关闭' }} + + + {{ item.reportSelfMessage ? '开启' : '关闭' }} - - + - {{ item.enableForcePushEvent ? '开启' : '关闭' }} + @click="toggleProperty(item, 'enableForcePushEvent')"> + {{ item.enableForcePushEvent ? '开启' : '关闭' }} @@ -175,30 +130,16 @@
- +
- + - + HTTP 服务器 HTTP SSE 服务器 @@ -208,10 +149,8 @@
- +
@@ -229,12 +168,10 @@ import { BrowseIcon, Wifi1Icon, } from 'tdesign-icons-vue-next'; -import { onMounted, onUnmounted, ref, resolveDynamicComponent, watch } from 'vue'; -import emitter from '@/ts/event-bus'; import { - mergeNetworkDefaultConfig, - mergeOneBotConfigs, - NetworkConfig, + loadConfig as loadConfigOnebot, + NetworkAdapterConfig, + NetworkConfigKey, OneBotConfig, } from '../../../src/onebot/config/config'; import HttpServerComponent from '@/pages/network/HttpServerComponent.vue'; @@ -243,6 +180,9 @@ import WebsocketServerComponent from '@/pages/network/WebsocketServerComponent.v import WebsocketClientComponent from '@/pages/network/WebsocketClientComponent.vue'; import { MessagePlugin } from 'tdesign-vue-next'; import { QQLoginManager } from '@/backend/shell'; +import { onMounted, onUnmounted, ref, watch, resolveDynamicComponent } from 'vue'; +import emitter from '@/ts/event-bus'; +import HttpSseServerComponent from './network/HttpSseServerComponent.vue'; const showToken = ref(false); const infoOneCol = ref(true); @@ -259,17 +199,17 @@ const visibleBody = ref(false); const newTab = ref<{ name: string; data: any; type: string }>({ name: '', data: {}, type: '' }); const dialogTitle = ref(''); -type ComponentKey = keyof typeof mergeNetworkDefaultConfig; - +type ComponentKey = Exclude const componentMap: Record< ComponentKey, | typeof HttpServerComponent | typeof HttpClientComponent | typeof WebsocketServerComponent | typeof WebsocketClientComponent + | typeof HttpSseServerComponent > = { httpServers: HttpServerComponent, - httpSseServers: HttpServerComponent, + httpSseServers: HttpSseServerComponent, httpClients: HttpClientComponent, websocketServers: WebsocketServerComponent, websocketClients: WebsocketClientComponent, @@ -280,7 +220,7 @@ const operateType = ref(''); //配置项索引 const configIndex = ref(0); //保存时所用数据 -const networkConfig: NetworkConfig & { [key: string]: any } = { +const networkConfig: { [key: string]: any } = { websocketClients: [], websocketServers: [], httpSseServers: [], @@ -322,15 +262,12 @@ const addConfig = () => { }; const editConfig = (item: any) => { - dialogTitle.value = '修改配置'; - const type = getKeyByValue(typeCh, item.type); - if (type) { - newTab.value = { name: item.name, data: item, type: type }; - } + dialogTitle.value = '编辑配置'; + newTab.value = { name: item.name, data: { ...item }, type: getKeyByValue(typeCh, item.type) || '' }; operateType.value = 'edit'; - configIndex.value = networkConfig[newTab.value.type].findIndex((obj: any) => obj.name === item.name); visibleBody.value = true; }; + const toggleProperty = async (item: any, tagData: string) => { const type = getKeyByValue(typeCh, item.type); const newData = { ...item }; @@ -356,11 +293,12 @@ const delConfig = (item: any) => { }; const selectType = (key: ComponentKey) => { - cardConfig.value = WebConfg.value.get(key); + console.log(WebConfg.value, key, WebConfg.value.get(key)); + cardConfig.value = WebConfg.value.get(key) || []; }; const onloadDefault = (key: ComponentKey) => { - newTab.value.data = structuredClone(mergeNetworkDefaultConfig[key]); + newTab.value.data = {}; }; //检测重名 const checkName = (name: string) => { @@ -390,7 +328,7 @@ const saveConfig = async () => { } const userConfig = await getOB11Config(); if (!userConfig) return; - userConfig.network = networkConfig; + userConfig.network = networkConfig as any; const success = await setOB11Config(userConfig); if (success) { operateType.value = ''; @@ -423,12 +361,12 @@ const setOB11Config = async (config: OneBotConfig): Promise => { }; //获取卡片数据 -const getAllData = (data: NetworkConfig) => { +const getAllData = (data: { [key: string]: Array }) => { cardConfig.value = []; WebConfg.value.set('all', []); for (const key in data) { - const configs = data[key as keyof NetworkConfig]; - if (key in mergeNetworkDefaultConfig) { + const configs = data[key as keyof NetworkAdapterConfig]; + if (key in networkConfig) { networkConfig[key] = [...configs]; const newConfigsArray = configs.map((config: any) => ({ ...config, @@ -449,13 +387,12 @@ const loadConfig = async () => { try { const userConfig = await getOB11Config(); if (!userConfig) return; - const mergedConfig = mergeOneBotConfigs(userConfig); + const mergedConfig = loadConfigOnebot(userConfig); getAllData(mergedConfig.network); } catch (error) { console.error('Error loading config:', error); } }; - const copyText = async (text: string) => { const textarea = document.createElement('textarea'); textarea.value = text; @@ -481,9 +418,9 @@ const handleResize = () => { cardWidth.value = tabsWidth.value; } loadPage.value = true; - setTimeout(()=>{ + setTimeout(() => { cardHeight.value = window.innerHeight - (headerBox.value?.offsetHeight ?? 0) - (setting.value?.offsetHeight ?? 0) - 21; - },300) + }, 300) }; emitter.on('sendWidth', (width) => { if (typeof width === 'string') { @@ -493,30 +430,30 @@ emitter.on('sendWidth', (width) => { }); watch(menuWidth, (newValue, oldValue) => { loadPage.value = false; - setTimeout(()=>{ + setTimeout(() => { handleResize(); - },300) + }, 300) }); onMounted(() => { loadConfig(); const cachedWidth = localStorage.getItem('menuWidth'); if (cachedWidth) { menuWidth.value = parseInt(cachedWidth); - setTimeout(()=>{ + setTimeout(() => { handleResize(); - },300) + }, 300) } - window.addEventListener('resize', ()=>{ - setTimeout(()=>{ + window.addEventListener('resize', () => { + setTimeout(() => { handleResize(); - },300) + }, 300) }); }); onUnmounted(() => { - window.removeEventListener('resize', ()=>{ - setTimeout(()=>{ + window.removeEventListener('resize', () => { + setTimeout(() => { handleResize(); - },300) + }, 300) }); }); @@ -557,9 +494,11 @@ onUnmounted(() => { display: flex; margin-top: 2px; } + .local-icon { flex: 1; } + .local { flex: 6; margin: 0 10px 0 10px; @@ -586,22 +525,26 @@ onUnmounted(() => { text-overflow: ellipsis; } -.tag-item-on{ +.tag-item-on { color: white; cursor: pointer; background-image: linear-gradient(to top, #0ba360 0%, #3cba92 100%) !important; } -.tag-item-off{ + +.tag-item-off { color: white; cursor: pointer; background-image: linear-gradient(to top, rgba(255, 8, 68, 0.93) 0%, #D54941 100%) !important; } + .browse-icon { flex: 2; } + :global(.t-dialog__ctx .t-dialog__position) { padding: 48px 10px; } + @media (max-width: 1024px) { .setting-box { grid-template-columns: 1fr 1fr; @@ -651,7 +594,7 @@ onUnmounted(() => { padding: 0 var(--td-comp-paddingLR-l) !important; } -.setting-base-info tr > td:last-child { +.setting-base-info tr>td:last-child { text-align: right; } diff --git a/napcat.webui/src/pages/network/HttpClientComponent.vue b/napcat.webui/src/pages/network/HttpClientComponent.vue index c79a4456..b0fa36fe 100644 --- a/napcat.webui/src/pages/network/HttpClientComponent.vue +++ b/napcat.webui/src/pages/network/HttpClientComponent.vue @@ -27,23 +27,35 @@ import { ref, watch } from 'vue'; import { HttpClientConfig } from '../../../../src/onebot/config/config'; +const defaultConfig: HttpClientConfig = { + name: 'http-client', + enable: false, + url: 'http://localhost:8080', + messagePostFormat: 'array', + reportSelfMessage: false, + token: '', + debug: false +}; + const props = defineProps<{ config: HttpClientConfig; }>(); +const config = ref(Object.assign({}, defaultConfig, props.config)); + const messageFormatOptions = ref([ { label: 'Array', value: 'array' }, { label: 'String', value: 'string' }, ]); watch( - () => props.config.messagePostFormat, + () => config.value.messagePostFormat, (newValue) => { if (newValue !== 'array' && newValue !== 'string') { - props.config.messagePostFormat = 'array'; + config.value.messagePostFormat = 'array'; } } ); - + \ No newline at end of file diff --git a/napcat.webui/src/pages/network/HttpServerComponent.vue b/napcat.webui/src/pages/network/HttpServerComponent.vue index 89837ad2..36100ce8 100644 --- a/napcat.webui/src/pages/network/HttpServerComponent.vue +++ b/napcat.webui/src/pages/network/HttpServerComponent.vue @@ -33,23 +33,37 @@ import { ref, watch } from 'vue'; import { HttpServerConfig } from '../../../../src/onebot/config/config'; +const defaultConfig: HttpServerConfig = { + name: 'http-server', + enable: false, + port: 3000, + host: '0.0.0.0', + enableCors: true, + enableWebsocket: true, + messagePostFormat: 'array', + token: '', + debug: false +}; + const props = defineProps<{ config: HttpServerConfig; }>(); +const config = ref(Object.assign({}, defaultConfig, props.config)); + const messageFormatOptions = ref([ { label: 'Array', value: 'array' }, { label: 'String', value: 'string' }, ]); watch( - () => props.config.messagePostFormat, + () => config.value.messagePostFormat, (newValue) => { if (newValue !== 'array' && newValue !== 'string') { - props.config.messagePostFormat = 'array'; + config.value.messagePostFormat = 'array'; } } ); - + \ No newline at end of file diff --git a/napcat.webui/src/pages/network/HttpSseServerComponent.vue b/napcat.webui/src/pages/network/HttpSseServerComponent.vue index 32f3a3b3..3d1aa715 100644 --- a/napcat.webui/src/pages/network/HttpSseServerComponent.vue +++ b/napcat.webui/src/pages/network/HttpSseServerComponent.vue @@ -36,23 +36,38 @@ import { ref, watch } from 'vue'; import { HttpSseServerConfig } from '../../../../src/onebot/config/config'; +const defaultConfig: HttpSseServerConfig = { + name: 'http-sse-server', + enable: false, + port: 3000, + host: '0.0.0.0', + enableCors: true, + enableWebsocket: true, + messagePostFormat: 'array', + token: '', + debug: false, + reportSelfMessage: false +}; + const props = defineProps<{ config: HttpSseServerConfig; }>(); +const config = ref(Object.assign({}, defaultConfig, props.config)); + const messageFormatOptions = ref([ { label: 'Array', value: 'array' }, { label: 'String', value: 'string' }, ]); watch( - () => props.config.messagePostFormat, + () => config.value.messagePostFormat, (newValue) => { if (newValue !== 'array' && newValue !== 'string') { - props.config.messagePostFormat = 'array'; + config.value.messagePostFormat = 'array'; } } ); - + \ No newline at end of file diff --git a/napcat.webui/src/pages/network/WebsocketClientComponent.vue b/napcat.webui/src/pages/network/WebsocketClientComponent.vue index fda4bb37..424a86f8 100644 --- a/napcat.webui/src/pages/network/WebsocketClientComponent.vue +++ b/napcat.webui/src/pages/network/WebsocketClientComponent.vue @@ -30,23 +30,37 @@ import { ref, watch } from 'vue'; import { WebsocketClientConfig } from '../../../../src/onebot/config/config'; +const defaultConfig: WebsocketClientConfig = { + name: 'websocket-client', + enable: false, + url: 'ws://localhost:8082', + messagePostFormat: 'array', + reportSelfMessage: false, + reconnectInterval: 5000, + token: '', + debug: false, + heartInterval: 30000 +}; + const props = defineProps<{ config: WebsocketClientConfig; }>(); +const config = ref(Object.assign({}, defaultConfig, props.config)); + const messageFormatOptions = ref([ { label: 'Array', value: 'array' }, { label: 'String', value: 'string' }, ]); watch( - () => props.config.messagePostFormat, + () => config.value.messagePostFormat, (newValue) => { if (newValue !== 'array' && newValue !== 'string') { - props.config.messagePostFormat = 'array'; + config.value.messagePostFormat = 'array'; } } ); - + \ No newline at end of file diff --git a/napcat.webui/src/pages/network/WebsocketServerComponent.vue b/napcat.webui/src/pages/network/WebsocketServerComponent.vue index a1333ce3..6f93191c 100644 --- a/napcat.webui/src/pages/network/WebsocketServerComponent.vue +++ b/napcat.webui/src/pages/network/WebsocketServerComponent.vue @@ -36,23 +36,38 @@ import { ref, watch } from 'vue'; import { WebsocketServerConfig } from '../../../../src/onebot/config/config'; +const defaultConfig: WebsocketServerConfig = { + name: 'websocket-server', + enable: false, + host: '0.0.0.0', + port: 3001, + messagePostFormat: 'array', + reportSelfMessage: false, + token: '', + enableForcePushEvent: true, + debug: false, + heartInterval: 30000 +}; + const props = defineProps<{ config: WebsocketServerConfig; }>(); +const config = ref(Object.assign({}, defaultConfig, props.config)); + const messageFormatOptions = ref([ { label: 'Array', value: 'array' }, { label: 'String', value: 'string' }, ]); watch( - () => props.config.messagePostFormat, + () => config.value.messagePostFormat, (newValue) => { if (newValue !== 'array' && newValue !== 'string') { - props.config.messagePostFormat = 'array'; + config.value.messagePostFormat = 'array'; } } ); - + \ No newline at end of file diff --git a/src/onebot/config/config.ts b/src/onebot/config/config.ts index 8279be69..7e0e092b 100644 --- a/src/onebot/config/config.ts +++ b/src/onebot/config/config.ts @@ -1,8 +1,6 @@ import { Type, Static } from '@sinclair/typebox'; import Ajv from 'ajv'; -const ajv = new Ajv({ useDefaults: true }); - const HttpServerConfigSchema = Type.Object({ name: Type.String({ default: 'http-server' }), enable: Type.Boolean({ default: false }), @@ -72,13 +70,13 @@ const PluginConfigSchema = Type.Object({ }); const NetworkConfigSchema = Type.Object({ - httpServers: Type.Array(HttpServerConfigSchema), - httpSseServers: Type.Array(HttpSseServerConfigSchema), - httpClients: Type.Array(HttpClientConfigSchema), - websocketServers: Type.Array(WebsocketServerConfigSchema), - websocketClients: Type.Array(WebsocketClientConfigSchema), - plugins: Type.Array(PluginConfigSchema) -}); + httpServers: Type.Array(HttpServerConfigSchema, { default: [] }), + httpSseServers: Type.Array(HttpSseServerConfigSchema, { default: [] }), + httpClients: Type.Array(HttpClientConfigSchema, { default: [] }), + websocketServers: Type.Array(WebsocketServerConfigSchema, { default: [] }), + websocketClients: Type.Array(WebsocketClientConfigSchema, { default: [] }), + plugins: Type.Array(PluginConfigSchema, { default: [] }) +}, { default: {} }); const OneBotConfigSchema = Type.Object({ network: NetworkConfigSchema, @@ -87,7 +85,6 @@ const OneBotConfigSchema = Type.Object({ parseMultMsg: Type.Boolean({ default: true }) }); - export type OneBotConfig = Static; export type HttpServerConfig = Static; export type HttpSseServerConfig = Static; @@ -96,11 +93,13 @@ export type WebsocketServerConfig = Static; export type WebsocketClientConfig = Static; export type PluginConfig = Static; -export type NetworkAdapterConfig = HttpServerConfig | HttpSseServerConfig | HttpClientConfig | WebsocketServerConfig | WebsocketClientConfig| PluginConfig; +export type NetworkAdapterConfig = HttpServerConfig | HttpSseServerConfig | HttpClientConfig | WebsocketServerConfig | WebsocketClientConfig | PluginConfig; +export type NetworkConfigKey = keyof OneBotConfig['network']; -const validate = ajv.compile(OneBotConfigSchema); export function loadConfig(config: Partial): OneBotConfig { + const ajv = new Ajv({ useDefaults: true }); + const validate = ajv.compile(OneBotConfigSchema); const valid = validate(config); if (!valid) { throw new Error(ajv.errorsText(validate.errors));