diff --git a/liteyuki/plugins/liteyuki_status/api.py b/liteyuki/plugins/liteyuki_status/api.py index b1bff3f..4559ceb 100644 --- a/liteyuki/plugins/liteyuki_status/api.py +++ b/liteyuki/plugins/liteyuki_status/api.py @@ -94,6 +94,9 @@ def get_local_data(lang_code) -> dict: "minutes" : lang.get("status.minutes"), "seconds" : lang.get("status.seconds"), "runtime" : lang.get("status.runtime"), + "threads" : lang.get("status.threads"), + "cores" : lang.get("status.cores"), + "process" : lang.get("status.process"), } @@ -149,7 +152,7 @@ async def get_hardware_data() -> dict: all_processes = psutil.Process().children(recursive=True) all_processes.append(psutil.Process()) - mem_used_bot = 0 + mem_used_process = 0 process_mem = {} for process in all_processes: try: @@ -157,7 +160,7 @@ async def get_hardware_data() -> dict: if ps_name not in process_mem: process_mem[ps_name] = 0 process_mem[ps_name] += process.memory_info().rss - mem_used_bot += process.memory_info().rss + mem_used_process += process.memory_info().rss except Exception: pass swap = psutil.swap_memory() @@ -169,31 +172,34 @@ async def get_hardware_data() -> dict: else: brand = "Unknown" result = { - "cpu" : { + "cpu" : { "percent": psutil.cpu_percent(), "name" : f"{brand} {cpuinfo.get_cpu_info().get('arch', 'Unknown')}", "cores" : psutil.cpu_count(logical=False), "threads": psutil.cpu_count(logical=True), - "freq" : psutil.cpu_freq().current # MHz + "freq" : psutil.cpu_freq().current # MHz }, - "memory" : { - "percent": mem.percent, - "total" : mem.total, - "used" : mem.used, - "free" : mem.free, + "memory": { + "percent" : mem.percent, + "total" : mem.total, + "used" : mem.used, + "free" : mem.free, + "usedProcess": mem_used_process, }, - "swap": { + "swap" : { "percent": swap.percent, "total" : swap.total, "used" : swap.used, "free" : swap.free }, - "disk": [], + "disk" : [], } for disk in psutil.disk_partitions(all=True): try: disk_usage = psutil.disk_usage(disk.mountpoint) + if disk_usage.total == 0: + continue # 虚拟磁盘 result["disk"].append({ "name" : disk.mountpoint, "percent": disk_usage.percent, diff --git a/liteyuki/plugins/liteyuki_status/status.py b/liteyuki/plugins/liteyuki_status/status.py index a2844df..a0615a1 100644 --- a/liteyuki/plugins/liteyuki_status/status.py +++ b/liteyuki/plugins/liteyuki_status/status.py @@ -10,9 +10,9 @@ require("nonebot_plugin_alconna") from nonebot_plugin_alconna import on_alconna, Alconna, Args, Subcommand, Arparma, UniMessage status_alc = on_alconna( - aliases={"#状态"}, + aliases={"状态"}, command=Alconna( - "#status", + "status", Subcommand( "memory", alias={"mem", "m", "内存"}, diff --git a/liteyuki/resources/lang/zh-CN.lang b/liteyuki/resources/lang/zh-CN.lang index e9d77ed..38676f1 100644 --- a/liteyuki/resources/lang/zh-CN.lang +++ b/liteyuki/resources/lang/zh-CN.lang @@ -152,4 +152,7 @@ status.runtime=运行时间 status.days=天 status.hours=时 status.minutes=分 -status.seconds=秒 \ No newline at end of file +status.seconds=秒 +status.cores=核心 +status.threads=线程 +status.process=进程 \ No newline at end of file diff --git a/liteyuki/resources/templates/css/status.css b/liteyuki/resources/templates/css/status.css index 78ddc42..724e8a5 100644 --- a/liteyuki/resources/templates/css/status.css +++ b/liteyuki/resources/templates/css/status.css @@ -2,6 +2,8 @@ --main-text-color: #fff; --sub-text-color: #bbb; --tip-text-color: #888; + + --device-info-width: 240px; } .bot-info { @@ -57,4 +59,72 @@ background: var(--tip-text-color); margin: 10px 0; width: 100%; +} + +#hardware-info { + display: flex; + justify-content: space-evenly; +} + +.device-info { + max-width: 30%; +} + +.device-chart { + display: flex; + height: var(--device-info-width); + width: var(--device-info-width); + margin-bottom: 20px; + justify-content: center; +} + +.device-tags { + text-align: center; + color: var(--sub-text-color); + font-size: 24px; + max-width: var(--device-info-width); + word-wrap: break-word; +} + +.disk-info { + display: flex; + position: relative; + width: 100%; + height: 60px; + background-color: #ffffff44; + border-radius: 30px; + align-items: center; +} + +.disk-usage { + background-color: #a2d8f4; + height: 100%; + border-radius: 30px; + position: absolute; + z-index: 1; +} + +.disk-title { + position: absolute; + color: var(--main-text-color); + font-size: 24px; + margin-bottom: 10px; + margin-left: 20px; + text-align: left; + z-index: 2; +} + +#motto-text { + font-size: 36px; + word-wrap: break-word; + color: var(--main-text-color); + text-align: center; + margin: 30px 0 10px 0; +} + +#motto-from { + font-size: 24px; + font-style: italic; + color: var(--sub-text-color); + text-align: right; } \ No newline at end of file diff --git a/liteyuki/resources/templates/img/bg10.png b/liteyuki/resources/templates/img/bg10.png deleted file mode 100644 index 0205c42..0000000 Binary files a/liteyuki/resources/templates/img/bg10.png and /dev/null differ diff --git a/liteyuki/resources/templates/img/bg2.png b/liteyuki/resources/templates/img/bg2.png deleted file mode 100644 index 306ee69..0000000 Binary files a/liteyuki/resources/templates/img/bg2.png and /dev/null differ diff --git a/liteyuki/resources/templates/img/bg8.png b/liteyuki/resources/templates/img/bg8.png deleted file mode 100644 index cb26c0f..0000000 Binary files a/liteyuki/resources/templates/img/bg8.png and /dev/null differ diff --git a/liteyuki/resources/templates/js/bg.js b/liteyuki/resources/templates/js/bg.js deleted file mode 100644 index f93abd9..0000000 --- a/liteyuki/resources/templates/js/bg.js +++ /dev/null @@ -1,14 +0,0 @@ -const bgs = [ - "bg1.png", - "bg2.png", - "bg3.png", - "bg4.png", - "bg5.png", - "bg6.png", - "bg7.png", - "bg8.png", - "bg9.png", - "bg10.png", -] -// 随机选择背景图片 -document.body.style.backgroundImage = `url(./img/${bgs[Math.floor(Math.random() * bgs.length)]})`; diff --git a/liteyuki/resources/templates/js/card.js b/liteyuki/resources/templates/js/card.js index f93abd9..e2f31c2 100644 --- a/liteyuki/resources/templates/js/card.js +++ b/liteyuki/resources/templates/js/card.js @@ -1,14 +1,11 @@ const bgs = [ "bg1.png", - "bg2.png", "bg3.png", "bg4.png", "bg5.png", "bg6.png", "bg7.png", - "bg8.png", "bg9.png", - "bg10.png", ] // 随机选择背景图片 document.body.style.backgroundImage = `url(./img/${bgs[Math.floor(Math.random() * bgs.length)]})`; diff --git a/liteyuki/resources/templates/js/motto.js b/liteyuki/resources/templates/js/motto.js index 54db2c3..54e0c12 100644 --- a/liteyuki/resources/templates/js/motto.js +++ b/liteyuki/resources/templates/js/motto.js @@ -6,7 +6,7 @@ const mottos = [ "source": "《琵琶行》" }, { - "text": "海Memory知己,天涯若比邻。", + "text": "海内存知己,天涯若比邻。", "author": "王勃", "source": "《送杜少府之任蜀州》" }, @@ -20,6 +20,16 @@ const mottos = [ "author": "苏轼", "source": "《水调歌头》" }, + { + "text": "人生自古谁无死,留取丹心照汗青。", + "author": "文天祥", + "source": "《过零丁洋》" + }, + { + "text": "山重水复疑无路,柳暗花明又一村。", + "author": "陆游", + "source": "《游山西村》" + }, { "text": "逸一时,误一世,逸久逸久罢已龄", "author": "田所浩二", @@ -46,8 +56,58 @@ const mottos = [ "source": "轻雪文档" }, { - "text": "你知道吗,轻雪的主题是基于Vue.js开发的", + "text": "你知道吗,轻雪的主题是基于HTML5开发的", "author": "SnowyKami", "source": "轻雪文档" + }, + { + "text": "路漫漫其修远兮,吾将上下而求索。", + "author": "屈原", + "source": "《离骚》" + }, + { + "text": "千里之行,始于足下。", + "author": "老子", + "source": "《道德经》" + }, + { + "text": "读书破万卷,下笔如有神。", + "author": "杜甫", + "source": "《奉赠韦左丞丈二十韵》" + }, + { + "text": "不登高山,不知天之高也;不临深溪,不知地之厚也。", + "author": "荀子", + "source": "《劝学》" + }, + { + "text": "知之者不如好之者,好之者不如乐之者。", + "author": "孔子", + "source": "《论语》" + }, + { + "text": "天行健,君子以自强不息;地势坤,君子以厚德载物。", + "source": "《易经》", + "author": "" + }, + { + "text": "书山有路勤为径,学海无涯苦作舟。", + "author": "韩愈", + "source": "《读书有感》" + }, + { + "text": "前事不忘,后事之师。", + "author": "孔子", + "source": "《论语》" + }, + { + "text": "志当存高远,若樽俎断绝。", + "author": "陶渊明", + "source": "《饮酒》" + }, + { + "text": "不以物喜,不以己悲。", + "author": "傅子", + "source": "《傅子》" } ] \ No newline at end of file diff --git a/liteyuki/resources/templates/js/status.js b/liteyuki/resources/templates/js/status.js index 6d59c7c..52391fa 100644 --- a/liteyuki/resources/templates/js/status.js +++ b/liteyuki/resources/templates/js/status.js @@ -19,7 +19,8 @@ function createPieChartOption(title, data) { top: 'center', textStyle: { color: '#fff', - fontSize: 30 + fontSize: 30, + lineHeight: 36 } }, tooltip: { @@ -90,8 +91,17 @@ function convertSize(size, precision = 2, addUnit = true, suffix = " XiB") { * @param title * @param percent 数据 */ -function createBarChartOption(title, percent) { +function createBarChart(title, percent) { // percent为百分比,最大值为100 + let diskDiv = document.createElement('div') + diskDiv.setAttribute('class', 'disk-info') + diskDiv.style.marginBottom = '20px' + diskDiv.innerHTML = ` +
${title}
+
+ ` + + return diskDiv } function secondsToTextTime(seconds) { @@ -112,7 +122,7 @@ function main() { // 设置机器人信息 botInfoDiv.className = 'info-box bot-info' - console.log(botInfoDiv.querySelector('.bot-icon-img')) + botInfoDiv.querySelector('.bot-icon-img').setAttribute('src', bot['icon']) botInfoDiv.querySelector('.bot-name').innerText = bot['name'] let tagArray = [ @@ -144,7 +154,7 @@ function main() { liteyukiInfoDiv.className = 'info-box bot-info' liteyukiInfoDiv.querySelector('.bot-icon-img').setAttribute('src', './img/liteyuki.png') liteyukiInfoDiv.querySelector('.bot-name').innerText = liteyukiData['name'] - console.log(liteyukiData) + let tagArray = [ `Liteyuki ${liteyukiData['version']}`, `Nonebot ${liteyukiData['nonebot']}`, @@ -173,12 +183,12 @@ function main() { const cpuTagArray = [ cpuData['name'], - `${cpuData['cores']}C ${cpuData['threads']}T`, + `${cpuData['cores']}${localData['cores']} ${cpuData['threads']}${localData['threads']}`, `${(cpuData['freq'] / 1000).toFixed(2)}GHz` ] const memTagArray = [ - `Bot ${convertSize(memData['bot'])}`, + `${localData['process']} ${convertSize(memData['usedProcess'])}`, `${localData['used']} ${convertSize(memData['used'])}`, `${localData['free']} ${convertSize(memData['free'])}`, `${localData['total']} ${convertSize(memData['total'])}` @@ -189,7 +199,96 @@ function main() { `${localData['free']} ${convertSize(swapData['free'])}`, `${localData['total']} ${convertSize(swapData['total'])}` ] - console.log(cpuTagArray, memTagArray, swapTagArray) + let cpuDeviceInfoDiv = document.importNode(document.getElementById('device-info').content, true) + let memDeviceInfoDiv = document.importNode(document.getElementById('device-info').content, true) + let swapDeviceInfoDiv = document.importNode(document.getElementById('device-info').content, true) + + cpuDeviceInfoDiv.querySelector('.device-info').setAttribute('id', 'cpu-info') + memDeviceInfoDiv.querySelector('.device-info').setAttribute('id', 'mem-info') + swapDeviceInfoDiv.querySelector('.device-info').setAttribute('id', 'swap-info') + cpuDeviceInfoDiv.querySelector('.device-chart').setAttribute('id', 'cpu-chart') + memDeviceInfoDiv.querySelector('.device-chart').setAttribute('id', 'mem-chart') + swapDeviceInfoDiv.querySelector('.device-chart').setAttribute('id', 'swap-chart') + + let devices = { + 'cpu': cpuDeviceInfoDiv, + 'mem': memDeviceInfoDiv, + 'swap': swapDeviceInfoDiv + } + // 遍历添加标签 + for (let device in devices) { + let tagArray = [] + switch (device) { + case 'cpu': + tagArray = cpuTagArray + break + case 'mem': + tagArray = memTagArray + break + case 'swap': + tagArray = swapTagArray + break + } + tagArray.forEach( + (tag, index) => { + let tagDiv = document.createElement('div') + tagDiv.className = 'device-tag' + tagDiv.innerText = tag + // 给最后一个标签不添加后缀 + tagDiv.setAttribute('suffix', index === tagArray.length - 1 ? '0' : '1') + devices[device].querySelector('.device-tags').appendChild(tagDiv) + } + ) + } + + + // 插入 + document.getElementById('hardware-info').appendChild(cpuDeviceInfoDiv) + document.getElementById('hardware-info').appendChild(memDeviceInfoDiv) + document.getElementById('hardware-info').appendChild(swapDeviceInfoDiv) + + let cpuChart = echarts.init(document.getElementById('cpu-chart')) + let memChart = echarts.init(document.getElementById('mem-chart')) + let swapChart = echarts.init(document.getElementById('swap-chart')) + + + cpuChart.setOption(createPieChartOption(`${localData['cpu']}\n${cpuData['percent'].toFixed(1)}%`, [ + {name: 'used', value: cpuData['percent']}, + {name: 'free', value: 100 - cpuData['percent']} + ])) + + memChart.setOption(createPieChartOption(`${localData['memory']}\n${memData['percent'].toFixed(1)}%`, [ + {name: 'process', value: memData['usedProcess']}, + {name: 'used', value: memData['used'] - memData['usedProcess']}, + {name: 'free', value: memData['free']} + ])) + + + swapChart.setOption(createPieChartOption(`${localData['swap']}\n${swapData['percent'].toFixed(1)}%`, [ + {name: 'used', value: swapData['used']}, + {name: 'free', value: swapData['free']} + ])) + + + // 磁盘信息 + const diskData = hardwareData['disk'] + diskData.forEach( + (disk) => { + let diskTitle = `${disk['name']} ${localData['free']} ${convertSize(disk['free'])} ${localData['total']} ${convertSize(disk['total'])}` + // 最后一个把margin-bottom去掉 + let diskDiv = createBarChart(diskTitle, disk['percent']) + if (disk === diskData[diskData.length - 1]) { + diskDiv.style.marginBottom = '0' + } + document.getElementById('disk-info').appendChild(createBarChart(diskTitle, disk['percent'])) + }) + // 随机一言 + let motto = mottos[Math.floor(Math.random() * mottos.length)] + let mottoText = motto['text'] + let mottoFrom = `${motto['author']} ${motto['source']}` + document.getElementById('motto-text').innerText = mottoText + document.getElementById('motto-from').innerText = mottoFrom + } diff --git a/liteyuki/resources/templates/status.html b/liteyuki/resources/templates/status.html index 2310800..12f3667 100644 --- a/liteyuki/resources/templates/status.html +++ b/liteyuki/resources/templates/status.html @@ -6,6 +6,7 @@ + + +
{{ data | tojson }}
-
- +
+
+
+
+ +