/** * 把本地文件上传到 OSS `static/mini-user/`(不进小程序主包)。 * 凭证优先读 system_config,其次 server/dukang-api/.env。 * * 用法:node scripts/upload-mini-user-static.mjs [objectName] */ import { readFileSync, existsSync } from 'node:fs'; import { basename, resolve, dirname } from 'node:path'; import { fileURLToPath } from 'node:url'; import { createRequire } from 'node:module'; const __dirname = dirname(fileURLToPath(import.meta.url)); const root = resolve(__dirname, '..'); const apiRoot = resolve(root, 'server/dukang-api'); const require = createRequire(resolve(apiRoot, 'package.json')); const OSS = require('ali-oss'); const { PrismaClient } = require('@prisma/client'); function loadEnvFile(path) { if (!existsSync(path)) return; for (const line of readFileSync(path, 'utf8').split(/\r?\n/)) { const trimmed = line.trim(); if (!trimmed || trimmed.startsWith('#')) continue; const eq = trimmed.indexOf('='); if (eq <= 0) continue; const key = trimmed.slice(0, eq).trim(); let value = trimmed.slice(eq + 1).trim(); if ( (value.startsWith('"') && value.endsWith('"')) || (value.startsWith("'") && value.endsWith("'")) ) { value = value.slice(1, -1); } if (process.env[key] === undefined) process.env[key] = value; } } loadEnvFile(resolve(apiRoot, '.env')); loadEnvFile(resolve(apiRoot, '.env.local')); const localFile = process.argv[2]; if (!localFile) { console.error('用法:node scripts/upload-mini-user-static.mjs [objectName]'); process.exit(1); } const absFile = resolve(process.cwd(), localFile); if (!existsSync(absFile)) { console.error(`文件不存在:${absFile}`); process.exit(1); } const objectName = process.argv[3] || basename(absFile); const ossKey = `static/mini-user/${objectName.replace(/^\/+/, '')}`; const prisma = new PrismaClient(); const rows = await prisma.systemConfig.findMany({ where: { configKey: { in: [ 'OSS_ACCESS_KEY_ID', 'OSS_ACCESS_KEY_SECRET', 'OSS_BUCKET', 'OSS_REGION', 'OSS_ENDPOINT', 'OSS_CDN_BASE', 'OSS_AUTHORIZATION_V4', 'MINI_USER_STATIC_OSS_BASE', ], }, }, }); await prisma.$disconnect(); for (const row of rows) { if (row.value?.trim()) process.env[row.configKey] = row.value.trim(); } const accessKeyId = process.env.OSS_ACCESS_KEY_ID ?? ''; const accessKeySecret = process.env.OSS_ACCESS_KEY_SECRET ?? ''; const bucket = process.env.OSS_BUCKET ?? ''; const region = process.env.OSS_REGION ?? 'oss-cn-hangzhou'; const endpoint = process.env.OSS_ENDPOINT ?? ''; const cdnBase = (process.env.OSS_CDN_BASE ?? '').replace(/\/$/, ''); const staticBase = (process.env.MINI_USER_STATIC_OSS_BASE ?? '').replace(/\/$/, '/'); if (!accessKeyId || !accessKeySecret || !bucket) { console.error('OSS 未配置:请在 HQ 系统设置或 .env 填写 OSS_ACCESS_KEY_ID / SECRET / BUCKET'); process.exit(1); } const client = new OSS({ region, accessKeyId, accessKeySecret, bucket, ...(endpoint ? { endpoint } : {}), ...(process.env.OSS_AUTHORIZATION_V4 === 'true' ? { authorizationV4: true } : {}), }); const mime = absFile.endsWith('.png') ? 'image/png' : absFile.endsWith('.gif') ? 'image/gif' : absFile.endsWith('.jpg') || absFile.endsWith('.jpeg') ? 'image/jpeg' : 'application/octet-stream'; const result = await client.put(ossKey, absFile, { mime, headers: { 'Content-Disposition': 'inline', 'Cache-Control': 'public, max-age=31536000', }, }); const publicUrl = (staticBase ? `${staticBase}${objectName}` : '') || (cdnBase ? `${cdnBase}/${ossKey}` : result.url); console.log(`uploaded bucket=${bucket} region=${region}`); console.log(`key=${ossKey}`); console.log(`url=${publicUrl}`);