358 lines
12 KiB
TypeScript
358 lines
12 KiB
TypeScript
import {
|
|
Controller,
|
|
Get,
|
|
Post,
|
|
Put,
|
|
Delete,
|
|
Body,
|
|
Param,
|
|
Query,
|
|
UseGuards,
|
|
BadRequestException,
|
|
} from '@nestjs/common';
|
|
import { AdminService, CouponInput } from './admin.service';
|
|
import { ProductDto } from './dto/product.dto';
|
|
import {
|
|
UpdatePricingSettingsDto,
|
|
ApplyGlobalMarginsDto,
|
|
BulkPriceAdjustmentDto,
|
|
} from './dto/pricing.dto';
|
|
import { AdminQueryDto } from './dto/admin-query.dto';
|
|
import { JwtAuthGuard } from '../auth/jwt-auth.guard';
|
|
import {
|
|
ApiTags,
|
|
ApiBearerAuth,
|
|
ApiOperation,
|
|
ApiQuery,
|
|
} from '@nestjs/swagger';
|
|
|
|
import { CreateUserDto, UpdateUserDto } from './dto/user.dto';
|
|
import { SettingsService } from '../settings/settings.service';
|
|
|
|
import { RolesGuard } from '../common/guards/roles.guard';
|
|
import { Roles } from '../common/decorators/roles.decorator';
|
|
|
|
@ApiTags('Admin - مدیریت سیستم')
|
|
@ApiBearerAuth()
|
|
@UseGuards(JwtAuthGuard, RolesGuard)
|
|
@Roles('Admin', 'SUPER_ADMIN')
|
|
@Controller('admin')
|
|
export class AdminController {
|
|
constructor(
|
|
private readonly adminService: AdminService,
|
|
private readonly settingsService: SettingsService,
|
|
) {}
|
|
|
|
@Get('dashboard/stats')
|
|
@ApiOperation({ summary: 'داشبورد مدیریت و آمار کلیدی سیستم' })
|
|
async getDashboardStats() {
|
|
const data = await this.adminService.getDashboardStats();
|
|
return { success: true, data };
|
|
}
|
|
|
|
@Get('users')
|
|
@ApiOperation({ summary: 'لیست کاربران سیستم (با صفحهبندی)' })
|
|
@ApiQuery({ name: 'page', required: false, description: 'شماره صفحه' })
|
|
@ApiQuery({ name: 'limit', required: false, description: 'تعداد آیتمها' })
|
|
@ApiQuery({ name: 'search', required: false, description: 'جستجو' })
|
|
async getUsers(@Query() query: AdminQueryDto) {
|
|
const result = await this.adminService.getUsers(query);
|
|
return { success: true, ...result };
|
|
}
|
|
|
|
@Post('users')
|
|
@ApiOperation({ summary: 'ایجاد کاربر جدید توسط ادمین' })
|
|
async createUser(@Body() dto: CreateUserDto) {
|
|
const user = await this.adminService.createUser(dto);
|
|
return {
|
|
success: true,
|
|
message: 'کاربر جدید با موفقیت ایجاد شد',
|
|
data: user,
|
|
};
|
|
}
|
|
|
|
@Get('users/:id')
|
|
@ApiOperation({ summary: 'جزئیات کاربر' })
|
|
async getUserDetails(@Param('id') id: string) {
|
|
const data = await this.adminService.getUserDetails(id);
|
|
return { success: true, data };
|
|
}
|
|
|
|
@Put('users/:id')
|
|
@ApiOperation({ summary: 'ویرایش مشخصات کامل کاربر' })
|
|
async updateUser(@Param('id') id: string, @Body() dto: UpdateUserDto) {
|
|
const user = await this.adminService.updateUser(id, dto);
|
|
return {
|
|
success: true,
|
|
message: 'اطلاعات کاربر با موفقیت ویرایش شد',
|
|
data: user,
|
|
};
|
|
}
|
|
|
|
@Delete('users/:id')
|
|
@ApiOperation({ summary: 'حذف کاربر و دادههای مرتبط' })
|
|
async deleteUser(@Param('id') id: string) {
|
|
await this.adminService.deleteUser(id);
|
|
return {
|
|
success: true,
|
|
message: 'کاربر با موفقیت از سیستم حذف شد',
|
|
};
|
|
}
|
|
|
|
@Put('users/:id/role')
|
|
@ApiOperation({ summary: 'تغییر نقش کاربر' })
|
|
async updateUserRole(@Param('id') id: string, @Body('role') role: string) {
|
|
const user = await this.adminService.updateUserRole(id, role);
|
|
return { success: true, data: user };
|
|
}
|
|
|
|
@Post('users/:id/wallet-adjust')
|
|
@ApiOperation({ summary: 'شارژ یا کسر مستقیم کیف پول کاربر توسط ادمین' })
|
|
async adjustWallet(
|
|
@Param('id') id: string,
|
|
@Body('amount') amount: number,
|
|
@Body('type') type: 'deposit' | 'withdrawal' | 'refund',
|
|
@Body('description') description?: string,
|
|
) {
|
|
const numAmount = Number(amount);
|
|
if (!numAmount || isNaN(numAmount) || numAmount <= 0) {
|
|
throw new BadRequestException('مبلغ باید یک عدد مثبت باشد');
|
|
}
|
|
if (numAmount > 100_000_000_000) {
|
|
throw new BadRequestException('مبلغ بیش از حد مجاز است');
|
|
}
|
|
if (!['deposit', 'withdrawal', 'refund'].includes(type)) {
|
|
throw new BadRequestException('نوع تراکنش معتبر نیست');
|
|
}
|
|
|
|
const result = await this.adminService.adjustUserWallet(
|
|
id,
|
|
numAmount,
|
|
type,
|
|
description,
|
|
);
|
|
return {
|
|
success: true,
|
|
message: 'موجود کیف پول با موفقیت بروزرسانی شد',
|
|
data: result,
|
|
};
|
|
}
|
|
|
|
@Get('products')
|
|
@ApiOperation({ summary: 'لیست محصولات (مدیریت)' })
|
|
@ApiQuery({ name: 'page', required: false, description: 'شماره صفحه' })
|
|
@ApiQuery({ name: 'limit', required: false, description: 'تعداد آیتمها' })
|
|
@ApiQuery({ name: 'search', required: false, description: 'جستجو' })
|
|
async getProducts(@Query() query: AdminQueryDto) {
|
|
const result = await this.adminService.getProducts(query);
|
|
return { success: true, ...result };
|
|
}
|
|
|
|
@Post('products')
|
|
@ApiOperation({ summary: 'ایجاد محصول جدید' })
|
|
async createProduct(@Body() data: ProductDto) {
|
|
const product = await this.adminService.createProduct(data);
|
|
return { success: true, data: product };
|
|
}
|
|
|
|
@Put('products/:id')
|
|
@ApiOperation({ summary: 'ویرایش محصول' })
|
|
async updateProduct(@Param('id') id: string, @Body() data: ProductDto) {
|
|
const product = await this.adminService.updateProduct(id, data);
|
|
return {
|
|
success: true,
|
|
data: product,
|
|
};
|
|
}
|
|
|
|
@Delete('products/:id')
|
|
@ApiOperation({ summary: 'حذف محصول' })
|
|
async deleteProduct(@Param('id') id: string) {
|
|
await this.adminService.deleteProduct(id);
|
|
return { success: true };
|
|
}
|
|
|
|
@Get('pricing/settings')
|
|
@ApiOperation({ summary: 'دریافت تنظیمات هوشمند قیمتگذاری و گرد کردن' })
|
|
async getPricingSettings() {
|
|
const data = await this.adminService.getPricingSettings();
|
|
return { success: true, data };
|
|
}
|
|
|
|
@Put('pricing/settings')
|
|
@ApiOperation({ summary: 'بروزرسانی تنظیمات هوشمند قیمتگذاری و گرد کردن' })
|
|
async updatePricingSettings(@Body() dto: UpdatePricingSettingsDto) {
|
|
return this.adminService.updatePricingSettings(dto);
|
|
}
|
|
|
|
@Post('pricing/apply-global-margins')
|
|
@ApiOperation({ summary: 'اعمال سراسری درصد سود تک و عمده بر روی محصولات' })
|
|
async applyGlobalMargins(@Body() dto: ApplyGlobalMarginsDto) {
|
|
return this.adminService.applyGlobalMargins(dto);
|
|
}
|
|
|
|
@Post('pricing/bulk-adjust')
|
|
@ApiOperation({
|
|
summary: 'تغییرات گروهی قیمت (درصدی یا مبلغ ثابت) بر روی محصولات',
|
|
})
|
|
async bulkPriceAdjustment(@Body() dto: BulkPriceAdjustmentDto) {
|
|
return this.adminService.bulkPriceAdjustment(dto);
|
|
}
|
|
|
|
@Get('orders')
|
|
@ApiOperation({ summary: 'لیست سفارشها (مدیریت)' })
|
|
@ApiQuery({ name: 'page', required: false, description: 'شماره صفحه' })
|
|
@ApiQuery({ name: 'limit', required: false, description: 'تعداد آیتمها' })
|
|
@ApiQuery({ name: 'status', required: false, description: 'فیلتر وضعیت' })
|
|
async getOrders(@Query() query: AdminQueryDto) {
|
|
const result = await this.adminService.getOrders(query);
|
|
return { success: true, ...result };
|
|
}
|
|
|
|
@Get('orders/:id')
|
|
@ApiOperation({ summary: 'دریافت جزئیات کامل یک سفارش با شناسه' })
|
|
async getOrderById(@Param('id') id: string) {
|
|
const order = await this.adminService.getOrderById(id);
|
|
return { success: true, data: order };
|
|
}
|
|
|
|
@Put('orders/:id/status')
|
|
@ApiOperation({ summary: 'بروزرسانی وضعیت سفارش' })
|
|
async updateOrderStatus(
|
|
@Param('id') id: string,
|
|
@Body('status') status: string,
|
|
@Body('trackingCode') trackingCode?: string,
|
|
@Body('trackingNumber') trackingNumber?: string,
|
|
) {
|
|
const finalTracking =
|
|
trackingNumber !== undefined ? trackingNumber : trackingCode;
|
|
const order = await this.adminService.updateOrderStatus(
|
|
id,
|
|
status,
|
|
finalTracking,
|
|
);
|
|
return { success: true, data: order };
|
|
}
|
|
|
|
@Post('orders/:id/refund-wallet')
|
|
@ApiOperation({ summary: 'استرداد مستقیم مبلغ سفارش به کیف پول کاربر' })
|
|
async refundOrderToWallet(
|
|
@Param('id') id: string,
|
|
@Body('amount') amount?: number,
|
|
@Body('reason') reason?: string,
|
|
) {
|
|
const result = await this.adminService.refundOrderToWallet(
|
|
id,
|
|
amount ? Number(amount) : undefined,
|
|
reason,
|
|
);
|
|
return result;
|
|
}
|
|
|
|
@Get('coupons')
|
|
@ApiOperation({ summary: 'لیست کد تخفیفها' })
|
|
@ApiQuery({ name: 'page', required: false, description: 'شماره صفحه' })
|
|
@ApiQuery({ name: 'limit', required: false, description: 'تعداد آیتمها' })
|
|
@ApiQuery({ name: 'search', required: false, description: 'جستجو' })
|
|
async getCoupons(@Query() query: AdminQueryDto) {
|
|
const coupons = await this.adminService.getCoupons(query);
|
|
return { success: true, ...coupons };
|
|
}
|
|
|
|
@Post('coupons')
|
|
@ApiOperation({ summary: 'ایجاد کد تخفیف جدید' })
|
|
async createCoupon(@Body() data: CouponInput) {
|
|
const coupon = await this.adminService.createCoupon(data);
|
|
return { success: true, data: coupon };
|
|
}
|
|
|
|
@Put('coupons/:id')
|
|
@ApiOperation({ summary: 'ویرایش کد تخفیف' })
|
|
async updateCoupon(@Param('id') id: string, @Body() data: CouponInput) {
|
|
const coupon = await this.adminService.updateCoupon(id, data);
|
|
return { success: true, data: coupon };
|
|
}
|
|
|
|
@Put('coupons/:id/toggle')
|
|
@ApiOperation({ summary: 'فعال/غیرفعال کردن کد تخفیف' })
|
|
async toggleCoupon(
|
|
@Param('id') id: string,
|
|
@Body('isActive') isActive: boolean,
|
|
) {
|
|
const coupon = await this.adminService.toggleCoupon(id, isActive);
|
|
return { success: true, data: coupon };
|
|
}
|
|
|
|
@Delete('coupons/:id')
|
|
@ApiOperation({ summary: 'حذف کد تخفیف' })
|
|
async deleteCoupon(@Param('id') id: string) {
|
|
await this.adminService.deleteCoupon(id);
|
|
return { success: true };
|
|
}
|
|
|
|
@Get('doctors')
|
|
@ApiOperation({ summary: 'لیست پزشکان و متخصصین' })
|
|
async getDoctors() {
|
|
const data = await this.adminService.getDoctors();
|
|
return { success: true, data };
|
|
}
|
|
|
|
@Post('doctors')
|
|
@ApiOperation({ summary: 'افزودن پزشک جدید' })
|
|
async createDoctor(
|
|
@Body()
|
|
body: {
|
|
name: string;
|
|
title: string;
|
|
avatarUrl?: string;
|
|
bio?: string;
|
|
clinic?: string;
|
|
},
|
|
) {
|
|
const data = await this.adminService.createDoctor(body);
|
|
return { success: true, data };
|
|
}
|
|
|
|
@Put('doctors/:id')
|
|
@ApiOperation({ summary: 'ویرایش پزشک' })
|
|
async updateDoctor(
|
|
@Param('id') id: string,
|
|
@Body()
|
|
body: {
|
|
name?: string;
|
|
title?: string;
|
|
avatarUrl?: string;
|
|
bio?: string;
|
|
clinic?: string;
|
|
},
|
|
) {
|
|
const data = await this.adminService.updateDoctor(id, body);
|
|
return { success: true, data };
|
|
}
|
|
|
|
@Delete('doctors/:id')
|
|
@ApiOperation({ summary: 'حذف پزشک' })
|
|
async deleteDoctor(@Param('id') id: string) {
|
|
await this.adminService.deleteDoctor(id);
|
|
return { success: true };
|
|
}
|
|
|
|
@Get('settings')
|
|
@ApiOperation({ summary: 'دریافت تنظیمات کلی سیستم' })
|
|
async getSettings() {
|
|
const data = await this.settingsService.getUiTexts();
|
|
const map: Record<string, string> = {};
|
|
data.forEach((item) => {
|
|
map[item.key] = item.value;
|
|
});
|
|
return { success: true, data: map };
|
|
}
|
|
|
|
@Put('settings')
|
|
@ApiOperation({ summary: 'بروزرسانی تنظیمات کلی سیستم' })
|
|
async updateSettings(@Body() body: Record<string, string>) {
|
|
await this.settingsService.updateBulkUiTexts(body);
|
|
return { success: true, data: body };
|
|
}
|
|
}
|