feat: 添加学生名单导入功能并优化构建流程

- 新增从 SecRandom 和 xlsx 导入学生名单功能
- 添加 IPC 通信模块用于与 SecRandom 交互
- 实现 xlsx 文件解析和姓名列选择功能
- 优化构建流程,添加 CI/CD 相关脚本
- 移除 snap 构建目标
- 更新 ESLint 配置忽略新增脚本文件
This commit is contained in:
Fox_block
2026-01-18 15:32:40 +08:00
parent e83f17af56
commit 8c48b35c08
10 changed files with 966 additions and 7 deletions
+130
View File
@@ -0,0 +1,130 @@
#!/usr/bin/env node
/**
* SecRandom IPC URL 发送脚本 (Node.js 版本)
*
* 用途
* - 向本机正在运行的 SecRandom 实例发送 URL(例如 SecRandom://settings
* - 通过“命名 IPC 通道”连接(Windows 命名管道 / Linux socket),无需端口
*
* 前提
* - SecRandom 主程序已启动,并已启动 URL IPC 服务端
*
* 基本用法(Windows / Linux 通用)
* - 发送打开设置页:
* node secrandom_ipc_send_url.js "SecRandom://settings"
* - 发送切换页面:
* node secrandom_ipc_send_url.js "SecRandom://main/lottery"
*
* 参数说明
* - url:要发送的 URL(大小写不敏感)
* --ipc-name:目标通道名,默认 SecRandom.secrandom
* - Windows 对应:\\.\pipe\SecRandom.secrandom
* - Linux 对应:/tmp/SecRandom.secrandom.sock
*
* 返回与退出码
* - 输出:打印服务端响应 JSON
* - 退出码:
* - 0success 为 true
* - 2success 为 false(例如命令不支持/被拒绝/服务端返回失败)
* - 1:脚本运行异常(例如连接失败、序列化失败等)
*/
const net = require('net')
function parseArgs(argv) {
const out = { url: '', ipcName: 'SecRandom.secrandom', timeout: 5000 }
const args = Array.from(argv)
for (let i = 0; i < args.length; i++) {
const a = String(args[i] ?? '')
if (a === '--help' || a === '-h') return { help: true }
if (a === '--ipc-name') {
out.ipcName = String(args[i + 1] ?? '').trim() || out.ipcName
i++
continue
}
if (a.startsWith('--ipc-name=')) {
out.ipcName = a.slice('--ipc-name='.length).trim() || out.ipcName
continue
}
if (a === '--timeout') {
const n = Number.parseInt(String(args[i + 1] ?? ''), 10)
if (Number.isFinite(n) && n > 0) out.timeout = n
i++
continue
}
if (a.startsWith('--timeout=')) {
const n = Number.parseInt(a.slice('--timeout='.length), 10)
if (Number.isFinite(n) && n > 0) out.timeout = n
continue
}
if (!a.startsWith('-') && !out.url) {
out.url = a
}
}
return out
}
const parsed = parseArgs(process.argv.slice(2))
if (parsed.help || !parsed.url) {
console.log(
'Usage: node secrandom_ipc_send_url.js <url> [--ipc-name <name>] [--timeout <ms>]\n' +
'Example: node secrandom_ipc_send_url.js "SecRandom://settings"'
)
process.exit(parsed.help ? 0 : 1)
}
const { url, ipcName, timeout } = parsed
function getIpcAddress(ipcName) {
if (process.platform === 'win32') {
return `\\\\.\\pipe\\${ipcName}`
}
return `/tmp/${ipcName}.sock`
}
const ipcAddress = getIpcAddress(ipcName)
const message = JSON.stringify({ type: 'url', payload: { url } })
const client = net.createConnection(ipcAddress)
client.setTimeout(parseInt(timeout))
client.on('connect', () => {
client.write(message + '\n')
})
client.on('data', (data) => {
try {
const response = JSON.parse(data.toString())
console.log(JSON.stringify(response, null, 2))
process.exit(response.success ? 0 : 2)
} catch (error) {
console.error('Failed to parse response:', error)
process.exit(1)
}
})
client.on('timeout', () => {
console.error('Connection timeout')
client.destroy()
process.exit(1)
})
client.on('error', (error) => {
if (error.code === 'ENOENT') {
console.error(`IPC 通道不存在: ${ipcAddress}. 请确认 SecRandom 已运行且已启动 IPC 服务端。`)
} else {
console.error('IPC send failed:', error.message)
}
process.exit(1)
})
client.on('close', () => {
if (process.exitCode === undefined) {
console.error('Connection closed without response')
process.exit(1)
}
})