优化后端构建方式,修改首页报表 bug

This commit is contained in:
eafonyang
2026-07-30 15:08:05 +08:00
parent f2bbaa6876
commit b1c88fc5e6
12 changed files with 56 additions and 54 deletions
+6 -13
View File
@@ -11,22 +11,15 @@ WORKDIR /app
# Create logs directory
RUN mkdir -p /app/logs
# Install dependencies (including devDependencies for build)
COPY package.json pnpm-lock.yaml ./
RUN corepack enable pnpm && pnpm install --frozen-lockfile
# Install production dependencies only
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
RUN corepack enable pnpm && pnpm install --frozen-lockfile --prod
# Copy application code
COPY tsconfig.json drizzle.config.ts ./
COPY src/ ./src/
# Build TypeScript → dist/
RUN pnpm build
# Remove devDependencies after build
RUN pnpm prune --prod
# Copy pre-built application
COPY dist/ ./dist/
# Expose port
EXPOSE 8000
# Run the compiled application
CMD ["node", "--conditions", "@zod/source", "dist/app.js"]
CMD ["node", "dist/app.js"]
+14 -14
View File
@@ -6,36 +6,36 @@
"type": "module",
"main": "dist/app.js",
"scripts": {
"dev": "tsx watch --conditions @zod/source src/app.ts",
"dev": "tsx watch src/app.ts",
"build": "tsc",
"start": "node --conditions @zod/source dist/app.js",
"start": "node dist/app.js",
"db:generate": "drizzle-kit generate",
"db:migrate": "drizzle-kit migrate",
"db:push": "drizzle-kit push",
"db:studio": "drizzle-kit studio"
},
"dependencies": {
"express": "^5.2",
"@aws-sdk/client-s3": "^3.1098",
"axios": "^1.19",
"cors": "^2.8",
"mysql2": "^3.23",
"dotenv": "^17.4",
"drizzle-orm": "^0.45",
"express": "^5.2",
"ioredis": "^5.11",
"jsonwebtoken": "^9.0",
"multer": "^2.2",
"axios": "^1.19",
"dotenv": "^17.4",
"zod": "^3.25",
"@aws-sdk/client-s3": "^3.1098",
"mysql2": "^3.23",
"winston": "^3.19",
"ioredis": "^5.11"
"zod": "^4.4.3"
},
"devDependencies": {
"tsx": "^4.23",
"typescript": "^7.0",
"drizzle-kit": "^0.31",
"@types/express": "^5.0",
"@types/cors": "^2.8",
"@types/express": "^5.0",
"@types/jsonwebtoken": "^9.0",
"@types/multer": "^2.2",
"@types/node": "^22.0"
"@types/node": "^22.0",
"drizzle-kit": "^0.31",
"tsx": "^4.23",
"typescript": "^7.0"
}
}
+5 -5
View File
@@ -42,8 +42,8 @@ importers:
specifier: ^3.19
version: 3.19.0
zod:
specifier: ^3.25
version: 3.25.0
specifier: ^4.4.3
version: 4.4.3
devDependencies:
'@types/cors':
specifier: ^2.8
@@ -1482,8 +1482,8 @@ packages:
wrappy@1.0.2:
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
zod@3.25.0:
resolution: {integrity: sha512-ficnZKUW0mlNivqeJkosTEkGbJ6NKCtSaOHGx5aXbtfeWMdRyzXLbAIn19my4C/KB7WPY/p9vlGPt+qpOp6c4Q==}
zod@4.4.3:
resolution: {integrity: sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==}
snapshots:
@@ -2778,4 +2778,4 @@ snapshots:
wrappy@1.0.2: {}
zod@3.25.0: {}
zod@4.4.3: {}
+1 -1
View File
@@ -46,4 +46,4 @@ echo "按 Ctrl+C 停止服务"
echo "================================================"
echo ""
exec node --conditions @zod/source dist/app.js
exec node dist/app.js
+2 -2
View File
@@ -139,7 +139,7 @@ router.post('/api/blacklist/', async (req: Request, res: Response) => {
try {
const parsed = BlackListCreateSchema.safeParse(req.body);
if (!parsed.success) {
const errors = parsed.error.errors.map((e) => e.message).join('; ');
const errors = parsed.error.issues.map((e: { message: string }) => e.message).join('; ');
res.json(ApiResponse.error(errors));
return;
}
@@ -174,7 +174,7 @@ router.put('/api/blacklist/:id', async (req: Request, res: Response) => {
const parsed = BlackListUpdateSchema.safeParse(req.body);
if (!parsed.success) {
const errors = parsed.error.errors.map((e) => e.message).join('; ');
const errors = parsed.error.issues.map((e: { message: string }) => e.message).join('; ');
res.json(ApiResponse.error(errors));
return;
}
+11 -3
View File
@@ -8,6 +8,14 @@ import { authMiddleware } from '../middleware/auth.js';
const router: RouterType = Router();
/** 格式化为本地日期字符串 YYYY-MM-DD(避免 toISOString 的 UTC 偏移) */
function toLocalDateStr(d: Date): string {
const y = d.getFullYear();
const m = String(d.getMonth() + 1).padStart(2, '0');
const day = String(d.getDate()).padStart(2, '0');
return `${y}-${m}-${day}`;
}
// 所有 dashboard 接口需登录
router.use(authMiddleware);
@@ -135,7 +143,7 @@ router.get('/api/dashboard/device-daily', async (req: Request, res: Response) =>
const dateList: string[] = [];
const tmp = new Date(startDate);
while (tmp <= now) {
dateList.push(tmp.toISOString().slice(0, 10));
dateList.push(toLocalDateStr(tmp));
tmp.setDate(tmp.getDate() + 1);
}
@@ -228,14 +236,14 @@ router.get('/api/dashboard/active-daily', async (req: Request, res: Response) =>
const dateList: string[] = [];
const tmp = new Date(startDate);
while (tmp <= now) {
dateList.push(tmp.toISOString().slice(0, 10));
dateList.push(toLocalDateStr(tmp));
tmp.setDate(tmp.getDate() + 1);
}
const modelSet = new Set<string>();
const dataMap = new Map<string, Record<string, number>>();
for (const row of rows) {
const dateStr = String(row.active_date).slice(0, 10);
const dateStr = toLocalDateStr(new Date(row.active_date));
modelSet.add(row.model);
if (!dataMap.has(dateStr)) dataMap.set(dateStr, {});
dataMap.get(dateStr)![row.model] = Number(row.count);
+2 -2
View File
@@ -184,7 +184,7 @@ router.post('/api/ota/', async (req: Request, res: Response) => {
try {
const parsed = OtaCreateSchema.safeParse(req.body);
if (!parsed.success) {
const errors = parsed.error.errors.map((e) => e.message).join('; ');
const errors = parsed.error.issues.map((e: { message: string }) => e.message).join('; ');
res.json(ApiResponse.error(errors));
return;
}
@@ -241,7 +241,7 @@ router.put('/api/ota/:ota_id', async (req: Request, res: Response) => {
const parsed = OtaUpdateSchema.safeParse(req.body);
if (!parsed.success) {
const errors = parsed.error.errors.map((e) => e.message).join('; ');
const errors = parsed.error.issues.map((e: { message: string }) => e.message).join('; ');
res.json(ApiResponse.error(errors));
return;
}
@@ -139,7 +139,7 @@ router.post('/api/ota-target-device/', async (req: Request, res: Response) => {
try {
const parsed = OtaTargetDeviceCreateSchema.safeParse(req.body);
if (!parsed.success) {
const errors = parsed.error.errors.map((e) => e.message).join('; ');
const errors = parsed.error.issues.map((e: { message: string }) => e.message).join('; ');
res.json(ApiResponse.error(errors));
return;
}
@@ -185,7 +185,7 @@ router.put('/api/ota-target-device/:id', async (req: Request, res: Response) =>
const parsed = OtaTargetDeviceUpdateSchema.safeParse(req.body);
if (!parsed.success) {
const errors = parsed.error.errors.map((e) => e.message).join('; ');
const errors = parsed.error.issues.map((e: { message: string }) => e.message).join('; ');
res.json(ApiResponse.error(errors));
return;
}
+1 -1
View File
@@ -20,4 +20,4 @@ echo "Building TypeScript..."
pnpm build
echo "Starting server..."
exec node --conditions @zod/source dist/app.js
exec node dist/app.js
-1
View File
@@ -3,7 +3,6 @@
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "bundler",
"customConditions": ["@zod/source"],
"esModuleInterop": true,
"strict": true,
"outDir": "dist",