增加核销接口
增加hq管理端日志
This commit is contained in:
@@ -16,6 +16,7 @@ import { AnalyticsModule } from './modules/analytics/analytics.module';
|
||||
import { JobsModule } from './jobs/jobs.module';
|
||||
import { OpsModule } from './modules/ops/ops.module';
|
||||
import { CommonModule } from './modules/common/common.module';
|
||||
import { HqOperationModule } from './common/hq-operation/hq-operation.module';
|
||||
import { CallbacksModule } from './callbacks/callbacks.module';
|
||||
|
||||
@Module({
|
||||
@@ -41,6 +42,7 @@ import { CallbacksModule } from './callbacks/callbacks.module';
|
||||
JobsModule,
|
||||
OpsModule,
|
||||
CommonModule,
|
||||
HqOperationModule,
|
||||
CallbacksModule,
|
||||
],
|
||||
})
|
||||
|
||||
@@ -65,3 +65,53 @@ export function orderStatusLogWhere(orderId: bigint): Prisma.CommonEventWhereInp
|
||||
refId: orderId,
|
||||
};
|
||||
}
|
||||
|
||||
export function buildHqOperationEvent(data: {
|
||||
hqAccountId: bigint;
|
||||
action: string;
|
||||
refType: string;
|
||||
refId: bigint;
|
||||
status?: string;
|
||||
detail?: Record<string, unknown>;
|
||||
remark?: string;
|
||||
}): Prisma.CommonEventCreateInput {
|
||||
return {
|
||||
eventType: 'HQ_OPERATION',
|
||||
refType: data.refType,
|
||||
refId: data.refId,
|
||||
actorType: 'HQ',
|
||||
actorId: data.hqAccountId,
|
||||
status: data.status,
|
||||
param1: data.action,
|
||||
param1Desc: 'action',
|
||||
param2: data.refType,
|
||||
param2Desc: 'target_type',
|
||||
param3: data.refId.toString(),
|
||||
param3Desc: 'target_id',
|
||||
remark: data.remark,
|
||||
extraJson: data.detail as Prisma.InputJsonValue,
|
||||
};
|
||||
}
|
||||
|
||||
export function hqOperationLogWhere(filters?: {
|
||||
hqAccountId?: bigint;
|
||||
action?: string;
|
||||
refType?: string;
|
||||
from?: Date;
|
||||
to?: Date;
|
||||
}): Prisma.CommonEventWhereInput {
|
||||
return {
|
||||
eventType: 'HQ_OPERATION',
|
||||
...(filters?.hqAccountId ? { actorType: 'HQ' as const, actorId: filters.hqAccountId } : {}),
|
||||
...(filters?.action ? { param1: filters.action } : {}),
|
||||
...(filters?.refType ? { param2: filters.refType } : {}),
|
||||
...(filters?.from || filters?.to
|
||||
? {
|
||||
createdAt: {
|
||||
...(filters.from ? { gte: filters.from } : {}),
|
||||
...(filters.to ? { lte: filters.to } : {}),
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { PrismaService } from '../prisma/prisma.module';
|
||||
import { buildHqOperationEvent } from '../event/event.helpers';
|
||||
|
||||
export type LogHqOperationInput = {
|
||||
hqAccountId: bigint;
|
||||
action: string;
|
||||
refType: string;
|
||||
refId: bigint;
|
||||
status?: string;
|
||||
detail?: Record<string, unknown>;
|
||||
remark?: string;
|
||||
};
|
||||
|
||||
@Injectable()
|
||||
export class HqOperationLogService {
|
||||
constructor(private readonly prisma: PrismaService) {}
|
||||
|
||||
async log(input: LogHqOperationInput): Promise<void> {
|
||||
await this.prisma.commonEvent.create({
|
||||
data: buildHqOperationEvent(input),
|
||||
});
|
||||
}
|
||||
|
||||
logSafe(input: LogHqOperationInput): void {
|
||||
void this.log(input).catch((err) => {
|
||||
console.error('[HqOperationLog] write failed', err);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
/** HQ 后台写操作审计 action(写入 common_event.param1) */
|
||||
export const HqOperationAction = {
|
||||
CITY_CREATE: 'CITY_CREATE',
|
||||
CITY_UPDATE: 'CITY_UPDATE',
|
||||
PARTNER_CREATE: 'PARTNER_CREATE',
|
||||
PARTNER_UPDATE: 'PARTNER_UPDATE',
|
||||
PARTNER_ACCOUNT_CREATE: 'PARTNER_ACCOUNT_CREATE',
|
||||
PARTNER_ACCOUNT_UPDATE: 'PARTNER_ACCOUNT_UPDATE',
|
||||
HQ_ACCOUNT_CREATE: 'HQ_ACCOUNT_CREATE',
|
||||
HQ_ACCOUNT_UPDATE: 'HQ_ACCOUNT_UPDATE',
|
||||
USER_DELETE: 'USER_DELETE',
|
||||
USER_BATCH_DELETE: 'USER_BATCH_DELETE',
|
||||
ORDER_SHIP: 'ORDER_SHIP',
|
||||
ORDER_STATUS_DEBUG: 'ORDER_STATUS_DEBUG',
|
||||
ORDER_BATCH_DELETE: 'ORDER_BATCH_DELETE',
|
||||
STORE_CREATE: 'STORE_CREATE',
|
||||
STORE_UPDATE: 'STORE_UPDATE',
|
||||
STORE_STATUS: 'STORE_STATUS',
|
||||
STORE_AUDIT: 'STORE_AUDIT',
|
||||
STORE_ACCOUNT_CREATE: 'STORE_ACCOUNT_CREATE',
|
||||
STORE_ACCOUNT_UPDATE: 'STORE_ACCOUNT_UPDATE',
|
||||
STORE_MEDIA_CREATE: 'STORE_MEDIA_CREATE',
|
||||
STORE_MEDIA_UPDATE: 'STORE_MEDIA_UPDATE',
|
||||
STORE_MEDIA_DELETE: 'STORE_MEDIA_DELETE',
|
||||
PRODUCT_CREATE: 'PRODUCT_CREATE',
|
||||
PRODUCT_UPDATE: 'PRODUCT_UPDATE',
|
||||
PRODUCT_DELETE: 'PRODUCT_DELETE',
|
||||
PRODUCT_TEMPLATE_CREATE: 'PRODUCT_TEMPLATE_CREATE',
|
||||
PRODUCT_TEMPLATE_UPDATE: 'PRODUCT_TEMPLATE_UPDATE',
|
||||
BENEFIT_COUPON_VOID: 'BENEFIT_COUPON_VOID',
|
||||
DELIVERY_UPDATE: 'DELIVERY_UPDATE',
|
||||
TICKET_APPROVE: 'TICKET_APPROVE',
|
||||
TICKET_REJECT: 'TICKET_REJECT',
|
||||
STORE_PAYOUT_CONFIRM: 'STORE_PAYOUT_CONFIRM',
|
||||
STORE_PAYOUT_BATCH_CONFIRM: 'STORE_PAYOUT_BATCH_CONFIRM',
|
||||
PARTNER_BILL_GENERATE: 'PARTNER_BILL_GENERATE',
|
||||
PARTNER_BILL_CONFIRM: 'PARTNER_BILL_CONFIRM',
|
||||
PARTNER_BILL_MARK_PAID: 'PARTNER_BILL_MARK_PAID',
|
||||
REDEEM_DEBUG_CREATE_TOKEN: 'REDEEM_DEBUG_CREATE_TOKEN',
|
||||
REDEEM_DEBUG_CONFIRM: 'REDEEM_DEBUG_CONFIRM',
|
||||
} as const;
|
||||
|
||||
export type HqOperationActionCode = (typeof HqOperationAction)[keyof typeof HqOperationAction];
|
||||
|
||||
export const HQ_OPERATION_ACTION_LABELS: Record<string, string> = {
|
||||
[HqOperationAction.CITY_CREATE]: '新增开城城市',
|
||||
[HqOperationAction.CITY_UPDATE]: '编辑开城城市',
|
||||
[HqOperationAction.PARTNER_CREATE]: '新增城市合伙人',
|
||||
[HqOperationAction.PARTNER_UPDATE]: '编辑城市合伙人',
|
||||
[HqOperationAction.PARTNER_ACCOUNT_CREATE]: '新增合伙人账户',
|
||||
[HqOperationAction.PARTNER_ACCOUNT_UPDATE]: '编辑合伙人账户',
|
||||
[HqOperationAction.HQ_ACCOUNT_CREATE]: '新增 HQ 管理员',
|
||||
[HqOperationAction.HQ_ACCOUNT_UPDATE]: '编辑 HQ 管理员/权限',
|
||||
[HqOperationAction.USER_DELETE]: '删除用户',
|
||||
[HqOperationAction.USER_BATCH_DELETE]: '批量删除用户',
|
||||
[HqOperationAction.ORDER_SHIP]: '订单发货',
|
||||
[HqOperationAction.ORDER_STATUS_DEBUG]: '订单状态调试',
|
||||
[HqOperationAction.ORDER_BATCH_DELETE]: '批量删除订单',
|
||||
[HqOperationAction.STORE_CREATE]: '新增门店',
|
||||
[HqOperationAction.STORE_UPDATE]: '编辑门店',
|
||||
[HqOperationAction.STORE_STATUS]: '变更门店状态',
|
||||
[HqOperationAction.STORE_AUDIT]: '门店审核',
|
||||
[HqOperationAction.STORE_ACCOUNT_CREATE]: '新增门店账户',
|
||||
[HqOperationAction.STORE_ACCOUNT_UPDATE]: '编辑门店账户',
|
||||
[HqOperationAction.STORE_MEDIA_CREATE]: '新增门店资源',
|
||||
[HqOperationAction.STORE_MEDIA_UPDATE]: '编辑门店资源',
|
||||
[HqOperationAction.STORE_MEDIA_DELETE]: '删除门店资源',
|
||||
[HqOperationAction.PRODUCT_CREATE]: '新增商品',
|
||||
[HqOperationAction.PRODUCT_UPDATE]: '编辑商品',
|
||||
[HqOperationAction.PRODUCT_DELETE]: '删除商品',
|
||||
[HqOperationAction.PRODUCT_TEMPLATE_CREATE]: '新增详情模板',
|
||||
[HqOperationAction.PRODUCT_TEMPLATE_UPDATE]: '编辑详情模板',
|
||||
[HqOperationAction.BENEFIT_COUPON_VOID]: '作废权益券',
|
||||
[HqOperationAction.DELIVERY_UPDATE]: '编辑配送单',
|
||||
[HqOperationAction.TICKET_APPROVE]: '工单通过',
|
||||
[HqOperationAction.TICKET_REJECT]: '工单驳回',
|
||||
[HqOperationAction.STORE_PAYOUT_CONFIRM]: '门店打款确认',
|
||||
[HqOperationAction.STORE_PAYOUT_BATCH_CONFIRM]: '批量门店打款',
|
||||
[HqOperationAction.PARTNER_BILL_GENERATE]: '生成合伙人账单',
|
||||
[HqOperationAction.PARTNER_BILL_CONFIRM]: '确认合伙人账单',
|
||||
[HqOperationAction.PARTNER_BILL_MARK_PAID]: '合伙人账单结算',
|
||||
[HqOperationAction.REDEEM_DEBUG_CREATE_TOKEN]: '核销调试-生成码',
|
||||
[HqOperationAction.REDEEM_DEBUG_CONFIRM]: '核销调试-确认核销',
|
||||
STORE_PAYOUT: '门店打款确认',
|
||||
};
|
||||
|
||||
export function resolveHqOperationLabel(action: string | null | undefined, refType?: string | null): string {
|
||||
if (action && HQ_OPERATION_ACTION_LABELS[action]) {
|
||||
return HQ_OPERATION_ACTION_LABELS[action];
|
||||
}
|
||||
if (refType && HQ_OPERATION_ACTION_LABELS[refType]) {
|
||||
return HQ_OPERATION_ACTION_LABELS[refType];
|
||||
}
|
||||
return action || refType || 'HQ 操作';
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import { SetMetadata } from '@nestjs/common';
|
||||
import type { HqOperationActionCode } from './hq-operation.constants';
|
||||
|
||||
export const HQ_OPERATION_KEY = 'hq_operation';
|
||||
|
||||
export type HqOperationMeta = {
|
||||
action: HqOperationActionCode | string;
|
||||
refType: string;
|
||||
/** 从路由 params 取 refId */
|
||||
refIdParam?: string;
|
||||
/** 从响应体字段取 refId,默认 id */
|
||||
refIdField?: string;
|
||||
/** 批量操作无单一 refId 时用 0 */
|
||||
batch?: boolean;
|
||||
/** 记录请求体到 extraJson */
|
||||
includeBody?: boolean;
|
||||
/** 记录响应体到 extraJson(截断) */
|
||||
includeResponse?: boolean;
|
||||
};
|
||||
|
||||
export const HqOperation = (meta: HqOperationMeta) => SetMetadata(HQ_OPERATION_KEY, meta);
|
||||
@@ -0,0 +1,103 @@
|
||||
import {
|
||||
CallHandler,
|
||||
ExecutionContext,
|
||||
Injectable,
|
||||
NestInterceptor,
|
||||
} from '@nestjs/common';
|
||||
import { Reflector } from '@nestjs/core';
|
||||
import { Observable, tap } from 'rxjs';
|
||||
import type { AuthUser } from '../guards/jwt-auth.guard';
|
||||
import { HQ_OPERATION_KEY, type HqOperationMeta } from './hq-operation.decorator';
|
||||
import { HqOperationLogService } from './hq-operation-log.service';
|
||||
|
||||
function pickRefId(value: unknown): bigint | null {
|
||||
if (value == null || value === '') return null;
|
||||
try {
|
||||
return BigInt(String(value));
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function sanitizeBody(body: unknown): unknown {
|
||||
if (!body || typeof body !== 'object') return body;
|
||||
const copy = { ...(body as Record<string, unknown>) };
|
||||
for (const key of Object.keys(copy)) {
|
||||
if (/password|secret|token/i.test(key)) {
|
||||
copy[key] = '***';
|
||||
}
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
function summarizeResponse(data: unknown): unknown {
|
||||
if (data == null) return null;
|
||||
if (typeof data !== 'object') return data;
|
||||
const obj = data as Record<string, unknown>;
|
||||
const summary: Record<string, unknown> = {};
|
||||
for (const key of ['id', 'ok', 'deleted', 'orderNo', 'userNo', 'redeemNo', 'message', 'status']) {
|
||||
if (obj[key] !== undefined) summary[key] = obj[key];
|
||||
}
|
||||
if (Array.isArray(obj.items)) {
|
||||
summary.itemCount = obj.items.length;
|
||||
}
|
||||
if (Array.isArray(obj.orderNos)) {
|
||||
summary.orderNos = obj.orderNos;
|
||||
}
|
||||
return Object.keys(summary).length ? summary : obj;
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class HqOperationInterceptor implements NestInterceptor {
|
||||
constructor(
|
||||
private readonly reflector: Reflector,
|
||||
private readonly logService: HqOperationLogService,
|
||||
) {}
|
||||
|
||||
intercept(context: ExecutionContext, next: CallHandler): Observable<unknown> {
|
||||
const meta = this.reflector.get<HqOperationMeta | undefined>(
|
||||
HQ_OPERATION_KEY,
|
||||
context.getHandler(),
|
||||
);
|
||||
if (!meta) return next.handle();
|
||||
|
||||
const req = context.switchToHttp().getRequest();
|
||||
const user = req.user as AuthUser | undefined;
|
||||
if (!user || user.actorType !== 'HQ') {
|
||||
return next.handle();
|
||||
}
|
||||
|
||||
return next.handle().pipe(
|
||||
tap((data) => {
|
||||
const refId = meta.batch
|
||||
? 0n
|
||||
: pickRefId(meta.refIdParam ? req.params?.[meta.refIdParam] : null)
|
||||
?? pickRefId(
|
||||
meta.refIdField
|
||||
? (data as Record<string, unknown> | null)?.[meta.refIdField]
|
||||
: (data as Record<string, unknown> | null)?.id,
|
||||
)
|
||||
?? 0n;
|
||||
|
||||
const detail: Record<string, unknown> = {
|
||||
method: req.method,
|
||||
path: req.originalUrl ?? req.url,
|
||||
};
|
||||
if (meta.includeBody && req.body) {
|
||||
detail.requestBody = sanitizeBody(req.body);
|
||||
}
|
||||
if (meta.includeResponse !== false && data != null) {
|
||||
detail.response = summarizeResponse(data);
|
||||
}
|
||||
|
||||
this.logService.logSafe({
|
||||
hqAccountId: user.actorId,
|
||||
action: meta.action,
|
||||
refType: meta.refType,
|
||||
refId,
|
||||
detail,
|
||||
});
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { APP_INTERCEPTOR } from '@nestjs/core';
|
||||
import { HqOperationLogService } from './hq-operation-log.service';
|
||||
import { HqOperationInterceptor } from './hq-operation.interceptor';
|
||||
|
||||
@Module({
|
||||
providers: [
|
||||
HqOperationLogService,
|
||||
HqOperationInterceptor,
|
||||
{
|
||||
provide: APP_INTERCEPTOR,
|
||||
useClass: HqOperationInterceptor,
|
||||
},
|
||||
],
|
||||
exports: [HqOperationLogService],
|
||||
})
|
||||
export class HqOperationModule {}
|
||||
@@ -1,5 +1,7 @@
|
||||
import { Controller, Get, Param, Post, Query, UseGuards } from '@nestjs/common';
|
||||
import { HqAuthGuard } from '../../common/guards/hq-auth.guard';
|
||||
import { HqOperation } from '../../common/hq-operation/hq-operation.decorator';
|
||||
import { HqOperationAction } from '../../common/hq-operation/hq-operation.constants';
|
||||
import { AdminBenefitService } from './admin-benefit.service';
|
||||
import { AdminBenefitCouponsQueryDto, AdminBenefitLedgersQueryDto } from './dto/admin-query.dto';
|
||||
|
||||
@@ -19,6 +21,7 @@ export class AdminBenefitCouponsController {
|
||||
}
|
||||
|
||||
@Post(':id/void')
|
||||
@HqOperation({ action: HqOperationAction.BENEFIT_COUPON_VOID, refType: 'BENEFIT_COUPON', refIdParam: 'id' })
|
||||
voidCoupon(@Param('id') id: string) {
|
||||
return this.service.voidCoupon(BigInt(id));
|
||||
}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { Controller, Get, Param, Post, Put, Query, UseGuards } from '@nestjs/common';
|
||||
import { Body, Controller, Get, Param, Post, Put, Query, UseGuards } from '@nestjs/common';
|
||||
import { HqAuthGuard } from '../../common/guards/hq-auth.guard';
|
||||
import { HqOperation } from '../../common/hq-operation/hq-operation.decorator';
|
||||
import { HqOperationAction } from '../../common/hq-operation/hq-operation.constants';
|
||||
import { AdminCitiesService } from './admin-cities.service';
|
||||
import { AdminCitiesQueryDto } from './dto/admin-query.dto';
|
||||
import { CreateCityDto, UpdateCityDto } from './dto/admin-mutate.dto';
|
||||
import { Body } from '@nestjs/common';
|
||||
|
||||
@Controller('admin/cities')
|
||||
@UseGuards(HqAuthGuard)
|
||||
@@ -21,11 +22,18 @@ export class AdminCitiesController {
|
||||
}
|
||||
|
||||
@Post()
|
||||
@HqOperation({ action: HqOperationAction.CITY_CREATE, refType: 'CITY', refIdField: 'id', includeBody: true })
|
||||
create(@Body() dto: CreateCityDto) {
|
||||
return this.service.create(dto);
|
||||
}
|
||||
|
||||
@Put(':id')
|
||||
@HqOperation({
|
||||
action: HqOperationAction.CITY_UPDATE,
|
||||
refType: 'CITY',
|
||||
refIdParam: 'id',
|
||||
includeBody: true,
|
||||
})
|
||||
update(@Param('id') id: string, @Body() dto: UpdateCityDto) {
|
||||
return this.service.update(BigInt(id), dto);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { Body, Controller, Get, Param, Post, Put, Query, 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 { AdminHqAccountsService } from './admin-hq-accounts.service';
|
||||
import { AdminHqAccountsQueryDto } from './dto/admin-query.dto';
|
||||
import { CreateHqAccountDto, UpdateHqAccountDto } from './dto/admin-mutate.dto';
|
||||
@@ -22,12 +24,24 @@ export class AdminHqAccountsController {
|
||||
|
||||
@Post()
|
||||
@UseGuards(SuperAdminGuard)
|
||||
@HqOperation({
|
||||
action: HqOperationAction.HQ_ACCOUNT_CREATE,
|
||||
refType: 'HQ_ACCOUNT',
|
||||
refIdField: 'id',
|
||||
includeBody: true,
|
||||
})
|
||||
create(@Body() dto: CreateHqAccountDto) {
|
||||
return this.service.create(dto);
|
||||
}
|
||||
|
||||
@Put(':id')
|
||||
@UseGuards(SuperAdminGuard)
|
||||
@HqOperation({
|
||||
action: HqOperationAction.HQ_ACCOUNT_UPDATE,
|
||||
refType: 'HQ_ACCOUNT',
|
||||
refIdParam: 'id',
|
||||
includeBody: true,
|
||||
})
|
||||
update(@Param('id') id: string, @Body() dto: UpdateHqAccountDto) {
|
||||
return this.service.update(BigInt(id), dto);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
import { Controller, Get, Param, Query, UseGuards } from '@nestjs/common';
|
||||
import { HqAuthGuard } from '../../common/guards/hq-auth.guard';
|
||||
import { AdminHqLogsService } from './admin-hq-logs.service';
|
||||
import { AdminHqLogsQueryDto } from './dto/admin-query.dto';
|
||||
|
||||
@Controller('admin/logs/hq')
|
||||
@UseGuards(HqAuthGuard)
|
||||
export class AdminHqLogsController {
|
||||
constructor(private readonly service: AdminHqLogsService) {}
|
||||
|
||||
@Get()
|
||||
list(@Query() query: AdminHqLogsQueryDto) {
|
||||
return this.service.list(query);
|
||||
}
|
||||
|
||||
@Get(':id')
|
||||
detail(@Param('id') id: string) {
|
||||
return this.service.detail(BigInt(id));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
import { Injectable, NotFoundException } from '@nestjs/common';
|
||||
import { PrismaService } from '../../common/prisma/prisma.module';
|
||||
import { serializeBigInt } from '../../common/decorators/current-user.decorator';
|
||||
import { hqOperationLogWhere } from '../../common/event/event.helpers';
|
||||
import { resolveHqOperationLabel } from '../../common/hq-operation/hq-operation.constants';
|
||||
import type { AdminHqLogsQueryDto } from './dto/admin-query.dto';
|
||||
|
||||
@Injectable()
|
||||
export class AdminHqLogsService {
|
||||
constructor(private readonly prisma: PrismaService) {}
|
||||
|
||||
async list(query: AdminHqLogsQueryDto) {
|
||||
const page = query.page ?? 1;
|
||||
const pageSize = query.pageSize ?? 20;
|
||||
const where = hqOperationLogWhere({
|
||||
hqAccountId: query.hqAccountId ? BigInt(query.hqAccountId) : undefined,
|
||||
action: query.action,
|
||||
refType: query.refType,
|
||||
from: query.from ? new Date(query.from) : undefined,
|
||||
to: query.to ? new Date(query.to) : undefined,
|
||||
});
|
||||
|
||||
const [rows, total] = await Promise.all([
|
||||
this.prisma.commonEvent.findMany({
|
||||
where,
|
||||
orderBy: { createdAt: 'desc' },
|
||||
skip: (page - 1) * pageSize,
|
||||
take: pageSize,
|
||||
}),
|
||||
this.prisma.commonEvent.count({ where }),
|
||||
]);
|
||||
|
||||
const hqIds = [...new Set(rows.map((r) => r.actorId).filter((id): id is bigint => id != null))];
|
||||
const hqAccounts = hqIds.length
|
||||
? await this.prisma.hqAccount.findMany({
|
||||
where: { id: { in: hqIds } },
|
||||
select: { id: true, name: true, phone: true, adminRole: true },
|
||||
})
|
||||
: [];
|
||||
const hqMap = new Map(hqAccounts.map((a) => [a.id.toString(), a]));
|
||||
|
||||
return serializeBigInt({
|
||||
items: rows.map((row) => {
|
||||
const hq = row.actorId ? hqMap.get(row.actorId.toString()) : undefined;
|
||||
const action = row.param1Desc === 'action' ? row.param1 : row.param1;
|
||||
return {
|
||||
id: row.id,
|
||||
hqAccountId: row.actorId,
|
||||
hqName: hq?.name ?? null,
|
||||
hqPhone: hq?.phone ?? null,
|
||||
hqRole: hq?.adminRole ?? null,
|
||||
action,
|
||||
actionLabel: resolveHqOperationLabel(action, row.refType),
|
||||
refType: row.param2Desc === 'target_type' ? row.param2 : row.refType,
|
||||
refId: row.param3Desc === 'target_id' ? row.param3 : row.refId.toString(),
|
||||
status: row.status,
|
||||
remark: row.remark,
|
||||
detail: row.extraJson,
|
||||
createdAt: row.createdAt,
|
||||
};
|
||||
}),
|
||||
total,
|
||||
page,
|
||||
pageSize,
|
||||
});
|
||||
}
|
||||
|
||||
async detail(id: bigint) {
|
||||
const row = await this.prisma.commonEvent.findFirst({
|
||||
where: { id, eventType: 'HQ_OPERATION' },
|
||||
});
|
||||
if (!row) throw new NotFoundException('操作日志不存在');
|
||||
|
||||
const hq = row.actorId
|
||||
? await this.prisma.hqAccount.findUnique({
|
||||
where: { id: row.actorId },
|
||||
select: { id: true, name: true, phone: true, adminRole: true },
|
||||
})
|
||||
: null;
|
||||
|
||||
const action = row.param1Desc === 'action' ? row.param1 : row.param1;
|
||||
return serializeBigInt({
|
||||
id: row.id,
|
||||
hqAccountId: row.actorId,
|
||||
hqAccount: hq,
|
||||
action,
|
||||
actionLabel: resolveHqOperationLabel(action, row.refType),
|
||||
refType: row.param2Desc === 'target_type' ? row.param2 : row.refType,
|
||||
refId: row.param3Desc === 'target_id' ? row.param3 : row.refId.toString(),
|
||||
status: row.status,
|
||||
remark: row.remark,
|
||||
detail: row.extraJson,
|
||||
createdAt: row.createdAt,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
import { Body, Controller, Get, Param, Post, Put, Query, 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 { AdminOrdersService } from './admin-orders.service';
|
||||
import { AdminShipOrderDto, BatchDeleteOrdersDto, UpdateOrderStatusDto } from './dto/admin-mutate.dto';
|
||||
import { AdminOrdersQueryDto } from './dto/admin-query.dto';
|
||||
@@ -17,6 +19,12 @@ export class AdminOrdersController {
|
||||
|
||||
@Post('batch-delete')
|
||||
@UseGuards(SuperAdminGuard)
|
||||
@HqOperation({
|
||||
action: HqOperationAction.ORDER_BATCH_DELETE,
|
||||
refType: 'ORDER',
|
||||
batch: true,
|
||||
includeBody: true,
|
||||
})
|
||||
batchDelete(@Body() dto: BatchDeleteOrdersDto) {
|
||||
return this.ordersService.batchDeleteOrders(dto.ids.map((id) => BigInt(id)));
|
||||
}
|
||||
@@ -33,12 +41,24 @@ export class AdminOrdersController {
|
||||
|
||||
/** HQ 发货:调用小飞侠创建运单并更新配送信息 */
|
||||
@Post(':id/ship')
|
||||
@HqOperation({
|
||||
action: HqOperationAction.ORDER_SHIP,
|
||||
refType: 'ORDER',
|
||||
refIdParam: 'id',
|
||||
includeBody: true,
|
||||
})
|
||||
ship(@Param('id') id: string, @Body() dto: AdminShipOrderDto) {
|
||||
return this.ordersService.shipOrder(BigInt(id), dto);
|
||||
}
|
||||
|
||||
/** preV1 调试:直接改订单状态,不走业务校验 */
|
||||
@Put(':id/status')
|
||||
@HqOperation({
|
||||
action: HqOperationAction.ORDER_STATUS_DEBUG,
|
||||
refType: 'ORDER',
|
||||
refIdParam: 'id',
|
||||
includeBody: true,
|
||||
})
|
||||
updateStatus(@Param('id') id: string, @Body() dto: UpdateOrderStatusDto) {
|
||||
return this.ordersService.updateStatusDebug(BigInt(id), dto.status);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { Body, Controller, Get, Param, Post, Put, Query, UseGuards } from '@nestjs/common';
|
||||
import { HqAuthGuard } from '../../common/guards/hq-auth.guard';
|
||||
import { HqOperation } from '../../common/hq-operation/hq-operation.decorator';
|
||||
import { HqOperationAction } from '../../common/hq-operation/hq-operation.constants';
|
||||
import { AdminPartnersService } from './admin-partners.service';
|
||||
import { AdminPartnerAccountsQueryDto, AdminPartnersQueryDto } from './dto/admin-query.dto';
|
||||
import {
|
||||
@@ -25,11 +27,23 @@ export class AdminPartnersController {
|
||||
}
|
||||
|
||||
@Post()
|
||||
@HqOperation({
|
||||
action: HqOperationAction.PARTNER_CREATE,
|
||||
refType: 'PARTNER',
|
||||
refIdField: 'id',
|
||||
includeBody: true,
|
||||
})
|
||||
create(@Body() dto: CreatePartnerDto) {
|
||||
return this.service.createPartner(dto);
|
||||
}
|
||||
|
||||
@Put(':id')
|
||||
@HqOperation({
|
||||
action: HqOperationAction.PARTNER_UPDATE,
|
||||
refType: 'PARTNER',
|
||||
refIdParam: 'id',
|
||||
includeBody: true,
|
||||
})
|
||||
update(@Param('id') id: string, @Body() dto: UpdatePartnerDto) {
|
||||
return this.service.updatePartner(BigInt(id), dto);
|
||||
}
|
||||
@@ -51,11 +65,23 @@ export class AdminPartnerAccountsController {
|
||||
}
|
||||
|
||||
@Post()
|
||||
@HqOperation({
|
||||
action: HqOperationAction.PARTNER_ACCOUNT_CREATE,
|
||||
refType: 'PARTNER_ACCOUNT',
|
||||
refIdField: 'id',
|
||||
includeBody: true,
|
||||
})
|
||||
create(@Body() dto: CreatePartnerAccountDto) {
|
||||
return this.service.createPartnerAccount(dto);
|
||||
}
|
||||
|
||||
@Put(':id')
|
||||
@HqOperation({
|
||||
action: HqOperationAction.PARTNER_ACCOUNT_UPDATE,
|
||||
refType: 'PARTNER_ACCOUNT',
|
||||
refIdParam: 'id',
|
||||
includeBody: true,
|
||||
})
|
||||
update(@Param('id') id: string, @Body() dto: UpdatePartnerAccountDto) {
|
||||
return this.service.updatePartnerAccount(BigInt(id), dto);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { Body, Controller, Get, Param, Post, Put, Query, UseGuards } from '@nestjs/common';
|
||||
import { HqAuthGuard } from '../../common/guards/hq-auth.guard';
|
||||
import { HqOperation } from '../../common/hq-operation/hq-operation.decorator';
|
||||
import { HqOperationAction } from '../../common/hq-operation/hq-operation.constants';
|
||||
import { AdminProductDetailTemplatesService } from './admin-product-detail-templates.service';
|
||||
import { AdminProductDetailTemplatesQueryDto } from './dto/admin-query.dto';
|
||||
import {
|
||||
@@ -23,11 +25,23 @@ export class AdminProductDetailTemplatesController {
|
||||
}
|
||||
|
||||
@Post()
|
||||
@HqOperation({
|
||||
action: HqOperationAction.PRODUCT_TEMPLATE_CREATE,
|
||||
refType: 'PRODUCT_TEMPLATE',
|
||||
refIdField: 'id',
|
||||
includeBody: true,
|
||||
})
|
||||
create(@Body() dto: CreateProductDetailTemplateDto) {
|
||||
return this.service.create(dto);
|
||||
}
|
||||
|
||||
@Put(':id')
|
||||
@HqOperation({
|
||||
action: HqOperationAction.PRODUCT_TEMPLATE_UPDATE,
|
||||
refType: 'PRODUCT_TEMPLATE',
|
||||
refIdParam: 'id',
|
||||
includeBody: true,
|
||||
})
|
||||
update(@Param('id') id: string, @Body() dto: UpdateProductDetailTemplateDto) {
|
||||
return this.service.update(BigInt(id), dto);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { Body, Controller, Delete, Get, Param, Post, Put, Query, UseGuards } from '@nestjs/common';
|
||||
import { HqAuthGuard } from '../../common/guards/hq-auth.guard';
|
||||
import { HqOperation } from '../../common/hq-operation/hq-operation.decorator';
|
||||
import { HqOperationAction } from '../../common/hq-operation/hq-operation.constants';
|
||||
import { AdminProductsService } from './admin-products.service';
|
||||
import { AdminProductsQueryDto } from './dto/admin-query.dto';
|
||||
import { CreateProductDto, UpdateProductDto } from './dto/admin-mutate.dto';
|
||||
@@ -20,16 +22,19 @@ export class AdminProductsController {
|
||||
}
|
||||
|
||||
@Post()
|
||||
@HqOperation({ action: HqOperationAction.PRODUCT_CREATE, refType: 'PRODUCT', refIdField: 'id', includeBody: true })
|
||||
create(@Body() dto: CreateProductDto) {
|
||||
return this.service.create(dto);
|
||||
}
|
||||
|
||||
@Put(':id')
|
||||
@HqOperation({ action: HqOperationAction.PRODUCT_UPDATE, refType: 'PRODUCT', refIdParam: 'id', includeBody: true })
|
||||
update(@Param('id') id: string, @Body() dto: UpdateProductDto) {
|
||||
return this.service.update(BigInt(id), dto);
|
||||
}
|
||||
|
||||
@Delete(':id')
|
||||
@HqOperation({ action: HqOperationAction.PRODUCT_DELETE, refType: 'PRODUCT', refIdParam: 'id' })
|
||||
remove(@Param('id') id: string) {
|
||||
return this.service.remove(BigInt(id));
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { Body, Controller, Post, UseGuards } from '@nestjs/common';
|
||||
import { HqAuthGuard } from '../../common/guards/hq-auth.guard';
|
||||
import { HqOperation } from '../../common/hq-operation/hq-operation.decorator';
|
||||
import { HqOperationAction } from '../../common/hq-operation/hq-operation.constants';
|
||||
import { AdminRedeemDebugService } from './admin-redeem-debug.service';
|
||||
import type {
|
||||
AdminRedeemDebugCreateTokenDto,
|
||||
@@ -13,6 +15,12 @@ export class AdminRedeemDebugController {
|
||||
|
||||
/** preV1 调试:为用户生成核销码 */
|
||||
@Post('create-token')
|
||||
@HqOperation({
|
||||
action: HqOperationAction.REDEEM_DEBUG_CREATE_TOKEN,
|
||||
refType: 'REDEEM_DEBUG',
|
||||
batch: true,
|
||||
includeBody: true,
|
||||
})
|
||||
createToken(@Body() dto: AdminRedeemDebugCreateTokenDto) {
|
||||
return this.service.createToken(dto);
|
||||
}
|
||||
@@ -25,6 +33,12 @@ export class AdminRedeemDebugController {
|
||||
|
||||
/** preV1 调试:门店侧确认核销 */
|
||||
@Post('confirm')
|
||||
@HqOperation({
|
||||
action: HqOperationAction.REDEEM_DEBUG_CONFIRM,
|
||||
refType: 'REDEEM_DEBUG',
|
||||
batch: true,
|
||||
includeBody: true,
|
||||
})
|
||||
confirm(@Body() dto: AdminRedeemDebugStoreTokenDto) {
|
||||
return this.service.confirm(dto);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { Body, Controller, Get, Param, Put, Query, UseGuards } from '@nestjs/common';
|
||||
import { HqAuthGuard } from '../../common/guards/hq-auth.guard';
|
||||
import { HqOperation } from '../../common/hq-operation/hq-operation.decorator';
|
||||
import { HqOperationAction } from '../../common/hq-operation/hq-operation.constants';
|
||||
import { AdminRedeemService, AdminDeliveriesService } from './admin-redeem.service';
|
||||
import { AdminDeliveriesQueryDto, AdminRedeemRecordsQueryDto } from './dto/admin-query.dto';
|
||||
import { UpdateDeliveryDto } from './dto/admin-mutate.dto';
|
||||
@@ -36,6 +38,12 @@ export class AdminDeliveriesController {
|
||||
}
|
||||
|
||||
@Put(':id')
|
||||
@HqOperation({
|
||||
action: HqOperationAction.DELIVERY_UPDATE,
|
||||
refType: 'DELIVERY',
|
||||
refIdParam: 'id',
|
||||
includeBody: true,
|
||||
})
|
||||
update(@Param('id') id: string, @Body() dto: UpdateDeliveryDto) {
|
||||
return this.service.update(BigInt(id), dto);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { Body, Controller, Delete, Get, Param, Post, Put, Query, UseGuards } from '@nestjs/common';
|
||||
import { HqAuthGuard } from '../../common/guards/hq-auth.guard';
|
||||
import { HqOperation } from '../../common/hq-operation/hq-operation.decorator';
|
||||
import { HqOperationAction } from '../../common/hq-operation/hq-operation.constants';
|
||||
import { AdminStoresService } from './admin-stores.service';
|
||||
import {
|
||||
AdminStoreAccountsQueryDto,
|
||||
@@ -32,21 +34,25 @@ export class AdminStoresController {
|
||||
}
|
||||
|
||||
@Post()
|
||||
@HqOperation({ action: HqOperationAction.STORE_CREATE, refType: 'STORE', refIdField: 'id', includeBody: true })
|
||||
create(@Body() dto: CreateStoreDto) {
|
||||
return this.service.createStore(dto);
|
||||
}
|
||||
|
||||
@Put(':id')
|
||||
@HqOperation({ action: HqOperationAction.STORE_UPDATE, refType: 'STORE', refIdParam: 'id', includeBody: true })
|
||||
update(@Param('id') id: string, @Body() dto: UpdateStoreDto) {
|
||||
return this.service.updateStore(BigInt(id), dto);
|
||||
}
|
||||
|
||||
@Put(':id/status')
|
||||
@HqOperation({ action: HqOperationAction.STORE_STATUS, refType: 'STORE', refIdParam: 'id', includeBody: true })
|
||||
updateStatus(@Param('id') id: string, @Body() dto: UpdateStoreStatusDto) {
|
||||
return this.service.updateStoreStatus(BigInt(id), dto);
|
||||
}
|
||||
|
||||
@Put(':id/audit')
|
||||
@HqOperation({ action: HqOperationAction.STORE_AUDIT, refType: 'STORE', refIdParam: 'id', includeBody: true })
|
||||
audit(@Param('id') id: string, @Body() body: { approved: boolean; remark?: string }) {
|
||||
return this.service.auditStore(BigInt(id), body);
|
||||
}
|
||||
@@ -68,11 +74,23 @@ export class AdminStoreAccountsController {
|
||||
}
|
||||
|
||||
@Post()
|
||||
@HqOperation({
|
||||
action: HqOperationAction.STORE_ACCOUNT_CREATE,
|
||||
refType: 'STORE_ACCOUNT',
|
||||
refIdField: 'id',
|
||||
includeBody: true,
|
||||
})
|
||||
create(@Body() dto: CreateStoreAccountDto) {
|
||||
return this.service.createStoreAccount(dto);
|
||||
}
|
||||
|
||||
@Put(':id')
|
||||
@HqOperation({
|
||||
action: HqOperationAction.STORE_ACCOUNT_UPDATE,
|
||||
refType: 'STORE_ACCOUNT',
|
||||
refIdParam: 'id',
|
||||
includeBody: true,
|
||||
})
|
||||
update(@Param('id') id: string, @Body() dto: UpdateStoreAccountDto) {
|
||||
return this.service.updateStoreAccount(BigInt(id), dto);
|
||||
}
|
||||
@@ -89,16 +107,29 @@ export class AdminStoreMediaController {
|
||||
}
|
||||
|
||||
@Post()
|
||||
@HqOperation({
|
||||
action: HqOperationAction.STORE_MEDIA_CREATE,
|
||||
refType: 'STORE_MEDIA',
|
||||
refIdField: 'id',
|
||||
includeBody: true,
|
||||
})
|
||||
create(@Body() dto: CreateStoreMediaDto) {
|
||||
return this.service.createStoreMedia(dto);
|
||||
}
|
||||
|
||||
@Put(':id')
|
||||
@HqOperation({
|
||||
action: HqOperationAction.STORE_MEDIA_UPDATE,
|
||||
refType: 'STORE_MEDIA',
|
||||
refIdParam: 'id',
|
||||
includeBody: true,
|
||||
})
|
||||
update(@Param('id') id: string, @Body() dto: UpdateStoreMediaDto) {
|
||||
return this.service.updateStoreMedia(BigInt(id), dto);
|
||||
}
|
||||
|
||||
@Delete(':id')
|
||||
@HqOperation({ action: HqOperationAction.STORE_MEDIA_DELETE, refType: 'STORE_MEDIA', refIdParam: 'id' })
|
||||
remove(@Param('id') id: string) {
|
||||
return this.service.deleteStoreMedia(BigInt(id));
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { Body, Controller, Get, Param, Post, Query, UseGuards } from '@nestjs/common';
|
||||
import { HqAuthGuard } from '../../common/guards/hq-auth.guard';
|
||||
import { HqOperation } from '../../common/hq-operation/hq-operation.decorator';
|
||||
import { HqOperationAction } from '../../common/hq-operation/hq-operation.constants';
|
||||
import { AdminTicketsService } from './admin-tickets.service';
|
||||
import { TicketListQueryDto } from '../common/dto/common-query.dto';
|
||||
|
||||
@@ -19,11 +21,23 @@ export class AdminTicketsController {
|
||||
}
|
||||
|
||||
@Post(':id/approve')
|
||||
@HqOperation({
|
||||
action: HqOperationAction.TICKET_APPROVE,
|
||||
refType: 'TICKET',
|
||||
refIdParam: 'id',
|
||||
includeBody: true,
|
||||
})
|
||||
approve(@Param('id') id: string, @Body() body: { remark?: string }) {
|
||||
return this.service.approve(BigInt(id), body.remark);
|
||||
}
|
||||
|
||||
@Post(':id/reject')
|
||||
@HqOperation({
|
||||
action: HqOperationAction.TICKET_REJECT,
|
||||
refType: 'TICKET',
|
||||
refIdParam: 'id',
|
||||
includeBody: true,
|
||||
})
|
||||
reject(@Param('id') id: string, @Body() body: { remark?: string }) {
|
||||
return this.service.reject(BigInt(id), body.remark);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { Body, Controller, Delete, Get, Param, Post, Query, 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 { AdminUsersService } from './admin-users.service';
|
||||
import { AdminUsersQueryDto } from './dto/admin-query.dto';
|
||||
import { BatchDeleteUsersConfirmDto, BatchDeleteUsersDto } from './dto/admin-mutate.dto';
|
||||
@@ -23,6 +25,12 @@ export class AdminUsersController {
|
||||
|
||||
@Post('batch-delete')
|
||||
@UseGuards(SuperAdminGuard)
|
||||
@HqOperation({
|
||||
action: HqOperationAction.USER_BATCH_DELETE,
|
||||
refType: 'USER',
|
||||
batch: true,
|
||||
includeBody: true,
|
||||
})
|
||||
batchDelete(@Body() dto: BatchDeleteUsersConfirmDto) {
|
||||
return this.usersService.batchDeleteUsers(
|
||||
dto.ids.map((id) => BigInt(id)),
|
||||
@@ -37,6 +45,11 @@ export class AdminUsersController {
|
||||
|
||||
@Delete(':id')
|
||||
@UseGuards(SuperAdminGuard)
|
||||
@HqOperation({
|
||||
action: HqOperationAction.USER_DELETE,
|
||||
refType: 'USER',
|
||||
refIdParam: 'id',
|
||||
})
|
||||
remove(@Param('id') id: string) {
|
||||
return this.usersService.deleteUser(BigInt(id));
|
||||
}
|
||||
|
||||
@@ -275,6 +275,28 @@ export class AdminUserLogsQueryDto extends PaginationQueryDto {
|
||||
to?: string;
|
||||
}
|
||||
|
||||
export class AdminHqLogsQueryDto extends PaginationQueryDto {
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
hqAccountId?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
action?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
refType?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
from?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
to?: string;
|
||||
}
|
||||
|
||||
export class AdminStoreMediaQueryDto extends PaginationQueryDto {
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
|
||||
@@ -23,6 +23,8 @@ import { AdminProductsController } from './admin-products.controller';
|
||||
import { AdminProductsService } from './admin-products.service';
|
||||
import { AdminUserLogsController } from './admin-user-logs.controller';
|
||||
import { AdminUserLogsService } from './admin-user-logs.service';
|
||||
import { AdminHqLogsController } from './admin-hq-logs.controller';
|
||||
import { AdminHqLogsService } from './admin-hq-logs.service';
|
||||
import { AdminTicketsController } from './admin-tickets.controller';
|
||||
import { AdminTicketsService } from './admin-tickets.service';
|
||||
import { SuperAdminGuard } from '../../common/guards/super-admin.guard';
|
||||
@@ -56,6 +58,7 @@ import { AdminRedeemDebugService } from './admin-redeem-debug.service';
|
||||
AdminHqAccountsController,
|
||||
AdminProductsController,
|
||||
AdminUserLogsController,
|
||||
AdminHqLogsController,
|
||||
AdminTicketsController,
|
||||
AdminXiaofeixiaController,
|
||||
AdminProductDetailTemplatesController,
|
||||
@@ -74,6 +77,7 @@ import { AdminRedeemDebugService } from './admin-redeem-debug.service';
|
||||
AdminHqAccountsService,
|
||||
AdminProductsService,
|
||||
AdminUserLogsService,
|
||||
AdminHqLogsService,
|
||||
AdminTicketsService,
|
||||
AdminXiaofeixiaService,
|
||||
AdminProductDetailTemplatesService,
|
||||
|
||||
@@ -3,6 +3,8 @@ import { SettlementService } from './settlement.service';
|
||||
import { JwtAuthGuard, AuthUser } from '../../common/guards/jwt-auth.guard';
|
||||
import { CurrentUser } from '../../common/decorators/current-user.decorator';
|
||||
import { HqAuthGuard } from '../../common/guards/hq-auth.guard';
|
||||
import { HqOperation } from '../../common/hq-operation/hq-operation.decorator';
|
||||
import { HqOperationAction } from '../../common/hq-operation/hq-operation.constants';
|
||||
import { PrismaService } from '../../common/prisma/prisma.module';
|
||||
|
||||
@Controller('partner/settlement')
|
||||
@@ -52,11 +54,23 @@ export class AdminStorePayoutController {
|
||||
}
|
||||
|
||||
@Post(':id/confirm')
|
||||
@HqOperation({
|
||||
action: HqOperationAction.STORE_PAYOUT_CONFIRM,
|
||||
refType: 'STORE_PAYOUT',
|
||||
refIdParam: 'id',
|
||||
includeBody: true,
|
||||
})
|
||||
confirm(@Param('id') id: string, @Body() body: { paymentRef?: string; batchNo?: string; remark?: string }) {
|
||||
return this.settlementService.confirmStorePayout(BigInt(id), body);
|
||||
}
|
||||
|
||||
@Post('batch-confirm')
|
||||
@HqOperation({
|
||||
action: HqOperationAction.STORE_PAYOUT_BATCH_CONFIRM,
|
||||
refType: 'STORE_PAYOUT',
|
||||
batch: true,
|
||||
includeBody: true,
|
||||
})
|
||||
batchConfirm(@Body() body: { ids: string[]; batchNo?: string }) {
|
||||
return this.settlementService.batchConfirmStorePayouts(body.ids ?? [], body);
|
||||
}
|
||||
@@ -73,6 +87,12 @@ export class AdminPartnerBillController {
|
||||
constructor(private readonly settlementService: SettlementService) {}
|
||||
|
||||
@Post('generate')
|
||||
@HqOperation({
|
||||
action: HqOperationAction.PARTNER_BILL_GENERATE,
|
||||
refType: 'PARTNER_BILL',
|
||||
refIdField: 'id',
|
||||
includeBody: true,
|
||||
})
|
||||
generate(@Body() body: { partnerId: string; year: number; month: number }) {
|
||||
return this.settlementService.generatePartnerBill(body);
|
||||
}
|
||||
@@ -101,11 +121,22 @@ export class AdminPartnerBillController {
|
||||
}
|
||||
|
||||
@Post(':id/confirm')
|
||||
@HqOperation({
|
||||
action: HqOperationAction.PARTNER_BILL_CONFIRM,
|
||||
refType: 'PARTNER_BILL',
|
||||
refIdParam: 'id',
|
||||
})
|
||||
confirm(@Param('id') id: string) {
|
||||
return this.settlementService.confirmPartnerBill(BigInt(id));
|
||||
}
|
||||
|
||||
@Post(':id/mark-paid')
|
||||
@HqOperation({
|
||||
action: HqOperationAction.PARTNER_BILL_MARK_PAID,
|
||||
refType: 'PARTNER_BILL',
|
||||
refIdParam: 'id',
|
||||
includeBody: true,
|
||||
})
|
||||
markPaid(@Param('id') id: string, @Body() body: { paymentRef?: string }) {
|
||||
return this.settlementService.markPartnerBillPaid(BigInt(id), body);
|
||||
}
|
||||
|
||||
@@ -106,18 +106,6 @@ export class SettlementService {
|
||||
},
|
||||
});
|
||||
|
||||
await this.prisma.commonEvent.create({
|
||||
data: {
|
||||
eventType: 'HQ_OPERATION',
|
||||
refType: 'STORE_PAYOUT',
|
||||
refId: id,
|
||||
actorType: 'HQ',
|
||||
status: 'PAID',
|
||||
param1: dto.paymentRef ?? '',
|
||||
remark: dto.remark ?? '门店 T+1 打款确认',
|
||||
},
|
||||
});
|
||||
|
||||
return serializeBigInt(updated);
|
||||
}
|
||||
|
||||
@@ -269,17 +257,6 @@ export class SettlementService {
|
||||
data: { status: 'CONFIRMED', confirmedAt: new Date() },
|
||||
});
|
||||
|
||||
await this.prisma.commonEvent.create({
|
||||
data: {
|
||||
eventType: 'HQ_OPERATION',
|
||||
refType: 'PARTNER_BILL',
|
||||
refId: id,
|
||||
actorType: 'HQ',
|
||||
status: 'CONFIRMED',
|
||||
amount1: Number(updated.totalAmount),
|
||||
},
|
||||
});
|
||||
|
||||
return serializeBigInt(updated);
|
||||
}
|
||||
|
||||
@@ -293,18 +270,6 @@ export class SettlementService {
|
||||
data: { status: 'PAID', paidAt: new Date() },
|
||||
});
|
||||
|
||||
await this.prisma.commonEvent.create({
|
||||
data: {
|
||||
eventType: 'HQ_OPERATION',
|
||||
refType: 'PARTNER_BILL',
|
||||
refId: id,
|
||||
actorType: 'HQ',
|
||||
status: 'PAID',
|
||||
param1: dto.paymentRef ?? '',
|
||||
amount1: Number(updated.totalAmount),
|
||||
},
|
||||
});
|
||||
|
||||
return serializeBigInt(updated);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user