webadmin端增加版本号和部署功能

This commit is contained in:
2026-07-12 13:52:22 +08:00
parent 63af3321dd
commit d271ac5b13
16 changed files with 329 additions and 5 deletions
@@ -11,4 +11,9 @@ export class AdminDashboardController {
stats() {
return this.dashboardService.getStats();
}
@Get('version')
version() {
return this.dashboardService.getLatestVersion();
}
}
@@ -65,4 +65,20 @@ export class AdminDashboardService {
})),
};
}
async getLatestVersion() {
const row = await this.prisma.systemVersion.findFirst({
orderBy: { deployedAt: 'desc' },
});
if (!row) return null;
return {
id: row.id.toString(),
gitTag: row.gitTag,
commitId: row.commitId,
commitMessage: row.commitMessage,
branch: row.branch,
deployedBy: row.deployedBy,
deployedAt: row.deployedAt.toISOString(),
};
}
}
@@ -0,0 +1,22 @@
import { Controller, Post, UseGuards } from '@nestjs/common';
import { HqAuthGuard } from '../../common/guards/hq-auth.guard';
import { SuperAdminGuard } from '../../common/guards/super-admin.guard';
import { HqOperation } from '../../common/hq-operation/hq-operation.decorator';
import { HqOperationAction } from '../../common/hq-operation/hq-operation.constants';
import { AdminDeployService } from './admin-deploy.service';
@Controller('admin/deploy')
@UseGuards(HqAuthGuard, SuperAdminGuard)
export class AdminDeployController {
constructor(private readonly deployService: AdminDeployService) {}
@Post('trigger')
@HqOperation({
action: HqOperationAction.DEPLOY_TRIGGER,
refType: 'DEPLOY',
batch: true,
})
trigger() {
return this.deployService.triggerDeploy();
}
}
@@ -0,0 +1,49 @@
import { BadRequestException, Injectable, ServiceUnavailableException } from '@nestjs/common';
@Injectable()
export class AdminDeployService {
async triggerDeploy() {
const url = (process.env.DEPLOY_WEBHOOK_URL || 'http://127.0.0.1:8095/deploy').trim();
const secret = (process.env.DEPLOY_WEBHOOK_SECRET || '').trim();
if (!secret) {
throw new ServiceUnavailableException('未配置 DEPLOY_WEBHOOK_SECRET,无法触发发布');
}
let res: Response;
try {
res = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Deploy-Token': secret,
},
body: JSON.stringify({ source: 'admin' }),
});
} catch (err) {
throw new ServiceUnavailableException(
`无法连接部署 webhook${err instanceof Error ? err.message : 'network error'}`,
);
}
const text = await res.text();
let data: { ok?: boolean; accepted?: boolean; started?: boolean; message?: string; skipped?: boolean } = {};
try {
data = text ? (JSON.parse(text) as typeof data) : {};
} catch {
throw new ServiceUnavailableException(`部署 webhook 返回非 JSONHTTP ${res.status}`);
}
if (res.status === 403) {
throw new BadRequestException(data.message || '部署 webhook 鉴权失败');
}
if (!res.ok && res.status !== 202) {
throw new ServiceUnavailableException(data.message || `部署 webhook 失败(HTTP ${res.status}`);
}
return {
accepted: true,
started: data.started !== false && !data.skipped,
message: data.message || (data.started === false ? 'deploy debounced' : 'deploy started'),
};
}
}
@@ -49,11 +49,14 @@ import { AdminWechatBindingsController } from './admin-wechat-bindings.controlle
import { AdminWechatBindingsService } from './admin-wechat-bindings.service';
import { AdminHqPermissionsController } from './admin-hq-permissions.controller';
import { AdminHqPermissionsService } from './admin-hq-permissions.service';
import { AdminDeployController } from './admin-deploy.controller';
import { AdminDeployService } from './admin-deploy.service';
@Module({
imports: [CityScopeModule, IamModule, TradeModule, BenefitModule, CommonModule, IntegrationsModule, RedeemModule],
controllers: [
AdminDashboardController,
AdminDeployController,
AdminUsersController,
AdminOrdersController,
AdminStoresController,
@@ -104,6 +107,7 @@ import { AdminHqPermissionsService } from './admin-hq-permissions.service';
AdminRedeemDebugService,
AdminWechatBindingsService,
AdminHqPermissionsService,
AdminDeployService,
SuperAdminGuard,
],
exports: [CityScopeModule],