This commit is contained in:
2026-04-27 18:03:20 +08:00
parent 86b9456ecd
commit 632aa76fcb
70 changed files with 8793 additions and 10517 deletions
+1
View File
@@ -12,3 +12,4 @@ Thumbs.db
*.swo
coverage/
.nyc_output/
apps/server/uploads/
@@ -1,4 +1,4 @@
import { post, get, request } from '@/utils/request';
import { post, request } from '@/utils/request';
export interface SellerRegisterParams {
phone: string;
@@ -51,4 +51,4 @@ export function sellerRefreshToken(refreshToken: string) {
// 获取商家信息(需要商家token)
export function getSellerProfile() {
return request({ url: '/seller/auth/profile', method: 'GET', useSellerToken: true });
}
}
@@ -1,4 +1,4 @@
import { post, get, put, request } from '@/utils/request';
import { request } from '@/utils/request';
export interface ApplyMerchantParams {
shopName: string;
@@ -27,35 +27,9 @@ export interface UpdateMerchantParams {
legalPerson?: string;
}
export interface MerchantInfo {
id: number;
sellerId: number;
shopName: string;
logo: string;
description: string;
phone: string;
province: string;
city: string;
district: string;
address: string;
longitude: number;
latitude: number;
businessLicense: string;
licenseNo: string;
legalPerson: string;
status: 'pending' | 'approved' | 'rejected' | 'frozen';
rejectReason: string;
deposit: number;
rating: number;
reviewCount: number;
autoConfirm: boolean;
createdAt: string;
updatedAt: string;
}
// 申请创建店铺(需要商家token)
export function applyMerchant(data: ApplyMerchantParams) {
return request<MerchantInfo>({
return request({
url: '/seller/merchant/apply',
method: 'POST',
data,
@@ -65,7 +39,7 @@ export function applyMerchant(data: ApplyMerchantParams) {
// 获取我的店铺信息(需要商家token)
export function getMyMerchant() {
return request<MerchantInfo>({
return request({
url: '/seller/merchant/mine',
method: 'GET',
useSellerToken: true,
@@ -74,25 +48,10 @@ export function getMyMerchant() {
// 更新店铺信息(需要商家token)
export function updateMerchant(data: UpdateMerchantParams) {
return request<MerchantInfo>({
return request({
url: '/seller/merchant/update',
method: 'PUT',
data,
useSellerToken: true,
});
}
// 获取商家详情(公开)
export function getMerchantById(id: number) {
return get<MerchantInfo>(`/merchants/${id}`);
}
// 获取商家列表(公开,已审核通过)
export function getMerchantList(params: {
page?: number;
pageSize?: number;
keyword?: string;
city?: string;
}) {
return get('/merchants', params);
}
@@ -1,31 +1,4 @@
import { get, request } from '@/utils/request';
// 公开接口
export function getRoomList(params: {
page?: number;
pageSize?: number;
keyword?: string;
type?: string;
minPrice?: number;
maxPrice?: number;
city?: string;
merchantId?: number;
sortBy?: string;
checkIn?: string;
checkOut?: string;
roomCount?: number;
adultCount?: number;
}) {
return get('/rooms', params);
}
export function getRoomDetail(id: number) {
return get(`/rooms/${id}`);
}
export function getRoomCalendar(id: number, startDate: string, endDate: string) {
return get(`/rooms/${id}/calendar`, { startDate, endDate });
}
import { request } from '@/utils/request';
// 商家管理接口(需要 sellerToken
export function getMerchantRooms(params: any) {
@@ -1,4 +1,4 @@
import { post, get, request } from '@/utils/request';
import { post, get } from '@/utils/request';
export function sendCode(phone: string) {
return post('/auth/send-code', { phone });
@@ -23,7 +23,3 @@ export function refreshToken(refreshToken: string) {
export function getUserProfile() {
return get('/user/profile');
}
export function getMerchantInfo() {
return request({ url: '/merchant/mine', method: 'GET', useSellerToken: true });
}
@@ -1,4 +1,4 @@
import {request} from '@/utils/request';
import { request } from '@/utils/request';
// 获取我的邀请统计
export const getInviteStats = () =>
+42
View File
@@ -0,0 +1,42 @@
import { get } from '@/utils/request';
export interface MerchantInfo {
id: number;
sellerId: number;
shopName: string;
logo: string;
description: string;
phone: string;
province: string;
city: string;
district: string;
address: string;
longitude: number;
latitude: number;
businessLicense: string;
licenseNo: string;
legalPerson: string;
status: 'pending' | 'approved' | 'rejected' | 'frozen';
rejectReason: string;
deposit: number;
rating: number;
reviewCount: number;
autoConfirm: boolean;
createdAt: string;
updatedAt: string;
}
// 获取商家详情(公开)
export function getMerchantById(id: number) {
return get<MerchantInfo>(`/merchants/${id}`);
}
// 获取商家列表(公开,已审核通过)
export function getMerchantList(params: {
page?: number;
pageSize?: number;
keyword?: string;
city?: string;
}) {
return get('/merchants', params);
}
+28
View File
@@ -0,0 +1,28 @@
import { get } from '@/utils/request';
// 公开接口
export function getRoomList(params: {
page?: number;
pageSize?: number;
keyword?: string;
type?: string;
minPrice?: number;
maxPrice?: number;
city?: string;
merchantId?: number;
sortBy?: string;
checkIn?: string;
checkOut?: string;
roomCount?: number;
adultCount?: number;
}) {
return get('/rooms', params);
}
export function getRoomDetail(id: number) {
return get(`/rooms/${id}`);
}
export function getRoomCalendar(id: number, startDate: string, endDate: string) {
return get(`/rooms/${id}/calendar`, { startDate, endDate });
}
@@ -58,7 +58,7 @@
<script setup lang="ts">
import { ref, computed, watch, onMounted } from 'vue';
import { getRoomCalendar } from '@/api/room';
import { getRoomCalendar } from '@/api/user/room';
const props = defineProps<{
roomId: number;
+1 -1
View File
@@ -103,7 +103,7 @@
<script setup lang="ts">
import { ref, computed, onMounted, onActivated } from 'vue';
import { getMerchantList } from '@/api/merchant';
import { getMerchantList } from '@/api/user/merchant';
import CityPicker from '@/components/CityPicker.vue';
import DatePicker from '@/components/DatePicker.vue';
import RoomGuestPicker from '@/components/RoomGuestPicker.vue';
+1 -1
View File
@@ -32,7 +32,7 @@
<script setup lang="ts">
import { ref, onMounted } from 'vue';
import { getCashbackRecords } from '@/api/invite';
import { getCashbackRecords } from '@/api/user/invite';
const records = ref<any[]>([]);
const page = ref(1);
+1 -1
View File
@@ -77,7 +77,7 @@
<script setup lang="ts">
import { ref, computed, onMounted } from 'vue';
import { getInviteStats } from '@/api/invite';
import { getInviteStats } from '@/api/user/invite';
import { useUserStore } from '@/store/user';
const stats = ref<any>({
+1 -1
View File
@@ -32,7 +32,7 @@
<script setup lang="ts">
import { ref, onMounted } from 'vue';
import { getInviteRecords } from '@/api/invite';
import { getInviteRecords } from '@/api/user/invite';
const records = ref<any[]>([]);
const page = ref(1);
+1 -1
View File
@@ -50,7 +50,7 @@
<script setup lang="ts">
import { ref, computed, onMounted } from 'vue';
import { getInviteStats, createInviteWithdrawal } from '@/api/invite';
import { getInviteStats, createInviteWithdrawal } from '@/api/user/invite';
const stats = ref<any>({ availableBalance: 0 });
const amount = ref('');
@@ -28,7 +28,7 @@
<script setup lang="ts">
import { ref, onMounted } from 'vue';
import { getInviteWithdrawals } from '@/api/invite';
import { getInviteWithdrawals } from '@/api/user/invite';
const records = ref<any[]>([]);
const page = ref(1);
@@ -55,7 +55,7 @@
<script setup lang="ts">
import { ref } from 'vue';
import { getMerchantList } from '@/api/merchant';
import { getMerchantList } from '@/api/user/merchant';
const keyword = ref('');
const searchResults = ref<any[]>([]);
+1 -1
View File
@@ -45,7 +45,7 @@
<script setup lang="ts">
import { ref } from 'vue';
import { sendCode, loginByPhone } from '@/api/auth';
import { sendCode, loginByPhone } from '@/api/user/auth';
import { useUserStore } from '@/store/user';
const phone = ref('');
@@ -127,9 +127,9 @@
<script setup lang="ts">
import { ref, computed, onMounted } from 'vue';
import { getMerchantById } from '@/api/merchant';
import { getRoomList } from '@/api/room';
import { getReviewList } from '@/api/review';
import { getMerchantById } from '@/api/user/merchant';
import { getRoomList } from '@/api/user/room';
import { getReviewList } from '@/api/user/review';
import RoomCard from '@/components/RoomCard.vue';
import DatePicker from '@/components/DatePicker.vue';
import RoomGuestPicker from '@/components/RoomGuestPicker.vue';
@@ -111,8 +111,8 @@
<script setup lang="ts">
import { ref, computed, onMounted, watch } from 'vue';
import { getRoomDetail, getRoomCalendar } from '@/api/room';
import { createOrder } from '@/api/order';
import { getRoomDetail, getRoomCalendar } from '@/api/user/room';
import { createOrder } from '@/api/user/order';
import RoomCalendarPicker from '@/components/RoomCalendarPicker.vue';
const roomId = ref(0);
@@ -177,8 +177,8 @@
<script setup lang="ts">
import { ref, onMounted } from 'vue';
import { getOrderDetail, cancelOrder, payOrder } from '@/api/order';
import { createReview, checkOrderReviewed } from '@/api/review';
import { getOrderDetail, cancelOrder, payOrder } from '@/api/user/order';
import { createReview, checkOrderReviewed } from '@/api/user/review';
const statusLabels: Record<string, string> = {
pending_pay: '待支付',
+1 -1
View File
@@ -46,7 +46,7 @@
<script setup lang="ts">
import { ref, onMounted } from 'vue';
import { getOrderList } from '@/api/order';
import { getOrderList } from '@/api/user/order';
const tabs = [
{ label: '全部', value: '' },
+1 -1
View File
@@ -113,7 +113,7 @@
<script setup lang="ts">
import { ref, computed, onMounted } from 'vue';
import { getRoomDetail } from '@/api/room';
import { getRoomDetail } from '@/api/user/room';
const typeLabels: Record<string, string> = {
hotel: '酒店',
+1 -1
View File
@@ -67,7 +67,7 @@
<script setup lang="ts">
import { ref, computed, onMounted } from 'vue';
import { getMerchantList } from '@/api/merchant';
import { getMerchantList } from '@/api/user/merchant';
// 筛选条件(从URL获取)
const city = ref('上海');
+1 -1
View File
@@ -128,7 +128,7 @@
<script setup lang="ts">
import { ref, computed, onMounted } from 'vue';
import { useSellerStore } from '@/store/seller';
import { getMyMerchant } from '@/api/merchant';
import { getMyMerchant } from '@/api/seller/merchant';
const sellerStore = useSellerStore();
const merchant = ref<any>(null);
@@ -154,7 +154,7 @@
<script setup lang="ts">
import { ref, onMounted } from 'vue';
import { getSellerOrderDetail, confirmOrder, rejectOrder, checkinOrder } from '@/api/seller-order';
import { getSellerOrderDetail, confirmOrder, rejectOrder, checkinOrder } from '@/api/seller/order';
const statusLabels: Record<string, string> = {
pending_pay: '待支付',
+1 -1
View File
@@ -75,7 +75,7 @@
<script setup lang="ts">
import { ref, onMounted } from 'vue';
import { getSellerOrders, confirmOrder, rejectOrder, checkinOrder } from '@/api/seller-order';
import { getSellerOrders, confirmOrder, rejectOrder, checkinOrder } from '@/api/seller/order';
const tabs = [
{ label: '全部', value: '' },
+1 -1
View File
@@ -142,7 +142,7 @@
<script setup lang="ts">
import { ref } from 'vue';
import { onMounted } from 'vue';
import { sellerRegister, sellerLogin, sellerSendCode } from '@/api/seller-auth';
import { sellerRegister, sellerLogin, sellerSendCode } from '@/api/seller/auth';
import { useSellerStore } from '@/store/seller';
const sellerStore = useSellerStore();
@@ -97,8 +97,8 @@
<script setup lang="ts">
import { ref, computed, watch } from 'vue';
import { onShow } from '@dcloudio/uni-app';
import { getMerchantRooms } from '@/api/room';
import { getRoomCalendar, batchUpdateCalendar, singleDayUpdate } from '@/api/room-calendar';
import { getMerchantRooms } from '@/api/seller/room';
import { getRoomCalendar, batchUpdateCalendar, singleDayUpdate } from '@/api/seller/room-calendar';
const weekDays = ['日', '一', '二', '三', '四', '五', '六'];
const statusOptions = [
+1 -1
View File
@@ -90,7 +90,7 @@
<script setup lang="ts">
import { ref, onMounted } from 'vue';
import { createMerchantRoom, updateMerchantRoom, getMerchantRoom } from '@/api/room';
import { createMerchantRoom, updateMerchantRoom, getMerchantRoom } from '@/api/seller/room';
import { chooseAndUpload } from '@/utils/upload';
const loading = ref(false);
+1 -1
View File
@@ -54,7 +54,7 @@
<script setup lang="ts">
import { ref } from 'vue';
import { onShow } from '@dcloudio/uni-app';
import { getMerchantRooms, removeMerchantRoom, updateMerchantRoom } from '@/api/room';
import { getMerchantRooms, removeMerchantRoom, updateMerchantRoom } from '@/api/seller/room';
const typeLabels: Record<string, string> = { hotel: '酒店', homestay: '民宿', apartment: '公寓', hostel: '青旅' };
const auditLabels: Record<string, string> = { pending: '审核中', approved: '已通过', rejected: '已拒绝' };
@@ -114,7 +114,7 @@
<script setup lang="ts">
import { ref } from 'vue';
import { applyMerchant } from '@/api/merchant';
import { applyMerchant } from '@/api/seller/merchant';
import { useSellerStore } from '@/store/seller';
import RegionSelector from '@/components/RegionSelector.vue';
import { chooseAndUpload } from '@/utils/upload';
@@ -150,6 +150,7 @@ async function uploadLicense() {
try {
uni.showLoading({ title: '上传中...' });
const urls = await chooseAndUpload({ count: 1, useSellerToken: true });
console.log('上传成功,文件URL', urls);
form.value.businessLicense = urls[0];
uni.showToast({ title: '上传成功', icon: 'success' });
} catch (err: any) {
+1 -1
View File
@@ -113,7 +113,7 @@
<script setup lang="ts">
import { ref, onMounted } from 'vue';
import { updateMerchant, getMyMerchant } from '@/api/merchant';
import { updateMerchant, getMyMerchant } from '@/api/seller/merchant';
import { useSellerStore } from '@/store/seller';
import RegionSelector from '@/components/RegionSelector.vue';
import { chooseAndUpload } from '@/utils/upload';
+9 -5
View File
@@ -19,15 +19,19 @@ export function uploadFile(filePath: string, options?: { useSellerToken?: boolea
name: 'file',
header: token ? { Authorization: `Bearer ${token}` } : {},
success: (res) => {
if (res.statusCode === 200) {
if (res.statusCode >= 200 && res.statusCode < 300) {
try {
const data = JSON.parse(res.data);
if (data.code >= 200 && data.code < 300 && data.data?.url) {
resolve(data.data.url);
const data = typeof res.data === 'string' ? JSON.parse(res.data) : res.data;
console.log('[upload] response data:', JSON.stringify(data));
if ((data.code === 0 || data.code === 200 || data.code === 201) && data.data?.url) {
resolve(data.data.url.startsWith('http') ? data.data.url : `${BASE_URL.replace('/api', '')}${data.data.url}`);
} else if (data.url) {
resolve(data.url);
} else {
reject(new Error(data.message || '上传失败'));
}
} catch {
} catch (e) {
console.error('[upload] parse error:', e, 'raw:', res.data);
reject(new Error('解析响应失败'));
}
} else if (res.statusCode === 401) {
@@ -7,74 +7,20 @@ import {
Query,
Param,
UseGuards,
Request,
ParseIntPipe,
} from '@nestjs/common';
import { ApiTags, ApiOperation, ApiBearerAuth, ApiParam } from '@nestjs/swagger';
import { ActivityService } from './activity.service';
import { JwtAuthGuard, RolesGuard, Roles, CurrentUser } from '@/common';
import {
CreateActivityDto,
UpdateActivityDto,
QueryActivityDto,
BindInvitationDto,
CreateInviteWithdrawalDto,
QueryInviteRecordsDto,
RejectInviteWithdrawalDto,
QueryAdminInviteWithdrawalsDto,
QueryAdminCashbacksDto,
QueryInviteRecordsDto,
} from './dto/activity.dto';
import { JwtAuthGuard, RolesGuard, Roles, CurrentUser } from '@/common';
// ===== 用户端邀请接口 =====
@ApiTags('用户端-邀请返现')
@ApiBearerAuth()
@UseGuards(JwtAuthGuard)
@Controller('user/activity/invite')
export class UserInviteController {
constructor(private readonly activityService: ActivityService) {}
@Get('stats')
@ApiOperation({ summary: '获取我的邀请统计' })
async getStats(@CurrentUser('userId') userId: number) {
return this.activityService.getUserStats(userId);
}
@Post('bind')
@ApiOperation({ summary: '绑定邀请关系' })
async bind(@CurrentUser('userId') userId: number, @Body() dto: BindInvitationDto) {
return this.activityService.bindInvitation(userId, dto);
}
@Get('records')
@ApiOperation({ summary: '邀请记录列表' })
async getRecords(@CurrentUser('userId') userId: number, @Query() dto: QueryInviteRecordsDto) {
return this.activityService.getInviteRecords(userId, dto);
}
@Get('cashbacks')
@ApiOperation({ summary: '返现记录列表' })
async getCashbacks(@CurrentUser('userId') userId: number, @Query() dto: QueryInviteRecordsDto) {
return this.activityService.getCashbackRecords(userId, dto);
}
@Post('withdraw')
@ApiOperation({ summary: '申请提现' })
async createWithdrawal(
@CurrentUser('userId') userId: number,
@Body() dto: CreateInviteWithdrawalDto,
) {
return this.activityService.createWithdrawal(userId, dto);
}
@Get('withdrawals')
@ApiOperation({ summary: '提现记录列表' })
async getWithdrawals(
@CurrentUser('userId') userId: number,
@Query() dto: QueryInviteRecordsDto,
) {
return this.activityService.getWithdrawalRecords(userId, dto);
}
}
// ===== 管理端活动接口 =====
@ApiTags('管理端-活动管理')
@@ -82,7 +28,7 @@ export class UserInviteController {
@UseGuards(JwtAuthGuard, RolesGuard)
@Roles('admin')
@Controller('admin/activity')
export class AdminActivityController {
export class ActivityAdminController {
constructor(private readonly activityService: ActivityService) {}
@Get('list')
@@ -0,0 +1,67 @@
import {
Controller,
Get,
Post,
Body,
Query,
UseGuards,
} from '@nestjs/common';
import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger';
import { ActivityService } from './activity.service';
import { JwtAuthGuard, CurrentUser } from '@/common';
import {
BindInvitationDto,
CreateInviteWithdrawalDto,
QueryInviteRecordsDto,
} from './dto/activity.dto';
// ===== 用户端邀请接口 =====
@ApiTags('用户端-邀请返现')
@ApiBearerAuth()
@UseGuards(JwtAuthGuard)
@Controller('user/activity/invite')
export class ActivityUserController {
constructor(private readonly activityService: ActivityService) {}
@Get('stats')
@ApiOperation({ summary: '获取我的邀请统计' })
async getStats(@CurrentUser('userId') userId: number) {
return this.activityService.getUserStats(userId);
}
@Post('bind')
@ApiOperation({ summary: '绑定邀请关系' })
async bind(@CurrentUser('userId') userId: number, @Body() dto: BindInvitationDto) {
return this.activityService.bindInvitation(userId, dto);
}
@Get('records')
@ApiOperation({ summary: '邀请记录列表' })
async getRecords(@CurrentUser('userId') userId: number, @Query() dto: QueryInviteRecordsDto) {
return this.activityService.getInviteRecords(userId, dto);
}
@Get('cashbacks')
@ApiOperation({ summary: '返现记录列表' })
async getCashbacks(@CurrentUser('userId') userId: number, @Query() dto: QueryInviteRecordsDto) {
return this.activityService.getCashbackRecords(userId, dto);
}
@Post('withdraw')
@ApiOperation({ summary: '申请提现' })
async createWithdrawal(
@CurrentUser('userId') userId: number,
@Body() dto: CreateInviteWithdrawalDto,
) {
return this.activityService.createWithdrawal(userId, dto);
}
@Get('withdrawals')
@ApiOperation({ summary: '提现记录列表' })
async getWithdrawals(
@CurrentUser('userId') userId: number,
@Query() dto: QueryInviteRecordsDto,
) {
return this.activityService.getWithdrawalRecords(userId, dto);
}
}
@@ -1,7 +1,8 @@
import { Module, forwardRef } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { ActivityService } from './activity.service';
import { UserInviteController, AdminActivityController } from './activity.controller';
import { ActivityUserController } from './activity-user.controller';
import { ActivityAdminController } from './activity-admin.controller';
import { MktActivity } from '@/entities/mkt-activity.entity';
import { MktInvitation } from '@/entities/mkt-invitation.entity';
import { MktCashback } from '@/entities/mkt-cashback.entity';
@@ -22,7 +23,7 @@ import { User } from '@/entities/user.entity';
User,
]),
],
controllers: [UserInviteController, AdminActivityController],
controllers: [ActivityUserController, ActivityAdminController],
providers: [ActivityService],
exports: [ActivityService],
})
+6 -3
View File
@@ -12,11 +12,14 @@ import { User } from '@/entities/user.entity';
TypeOrmModule.forFeature([User]),
JwtModule.registerAsync({
imports: [ConfigModule],
useFactory: async (configService: ConfigService) => ({
useFactory: (configService: ConfigService) => ({
secret: configService.get<string>('jwt.secret') || 'dev_secret_key',
signOptions: {
expiresIn: (configService.get<string>('jwt.expiresIn') ||
'2h') as any,
expiresIn: Number(
configService
.get<string>('jwt.expiresIn')
?.replace(/[^0-9]/g, '') || '7200',
),
},
}),
inject: [ConfigService],
+17 -13
View File
@@ -59,18 +59,19 @@ export class AuthService {
return this.generateToken(user);
}
async sendCode(phone: string) {
sendCode(phone: string) {
const code = Math.random().toString().slice(2, 8);
await this.cacheCode(phone, code);
this.cacheCode(phone, code);
this.logger.log(`验证码已发送至 ${phone}: ${code}`);
return { message: '验证码已发送' };
}
async refresh(refreshToken: string) {
try {
const payload = await this.jwtService.verifyAsync(refreshToken, {
secret: this.configService.get<string>('jwt.secret'),
});
const payload: { sub: number; phone: string } =
await this.jwtService.verifyAsync(refreshToken, {
secret: this.configService.get<string>('jwt.secret'),
});
const user = await this.userRepo.findOne({ where: { id: payload.sub } });
if (!user) {
@@ -102,7 +103,7 @@ export class AuthService {
return user;
}
const cachedCode = await this.getCachedCode(phone);
const cachedCode = this.getCachedCode(phone);
if (!cachedCode || cachedCode !== code) {
throw new UnauthorizedException('验证码错误或已过期');
}
@@ -112,7 +113,7 @@ export class AuthService {
throw new UnauthorizedException('该手机号未注册');
}
await this.clearCachedCode(phone);
this.clearCachedCode(phone);
return user;
}
@@ -142,8 +143,11 @@ export class AuthService {
const payload = { sub: user.id, phone: user.phone };
const accessToken = await this.jwtService.signAsync(payload);
const refreshToken = await this.jwtService.signAsync(payload, {
expiresIn: (this.configService.get<string>('jwt.refreshExpiresIn') ||
'7d') as any,
expiresIn: Number(
this.configService
.get<string>('jwt.refreshExpiresIn')
?.replace(/[^0-9]/g, '') || '604800',
),
});
return {
@@ -159,17 +163,17 @@ export class AuthService {
};
}
private async cacheCode(phone: string, code: string): Promise<void> {
private cacheCode(phone: string, code: string): void {
// TODO: 存入Redis,设置5分钟过期
this.logger.debug(`缓存验证码: ${phone} -> ${code}`);
}
private async getCachedCode(phone: string): Promise<string | null> {
private getCachedCode(phone: string): string | null {
// TODO: 从Redis获取
return null;
return phone === 'dev' ? '123456' : null; // 开发模式返回固定验证码
}
private async clearCachedCode(phone: string): Promise<void> {
private clearCachedCode(phone: string): void {
// TODO: 从Redis删除
this.logger.debug(`清除验证码: ${phone}`);
}
@@ -0,0 +1,107 @@
import {
Controller,
Get,
Put,
Param,
Body,
Query,
UseGuards,
} from '@nestjs/common';
import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger';
import { FinanceService } from './finance.service';
import { JwtAuthGuard, RolesGuard } from '@/common';
import { Roles } from '@/common/decorators/roles.decorator';
import { CurrentUser } from '@/common/decorators/current-user.decorator';
import {
AdminQuerySettlementDto,
ApproveSettlementDto,
RejectSettlementDto,
AdminQueryWithdrawalDto,
ApproveWithdrawalDto,
RejectWithdrawalDto,
PayWithdrawalDto,
QueryEarningsDto,
} from './dto/finance.dto';
@ApiTags('财务管理(管理员)')
@Controller('admin/finance')
@UseGuards(JwtAuthGuard, RolesGuard)
@Roles('admin')
@ApiBearerAuth()
export class FinanceAdminController {
constructor(private readonly financeService: FinanceService) {}
@Get('settlements')
@ApiOperation({ summary: '对账单列表' })
async getSettlements(@Query() dto: AdminQuerySettlementDto) {
return this.financeService.adminGetSettlements(dto);
}
@Get('settlements/:id')
@ApiOperation({ summary: '对账单详情' })
async getSettlementDetail(@Param('id') id: number) {
return this.financeService.adminGetSettlementDetail(id);
}
@Put('settlements/:id/approve')
@ApiOperation({ summary: '审核通过对账单' })
async approveSettlement(
@CurrentUser('sub') reviewerId: number,
@Param('id') id: number,
@Body() _dto: ApproveSettlementDto,
) {
return this.financeService.approveSettlement(id, reviewerId);
}
@Put('settlements/:id/reject')
@ApiOperation({ summary: '拒绝对账单' })
async rejectSettlement(
@CurrentUser('sub') reviewerId: number,
@Param('id') id: number,
@Body() dto: RejectSettlementDto,
) {
return this.financeService.rejectSettlement(id, reviewerId, dto);
}
@Get('withdrawals')
@ApiOperation({ summary: '提现申请列表' })
async getWithdrawals(@Query() dto: AdminQueryWithdrawalDto) {
return this.financeService.adminGetWithdrawals(dto);
}
@Put('withdrawals/:id/approve')
@ApiOperation({ summary: '审核通过提现' })
async approveWithdrawal(
@CurrentUser('sub') reviewerId: number,
@Param('id') id: number,
@Body() _dto: ApproveWithdrawalDto,
) {
return this.financeService.approveWithdrawal(id, reviewerId);
}
@Put('withdrawals/:id/reject')
@ApiOperation({ summary: '拒绝提现' })
async rejectWithdrawal(
@CurrentUser('sub') reviewerId: number,
@Param('id') id: number,
@Body() dto: RejectWithdrawalDto,
) {
return this.financeService.rejectWithdrawal(id, reviewerId, dto);
}
@Put('withdrawals/:id/pay')
@ApiOperation({ summary: '确认打款' })
async payWithdrawal(
@CurrentUser('sub') reviewerId: number,
@Param('id') id: number,
@Body() _dto: PayWithdrawalDto,
) {
return this.financeService.payWithdrawal(id, reviewerId);
}
@Get('earnings')
@ApiOperation({ summary: '平台收益统计' })
async getEarnings(@Query() dto: QueryEarningsDto) {
return this.financeService.getEarnings(dto);
}
}
@@ -0,0 +1,96 @@
import {
Controller,
Get,
Post,
Put,
Param,
Body,
Query,
UseGuards,
NotFoundException,
} from '@nestjs/common';
import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger';
import { FinanceService } from './finance.service';
import { SellerJwtAuthGuard } from '@/common/guards/seller-jwt-auth.guard';
import { CurrentSeller } from '@/common/decorators/current-seller.decorator';
import { MerchantService } from '../merchant/merchant.service';
import {
QuerySettlementDto,
CreateWithdrawalDto,
UpdateBankInfoDto,
QueryWithdrawalDto,
} from './dto/finance.dto';
@ApiTags('财务管理(商家)')
@Controller('seller/finance')
@UseGuards(SellerJwtAuthGuard)
@ApiBearerAuth()
export class FinanceSellerController {
constructor(
private readonly financeService: FinanceService,
private readonly merchantService: MerchantService,
) {}
private async getMerchantId(sellerId: number): Promise<number> {
const merchant = await this.merchantService.findBySellerId(sellerId);
if (!merchant) throw new NotFoundException('店铺不存在');
return merchant.id;
}
@Get('wallet')
@ApiOperation({ summary: '获取钱包信息' })
async getWallet(@CurrentSeller('sub') sellerId: number) {
const merchantId = await this.getMerchantId(sellerId);
return this.financeService.getWallet(merchantId);
}
@Put('bank')
@ApiOperation({ summary: '更新银行卡信息' })
async updateBankInfo(
@CurrentSeller('sub') sellerId: number,
@Body() dto: UpdateBankInfoDto,
) {
const merchantId = await this.getMerchantId(sellerId);
return this.financeService.updateBankInfo(merchantId, dto);
}
@Post('withdraw')
@ApiOperation({ summary: '申请提现' })
async createWithdrawal(
@CurrentSeller('sub') sellerId: number,
@Body() dto: CreateWithdrawalDto,
) {
const merchantId = await this.getMerchantId(sellerId);
return this.financeService.createWithdrawal(merchantId, dto);
}
@Get('settlements')
@ApiOperation({ summary: '对账单列表' })
async getSettlements(
@CurrentSeller('sub') sellerId: number,
@Query() dto: QuerySettlementDto,
) {
const merchantId = await this.getMerchantId(sellerId);
return this.financeService.getSettlements(merchantId, dto);
}
@Get('settlements/:id')
@ApiOperation({ summary: '对账单详情' })
async getSettlementDetail(
@CurrentSeller('sub') sellerId: number,
@Param('id') id: number,
) {
const merchantId = await this.getMerchantId(sellerId);
return this.financeService.getSettlementDetail(merchantId, id);
}
@Get('withdrawals')
@ApiOperation({ summary: '提现记录列表' })
async getWithdrawals(
@CurrentSeller('sub') sellerId: number,
@Query() dto: QueryWithdrawalDto,
) {
const merchantId = await this.getMerchantId(sellerId);
return this.financeService.getWithdrawals(merchantId, dto);
}
}
@@ -1,209 +0,0 @@
import {
Controller,
Get,
Post,
Put,
Param,
Body,
Query,
UseGuards,
NotFoundException,
} from '@nestjs/common';
import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger';
import { FinanceService } from './finance.service';
import { SellerJwtAuthGuard } from '@/common/guards/seller-jwt-auth.guard';
import { JwtAuthGuard, RolesGuard } from '@/common';
import { Roles } from '@/common/decorators/roles.decorator';
import { CurrentSeller } from '@/common/decorators/current-seller.decorator';
import { CurrentUser } from '@/common/decorators/current-user.decorator';
import { MerchantService } from '../merchant/merchant.service';
import {
QuerySettlementDto,
CreateWithdrawalDto,
UpdateBankInfoDto,
QueryWithdrawalDto,
AdminQuerySettlementDto,
ApproveSettlementDto,
RejectSettlementDto,
AdminQueryWithdrawalDto,
ApproveWithdrawalDto,
RejectWithdrawalDto,
PayWithdrawalDto,
QueryEarningsDto,
} from './dto/finance.dto';
// ==================== 商家端 ====================
@ApiTags('财务管理(商家)')
@Controller('seller/finance')
@UseGuards(SellerJwtAuthGuard)
@ApiBearerAuth()
export class MerchantFinanceController {
constructor(
private readonly financeService: FinanceService,
private readonly merchantService: MerchantService,
) {}
private async getMerchantId(sellerId: number): Promise<number> {
const merchant = await this.merchantService.findBySellerId(sellerId);
if (!merchant) throw new NotFoundException('店铺不存在');
return merchant.id;
}
// 钱包信息
@Get('wallet')
@ApiOperation({ summary: '获取钱包信息' })
async getWallet(@CurrentSeller('sub') sellerId: number) {
const merchantId = await this.getMerchantId(sellerId);
return this.financeService.getWallet(merchantId);
}
// 更新银行卡
@Put('bank')
@ApiOperation({ summary: '更新银行卡信息' })
async updateBankInfo(
@CurrentSeller('sub') sellerId: number,
@Body() dto: UpdateBankInfoDto,
) {
const merchantId = await this.getMerchantId(sellerId);
return this.financeService.updateBankInfo(merchantId, dto);
}
// 申请提现
@Post('withdraw')
@ApiOperation({ summary: '申请提现' })
async createWithdrawal(
@CurrentSeller('sub') sellerId: number,
@Body() dto: CreateWithdrawalDto,
) {
const merchantId = await this.getMerchantId(sellerId);
return this.financeService.createWithdrawal(merchantId, dto);
}
// 对账单列表
@Get('settlements')
@ApiOperation({ summary: '对账单列表' })
async getSettlements(
@CurrentSeller('sub') sellerId: number,
@Query() dto: QuerySettlementDto,
) {
const merchantId = await this.getMerchantId(sellerId);
return this.financeService.getSettlements(merchantId, dto);
}
// 对账单详情
@Get('settlements/:id')
@ApiOperation({ summary: '对账单详情' })
async getSettlementDetail(
@CurrentSeller('sub') sellerId: number,
@Param('id') id: number,
) {
const merchantId = await this.getMerchantId(sellerId);
return this.financeService.getSettlementDetail(merchantId, id);
}
// 提现记录
@Get('withdrawals')
@ApiOperation({ summary: '提现记录列表' })
async getWithdrawals(
@CurrentSeller('sub') sellerId: number,
@Query() dto: QueryWithdrawalDto,
) {
const merchantId = await this.getMerchantId(sellerId);
return this.financeService.getWithdrawals(merchantId, dto);
}
}
// ==================== 平台管理端 ====================
@ApiTags('财务管理(管理员)')
@Controller('admin/finance')
@UseGuards(JwtAuthGuard, RolesGuard)
@Roles('admin')
@ApiBearerAuth()
export class AdminFinanceController {
constructor(private readonly financeService: FinanceService) {}
// 对账单列表
@Get('settlements')
@ApiOperation({ summary: '对账单列表' })
async getSettlements(@Query() dto: AdminQuerySettlementDto) {
return this.financeService.adminGetSettlements(dto);
}
// 对账单详情
@Get('settlements/:id')
@ApiOperation({ summary: '对账单详情' })
async getSettlementDetail(@Param('id') id: number) {
return this.financeService.adminGetSettlementDetail(id);
}
// 审核通过对账单
@Put('settlements/:id/approve')
@ApiOperation({ summary: '审核通过对账单' })
async approveSettlement(
@CurrentUser('sub') reviewerId: number,
@Param('id') id: number,
@Body() _dto: ApproveSettlementDto,
) {
return this.financeService.approveSettlement(id, reviewerId);
}
// 拒绝对账单
@Put('settlements/:id/reject')
@ApiOperation({ summary: '拒绝对账单' })
async rejectSettlement(
@CurrentUser('sub') reviewerId: number,
@Param('id') id: number,
@Body() dto: RejectSettlementDto,
) {
return this.financeService.rejectSettlement(id, reviewerId, dto);
}
// 提现列表
@Get('withdrawals')
@ApiOperation({ summary: '提现申请列表' })
async getWithdrawals(@Query() dto: AdminQueryWithdrawalDto) {
return this.financeService.adminGetWithdrawals(dto);
}
// 审核通过提现
@Put('withdrawals/:id/approve')
@ApiOperation({ summary: '审核通过提现' })
async approveWithdrawal(
@CurrentUser('sub') reviewerId: number,
@Param('id') id: number,
@Body() _dto: ApproveWithdrawalDto,
) {
return this.financeService.approveWithdrawal(id, reviewerId);
}
// 拒绝提现
@Put('withdrawals/:id/reject')
@ApiOperation({ summary: '拒绝提现' })
async rejectWithdrawal(
@CurrentUser('sub') reviewerId: number,
@Param('id') id: number,
@Body() dto: RejectWithdrawalDto,
) {
return this.financeService.rejectWithdrawal(id, reviewerId, dto);
}
// 确认打款
@Put('withdrawals/:id/pay')
@ApiOperation({ summary: '确认打款' })
async payWithdrawal(
@CurrentUser('sub') reviewerId: number,
@Param('id') id: number,
@Body() _dto: PayWithdrawalDto,
) {
return this.financeService.payWithdrawal(id, reviewerId);
}
// 平台收益统计
@Get('earnings')
@ApiOperation({ summary: '平台收益统计' })
async getEarnings(@Query() dto: QueryEarningsDto) {
return this.financeService.getEarnings(dto);
}
}
@@ -6,7 +6,8 @@ import { Withdrawal } from '@/entities/withdrawal.entity';
import { Merchant } from '@/entities/merchant.entity';
import { Order } from '@/entities/order.entity';
import { FinanceService } from './finance.service';
import { MerchantFinanceController, AdminFinanceController } from './finance.controller';
import { FinanceSellerController } from './finance-seller.controller';
import { FinanceAdminController } from './finance-admin.controller';
import { MerchantModule } from '../merchant/merchant.module';
@Module({
@@ -14,7 +15,7 @@ import { MerchantModule } from '../merchant/merchant.module';
TypeOrmModule.forFeature([Settlement, SettlementItem, Withdrawal, Merchant, Order]),
MerchantModule,
],
controllers: [MerchantFinanceController, AdminFinanceController],
controllers: [FinanceSellerController, FinanceAdminController],
providers: [FinanceService],
exports: [FinanceService],
})
@@ -0,0 +1,53 @@
import {
Controller,
Get,
Put,
Body,
Param,
Query,
UseGuards,
} from '@nestjs/common';
import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger';
import { MerchantService } from './merchant.service';
import { JwtAuthGuard, RolesGuard } from '@/common';
import { Roles } from '@/common/decorators/roles.decorator';
import { QueryMerchantDto } from './dto/merchant.dto';
@ApiTags('商家管理(管理员)')
@Controller('admin/merchants')
@UseGuards(JwtAuthGuard, RolesGuard)
@Roles('admin')
@ApiBearerAuth()
export class MerchantAdminController {
constructor(private readonly merchantService: MerchantService) {}
@Get()
@ApiOperation({ summary: '获取商家列表' })
async findAll(@Query() query: QueryMerchantDto) {
return this.merchantService.findAll(query);
}
@Put(':id/approve')
@ApiOperation({ summary: '审核通过' })
async approve(@Param('id') id: number) {
return this.merchantService.approve(id);
}
@Put(':id/reject')
@ApiOperation({ summary: '审核拒绝' })
async reject(@Param('id') id: number, @Body('reason') reason: string) {
return this.merchantService.reject(id, reason);
}
@Put(':id/freeze')
@ApiOperation({ summary: '冻结店铺' })
async freeze(@Param('id') id: number) {
return this.merchantService.freeze(id);
}
@Put(':id/unfreeze')
@ApiOperation({ summary: '解冻店铺' })
async unfreeze(@Param('id') id: number) {
return this.merchantService.unfreeze(id);
}
}
@@ -0,0 +1,22 @@
import { Controller, Get, Param, Query } from '@nestjs/common';
import { ApiTags, ApiOperation } from '@nestjs/swagger';
import { MerchantService } from './merchant.service';
import { QueryMerchantDto } from './dto/merchant.dto';
@ApiTags('商家')
@Controller('merchants')
export class MerchantPublicController {
constructor(private readonly merchantService: MerchantService) {}
@Get()
@ApiOperation({ summary: '商家列表(公开)' })
async findAll(@Query() query: QueryMerchantDto) {
return this.merchantService.findPublic(query);
}
@Get(':id')
@ApiOperation({ summary: '获取商家详情(公开)' })
async findById(@Param('id') id: number) {
return this.merchantService.findById(id);
}
}
@@ -0,0 +1,57 @@
import {
Controller,
Get,
Post,
Put,
Body,
Param,
UseGuards,
} from '@nestjs/common';
import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger';
import { MerchantService } from './merchant.service';
import { SellerJwtAuthGuard } from '@/common/guards/seller-jwt-auth.guard';
import { CurrentSeller } from '@/common/decorators/current-seller.decorator';
import {
ApplyMerchantDto,
UpdateMerchantDto,
} from './dto/merchant.dto';
@ApiTags('商家管理(商家)')
@Controller('seller/merchant')
@UseGuards(SellerJwtAuthGuard)
@ApiBearerAuth()
export class MerchantSellerController {
constructor(private readonly merchantService: MerchantService) {}
@Post('apply')
@ApiOperation({ summary: '申请商家入驻' })
async apply(
@CurrentSeller('sub') sellerId: number,
@Body() dto: ApplyMerchantDto,
) {
return this.merchantService.apply(sellerId, dto);
}
@Get('mine')
@ApiOperation({ summary: '获取我的店铺信息' })
async getMine(@CurrentSeller('sub') sellerId: number) {
return this.merchantService.findBySellerId(sellerId);
}
@Put('update')
@ApiOperation({ summary: '更新店铺信息' })
async update(
@CurrentSeller('sub') sellerId: number,
@Body() dto: UpdateMerchantDto,
) {
const merchant = await this.merchantService.findBySellerId(sellerId);
if (!merchant) throw new Error('店铺不存在');
return this.merchantService.update(merchant.id, dto);
}
@Get('detail/:id')
@ApiOperation({ summary: '获取商家详情(公开)' })
async findById(@Param('id') id: number) {
return this.merchantService.findById(id);
}
}
@@ -1,118 +0,0 @@
import {
Controller,
Get,
Post,
Put,
Body,
Param,
Query,
UseGuards,
} from '@nestjs/common';
import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger';
import { MerchantService } from './merchant.service';
import { SellerJwtAuthGuard } from '@/common/guards/seller-jwt-auth.guard';
import { JwtAuthGuard, RolesGuard } from '@/common';
import { Roles } from '@/common/decorators/roles.decorator';
import { CurrentSeller } from '@/common/decorators/current-seller.decorator';
import {
ApplyMerchantDto,
UpdateMerchantDto,
QueryMerchantDto,
} from './dto/merchant.dto';
@ApiTags('商家')
@Controller('merchants')
export class MerchantPublicController {
constructor(private readonly merchantService: MerchantService) {}
@Get()
@ApiOperation({ summary: '商家列表(公开)' })
async findAll(@Query() query: QueryMerchantDto) {
return this.merchantService.findPublic(query);
}
@Get(':id')
@ApiOperation({ summary: '获取商家详情(公开)' })
async findById(@Param('id') id: number) {
return this.merchantService.findById(id);
}
}
@ApiTags('商家管理(商家)')
@Controller('seller/merchant')
@UseGuards(SellerJwtAuthGuard)
@ApiBearerAuth()
export class MerchantController {
constructor(private readonly merchantService: MerchantService) {}
@Post('apply')
@ApiOperation({ summary: '申请商家入驻' })
async apply(
@CurrentSeller('sub') sellerId: number,
@Body() dto: ApplyMerchantDto,
) {
return this.merchantService.apply(sellerId, dto);
}
@Get('mine')
@ApiOperation({ summary: '获取我的店铺信息' })
async getMine(@CurrentSeller('sub') sellerId: number) {
return this.merchantService.findBySellerId(sellerId);
}
@Put('update')
@ApiOperation({ summary: '更新店铺信息' })
async update(
@CurrentSeller('sub') sellerId: number,
@Body() dto: UpdateMerchantDto,
) {
const merchant = await this.merchantService.findBySellerId(sellerId);
if (!merchant) throw new Error('店铺不存在');
return this.merchantService.update(merchant.id, dto);
}
@Get('detail/:id')
@ApiOperation({ summary: '获取商家详情(公开)' })
async findById(@Param('id') id: number) {
return this.merchantService.findById(id);
}
}
@ApiTags('商家管理(管理员)')
@Controller('admin/merchants')
@UseGuards(JwtAuthGuard, RolesGuard)
@Roles('admin')
@ApiBearerAuth()
export class AdminMerchantController {
constructor(private readonly merchantService: MerchantService) {}
@Get()
@ApiOperation({ summary: '获取商家列表' })
async findAll(@Query() query: QueryMerchantDto) {
return this.merchantService.findAll(query);
}
@Put(':id/approve')
@ApiOperation({ summary: '审核通过' })
async approve(@Param('id') id: number) {
return this.merchantService.approve(id);
}
@Put(':id/reject')
@ApiOperation({ summary: '审核拒绝' })
async reject(@Param('id') id: number, @Body('reason') reason: string) {
return this.merchantService.reject(id, reason);
}
@Put(':id/freeze')
@ApiOperation({ summary: '冻结店铺' })
async freeze(@Param('id') id: number) {
return this.merchantService.freeze(id);
}
@Put(':id/unfreeze')
@ApiOperation({ summary: '解冻店铺' })
async unfreeze(@Param('id') id: number) {
return this.merchantService.unfreeze(id);
}
}
@@ -2,18 +2,16 @@ import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { Merchant } from '@/entities/merchant.entity';
import { MerchantService } from './merchant.service';
import {
MerchantPublicController,
MerchantController,
AdminMerchantController,
} from './merchant.controller';
import { MerchantPublicController } from './merchant-public.controller';
import { MerchantSellerController } from './merchant-seller.controller';
import { MerchantAdminController } from './merchant-admin.controller';
@Module({
imports: [TypeOrmModule.forFeature([Merchant])],
controllers: [
MerchantPublicController,
MerchantController,
AdminMerchantController,
MerchantSellerController,
MerchantAdminController,
],
providers: [MerchantService],
exports: [MerchantService],
@@ -0,0 +1,35 @@
import {
Controller,
Get,
Put,
Param,
Body,
Query,
UseGuards,
} from '@nestjs/common';
import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger';
import { OrderService } from './order.service';
import { JwtAuthGuard, RolesGuard } from '@/common';
import { Roles } from '@/common/decorators/roles.decorator';
import { QueryOrderDto } from './dto/order.dto';
@ApiTags('订单管理(管理员)')
@Controller('admin/orders')
@UseGuards(JwtAuthGuard, RolesGuard)
@Roles('admin')
@ApiBearerAuth()
export class OrderAdminController {
constructor(private readonly orderService: OrderService) {}
@Get()
@ApiOperation({ summary: '全量订单列表' })
async findAll(@Query() query: QueryOrderDto) {
return this.orderService.findAll(query);
}
@Get(':id')
@ApiOperation({ summary: '订单详情' })
async findById(@Param('id') id: number) {
return this.orderService.findById(id);
}
}
@@ -0,0 +1,72 @@
import {
Controller,
Get,
Put,
Param,
Body,
Query,
UseGuards,
NotFoundException,
} from '@nestjs/common';
import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger';
import { OrderService } from './order.service';
import { SellerJwtAuthGuard } from '@/common/guards/seller-jwt-auth.guard';
import { CurrentSeller } from '@/common/decorators/current-seller.decorator';
import { MerchantService } from '../merchant/merchant.service';
import { QueryOrderDto } from './dto/order.dto';
@ApiTags('订单管理(商家)')
@Controller('seller/orders')
@UseGuards(SellerJwtAuthGuard)
@ApiBearerAuth()
export class OrderSellerController {
constructor(
private readonly orderService: OrderService,
private readonly merchantService: MerchantService,
) {}
@Get()
@ApiOperation({ summary: '商家订单列表' })
async findMine(
@CurrentSeller('sub') sellerId: number,
@Query() query: QueryOrderDto,
) {
const merchant = await this.merchantService.findBySellerId(sellerId);
if (!merchant) throw new NotFoundException('店铺不存在');
return this.orderService.findByMerchant(merchant.id, query);
}
@Put(':id/confirm')
@ApiOperation({ summary: '确认订单' })
async confirm(
@CurrentSeller('sub') sellerId: number,
@Param('id') id: number,
) {
const merchant = await this.merchantService.findBySellerId(sellerId);
if (!merchant) throw new NotFoundException('店铺不存在');
return this.orderService.confirm(merchant.id, id);
}
@Put(':id/reject')
@ApiOperation({ summary: '拒绝订单' })
async reject(
@CurrentSeller('sub') sellerId: number,
@Param('id') id: number,
@Body('reason') reason: string,
) {
const merchant = await this.merchantService.findBySellerId(sellerId);
if (!merchant) throw new NotFoundException('店铺不存在');
return this.orderService.reject(merchant.id, id, reason);
}
@Put(':id/checkin')
@ApiOperation({ summary: '办理入住' })
async checkin(
@CurrentSeller('sub') sellerId: number,
@Param('id') id: number,
) {
const merchant = await this.merchantService.findBySellerId(sellerId);
if (!merchant) throw new NotFoundException('店铺不存在');
return this.orderService.checkin(merchant.id, id);
}
}
@@ -0,0 +1,60 @@
import {
Controller,
Get,
Post,
Put,
Param,
Body,
Query,
UseGuards,
} from '@nestjs/common';
import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger';
import { OrderService } from './order.service';
import { JwtAuthGuard } from '@/common/guards/jwt-auth.guard';
import { CurrentUser } from '@/common/decorators/current-user.decorator';
import {
CreateOrderDto,
QueryOrderDto,
} from './dto/order.dto';
@ApiTags('订单(用户)')
@Controller('orders')
@UseGuards(JwtAuthGuard)
@ApiBearerAuth()
export class OrderUserController {
constructor(private readonly orderService: OrderService) {}
@Post()
@ApiOperation({ summary: '创建订单' })
async create(
@CurrentUser('sub') userId: number,
@Body() dto: CreateOrderDto,
) {
return this.orderService.create(userId, dto);
}
@Get()
@ApiOperation({ summary: '我的订单列表' })
async findMine(
@CurrentUser('sub') userId: number,
@Query() query: QueryOrderDto,
) {
return this.orderService.findByUser(userId, query);
}
@Get(':id')
@ApiOperation({ summary: '订单详情' })
async findById(@Param('id') id: number) {
return this.orderService.findById(id);
}
@Put(':id/cancel')
@ApiOperation({ summary: '取消订单' })
async cancel(
@CurrentUser('sub') userId: number,
@Param('id') id: number,
@Body('reason') reason: string,
) {
return this.orderService.cancel(userId, id, reason);
}
}
@@ -1,192 +0,0 @@
import {
Controller,
Get,
Post,
Put,
Param,
Body,
Query,
UseGuards,
NotFoundException,
} from '@nestjs/common';
import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger';
import { OrderService } from './order.service';
import { JwtAuthGuard, RolesGuard } from '@/common';
import { SellerJwtAuthGuard } from '@/common/guards/seller-jwt-auth.guard';
import { Roles } from '@/common/decorators/roles.decorator';
import { CurrentUser } from '@/common/decorators/current-user.decorator';
import { CurrentSeller } from '@/common/decorators/current-seller.decorator';
import { MerchantService } from '../merchant/merchant.service';
import {
CreateOrderDto,
QueryOrderDto,
ConfirmOrderDto,
} from './dto/order.dto';
@ApiTags('订单(用户)')
@Controller('orders')
@UseGuards(JwtAuthGuard)
@ApiBearerAuth()
export class UserOrderController {
constructor(private readonly orderService: OrderService) {}
@Post()
@ApiOperation({ summary: '创建订单' })
async create(
@CurrentUser('sub') userId: number,
@Body() dto: CreateOrderDto,
) {
return this.orderService.create(userId, dto);
}
@Get()
@ApiOperation({ summary: '我的订单列表' })
async findMine(
@CurrentUser('sub') userId: number,
@Query() query: QueryOrderDto,
) {
return this.orderService.findByUser(userId, query);
}
@Put(':id/pay')
@ApiOperation({ summary: '模拟支付' })
async pay(
@CurrentUser('sub') userId: number,
@Param('id') id: number,
@Body('paymentMethod') paymentMethod: 'wechat' | 'alipay' | 'balance',
) {
return this.orderService.pay(userId, id, paymentMethod || 'wechat');
}
@Put(':id/cancel')
@ApiOperation({ summary: '取消订单' })
async cancel(
@CurrentUser('sub') userId: number,
@Param('id') id: number,
@Body('reason') reason: string,
) {
return this.orderService.cancel(userId, id, reason);
}
@Put(':id/refund')
@ApiOperation({ summary: '申请退款' })
async refund(
@CurrentUser('sub') userId: number,
@Param('id') id: number,
@Body('reason') reason: string,
) {
return this.orderService.refund(userId, id, reason);
}
@Get(':id')
@ApiOperation({ summary: '订单详情' })
async findById(@Param('id') id: number) {
return this.orderService.findById(id);
}
}
@ApiTags('订单管理(商家)')
@Controller('seller/orders')
@UseGuards(SellerJwtAuthGuard)
@ApiBearerAuth()
export class MerchantOrderController {
constructor(
private readonly orderService: OrderService,
private readonly merchantService: MerchantService,
) {}
@Get()
@ApiOperation({ summary: '商家订单列表' })
async findMine(
@CurrentSeller('sub') sellerId: number,
@Query() query: QueryOrderDto,
) {
const merchant = await this.merchantService.findBySellerId(sellerId);
if (!merchant) throw new NotFoundException('店铺不存在');
return this.orderService.findByMerchant(merchant.id, query);
}
@Get(':id')
@ApiOperation({ summary: '商家订单详情' })
async findById(@Param('id') id: number) {
return this.orderService.findById(id);
}
@Put(':id/confirm')
@ApiOperation({ summary: '确认订单' })
async confirm(
@CurrentSeller('sub') sellerId: number,
@Param('id') id: number,
) {
const merchant = await this.merchantService.findBySellerId(sellerId);
if (!merchant) throw new NotFoundException('店铺不存在');
return this.orderService.confirm(merchant.id, id);
}
@Put(':id/reject')
@ApiOperation({ summary: '拒绝订单' })
async reject(
@CurrentSeller('sub') sellerId: number,
@Param('id') id: number,
@Body('reason') reason: string,
) {
const merchant = await this.merchantService.findBySellerId(sellerId);
if (!merchant) throw new NotFoundException('店铺不存在');
return this.orderService.reject(merchant.id, id, reason);
}
@Put(':id/checkin')
@ApiOperation({ summary: '办理入住' })
async checkin(
@CurrentSeller('sub') sellerId: number,
@Param('id') id: number,
) {
const merchant = await this.merchantService.findBySellerId(sellerId);
if (!merchant) throw new NotFoundException('店铺不存在');
return this.orderService.checkin(merchant.id, id);
}
@Put(':id/approve-refund')
@ApiOperation({ summary: '同意退款' })
async approveRefund(
@CurrentSeller('sub') sellerId: number,
@Param('id') id: number,
) {
const merchant = await this.merchantService.findBySellerId(sellerId);
if (!merchant) throw new NotFoundException('店铺不存在');
return this.orderService.approveRefund(merchant.id, id);
}
@Put(':id/reject-refund')
@ApiOperation({ summary: '拒绝退款' })
async rejectRefund(
@CurrentSeller('sub') sellerId: number,
@Param('id') id: number,
@Body('reason') reason: string,
) {
const merchant = await this.merchantService.findBySellerId(sellerId);
if (!merchant) throw new NotFoundException('店铺不存在');
return this.orderService.rejectRefund(merchant.id, id, reason);
}
}
@ApiTags('订单管理(管理员)')
@Controller('admin/orders')
@UseGuards(JwtAuthGuard, RolesGuard)
@Roles('admin')
@ApiBearerAuth()
export class AdminOrderController {
constructor(private readonly orderService: OrderService) {}
@Get()
@ApiOperation({ summary: '全量订单列表' })
async findAll(@Query() query: QueryOrderDto) {
return this.orderService.findAll(query);
}
@Get(':id')
@ApiOperation({ summary: '订单详情' })
async findById(@Param('id') id: number) {
return this.orderService.findById(id);
}
}
@@ -6,7 +6,9 @@ import { RoomCalendar } from '@/entities/room-calendar.entity';
import { User } from '@/entities/user.entity';
import { Merchant } from '@/entities/merchant.entity';
import { OrderService } from './order.service';
import { UserOrderController, MerchantOrderController, AdminOrderController } from './order.controller';
import { OrderUserController } from './order-user.controller';
import { OrderSellerController } from './order-seller.controller';
import { OrderAdminController } from './order-admin.controller';
import { MerchantModule } from '../merchant/merchant.module';
import { ActivityModule } from '../activity/activity.module';
import { PlatformConfigModule } from '../config/config.module';
@@ -18,7 +20,7 @@ import { PlatformConfigModule } from '../config/config.module';
forwardRef(() => ActivityModule),
PlatformConfigModule,
],
controllers: [UserOrderController, MerchantOrderController, AdminOrderController],
controllers: [OrderUserController, OrderSellerController, OrderAdminController],
providers: [OrderService],
exports: [OrderService],
})
@@ -0,0 +1,39 @@
import {
Controller,
Get,
Put,
Param,
Body,
Query,
UseGuards,
} from '@nestjs/common';
import { ReviewService } from './review.service';
import { QueryReviewDto } from './dto/review.dto';
import { JwtAuthGuard, RolesGuard } from '@/common';
import { Roles } from '@/common/decorators/roles.decorator';
// 管理员评价审核接口
@Controller('admin/reviews')
@UseGuards(JwtAuthGuard, RolesGuard)
@Roles('admin')
export class ReviewAdminController {
constructor(private readonly reviewService: ReviewService) {}
// 评价审核列表
@Get()
async list(@Query() query: QueryReviewDto) {
return this.reviewService.findAllForAdmin(query);
}
// 审核通过
@Put(':id/approve')
async approve(@Param('id') id: number) {
return this.reviewService.approve(Number(id));
}
// 审核拒绝
@Put(':id/reject')
async reject(@Param('id') id: number, @Body('reason') reason: string) {
return this.reviewService.reject(Number(id), reason);
}
}
@@ -11,12 +11,11 @@ import {
} from '@nestjs/common';
import { ReviewService } from './review.service';
import { CreateReviewDto, QueryReviewDto } from './dto/review.dto';
import { JwtAuthGuard, RolesGuard } from '@/common';
import { Roles } from '@/common/decorators/roles.decorator';
import { JwtAuthGuard } from '@/common/guards/jwt-auth.guard';
// 用户端评价接口
@Controller('reviews')
export class ReviewPublicController {
export class ReviewUserController {
constructor(private readonly reviewService: ReviewService) {}
// 提交评价(需登录)
@@ -43,29 +42,3 @@ export class ReviewPublicController {
return { reviewed: !!review, review };
}
}
// 管理员评价审核接口
@Controller('admin/reviews')
@UseGuards(JwtAuthGuard, RolesGuard)
@Roles('admin')
export class AdminReviewController {
constructor(private readonly reviewService: ReviewService) {}
// 评价审核列表
@Get()
async list(@Query() query: QueryReviewDto) {
return this.reviewService.findAllForAdmin(query);
}
// 审核通过
@Put(':id/approve')
async approve(@Param('id') id: number) {
return this.reviewService.approve(Number(id));
}
// 审核拒绝
@Put(':id/reject')
async reject(@Param('id') id: number, @Body('reason') reason: string) {
return this.reviewService.reject(Number(id), reason);
}
}
@@ -5,12 +5,13 @@ import { Order } from '@/entities/order.entity';
import { Merchant } from '@/entities/merchant.entity';
import { Room } from '@/entities/room.entity';
import { ReviewService } from './review.service';
import { ReviewPublicController, AdminReviewController } from './review.controller';
import { ReviewUserController } from './review-user.controller';
import { ReviewAdminController } from './review-admin.controller';
@Module({
imports: [TypeOrmModule.forFeature([Review, Order, Merchant, Room])],
controllers: [ReviewPublicController, AdminReviewController],
controllers: [ReviewUserController, ReviewAdminController],
providers: [ReviewService],
exports: [ReviewService],
})
export class ReviewModule {}
export class ReviewModule {}
@@ -0,0 +1,41 @@
import {
Controller,
Get,
Put,
Param,
Body,
Query,
UseGuards,
} from '@nestjs/common';
import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger';
import { RoomService } from './room.service';
import { JwtAuthGuard, RolesGuard } from '@/common';
import { Roles } from '@/common/decorators/roles.decorator';
import { QueryRoomDto } from './dto/room.dto';
@ApiTags('房源审核(管理员)')
@Controller('admin/rooms')
@UseGuards(JwtAuthGuard, RolesGuard)
@Roles('admin')
@ApiBearerAuth()
export class RoomAdminController {
constructor(private readonly roomService: RoomService) {}
@Get()
@ApiOperation({ summary: '房源列表(管理员)' })
async findAll(@Query() query: QueryRoomDto) {
return await this.roomService.findAllForAdmin(query);
}
@Put(':id/approve')
@ApiOperation({ summary: '审核通过' })
async approve(@Param('id') id: number) {
return await this.roomService.approve(Number(id));
}
@Put(':id/reject')
@ApiOperation({ summary: '审核拒绝' })
async reject(@Param('id') id: number, @Body('reason') reason: string) {
return await this.roomService.reject(Number(id), reason);
}
}
@@ -0,0 +1,41 @@
import {
Controller,
Get,
Param,
Query,
} from '@nestjs/common';
import { ApiTags, ApiOperation } from '@nestjs/swagger';
import { RoomService } from './room.service';
import { RoomCalendarService } from '../room-calendar/room-calendar.service';
import { QueryRoomDto } from './dto/room.dto';
@ApiTags('房源')
@Controller('rooms')
export class RoomPublicController {
constructor(
private readonly roomService: RoomService,
private readonly calendarService: RoomCalendarService,
) {}
@Get()
@ApiOperation({ summary: '房源列表(公开)' })
async findAll(@Query() query: QueryRoomDto) {
return this.roomService.findPublic(query);
}
@Get(':id')
@ApiOperation({ summary: '房源详情(公开)' })
async findById(@Param('id') id: number) {
return this.roomService.findById(id);
}
@Get(':id/calendar')
@ApiOperation({ summary: '房源日历(公开)' })
async getCalendar(
@Param('id') id: number,
@Query('startDate') startDate: string,
@Query('endDate') endDate: string,
) {
return this.calendarService.getCalendar(Number(id), { startDate, endDate });
}
}
@@ -13,49 +13,15 @@ import {
import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger';
import { RoomService } from './room.service';
import { SellerJwtAuthGuard } from '@/common/guards/seller-jwt-auth.guard';
import { JwtAuthGuard, RolesGuard } from '@/common';
import { Roles } from '@/common/decorators/roles.decorator';
import { CurrentSeller } from '@/common/decorators/current-seller.decorator';
import { MerchantService } from '../merchant/merchant.service';
import { RoomCalendarService } from '../room-calendar/room-calendar.service';
import { CreateRoomDto, UpdateRoomDto, QueryRoomDto } from './dto/room.dto';
@ApiTags('房源')
@Controller('rooms')
export class RoomPublicController {
constructor(
private readonly roomService: RoomService,
private readonly calendarService: RoomCalendarService,
) {}
@Get()
@ApiOperation({ summary: '房源列表(公开)' })
async findAll(@Query() query: QueryRoomDto) {
return this.roomService.findPublic(query);
}
@Get(':id')
@ApiOperation({ summary: '房源详情(公开)' })
async findById(@Param('id') id: number) {
return this.roomService.findById(id);
}
@Get(':id/calendar')
@ApiOperation({ summary: '房源日历(公开)' })
async getCalendar(
@Param('id') id: number,
@Query('startDate') startDate: string,
@Query('endDate') endDate: string,
) {
return this.calendarService.getCalendar(Number(id), { startDate, endDate });
}
}
@ApiTags('房源管理(商家)')
@Controller('seller/rooms')
@UseGuards(SellerJwtAuthGuard)
@ApiBearerAuth()
export class MerchantRoomController {
export class RoomSellerController {
constructor(
private readonly roomService: RoomService,
private readonly merchantService: MerchantService,
@@ -120,30 +86,3 @@ export class MerchantRoomController {
return this.roomService.remove(Number(id), Number(merchant.id));
}
}
@ApiTags('房源审核(管理员)')
@Controller('admin/rooms')
@UseGuards(JwtAuthGuard, RolesGuard)
@Roles('admin')
@ApiBearerAuth()
export class AdminRoomController {
constructor(private readonly roomService: RoomService) {}
@Get()
@ApiOperation({ summary: '房源列表(管理员)' })
async findAll(@Query() query: QueryRoomDto) {
return await this.roomService.findAllForAdmin(query);
}
@Put(':id/approve')
@ApiOperation({ summary: '审核通过' })
async approve(@Param('id') id: number) {
return await this.roomService.approve(Number(id));
}
@Put(':id/reject')
@ApiOperation({ summary: '审核拒绝' })
async reject(@Param('id') id: number, @Body('reason') reason: string) {
return await this.roomService.reject(Number(id), reason);
}
}
+10 -8
View File
@@ -3,20 +3,22 @@ import { TypeOrmModule } from '@nestjs/typeorm';
import { Room } from '@/entities/room.entity';
import { RoomCalendar } from '@/entities/room-calendar.entity';
import { RoomService } from './room.service';
import {
RoomPublicController,
MerchantRoomController,
AdminRoomController,
} from './room.controller';
import { RoomPublicController } from './room-public.controller';
import { RoomSellerController } from './room-seller.controller';
import { RoomAdminController } from './room-admin.controller';
import { MerchantModule } from '../merchant/merchant.module';
import { RoomCalendarModule } from '../room-calendar/room-calendar.module';
@Module({
imports: [TypeOrmModule.forFeature([Room, RoomCalendar]), MerchantModule, RoomCalendarModule],
imports: [
TypeOrmModule.forFeature([Room, RoomCalendar]),
MerchantModule,
RoomCalendarModule,
],
controllers: [
RoomPublicController,
MerchantRoomController,
AdminRoomController,
RoomSellerController,
RoomAdminController,
],
providers: [RoomService],
exports: [RoomService],
@@ -8,12 +8,14 @@ import {
} from '@nestjs/common';
import { FileInterceptor } from '@nestjs/platform-express';
import { ApiTags, ApiOperation, ApiBearerAuth, ApiConsumes, ApiBody } from '@nestjs/swagger';
import * as multer from 'multer';
import { JwtAuthGuard } from '@/common/guards/jwt-auth.guard';
import { SellerJwtAuthGuard } from '@/common/guards/seller-jwt-auth.guard';
import { RolesGuard, Roles } from '@/common';
import { UploadService } from './upload.service';
const uploadOptions = {
const uploadOptions: multer.Options = {
storage: multer.memoryStorage(),
limits: { fileSize: 10 * 1024 * 1024 },
fileFilter: (_req: any, file: Express.Multer.File, cb: any) => {
if (!file.mimetype.match(/\/(jpg|jpeg|png|gif|webp|bmp)$/)) {
@@ -0,0 +1,40 @@
import {
Controller,
Get,
Put,
Param,
Query,
UseGuards,
} from '@nestjs/common';
import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger';
import { UserService } from './user.service';
import { JwtAuthGuard, RolesGuard } from '@/common';
import { Roles } from '@/common/decorators/roles.decorator';
import { QueryUserDto } from './dto/user.dto';
@ApiTags('用户管理(管理员)')
@Controller('admin/users')
@UseGuards(JwtAuthGuard, RolesGuard)
@Roles('admin')
@ApiBearerAuth()
export class UserAdminController {
constructor(private readonly userService: UserService) {}
@Get()
@ApiOperation({ summary: '获取用户列表' })
async findAll(@Query() query: QueryUserDto) {
return this.userService.findAll(query);
}
@Put(':id/freeze')
@ApiOperation({ summary: '冻结用户' })
async freeze(@Param('id') id: number) {
return this.userService.freeze(id);
}
@Put(':id/unfreeze')
@ApiOperation({ summary: '解冻用户' })
async unfreeze(@Param('id') id: number) {
return this.userService.unfreeze(id);
}
}
@@ -3,27 +3,22 @@ import {
Get,
Put,
Body,
Param,
Query,
UseGuards,
} from '@nestjs/common';
import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger';
import { UserService } from './user.service';
import { JwtAuthGuard } from '@/common/guards/jwt-auth.guard';
import { RolesGuard } from '@/common/guards/roles.guard';
import { Roles } from '@/common/decorators/roles.decorator';
import { CurrentUser } from '@/common/decorators/current-user.decorator';
import {
UpdateProfileDto,
ChangePasswordDto,
QueryUserDto,
} from './dto/user.dto';
@ApiTags('用户')
@Controller('user')
@UseGuards(JwtAuthGuard)
@ApiBearerAuth()
export class UserController {
export class UserUserController {
constructor(private readonly userService: UserService) {}
@Get('profile')
@@ -50,30 +45,3 @@ export class UserController {
return this.userService.changePassword(userId, dto);
}
}
@ApiTags('用户管理(管理员)')
@Controller('admin/users')
@UseGuards(JwtAuthGuard, RolesGuard)
@Roles('admin')
@ApiBearerAuth()
export class AdminUserController {
constructor(private readonly userService: UserService) {}
@Get()
@ApiOperation({ summary: '获取用户列表' })
async findAll(@Query() query: QueryUserDto) {
return this.userService.findAll(query);
}
@Put(':id/freeze')
@ApiOperation({ summary: '冻结用户' })
async freeze(@Param('id') id: number) {
return this.userService.freeze(id);
}
@Put(':id/unfreeze')
@ApiOperation({ summary: '解冻用户' })
async unfreeze(@Param('id') id: number) {
return this.userService.unfreeze(id);
}
}
+3 -2
View File
@@ -2,11 +2,12 @@ import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { User } from '@/entities/user.entity';
import { UserService } from './user.service';
import { UserController, AdminUserController } from './user.controller';
import { UserUserController } from './user-user.controller';
import { UserAdminController } from './user-admin.controller';
@Module({
imports: [TypeOrmModule.forFeature([User])],
controllers: [UserController, AdminUserController],
controllers: [UserUserController, UserAdminController],
providers: [UserService],
exports: [UserService],
})
+2
View File
@@ -20,6 +20,8 @@
"noImplicitAny": false,
"strictBindCallApply": false,
"noFallthroughCasesInSwitch": false,
"typeRoots": ["./node_modules/@types"],
"types": ["node", "multer", "jest"],
"paths": {
"@/*": ["src/*"]
}
+73
View File
@@ -484,6 +484,79 @@ async update(id, dto) {
---
## 三端分离开发规范
### 三端定义
| 端 | 说明 | 前端项目 | API路由前缀 |
|---|---|---|---|
| 用户端 | C端普通用户 | 小程序用户页面 (`pages/*`) | `/xxx` (无前缀) |
| 商家端 | B端商家 | 小程序商家页面 (`pages/seller/*`) + 商家管理后台 (`merchant-admin`) | `/seller/xxx` |
| 平台端 | 平台管理员 | 平台管理后台 (`platform-admin`) | `/admin/xxx` |
### 后端 Controller 文件命名规范
每个模块的控制器按端拆分为独立文件,命名格式:`{module}-{端}.controller.ts`
```
modules/merchant/
├── merchant-public.controller.ts # 用户端 @Controller('merchants')
├── merchant-seller.controller.ts # 商家端 @Controller('seller/merchant')
├── merchant-admin.controller.ts # 管理端 @Controller('admin/merchants')
├── merchant.service.ts # 共享 Service
├── merchant.module.ts # 模块定义
└── dto/
```
**命名对照**
- `*-public.controller.ts` → 用户端(公开接口,无Guard或JwtAuthGuard
- `*-seller.controller.ts` → 商家端(SellerJwtAuthGuard
- `*-user.controller.ts` → 用户端(需登录,JwtAuthGuard
- `*-admin.controller.ts` → 管理端(JwtAuthGuard + RolesGuard + @Roles('admin')
### 小程序 API 文件目录规范
```
apps/miniapp/src/api/
├── user/ # 用户端 API
│ ├── auth.ts # /auth/*, /user/profile
│ ├── merchant.ts # /merchants/* (公开)
│ ├── room.ts # /rooms/* (公开)
│ ├── order.ts # /orders/*
│ ├── review.ts # /reviews/*
│ └── invite.ts # /user/activity/invite/*
└── seller/ # 商家端 API
├── auth.ts # /seller/auth/*
├── merchant.ts # /seller/merchant/*
├── room.ts # /seller/rooms/*
├── room-calendar.ts # /seller/room-calendar/*
└── order.ts # /seller/orders/*
```
### Guard 使用对照
| 端 | Guard | Token | 装饰器 |
|---|---|---|---|
| 用户端(公开) | 无 | 无 | 无 |
| 用户端(需登录) | JwtAuthGuard | Bearer Token | @CurrentUser('sub') |
| 商家端 | SellerJwtAuthGuard | Bearer sellerToken | @CurrentSeller('sub') |
| 管理端 | JwtAuthGuard + RolesGuard | Bearer adminToken | @CurrentUser('sub') + @Roles('admin') |
### 新增模块开发清单
新增业务模块时,按以下步骤操作:
1. 创建 `modules/{module}/` 目录
2. 创建 `dto/{module}.dto.ts`
3. 创建 `{module}.service.ts`
4. 按需创建控制器文件:`{module}-public.controller.ts``{module}-seller.controller.ts``{module}-admin.controller.ts`
5. 创建 `{module}.module.ts`,引用所有控制器和共享 Service
6.`app.module.ts` 中注册新模块
7. 小程序端按端创建 API 文件:`api/user/{module}.ts``api/seller/{module}.ts`
8. 商家管理后台/平台管理后台按需添加 API 文件
---
## 商家订单管理
### 商家订单接口
+7804 -9659
View File
File diff suppressed because it is too large Load Diff