Merge branch 'dev' of github.com:linyuchen/LiteLoaderQQNT-OneBotApi into dev

This commit is contained in:
linyuchen 2024-03-05 08:33:51 +08:00
commit 3fb4b6a8da
13 changed files with 405 additions and 386 deletions

View File

@ -34,9 +34,9 @@ wget -O fastboot.sh https://cdn.jsdelivr.net/gh/MliKiowa/llonebot-docker/fastboo
```
├── plugins
│ ├── LLOneBot
│ │ └── main.js
│ │ └── preload.js
│ │ └── renderer.js
│ │ └── main/
│ │ └── preload/
│ │ └── renderer/
│ │ └── manifest.json
│ │ └── node_modules/...
```

View File

@ -52,11 +52,11 @@ let config = {
emptyOutDir: true,
lib: {
formats: ["es"],
entry: { "renderer": "src/renderer.ts" },
entry: { "renderer": "src/renderer/index.ts" },
},
rollupOptions: {
// external: externalAll,
input: "src/renderer.ts",
input: "src/renderer/index.ts",
}
},
resolve:{

View File

@ -26,7 +26,7 @@
"darwin"
],
"injects": {
"renderer": "./renderer/renderer.js",
"renderer": "./renderer/index.js",
"main": "./main/main.cjs",
"preload": "./preload/preload.cjs"
}

View File

@ -1,380 +0,0 @@
/// <reference path="./global.d.ts" />
// 打开设置界面时触发
async function onSettingWindowCreated (view: Element) {
window.llonebot.log('setting window created')
const isEmpty = (value: any) => value === undefined || value === null || value === ''
const config = await window.llonebot.getConfig()
const httpClass = 'http'
const httpPostClass = 'http-post'
const wsClass = 'ws'
const reverseWSClass = 'reverse-ws'
const llonebotError = await window.llonebot.getError()
window.llonebot.log('获取error' + JSON.stringify(llonebotError))
function createHttpHostEleStr (host: string) {
const eleStr = `
<setting-item data-direction="row" class="hostItem vertical-list-item ${httpPostClass}">
<h2>HTTP事件上报地址(http)</h2>
<input class="httpHost input-text" type="text" value="${host}"
style="width:60%;padding: 5px"
placeholder="如:http://127.0.0.1:8080/onebot/v11/http"/>
</setting-item>
`
return eleStr
}
function createWsHostEleStr (host: string) {
const eleStr = `
<setting-item data-direction="row" class="hostItem vertical-list-item ${reverseWSClass}">
<h2>websocket地址:</h2>
<input class="wsHost input-text" type="text" value="${host}"
style="width:60%;padding: 5px"
placeholder="如: ws://127.0.0.1:5410/onebot"/>
</setting-item>
`
return eleStr
}
let httpHostsEleStr = ''
for (const host of config.ob11.httpHosts) {
httpHostsEleStr += createHttpHostEleStr(host)
}
let wsHostsEleStr = ''
for (const host of config.ob11.wsHosts) {
wsHostsEleStr += createWsHostEleStr(host)
}
const html = `
<div class="config_view llonebot">
<setting-section>
<setting-panel id="llonebotError" style="display:${llonebotError.ffmpegError || llonebotError.otherError ? '' : 'none'}">
<setting-item id="ffmpegError" data-direction="row"
style="diplay:${llonebotError.ffmpegError ? '' : 'none'}"
class="hostItem vertical-list-item">
<setting-text data-type="secondary" class="err-content">${llonebotError.ffmpegError}</setting-text>
</setting-item>
<setting-item id="otherError" data-direction="row"
style="diplay:${llonebotError.otherError ? '' : 'none'}"
class="hostItem vertical-list-item">
<setting-text data-type="secondary" class="err-content">${llonebotError.otherError}</setting-text>
</setting-item>
</setting-panel>
<setting-panel>
<setting-list class="wrap">
<setting-item data-direction="row" class="hostItem vertical-list-item">
<div>
<div>HTTP服务</div>
</div>
<setting-switch id="http" ${config.ob11.enableHttp ? 'is-active' : ''}></setting-switch>
</setting-item>
<setting-item class="vertical-list-item ${httpClass}" data-direction="row" style="display: ${config.ob11.enableHttp ? '' : 'none'}">
<setting-text>HTTP监听端口</setting-text>
<input id="httpPort" type="number" value="${config.ob11.httpPort}"/>
</setting-item>
<setting-item data-direction="row" class="hostItem vertical-list-item">
<div>
<div>HTTP事件上报</div>
</div>
<setting-switch id="httpPost" ${config.ob11.enableHttpPost ? 'is-active' : ''}></setting-switch>
</setting-item>
<div class="${httpPostClass}" style="display: ${config.ob11.enableHttpPost ? '' : 'none'}">
<div >
<button id="addHttpHost" class="q-button">HTTP POST上报地址</button>
</div>
<div id="httpHostItems">
${httpHostsEleStr}
</div>
</div>
<setting-item data-direction="row" class="hostItem vertical-list-item">
<div>
<div>Websocket协议</div>
</div>
<setting-switch id="websocket" ${config.ob11.enableWs ? 'is-active' : ''}></setting-switch>
</setting-item>
<setting-item class="vertical-list-item ${wsClass}" data-direction="row" style="display: ${config.ob11.enableWs ? '' : 'none'}">
<setting-text>Websocket监听端口</setting-text>
<input id="wsPort" type="number" value="${config.ob11.wsPort}"/>
</setting-item>
<setting-item data-direction="row" class="hostItem vertical-list-item">
<div>
<div>Websocket协议</div>
</div>
<setting-switch id="websocketReverse" ${config.ob11.enableWsReverse ? 'is-active' : ''}></setting-switch>
</setting-item>
<div class="${reverseWSClass}" style="display: ${config.ob11.enableWsReverse ? '' : 'none'}">
<div>
<button id="addWsHost" class="q-button">Websocket地址</button>
</div>
<div id="wsHostItems">
${wsHostsEleStr}
</div>
</div>
<setting-item class="vertical-list-item" data-direction="row">
<setting-text>Access Token</setting-text>
<input id="token" type="text" placeholder="可为空" value="${config.token}"/>
</setting-item>
<setting-item data-direction="row" class="vertical-list-item">
<setting-item data-direction="row" class="vertical-list-item" style="width: 80%">
<setting-text>ffmpeg路径</setting-text>
<input id="ffmpegPath" class="input-text" type="text"
style="width:80%;padding: 5px"
value="${config.ffmpeg || ''}"/>
</setting-item>
<button id="selectFFMPEG" class="q-button q-button--small q-button--secondary">ffmpeg</button>
</setting-item>
<button id="save" class="q-button"></button>
</setting-list>
</setting-panel>
<setting-panel>
<setting-item data-direction="row" class="vertical-list-item">
<div>
<setting-text></setting-text>
<setting-text data-type="secondary"> <a href="javascript:LiteLoader.api.openExternal('https://github.com/botuniverse/onebot-11/tree/master/message#readme');">OneBot v11 </a></setting-text>
</div>
<setting-select id="messagePostFormat">
<setting-option data-value="array" ${config.ob11.messagePostFormat !== 'string' ? 'is-selected' : ''}></setting-option>
<setting-option data-value="string" ${config.ob11.messagePostFormat === 'string' ? 'is-selected' : ''}>CQ码</setting-option>
</setting-select>
</setting-item>
<setting-item data-direction="row" class="vertical-list-item">
<div>
<div>使base64编码</div>
<div class="tips">/get_image/get_record时url时添加一个base64字段</div>
</div>
<setting-switch id="switchFileUrl" ${config.enableLocalFile2Url ? 'is-active' : ''}></setting-switch>
</setting-item>
<setting-item data-direction="row" class="vertical-list-item">
<div>
<div>debug模式</div>
<div class="tips">raw字段附带原始消息</div>
</div>
<setting-switch id="debug" ${config.debug ? 'is-active' : ''}></setting-switch>
</setting-item>
<setting-item data-direction="row" class="vertical-list-item">
<div>
<div></div>
<div class="tips"></div>
</div>
<setting-switch id="reportSelfMessage" ${config.reportSelfMessage ? 'is-active' : ''}></setting-switch>
</setting-item>
<setting-item data-direction="row" class="vertical-list-item">
<div>
<div></div>
<div class="tips">目录:${window.LiteLoader.plugins.LLOneBot.path.data}</div>
</div>
<setting-switch id="log" ${config.log ? 'is-active' : ''}></setting-switch>
</setting-item>
<setting-item data-direction="row" class="vertical-list-item">
<div>
<div></div>
<div class="tips">
<input id="autoDeleteMin"
min="1" style="width: 50px"
value="${config.autoDeleteFileSecond || 60}" type="number"/>
</div>
</div>
<setting-switch id="autoDeleteFile" ${config.autoDeleteFile ? 'is-active' : ''}></setting-switch>
</setting-item>
</setting-panel>
</setting-section>
</div>
<style>
setting-panel {
padding: 10px;
}
.tips {
font-size: 0.75rem;
}
@media (prefers-color-scheme: dark){
.llonebot input {
color: white;
}
}
</style>
`
const parser = new DOMParser()
const doc = parser.parseFromString(html, 'text/html')
const getError = async () => {
const llonebotError = await window.llonebot.getError()
console.log(llonebotError)
const llonebotErrorEle = document.getElementById('llonebotError')
const ffmpegErrorEle = document.getElementById('ffmpegError')
const otherErrorEle = document.getElementById('otherError')
if (llonebotError.otherError || llonebotError.ffmpegError) {
llonebotErrorEle.style.display = ''
} else {
llonebotErrorEle.style.display = 'none'
}
if (llonebotError.ffmpegError) {
const errContentEle = doc.querySelector('#ffmpegError .err-content')
// const errContent = ffmpegErrorEle.getElementsByClassName("err-content")[0];
errContentEle.textContent = llonebotError.ffmpegError;
(ffmpegErrorEle).style.display = ''
} else {
ffmpegErrorEle.style.display = ''
}
if (llonebotError.otherError) {
const errContentEle = doc.querySelector('#otherError .err-content')
errContentEle.textContent = llonebotError.otherError
otherErrorEle.style.display = ''
} else {
otherErrorEle.style.display = 'none'
}
}
function addHostEle (type: string, initValue: string = '') {
let addressEle, hostItemsEle
if (type === 'ws') {
const addressDoc = parser.parseFromString(createWsHostEleStr(initValue), 'text/html')
addressEle = addressDoc.querySelector('setting-item')
hostItemsEle = document.getElementById('wsHostItems')
} else {
const addressDoc = parser.parseFromString(createHttpHostEleStr(initValue), 'text/html')
addressEle = addressDoc.querySelector('setting-item')
hostItemsEle = document.getElementById('httpHostItems')
}
hostItemsEle.appendChild(addressEle)
}
doc.getElementById('addHttpHost').addEventListener('click', () => {
addHostEle('http')
})
doc.getElementById('addWsHost').addEventListener('click', () => {
addHostEle('ws')
})
doc.getElementById('messagePostFormat').addEventListener('selected', (e: CustomEvent) => {
config.ob11.messagePostFormat = e.detail && !isEmpty(e.detail.value) ? e.detail.value : 'array'
window.llonebot.setConfig(config)
})
function switchClick (eleId: string, configKey: string, _config = null) {
if (!_config) {
_config = config
}
doc.getElementById(eleId)?.addEventListener('click', (e) => {
const switchEle = e.target as HTMLInputElement
if (_config[configKey]) {
_config[configKey] = false
switchEle.removeAttribute('is-active')
} else {
_config[configKey] = true
switchEle.setAttribute('is-active', '')
}
// 妈蛋手动操作DOM越写越麻烦要不用vue算了
const keyClassMap = {
enableHttp: httpClass,
enableHttpPost: httpPostClass,
enableWs: wsClass,
enableWsReverse: reverseWSClass
}
for (const e of document.getElementsByClassName(keyClassMap[configKey])) {
(e as HTMLElement).style.display = _config[configKey] ? '' : 'none'
}
window.llonebot.setConfig(config)
})
}
switchClick('http', 'enableHttp', config.ob11)
switchClick('httpPost', 'enableHttpPost', config.ob11)
switchClick('websocket', 'enableWs', config.ob11)
switchClick('websocketReverse', 'enableWsReverse', config.ob11)
switchClick('debug', 'debug')
switchClick('switchFileUrl', 'enableLocalFile2Url')
switchClick('reportSelfMessage', 'reportSelfMessage')
switchClick('log', 'log')
switchClick('autoDeleteFile', 'autoDeleteFile')
doc.getElementById('save')?.addEventListener('click',
() => {
const httpPortEle: HTMLInputElement = document.getElementById('httpPort') as HTMLInputElement
const httpHostEles: HTMLCollectionOf<HTMLInputElement> = document.getElementsByClassName('httpHost') as HTMLCollectionOf<HTMLInputElement>
const wsPortEle: HTMLInputElement = document.getElementById('wsPort') as HTMLInputElement
const wsHostEles: HTMLCollectionOf<HTMLInputElement> = document.getElementsByClassName('wsHost') as HTMLCollectionOf<HTMLInputElement>
const tokenEle = document.getElementById('token') as HTMLInputElement
const ffmpegPathEle = document.getElementById('ffmpegPath') as HTMLInputElement
// 获取端口和host
const httpPort = httpPortEle.value
const httpHosts: string[] = []
for (const hostEle of httpHostEles) {
const value = hostEle.value.trim()
value && httpHosts.push(value)
}
const wsPort = wsPortEle.value
const token = tokenEle.value.trim()
const wsHosts: string[] = []
for (const hostEle of wsHostEles) {
const value = hostEle.value.trim()
value && wsHosts.push(value)
}
config.ob11.httpPort = parseInt(httpPort)
config.ob11.httpHosts = httpHosts
config.ob11.wsPort = parseInt(wsPort)
config.ob11.wsHosts = wsHosts
config.token = token
config.ffmpeg = ffmpegPathEle.value.trim()
window.llonebot.setConfig(config)
setTimeout(() => {
getError().then()
}, 1000)
alert('保存成功')
})
doc.getElementById('selectFFMPEG')?.addEventListener('click', () => {
window.llonebot.selectFile().then(selectPath => {
if (selectPath) {
config.ffmpeg = (document.getElementById('ffmpegPath') as HTMLInputElement).value = selectPath
// window.llonebot.setConfig(config);
}
})
})
// 自动保存删除文件延时时间
const autoDeleteMinEle = doc.getElementById('autoDeleteMin') as HTMLInputElement
let st = null
autoDeleteMinEle.addEventListener('change', () => {
if (st) {
clearTimeout(st)
}
st = setTimeout(() => {
console.log('auto delete file minute change')
config.autoDeleteFileSecond = parseInt(autoDeleteMinEle.value) || 1
window.llonebot.setConfig(config)
}, 1000)
})
doc.body.childNodes.forEach(node => {
view.appendChild(node)
})
}
function init () {
const hash = location.hash
if (hash === '#/blank') {
}
}
if (location.hash === '#/blank') {
(window as any).navigation.addEventListener('navigatesuccess', init, { once: true })
} else {
init()
}
export {
onSettingWindowCreated
}

View File

@ -0,0 +1,4 @@
export const SettingButton = (text: string, id?: string, type: string = 'secondary') => {
return `<setting-button ${type ? `data-type="${type}"` : ''} ${id ? `id="${id}"` : ''}>${text}</setting-button>`;
}

View File

@ -0,0 +1,5 @@
export * from './list';
export * from './item';
export * from './button';
export * from './switch';
export * from './select';

View File

@ -0,0 +1,10 @@
export const SettingItem = (title: string, subtitle?: string, action?: string, id?: string, visible: boolean = true) => {
return `<setting-item ${id ? `id="${id}"` : ''} ${!visible ? 'is-hidden' : ''}>
<div>
<setting-text>${title}</setting-text>
${subtitle ? `<setting-text data-type="secondary">${subtitle}</setting-text>` : ''}
</div>
${action ? `<div>${action}</div>` : ''}
</setting-item>`;
}

View File

@ -0,0 +1,10 @@
export const SettingList = (items: string[], title?: string, isCollapsible: boolean = false, direction: string = 'column') => {
return `<setting-section ${title && !isCollapsible ? `data-title="${title}"` : ''}>
<setting-panel>
<setting-list ${direction ? `data-direction="${direction}"` : ''} ${isCollapsible ? 'is-collapsible' : ''} ${title && isCollapsible ? `data-title="${title}"` : ''}>
${items.join('')}
</setting-list>
</setting-panel>
</setting-section>`;
}

View File

@ -0,0 +1,4 @@
export const SettingOption = (text: string, value?: string, isSelected: boolean = false) => {
return `<setting-option ${value ? `data-value="${value}"` : ''} ${isSelected ? 'is-selected' : ''}>${text}</setting-option>`;
}

View File

@ -0,0 +1,11 @@
import { SettingOption } from "./option";
export const SettingSelect = (items: Array<{ text: string, value: string }>, configKey?: string, configValue?: any) => {
return `<setting-select ${configKey ? `data-config-key="${configKey}"` : ''}>
<div>
${items.map((e, i) => {
return SettingOption(e.text, e.value, (configKey && configValue ? configValue === e.value : i === 0));
}).join('')}
</div>
</setting-select>`;
}

View File

@ -0,0 +1,9 @@
export const SettingSwitch = (configKey?: string, isActive: boolean = false, extraData?: Record<string, string>) => {
return `<setting-switch
${configKey ? `data-config-key="${configKey}"` : ''}
${isActive ? 'is-active' : ''}
${extraData ? Object.keys(extraData).map(key => `data-${key}="${extraData[key]}"`) : ''}
>
</setting-switch>`;
}

282
src/renderer/index.ts Normal file
View File

@ -0,0 +1,282 @@
/// <reference path="../global.d.ts" />
import {
SettingButton,
SettingItem,
SettingList,
SettingSelect,
SettingSwitch
} from './components';
import StyleRaw from './style.css?raw';
// 打开设置界面时触发
async function onSettingWindowCreated(view: Element) {
window.llonebot.log("setting window created");
const isEmpty = (value: any) => value === undefined || value === null || value === '';
let config = await window.llonebot.getConfig();
let ob11Config = { ...config.ob11 };
const setConfig = (key: string, value: any) => {
const configKey = key.split('.');
if (key.indexOf('ob11') === 0) {
if (configKey.length === 2) ob11Config[configKey[1]] = value;
else ob11Config[key] = value;
} else {
if (configKey.length === 2) config[configKey[0]][configKey[1]] = value;
else config[key] = value;
window.llonebot.setConfig(config);
}
};
const parser = new DOMParser();
const doc = parser.parseFromString([
'<div>',
`<style>${StyleRaw}</style>`,
SettingList([
SettingItem('启用 HTTP 服务', null,
SettingSwitch('ob11.enableHttp', config.ob11.enableHttp, { 'control-display-id': 'config-ob11-httpPort' }),
),
SettingItem('HTTP 服务监听端口', null,
`<div class="q-input"><input class="q-input__inner" data-config-key="ob11.httpPort" type="number" min="1" max="65534" value="${config.ob11.httpPort}" placeholder="${config.ob11.httpPort}" /></div>`,
'config-ob11-httpPort', config.ob11.enableHttp
),
SettingItem('启用 HTTP 事件上报', null,
SettingSwitch('ob11.enableHttpPost', config.ob11.enableHttpPost, { 'control-display-id': 'config-ob11-httpHosts' }),
),
`<div class="config-host-list" id="config-ob11-httpHosts" ${config.ob11.enableHttpPost ? '' : 'is-hidden'}>
<setting-item data-direction="row">
<div>
<setting-text>HTTP </setting-text>
</div>
<setting-button id="config-ob11-httpHosts-add" data-type="primary"></setting-button>
</setting-item>
<div id="config-ob11-httpHosts-list"></div>
</div>`,
SettingItem('启用正向 WebSocket 服务', null,
SettingSwitch('ob11.enableWs', config.ob11.enableWs, { 'control-display-id': 'config-ob11-wsPort' }),
),
SettingItem('正向 WebSocket 服务监听端口', null,
`<div class="q-input"><input class="q-input__inner" data-config-key="ob11.wsPort" type="number" min="1" max="65534" value="${config.ob11.wsPort}" placeholder="${config.ob11.wsPort}" /></div>`,
'config-ob11-wsPort', config.ob11.enableWs
),
SettingItem('启用反向 WebSocket 服务', null,
SettingSwitch('ob11.enableWsReverse', config.ob11.enableWsReverse, { 'control-display-id': 'config-ob11-wsHosts' }),
),
`<div class="config-host-list" id="config-ob11-wsHosts" ${config.ob11.enableWsReverse ? '' : 'is-hidden'}>
<setting-item data-direction="row">
<div>
<setting-text> WebSocket </setting-text>
</div>
<setting-button id="config-ob11-wsHosts-add" data-type="primary"></setting-button>
</setting-item>
<div id="config-ob11-wsHosts-list"></div>
</div>`,
SettingItem('反向 WebSocket 服务心跳间隔',
'控制每隔多久发送一个心跳包,单位为毫秒',
`<div class="q-input"><input class="q-input__inner" data-config-key="heartInterval" type="number" min="1000" value="${config.heartInterval}" placeholder="${config.heartInterval}" /></div>`,
),
SettingItem('Access token', null,
`<div class="q-input" style="width:210px;"><input class="q-input__inner" data-config-key="token" type="text" value="${config.token}" placeholder="未设置" /></div>`,
),
SettingItem(
'消息上报格式类型',
'如客户端无特殊需求推荐保持默认设置,两者的详细差异可参考 <a href="javascript:LiteLoader.api.openExternal(\'https://github.com/botuniverse/onebot-11/tree/master/message#readme\');">OneBot v11 文档</a>',
SettingSelect([
{ text: '消息段', value: 'array' },
{ text: 'CQ码', value: 'string' },
], 'ob11.messagePostFormat', config.ob11.messagePostFormat),
),
SettingItem(
'ffmpeg 路径', `<span id="config-ffmpeg-path-text">${!isEmpty(config.ffmpeg) ? config.ffmpeg : '未指定'}</span>`,
SettingButton('选择', 'config-ffmpeg-select'),
),
SettingItem(
'', null,
SettingButton('保存', 'config-ob11-save', 'primary'),
)
]),
SettingList([
SettingItem(
'使用 Base64 编码获取文件',
'开启后,调用 /get_image、/get_record 时,获取不到 url 时添加一个 Base64 字段',
SettingSwitch('enableLocalFile2Url', config.enableLocalFile2Url),
),
SettingItem(
'调试模式',
'开启后上报信息会添加 raw 字段以附带原始信息',
SettingSwitch('debug', config.debug),
),
SettingItem(
'上报 Bot 自身发送的消息',
'慎用,可能会导致自己跟自己聊个不停',
SettingSwitch('reportSelfMessage', config.reportSelfMessage),
),
SettingItem(
'自动删除收到的文件',
'在收到文件后的指定时间内删除该文件',
SettingSwitch('autoDeleteFile', config.autoDeleteFile, { 'control-display-id': 'config-auto-delete-file-second' }),
),
SettingItem(
'自动删除文件时间',
'单位为秒',
`<div class="q-input"><input class="q-input__inner" data-config-key="autoDeleteFileSecond" type="number" min="1" value="${config.autoDeleteFileSecond}" placeholder="${config.autoDeleteFileSecond}" /></div>`,
'config-auto-delete-file-second', config.autoDeleteFile
),
SettingItem(
'写入日志',
`将日志文件写入插件的数据文件夹`,
SettingSwitch('log', config.log),
),
SettingItem(
'日志文件目录',
`${window.LiteLoader.plugins['LLOneBot'].path.data}`,
SettingButton('打开', 'config-open-log-path'),
),
]),
'</div>',
].join(''), "text/html");
// 生成反向地址列表
const buildHostListItem = (type: string, host: string, index: number) => {
const dom = {
container: document.createElement('setting-item'),
input: document.createElement('input'),
inputContainer: document.createElement('div'),
deleteBtn: document.createElement('setting-button'),
};
dom.container.classList.add('setting-host-list-item');
dom.container.dataset.direction = 'row';
dom.input.classList.add('q-input__inner');
dom.input.type = 'url';
dom.input.value = host;
dom.input.addEventListener('input', () => {
ob11Config[type][index] = dom.input.value;
});
dom.inputContainer.classList.add('q-input');
dom.inputContainer.appendChild(dom.input);
dom.deleteBtn.innerHTML = '删除';
dom.deleteBtn.dataset.type = 'secondary';
dom.deleteBtn.addEventListener('click', () => {
ob11Config[type].splice(index, 1);
initReverseHost(type);
});
dom.container.appendChild(dom.inputContainer);
dom.container.appendChild(dom.deleteBtn);
return dom.container;
};
const buildHostList = (hosts: string[], type: string) => {
const result: HTMLElement[] = [];
hosts.forEach((host, index) => {
result.push(buildHostListItem(type, host, index));
});
return result;
};
const addReverseHost = (type: string, doc: Document = document) => {
const hostContainerDom = doc.body.querySelector(`#config-ob11-${type}-list`);
hostContainerDom.appendChild(buildHostListItem(type, '', ob11Config[type].length));
ob11Config[type].push('');
};
const initReverseHost = (type: string, doc: Document = document) => {
const hostContainerDom = doc.body.querySelector(`#config-ob11-${type}-list`);
[ ...hostContainerDom.childNodes ].forEach(dom => dom.remove());
buildHostList(ob11Config[type], type).forEach(dom => {
hostContainerDom.appendChild(dom);
});
};
initReverseHost('httpHosts', doc);
initReverseHost('wsHosts', doc);
doc.querySelector('#config-ob11-httpHosts-add').addEventListener('click', () => addReverseHost('httpHosts'));
doc.querySelector('#config-ob11-wsHosts-add').addEventListener('click', () => addReverseHost('wsHosts'));
doc.querySelector('#config-ffmpeg-select').addEventListener('click', () => {
window.llonebot.selectFile()
.then(path => {
if (!isEmpty(path)) {
setConfig('ffmpeg', path);
document.querySelector('#config-ffmpeg-path-text').innerHTML = path;
}
})
});
doc.querySelector('#config-open-log-path').addEventListener('click', () => {
window.LiteLoader.api.openPath(window.LiteLoader.plugins['LLOneBot'].path.data);
})
// 开关
doc.querySelectorAll('setting-switch[data-config-key]').forEach((dom: HTMLElement) => {
dom.addEventListener('click', () => {
const active = dom.getAttribute('is-active') === null;
setConfig(dom.dataset.configKey, active);
if (active) dom.setAttribute('is-active', '');
else dom.removeAttribute('is-active');
if (!isEmpty(dom.dataset.controlDisplayId)) {
const displayDom = document.querySelector(`#${dom.dataset.controlDisplayId}`);
if (active) displayDom.removeAttribute('is-hidden');
else displayDom.setAttribute('is-hidden', '');
}
});
});
// 输入框
doc.querySelectorAll('setting-item .q-input input.q-input__inner[data-config-key]').forEach((dom: HTMLInputElement) => {
dom.addEventListener('input', () => {
const Type = dom.getAttribute('type');
const configKey = dom.dataset.configKey;
const configValue = Type === 'number' ? (parseInt(dom.value) >= 1 ? parseInt(dom.value) : 1) : dom.value;
setConfig(configKey, configValue);
});
});
// 下拉框
doc.querySelectorAll('setting-select').forEach((dom: HTMLElement) => {
dom.addEventListener('selected', (e: CustomEvent) => {
const configKey = dom.dataset.configKey;
const configValue = e.detail.value;
setConfig(configKey, configValue);
});
});
// 保存按钮
doc.querySelector('#config-ob11-save').addEventListener('click', () => {
config.ob11 = ob11Config;
window.llonebot.setConfig(config);
alert('保存成功');
});
doc.body.childNodes.forEach(node => {
view.appendChild(node);
});
}
function init () {
const hash = location.hash
if (hash === '#/blank') {
}
}
if (location.hash === '#/blank') {
(window as any).navigation.addEventListener('navigatesuccess', init, { once: true })
} else {
init()
}
export {
onSettingWindowCreated
}

64
src/renderer/style.css Normal file
View File

@ -0,0 +1,64 @@
setting-item[is-hidden],
setting-item[is-hidden] + setting-divider {
display: none !important;
}
.config-host-list {
width: 100%;
padding-left: 16px;
box-sizing: border-box;
}
.config-host-list[is-hidden],
.config-host-list[is-hidden] + setting-divider {
display: none !important;
}
setting-item .q-input {
height: 24px;
width: 100px;
border-top-left-radius: 4px;
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
border-bottom-left-radius: 4px;
box-sizing: border-box;
position: relative;
background: var(--bg_bottom_light);
border: 1px solid var(--border_dark);
}
setting-item .q-input .q-input__inner {
border-top-left-radius: 4px;
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
border-bottom-left-radius: 4px;
box-sizing: border-box;
color: var(--text_primary);
font-family: inherit;
font-size: 12px;
height: 24px;
line-height: 24px;
width: 100%;
border: 1px solid transparent;
padding: 0px 8px;
}
setting-item .q-input input[type=number].q-input__inner::-webkit-outer-spin-button,
setting-item .q-input input[type=number].q-input__inner::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}
.config-host-list setting-item.setting-host-list-item .q-input {
width: 260px;
}
setting-item a {
color: var(--text-link);
}
setting-item a:hover {
color: var(--hover-link);
}
setting-item a:active,
setting-item a:visited {
color: var(--text-link);
}