Compare commits

...

2 Commits

Author SHA1 Message Date
haomingming
b35ec1aef7 logo 2026-06-26 17:42:28 +08:00
haomingming
6804a7300f 34 2026-06-26 17:34:15 +08:00
23 changed files with 129 additions and 75 deletions

View File

@ -1,3 +0,0 @@
{
"pages": {}
}

View File

@ -1,16 +0,0 @@
{
"polyfillFiles": [
"static/chunks/polyfills.js"
],
"devFiles": [],
"ampDevFiles": [],
"lowPriorityFiles": [
"static/development/_buildManifest.js",
"static/development/_ssgManifest.js"
],
"rootMainFiles": [],
"pages": {
"/_app": []
},
"ampFirstPages": []
}

View File

@ -1 +0,0 @@
{"type": "commonjs"}

View File

@ -1 +0,0 @@
{}

View File

@ -1 +0,0 @@
{}

View File

@ -1 +0,0 @@
self.__INTERCEPTION_ROUTE_REWRITE_MANIFEST="[]"

View File

@ -1,18 +0,0 @@
self.__BUILD_MANIFEST = {
"polyfillFiles": [
"static/chunks/polyfills.js"
],
"devFiles": [],
"ampDevFiles": [],
"lowPriorityFiles": [],
"rootMainFiles": [],
"pages": {
"/_app": []
},
"ampFirstPages": []
};
self.__BUILD_MANIFEST.lowPriorityFiles = [
"/static/" + process.env.__NEXT_BUILD_ID + "/_buildManifest.js",
,"/static/" + process.env.__NEXT_BUILD_ID + "/_ssgManifest.js",
];

View File

@ -1,6 +0,0 @@
{
"version": 3,
"middleware": {},
"functions": {},
"sortedMiddleware": []
}

View File

@ -1 +0,0 @@
self.__REACT_LOADABLE_MANIFEST="{}"

View File

@ -1 +0,0 @@
self.__NEXT_FONT_MANIFEST="{\"pages\":{},\"app\":{},\"appUsingSizeAdjust\":false,\"pagesUsingSizeAdjust\":false}"

View File

@ -1 +0,0 @@
{"pages":{},"app":{},"appUsingSizeAdjust":false,"pagesUsingSizeAdjust":false}

View File

@ -1 +0,0 @@
{}

View File

@ -1 +0,0 @@
self.__RSC_SERVER_MANIFEST="{\n \"node\": {},\n \"edge\": {},\n \"encryptionKey\": \"process.env.NEXT_SERVER_ACTIONS_ENCRYPTION_KEY\"\n}"

View File

@ -1,5 +0,0 @@
{
"node": {},
"edge": {},
"encryptionKey": "29r7Ms7DcgtmNMSCLyvmj7peV+rATABBPVNlBdLbZzs="
}

File diff suppressed because one or more lines are too long

View File

@ -1 +0,0 @@
self.__BUILD_MANIFEST = {__rewrites:{afterFiles:[],beforeFiles:[],fallback:[]},sortedPages:["\u002F_app"]};self.__BUILD_MANIFEST_CB && self.__BUILD_MANIFEST_CB()

View File

@ -1 +0,0 @@
self.__SSG_MANIFEST=new Set;self.__SSG_MANIFEST_CB&&self.__SSG_MANIFEST_CB()

File diff suppressed because one or more lines are too long

View File

@ -1 +0,0 @@
{"type": "module"}

View File

@ -23,7 +23,8 @@ IMAGE_VERSION="v1.0.0"
USERNAME="742065561@qq.com" USERNAME="742065561@qq.com"
# Registry 登录密码 # Registry 登录密码
# 为安全起见,不在脚本中硬编码密码 # 为安全起见,不在脚本中硬编码密码 #vH#DYxZij8zk^Jr
echo "默认密码:#vH#DYxZij8zk^Jr"
PASSWORD="" PASSWORD=""
REGISTRY_HOST="registry.${REGISTRY_REGION}.aliyuncs.com" REGISTRY_HOST="registry.${REGISTRY_REGION}.aliyuncs.com"

View File

@ -36,8 +36,8 @@ export async function POST(request) {
const buffer = Buffer.from(await file.arrayBuffer()); const buffer = Buffer.from(await file.arrayBuffer());
fs.writeFileSync(filePath, buffer); fs.writeFileSync(filePath, buffer);
// 返回文件路径(相对于 public 的路径) // 返回动态访问路径,避免生产环境下 public 目录新增文件 404
const publicPath = `/uploads/${fileName}`; const publicPath = `/api/config/logo?file=${encodeURIComponent(fileName)}`;
return Response.json({ return Response.json({
path: publicPath, path: publicPath,
@ -51,3 +51,54 @@ export async function POST(request) {
); );
} }
} }
// GET /api/config/logo?file=xxx - 动态读取并返回 Logo 文件
export async function GET(request) {
try {
const { searchParams } = new URL(request.url);
const file = searchParams.get('file');
if (!file) {
return Response.json(
{ error: '缺少文件名' },
{ status: 400 }
);
}
const cleanFile = path.basename(file);
const filePath = path.join(process.cwd(), 'public', 'uploads', cleanFile);
if (!fs.existsSync(filePath)) {
return Response.json(
{ error: '文件不存在' },
{ status: 404 }
);
}
const buffer = fs.readFileSync(filePath);
const ext = path.extname(cleanFile).toLowerCase();
let contentType = 'application/octet-stream';
if (ext === '.png') contentType = 'image/png';
else if (ext === '.jpg' || ext === '.jpeg') contentType = 'image/jpeg';
else if (ext === '.gif') contentType = 'image/gif';
else if (ext === '.webp') contentType = 'image/webp';
else if (ext === '.bmp') contentType = 'image/bmp';
else if (ext === '.svg') contentType = 'image/svg+xml';
return new Response(buffer, {
headers: {
'Content-Type': contentType,
'Content-Length': buffer.length.toString(),
'Content-Disposition': `inline; filename="${encodeURIComponent(cleanFile)}"`,
'Cache-Control': 'public, max-age=31536000, immutable'
}
});
} catch (error) {
console.error('获取 Logo 失败:', error);
return Response.json(
{ error: '服务器内部错误' },
{ status: 500 }
);
}
}

View File

@ -2,15 +2,31 @@ export const dynamic = "force-dynamic";
import getDb from '@/lib/db'; import getDb from '@/lib/db';
import { getUserFromRequest, unauthorizedResponse, forbiddenResponse, checkRole } from '@/lib/auth'; import { getUserFromRequest, unauthorizedResponse, forbiddenResponse, checkRole } from '@/lib/auth';
function normalizeConfig(configs) {
const result = {};
for (const config of configs) {
let value = config.config_value;
if (config.config_key === 'company_logo' && value) {
const match = value.match(/^\/uploads\/(.+)$/);
if (match) {
value = `/api/config/logo?file=${encodeURIComponent(match[1])}`;
}
}
result[config.config_key] = value;
}
return result;
}
// GET /api/config - 获取系统配置(公开,无需认证) // GET /api/config - 获取系统配置(公开,无需认证)
export async function GET() { export async function GET() {
try { try {
const db = await getDb(); const db = await getDb();
const configs = db.prepare('SELECT config_key, config_value FROM system_config').all(); const configs = db.prepare('SELECT config_key, config_value FROM system_config').all();
const result = {}; const result = normalizeConfig(configs);
for (const config of configs) {
result[config.config_key] = config.config_value;
}
return Response.json(result); return Response.json(result);
} catch (error) { } catch (error) {
console.error('获取系统配置失败:', error); console.error('获取系统配置失败:', error);
@ -46,12 +62,8 @@ export async function PUT(request) {
}); });
updateMany(); updateMany();
// 返回更新后的配置
const configs = db.prepare('SELECT config_key, config_value FROM system_config').all(); const configs = db.prepare('SELECT config_key, config_value FROM system_config').all();
const result = {}; const result = normalizeConfig(configs);
for (const config of configs) {
result[config.config_key] = config.config_value;
}
return Response.json(result); return Response.json(result);
} catch (error) { } catch (error) {
console.error('更新系统配置失败:', error); console.error('更新系统配置失败:', error);

View File

@ -0,0 +1,53 @@
export const dynamic = "force-dynamic";
import path from 'path';
import fs from 'fs';
// GET /uploads/:file - 兼容历史 Logo 直链
export async function GET(request, { params }) {
try {
const file = params?.file;
if (!file) {
return Response.json(
{ error: '缺少文件名' },
{ status: 400 }
);
}
const cleanFile = path.basename(file);
const filePath = path.join(process.cwd(), 'public', 'uploads', cleanFile);
if (!fs.existsSync(filePath)) {
return Response.json(
{ error: '文件不存在' },
{ status: 404 }
);
}
const buffer = fs.readFileSync(filePath);
const ext = path.extname(cleanFile).toLowerCase();
let contentType = 'application/octet-stream';
if (ext === '.png') contentType = 'image/png';
else if (ext === '.jpg' || ext === '.jpeg') contentType = 'image/jpeg';
else if (ext === '.gif') contentType = 'image/gif';
else if (ext === '.webp') contentType = 'image/webp';
else if (ext === '.bmp') contentType = 'image/bmp';
else if (ext === '.svg') contentType = 'image/svg+xml';
return new Response(buffer, {
headers: {
'Content-Type': contentType,
'Content-Length': buffer.length.toString(),
'Content-Disposition': `inline; filename="${encodeURIComponent(cleanFile)}"`,
'Cache-Control': 'public, max-age=31536000, immutable'
}
});
} catch (error) {
console.error('获取上传文件失败:', error);
return Response.json(
{ error: '服务器内部错误' },
{ status: 500 }
);
}
}