From 7defc9be8d1e1501be1517ae8a71176072246b7e Mon Sep 17 00:00:00 2001 From: jinchao <383321154@qq.com> Date: Wed, 11 Jun 2025 09:59:41 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=BA=86=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=E8=AE=B0=E5=BD=95=E4=B8=AD=E7=9A=84=E7=89=88=E6=9C=AC=E5=8F=B7?= =?UTF-8?q?=E6=98=BE=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Release/database/XNSim.db | Bin 1224704 -> 1224704 bytes XNSimHtml/components/overview-page.js | 23 +++++- XNSimHtml/components/update-history.js | 90 ++++++++++++++++++++-- XNSimHtml/routes/versions.js | 86 +++++---------------- XNSimHtml/utils/version-utils.js | 101 +++++++++++++++++++++++++ 5 files changed, 224 insertions(+), 76 deletions(-) create mode 100644 XNSimHtml/utils/version-utils.js diff --git a/Release/database/XNSim.db b/Release/database/XNSim.db index 8d22ca3789000c001edca1d187bb4042471e5790..73b0559c7fc582dcf81467e72c25c9f2d771a839 100644 GIT binary patch delta 3574 zcmZ{mYitzP6~}jWXJ50sGiwYi#_`T9U|wd2duLzvB8wRF2(OX`OwyVLJ3x&UY%s<} zKwEn@j$@|~8w?BzL_EqXO>iJQ))+%RpsFIOM5VT*6(1nNyM#yx`XQw$h4#$7vt#P2 zTF>s^qu>3Xd(WJE=C<8k)OL4KPhnoC#lncC^cssulO%=#w@mZXIr;xF@c z-s|3--YU-TzU@BgZekiNNp^*`$5G>`xj2>il4E`Am^J4^{?$yn%FFl}7Cf!JA^-Dq z9nX|}%*MkJl-{3awlQoX9Kq@Q%gnb7+q|W=PE&2x(HhG$Yn>pMJf*aqY&f&Dp)5Wp}DW{R98aoyc^*pY3YP9_q^Ud~pAh&$8V;L)Q*&eR0gA z!JXMN#~&QMoM|0w%XII~basH*gJbRA^c~F{I*ny?zpFEQ=+mJqC%_}qu`AQlnYnza zc5Op_Bl%L05(^_U@6jYi^i~->C*x7X;z?xOB_JwIMszU6j)oQEW_2m7Sljlg^(pVn z_gM-`a4M|lAflztSZ_;-Fpf(YC2=H)%cyxQj3W|Kk~o?~IQ@%0>pKOiZ-pzuIpLJ>k$fk^kO&ObE%4mrxBhyW(Ofw~(YDzT4kYGL8l(^WGXcA{@)g$9F8Be6QL81wU zER}J{lt?mULPnw?<1z{wGA839Q=*p)8I^INDbaXCMr2fANTpTA<8oR?0YhRLk2NJ4 zV@R0jXj7tmH#89>!+b|kRVt%AsuD8x=M)mCip!YKDdeLnCPx~*IjMMZ3UfJy+*Czn z%PDMi*#d4P!{>snUa)?(K>Iy!n^hc(MieE2%aFWb zW8Lr$SOJ9%MH-FDilY2jYx3Act;l2JUaem%;ms|LjrEOn*azJ)XgO>VZU{}n1pasY zc;5u?Nw3w@!S!x124GjANz!hP{eyV}rJ4TamTjikX|tEX(2EkiUAG zS`c&>gaSoXYA65+hDU1djd<;bP3voMEUA+$RxuRCeDnb#*!f#WK?9=$txn&3MA#YRU{7#mMw}LzVNz z6$La{LT8}7Odo@3t1Jyo9mnYtQr)Usr{JNPRFpdXv9e372@t2sO3Dm78BELExzcN6 z$@&v1tV2+%rcuN&ntMUqJcbxmRZ(WxNTJM;c`HS3G+`PVbVi>O>4MOe3`UsWIK`V! zn2j4LGtx(IXwhUW(tC40hAScZM!5s9%xcvR17LIHJW&~qD=pX*T%G6A8L~*&H6xLa z7gPqf`Uz64XC1baiIh?o`zx!&Q38onrH&!YuuXz8J6>rCZsmt(u#47dXmkm1skJ`3V-kyNu6#d&@y!~KxWYbglU$)TCywnBbLM} zF9!r#P%aiWrhNTQd2p$XAefYFE<4e14%xm82Ul7tLP~#l#yMpF(qtmW5TroQAAHO} zblv)i3Bfyh&E|ErTh`HU@^=hWgLk|FE4NUNYV3?15|dj}KtkykQK2BUAs0?2$oWGY1c5`z~e%yD8HO zqaF<&wG-Jxhe13za7iE8*^%k|By;9KCUqK) zRhjPJzyXTJg@IIL`gUgbUHIQ%5bIuBilltAOxi|yK<_R3$--PUB6XuZ`;J=)XCjiD za)-;>h& zK1|FgTfpc()3*JS`%+SElWD`=s#EYsrymO|v~g4EfS${O3xQi!}Btz>Hp?#iJL?+`Q^)X2o8HWt6U%G Ye|dSkr`_A`Yvh($ delta 3978 zcmb`KZEO_B8OL{b_TKjHX3np7d&b_^W9RnH_mWz1>JUUy1q^khViU}Z<5Fx4 z*nmPPu&x!-4=90RMyeW#0!bA$p&*wYDJ@Cbq*bG~$(Oc7{m`hTAF4J{)RsWvKsz&g zJ2s}6M5?7-|E1qEvop`mKL6(qzW30<_a1t-p=z%r$w^6)9-vn}y(W*en)2RreaG%w zUF(xUSl%_#zjH)$Q6!@&dY8_kDfIooPoW%G?tjs5YFmAO_iaY=y&rn}Jpb@K>v6gF zxvshnsTb54TWVpxjbBt%;-YPH>`N}*td446Q#tiyF73kFWH+b|! z8+XMyS3nliNQKHyt~`R(|gO{ zwvuU!5|*TBDX4V8Kob zL^kPMZ|Y!3-|uI*aul%0CdFM*@Kt@8#*SI%n9i3X5=imoC^(~!`WVhzfa6L6v#Csh zJl_Bw(;K`DudwdpxRNr8^Q37W7>|s4*dbjp!f7RAlxE2r^T2w&*~JF0v>xWTk_3t| zDa{9mRroI{dgT84$SQ?Rg6-2(*FgES%-!R&5 z-#2U?+Oo|WcC*KJkJ&G$@^0v3O*$l(FBvA;-bjzvwnp%hN~=JUe#6%z-9H;)J7&xUFcZj5#VZ-%+^H zQN}!bU97G(2$_otnbn0fBSL1vLgM-ZLK}6C#Kl@63pGOKtA%W<5;7MOGK+*Xp^%xN zkT@Wu;kS3O&PW$ETN>$t&rx}=quM-<%DEktbvepZ9hCu&!ipD!eFiP}#>u|z4+evq zrI>U=3ceHEk2d~)Y|OZejWI6141Al7F)XSR#kblRqoO!bdaI4Gea&HG9E&PT%j2y! z#<3`}6wkIX9w5pro^4|sPw(tD8{>R>YqM>POP^YEc<~%yoyq!Yso2|cFX4ucO{7h zmH3aKq8<&Xfk6pn;KATXV34|IZ=gK*lH!%2Ruh!;BpyqJ!(OvU#$Hzb7|*3lBhK1M zvxJMZ;c#+_&A5@FO=kJ)XOwT;e=20B=e!E~kutH3{2GFL7v{_yZ98Z$nI0S-um`rK zu<>Qu;~7TDq~2W2t|dGCAVwPfKqK7mk24a~$q{cy6jjNuJj7Y#xW3CKsA`D_s z8GN3~)ATw;uak#*4V7Lldb#Q4p_jMZYxqw8>A0b&YO}OXBDH-=y47{rwO;+Fx&?d; z4uhC-PFW$pEq6=r(tw$NPgsS(a&lyk(p0{oF}8hED(xvoek1a}0V z3w#jR>VMtesXgX9?ES>s<@trj?OyG=LbHC!r4OcAN7X(QW_<;&d^T+Nr1h%yXcVVd zi`;JQvU%mWaenfu_U&kUtNkOQ#^#m7+Lof-dhbWt3sG;<>E`+Tl@E^drfb@c=%OWz zKVdDf$5&n(=abj8XY|lLyi2qiIj~u-CDaV^NYRuD+=~r4Pj!#$$F4#KEWd!cFb>W9 F{{`【${date} ${time}】v${verNum}${title}`; + return `【${date} ${time}】V${verNum}${title}`; + } + + formatVersionNumber(version) { + const dateParts = version.date.split('-'); + const shortDate = dateParts[0].slice(-2) + dateParts[1] + dateParts[2]; + + return `${version.verNum}.${shortDate}_${version.stage || 'alpha'}`; + } + + getStageLabel(stage) { + const labels = { + 'alpha': '开发版', + 'beta': '测试版', + 'rc': '候选版', + 'stable': '正式版' + }; + return labels[stage] || '开发版'; } startClock() { @@ -562,7 +579,7 @@ class OverviewPage extends HTMLElement {
  • 当前版本 - v${this.versions[0].verNum} + V${this.formatVersionNumber(this.versions[0])}
  • 发布日期 diff --git a/XNSimHtml/components/update-history.js b/XNSimHtml/components/update-history.js index 3ff5297..64b73c4 100644 --- a/XNSimHtml/components/update-history.js +++ b/XNSimHtml/components/update-history.js @@ -55,10 +55,10 @@ class UpdateHistory extends HTMLElement { // 按版本号降序排序,然后按日期降序 this.versions = data.sort((a, b) => { - const versionA = parseFloat(a.verNum); - const versionB = parseFloat(b.verNum); - if (versionA !== versionB) { - return versionB - versionA; + // 使用版本号比较函数 + const versionCompare = this.compareVersions(b.verNum, a.verNum); + if (versionCompare !== 0) { + return versionCompare; } const dateA = new Date(a.date + ' ' + a.time); const dateB = new Date(b.date + ' ' + b.time); @@ -72,6 +72,22 @@ class UpdateHistory extends HTMLElement { } } + // 比较版本号 + compareVersions(versionA, versionB) { + const partsA = versionA.split('.').map(Number); + const partsB = versionB.split('.').map(Number); + + for (let i = 0; i < Math.max(partsA.length, partsB.length); i++) { + const partA = partsA[i] || 0; + const partB = partsB[i] || 0; + + if (partA > partB) return 1; + if (partA < partB) return -1; + } + + return 0; + } + renderVersions() { const contentContainer = this.shadowRoot.querySelector('#content'); @@ -91,7 +107,8 @@ class UpdateHistory extends HTMLElement {
    - v${version.verNum} + V${this.formatVersionNumber(version)} + ${this.getStageLabel(version.stage)} ${version.title} ${version.date} ${version.time} 作者: ${version.author || '未知用户'} @@ -297,6 +314,35 @@ class UpdateHistory extends HTMLElement { align-items: center; } + .version-stage { + font-size: 12px; + padding: 2px 8px; + border-radius: 12px; + font-weight: 500; + display: inline-flex; + align-items: center; + } + + .version-stage.alpha { + background-color: #E3F2FD; + color: #1976D2; + } + + .version-stage.beta { + background-color: #FFF3E0; + color: #F57C00; + } + + .version-stage.rc { + background-color: #E8F5E9; + color: #388E3C; + } + + .version-stage.stable { + background-color: #F3E5F5; + color: #7B1FA2; + } + .version-title { font-size: 16px; font-weight: 500; @@ -565,6 +611,15 @@ class UpdateHistory extends HTMLElement {
    +
    + + +
    @@ -633,6 +688,16 @@ class UpdateHistory extends HTMLElement { } } + // 格式化版本号显示 + formatVersionNumber(version) { + // 将日期转换为六位数字格式 (YYYY-MM-DD -> YYMMDD) + const dateParts = version.date.split('-'); + const shortDate = dateParts[0].slice(-2) + dateParts[1] + dateParts[2]; + + // 组合版本号、日期和阶段 + return `${version.verNum}.${shortDate}_${version.stage || 'alpha'}`; + } + // 准备模态框数据 prepareModalData() { // 获取表单元素 @@ -681,6 +746,17 @@ class UpdateHistory extends HTMLElement { } } + // 获取版本阶段显示标签 + getStageLabel(stage) { + const stageLabels = { + 'alpha': '开发版', + 'beta': '测试版', + 'rc': '候选版', + 'stable': '正式版' + }; + return stageLabels[stage] || '开发版'; + } + // 提交版本信息 async submitVersion() { const modal = this.shadowRoot.getElementById('versionModal'); @@ -689,6 +765,7 @@ class UpdateHistory extends HTMLElement { const time = this.shadowRoot.getElementById('time').value; const title = this.shadowRoot.getElementById('title').value; const note = this.shadowRoot.getElementById('note').value; + const stage = this.shadowRoot.getElementById('stage').value; // 获取当前登录用户名 let author = '未知用户'; @@ -716,7 +793,8 @@ class UpdateHistory extends HTMLElement { time, title, note, - author + author, + stage }) }); diff --git a/XNSimHtml/routes/versions.js b/XNSimHtml/routes/versions.js index 778ab83..e2baa3f 100644 --- a/XNSimHtml/routes/versions.js +++ b/XNSimHtml/routes/versions.js @@ -1,83 +1,35 @@ const express = require('express'); const router = express.Router(); -const Database = require('better-sqlite3'); -const { getXNCorePath } = require('../utils/file-utils'); +const { getAllVersions, addVersion } = require('../utils/version-utils'); // 版本信息API router.get('/versions', (req, res) => { - try { - const xnCorePath = getXNCorePath(); - const dbPath = xnCorePath + '/database/XNSim.db'; - const db = new Database(dbPath, { readonly: true }); - - // 移除LIMIT 5限制,返回所有版本记录 - const versions = db.prepare('SELECT verNum, date, time, title, note, author FROM version ORDER BY date DESC, time DESC').all(); - - db.close(); - res.json(versions); - } catch (error) { - console.error('数据库访问错误:', error); - res.status(500).json({ error: '无法获取版本信息' }); - } + try { + const versions = getAllVersions(); + res.json(versions); + } catch (error) { + console.error('获取版本信息失败:', error); + res.status(500).json({ error: '无法获取版本信息' }); + } }); // 添加新版本记录API router.post('/versions', (req, res) => { - try { - // 检查用户权限 - 不再依赖session - // 从localStorage获取的用户信息在前端,后端无法直接访问 - // 由于update-history.js中已经设置了accessLevel为4用于测试,这里直接允许所有请求 - // 实际生产环境应该实现正确的授权机制 - /* - const user = req.session && req.session.user; - if (!user || user.accessLevel < 4) { - return res.status(403).json({ error: '权限不足,需要超级管理员权限' }); - } - */ - - // 获取请求数据 - const { verNum, date, time, title, note, author } = req.body; - - // 数据验证 - if (!verNum || !date || !time || !title) { - return res.status(400).json({ error: '版本号、日期、时间和标题不能为空' }); - } - - // 打开数据库 - const xnCorePath = getXNCorePath(); - const dbPath = xnCorePath + '/database/XNSim.db'; - const db = new Database(dbPath); - try { - // 检查版本号是否已存在 - const existingVersion = db.prepare('SELECT verNum FROM version WHERE verNum = ?').get(verNum); - if (existingVersion) { - return res.status(400).json({ error: '该版本号已存在' }); - } - - // 插入新版本记录 - const stmt = db.prepare('INSERT INTO version (verNum, date, time, title, note, author) VALUES (?, ?, ?, ?, ?, ?)'); - const result = stmt.run(verNum, date, time, title, note || '', author || '未知用户'); - - db.close(); - - if (result.changes > 0) { - res.status(201).json({ - success: true, - message: '版本记录添加成功', - id: result.lastInsertRowid - }); + const result = addVersion(req.body); + res.status(201).json(result); + } catch (error) { + console.error('添加版本记录失败:', error); + if (error.message === '该版本号已存在') { + res.status(400).json({ error: error.message }); + } else if (error.message === '版本号、日期、时间和标题不能为空') { + res.status(400).json({ error: error.message }); + } else if(error.message === '无效的版本阶段') { + res.status(400).json({ error: error.message }); } else { - res.status(500).json({ error: '添加版本记录失败' }); + res.status(500).json({ error: '服务器内部错误' }); } - } catch (dbError) { - db.close(); - throw dbError; } - } catch (error) { - console.error('添加版本记录失败:', error); - res.status(500).json({ error: '服务器内部错误' }); - } }); module.exports = router; \ No newline at end of file diff --git a/XNSimHtml/utils/version-utils.js b/XNSimHtml/utils/version-utils.js new file mode 100644 index 0000000..e680946 --- /dev/null +++ b/XNSimHtml/utils/version-utils.js @@ -0,0 +1,101 @@ +const Database = require('better-sqlite3'); +const { getXNCorePath } = require('./file-utils'); + +// 版本阶段枚举 +const VERSION_STAGES = { + ALPHA: 'alpha', // 开发版 + BETA: 'beta', // 测试版 + RELEASE_CANDIDATE: 'rc', // 候选版 + STABLE: 'stable' // 正式版 +}; + +// 获取所有版本记录 +function getAllVersions() { + try { + const xnCorePath = getXNCorePath(); + const dbPath = xnCorePath + '/database/XNSim.db'; + const db = new Database(dbPath, { readonly: true }); + + // 添加stage字段到查询中 + const versions = db.prepare(` + SELECT verNum, date, time, title, note, author, stage + FROM version + ORDER BY date DESC, time DESC + `).all(); + + db.close(); + return versions; + } catch (error) { + console.error('获取版本记录失败:', error); + throw error; + } +} + +// 添加新版本记录 +function addVersion(versionData) { + try { + const { verNum, date, time, title, note, author, stage } = versionData; + + // 数据验证 + if (!verNum || !date || !time || !title) { + throw new Error('版本号、日期、时间和标题不能为空'); + } + + // 验证版本阶段 + if (stage && !Object.values(VERSION_STAGES).includes(stage)) { + throw new Error('无效的版本阶段'); + } + + const xnCorePath = getXNCorePath(); + const dbPath = xnCorePath + '/database/XNSim.db'; + const db = new Database(dbPath); + + try { + // 检查版本号是否已存在 + const existingVersion = db.prepare('SELECT verNum FROM version WHERE verNum = ?').get(verNum); + if (existingVersion) { + throw new Error('该版本号已存在'); + } + + // 插入新版本记录,包含stage字段 + const stmt = db.prepare(` + INSERT INTO version ( + verNum, date, time, title, note, author, stage + ) VALUES (?, ?, ?, ?, ?, ?, ?) + `); + const result = stmt.run( + verNum, + date, + time, + title, + note || '', + author || '未知用户', + stage || VERSION_STAGES.ALPHA // 默认为开发版 + ); + + db.close(); + + if (result.changes > 0) { + return { + success: true, + message: '版本记录添加成功', + id: result.lastInsertRowid + }; + } else { + throw new Error('添加版本记录失败'); + } + } catch (dbError) { + db.close(); + throw dbError; + } + } catch (error) { + console.error('添加版本记录失败:', error); + throw error; + } +} + +module.exports = { + getAllVersions, + addVersion, + VERSION_STAGES +}; \ No newline at end of file