This commit is contained in:
oneao committed 2026-10-14 17:25:47 +08:00
1 parent 15e0ae5b67
commit e434374db5
71 files changed
+5726 -329

No files matched your search

+103
View File
@@ -0,0 +1,103 @@
#!/usr/bin/env node
/**
* 开发期取 token —— 给 AI / 脚本 / 命令行用,不必开浏览器点登录。
*
* 用法(在仓库根目录执行):
* node scripts/dev-login.mjs # 用 web/.env.development 里的账号
* node scripts/dev-login.mjs G3HD g3soft # 指定机构码 + 账号
* node scripts/dev-login.mjs G3HD g3soft pwd # 再指定密码
* node scripts/dev-login.mjs --token-only # 只输出 token 一行,便于 $(...) 取值
* node scripts/dev-login.mjs --target http://127.0.0.1:8088
*
* 直接打后端(默认 127.0.0.1:8088),不经过 Vite 代理。
*
* ⚠️ 同一账号重复登录会互踢(后端 ActiveSessionRegistry,业务码 40101):
* 这个脚本每跑一次就会把该账号上一个会话踢下线。别在别人正用同一账号时跑。
*/
import { readFileSync } from 'node:fs'
import { fileURLToPath } from 'node:url'
import path from 'node:path'
const ROOT = fileURLToPath(new URL('..', import.meta.url))
const ENV_FILE = path.join(ROOT, 'web', '.env.development')
/* ---------------- 读取 web/.env.development 作为默认值 ---------------- */
function readEnvValue(key) {
try {
for (const line of readFileSync(ENV_FILE, 'utf8').split(/\r?\n/)) {
const match = /^\s*([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*)$/.exec(line)
if (match && match[1] === key) {
return match[2].trim().replace(/^(['"])(.*)\1$/, '$2')
}
}
} catch {
// 文件不存在:回落到内置默认值,下面还会打印提示
}
return ''
}
/* ---------------- 参数 ---------------- */
const positional = []
let target = ''
let tokenOnly = false
const args = process.argv.slice(2)
for (let i = 0; i < args.length; i += 1) {
if (args[i] === '--target') {
target = args[i + 1] ?? ''
i += 1
} else if (args[i] === '--token-only') {
tokenOnly = true
} else {
positional.push(args[i])
}
}
const base = (target || process.env.VITE_PROXY_TARGET || 'http://127.0.0.1:8088').replace(/\/+$/, '')
const orgId = positional[0] || readEnvValue('VITE_DEV_ORG') || 'G3HD'
const account = positional[1] || readEnvValue('VITE_DEV_ACCOUNT') || 'g3soft'
const password = positional[2] ?? readEnvValue('VITE_DEV_PASSWORD')
/* ---------------- 登录 ---------------- */
let body
try {
const response = await fetch(`${base}/api/auth/login`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ orgid: orgId, userid: account, password }),
})
body = await response.json()
} catch (error) {
console.error(`连不上后端 ${base}:${error.message}`)
console.error('先在 server/ 下起后端(legacy TLS 用这条):')
console.error(' mvn "-Dspring-boot.run.jvmArguments=-Djava.security.properties=./config/legacy-tls.security" spring-boot:run')
process.exit(1)
}
/* 后端鉴权失败返回 HTTP 200 + body.code=401(不是 HTTP 401),两个都要判。 */
if (body?.code !== 0 || !body?.data?.token) {
console.error(`登录失败(code=${body?.code}):${body?.message || '响应里没有 token'}`)
console.error(`用的账号:机构码 ${orgId} / 账号 ${account}${password ? ' / 密码已填' : ' / 密码为空'}`)
console.error('账号密码来自 web/.env.development 的 VITE_DEV_*,也可命令行覆盖。')
console.error('超管 g3soft 的密码在库里是空串;若你的库不是,传第三个参数指定密码。')
process.exit(1)
}
const { token, user } = body.data
/* ---------------- 输出 ---------------- */
if (tokenOnly) {
process.stdout.write(`${token}\n`)
} else {
console.log(`已登录:${orgId}/${account}(${user?.name || '未命名'})`)
console.log('')
console.log('token:')
console.log(token)
console.log('')
console.log('直接调业务接口(浏览器里不用这个,开发期页面已自动登录):')
console.log(` curl -H "Authorization: Bearer ${token}" ${base}/api/data/loaddata`)
}