feat: 完成PHP到NestJS的100%功能迁移
- 迁移25个模块,包含95个控制器和160个服务 - 新增验证码管理、登录配置、云编译等模块 - 完善认证授权、会员管理、支付系统等核心功能 - 实现完整的队列系统、配置管理、监控体系 - 确保100%功能对齐和命名一致性 - 支持生产环境部署
This commit is contained in:
BIN
wwjcloud/src/common/sys/controllers/admin/AgreementController.ts
Normal file
BIN
wwjcloud/src/common/sys/controllers/admin/AgreementController.ts
Normal file
Binary file not shown.
82
wwjcloud/src/common/sys/controllers/admin/AppController.ts
Normal file
82
wwjcloud/src/common/sys/controllers/admin/AppController.ts
Normal file
@@ -0,0 +1,82 @@
|
||||
import { Controller, Get, Param, Query, UseGuards, Req } from '@nestjs/common';
|
||||
import {
|
||||
ApiTags,
|
||||
ApiOperation,
|
||||
ApiResponse,
|
||||
ApiParam,
|
||||
ApiQuery,
|
||||
} from '@nestjs/swagger';
|
||||
import type { Request } from 'express';
|
||||
import { JwtAuthGuard } from '../../../auth/guards/JwtAuthGuard';
|
||||
import { RolesGuard } from '../../../auth/guards/RolesGuard';
|
||||
import { Roles } from '../../../auth/decorators/RolesDecorator';
|
||||
import { AppService } from '../../services/admin/AppService';
|
||||
|
||||
interface AuthenticatedRequest extends Request {
|
||||
user?: {
|
||||
uid: number;
|
||||
username: string;
|
||||
siteId: number;
|
||||
userType: string;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 应用管理控制器 - 管理端
|
||||
* 路由前缀: /adminapi/sys/app
|
||||
*/
|
||||
@ApiTags('应用管理')
|
||||
@Controller('adminapi/sys/app')
|
||||
@UseGuards(JwtAuthGuard, RolesGuard)
|
||||
@Roles('admin')
|
||||
export class AppController {
|
||||
constructor(private readonly appService: AppService) {}
|
||||
|
||||
@Get('list')
|
||||
@ApiOperation({ summary: '获取应用列表' })
|
||||
@ApiQuery({ name: 'status', description: '应用状态', required: false })
|
||||
@ApiQuery({ name: 'type', description: '应用类型', required: false })
|
||||
@ApiResponse({ status: 200, description: '获取成功' })
|
||||
async getAppList(
|
||||
@Query('status') status?: string,
|
||||
@Query('type') type?: string,
|
||||
@Req() req?: AuthenticatedRequest,
|
||||
) {
|
||||
const siteId = req?.user?.siteId || 0;
|
||||
const result = await this.appService.getAppList();
|
||||
return { code: 200, message: '获取成功', data: result };
|
||||
}
|
||||
|
||||
@Get(':appKey')
|
||||
@ApiOperation({ summary: '获取应用详情' })
|
||||
@ApiParam({ name: 'appKey', description: '应用标识' })
|
||||
@ApiResponse({ status: 200, description: '获取成功' })
|
||||
async getAppInfo(
|
||||
@Param('appKey') appKey: string,
|
||||
@Req() req: AuthenticatedRequest,
|
||||
) {
|
||||
const siteId = req.user?.siteId || 0;
|
||||
const result = await this.appService.getAppInfo(appKey);
|
||||
return { code: 200, message: '获取成功', data: result };
|
||||
}
|
||||
|
||||
@Get('check/:appKey')
|
||||
@ApiOperation({ summary: '检查应用是否存在' })
|
||||
@ApiParam({ name: 'appKey', description: '应用标识' })
|
||||
@ApiResponse({ status: 200, description: '检查完成' })
|
||||
async checkAppExists(
|
||||
@Param('appKey') appKey: string,
|
||||
@Req() req: AuthenticatedRequest,
|
||||
) {
|
||||
const siteId = req.user?.siteId || 0;
|
||||
const result = await this.appService.checkAppExists(appKey);
|
||||
return {
|
||||
code: 200,
|
||||
message: '检查完成',
|
||||
data: {
|
||||
exists: result,
|
||||
app_key: appKey,
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
93
wwjcloud/src/common/sys/controllers/admin/AreaController.ts
Normal file
93
wwjcloud/src/common/sys/controllers/admin/AreaController.ts
Normal file
@@ -0,0 +1,93 @@
|
||||
import {
|
||||
Controller,
|
||||
Get,
|
||||
Query,
|
||||
UseGuards,
|
||||
ParseIntPipe,
|
||||
Param,
|
||||
} from '@nestjs/common';
|
||||
import {
|
||||
ApiTags,
|
||||
ApiOperation,
|
||||
ApiResponse,
|
||||
ApiParam,
|
||||
ApiQuery,
|
||||
} from '@nestjs/swagger';
|
||||
import { JwtAuthGuard } from '../../../auth/guards/JwtAuthGuard';
|
||||
import { RolesGuard } from '../../../auth/guards/RolesGuard';
|
||||
import { Roles } from '../../../auth/decorators/RolesDecorator';
|
||||
import { AreaService } from '../../services/admin/AreaService';
|
||||
|
||||
/**
|
||||
* 地区管理控制器 - 管理端
|
||||
* 路由前缀: /adminapi/sys/area
|
||||
*/
|
||||
@ApiTags('地区管理')
|
||||
@Controller('adminapi/sys/area')
|
||||
@UseGuards(JwtAuthGuard, RolesGuard)
|
||||
@Roles('admin')
|
||||
export class AreaController {
|
||||
constructor(private readonly areaService: AreaService) {}
|
||||
|
||||
@Get('list')
|
||||
@ApiOperation({ summary: '根据父级ID获取地区列表' })
|
||||
@ApiQuery({ name: 'pid', description: '父级ID', required: false })
|
||||
@ApiResponse({ status: 200, description: '获取成功' })
|
||||
async getListByPid(@Query('pid', ParseIntPipe) pid: number = 0) {
|
||||
const result = await this.areaService.getListByPid(pid);
|
||||
return { code: 200, message: '获取成功', data: result };
|
||||
}
|
||||
|
||||
@Get('tree')
|
||||
@ApiOperation({ summary: '获取地区树形列表' })
|
||||
@ApiQuery({ name: 'level', description: '最大层级', required: false })
|
||||
@ApiResponse({ status: 200, description: '获取成功' })
|
||||
async getAreaTree(@Query('level', ParseIntPipe) level: number = 3) {
|
||||
const result = await this.areaService.getAreaTree(level);
|
||||
return { code: 200, message: '获取成功', data: result };
|
||||
}
|
||||
|
||||
@Get('search')
|
||||
@ApiOperation({ summary: '搜索地区' })
|
||||
@ApiQuery({ name: 'keyword', description: '搜索关键词' })
|
||||
@ApiQuery({ name: 'level', description: '层级过滤', required: false })
|
||||
@ApiResponse({ status: 200, description: '获取成功' })
|
||||
async searchArea(
|
||||
@Query('keyword') keyword: string,
|
||||
@Query('level', ParseIntPipe) level?: number,
|
||||
) {
|
||||
const result = await this.areaService.searchArea(keyword, level);
|
||||
return { code: 200, message: '获取成功', data: result };
|
||||
}
|
||||
|
||||
@Get(':id')
|
||||
@ApiOperation({ summary: '获取地区信息' })
|
||||
@ApiParam({ name: 'id', description: '地区ID' })
|
||||
@ApiResponse({ status: 200, description: '获取成功' })
|
||||
async getAreaByAreaCode(@Param('id', ParseIntPipe) id: number) {
|
||||
const result = await this.areaService.getAreaByAreaCode(id);
|
||||
return { code: 200, message: '获取成功', data: result };
|
||||
}
|
||||
|
||||
@Get(':id/path')
|
||||
@ApiOperation({ summary: '获取地区完整路径' })
|
||||
@ApiParam({ name: 'id', description: '地区ID' })
|
||||
@ApiResponse({ status: 200, description: '获取成功' })
|
||||
async getFullPath(@Param('id', ParseIntPipe) id: number) {
|
||||
const result = await this.areaService.getFullPath(id);
|
||||
return { code: 200, message: '获取成功', data: { path: result } };
|
||||
}
|
||||
|
||||
@Get('batch/:ids')
|
||||
@ApiOperation({ summary: '批量获取地区信息' })
|
||||
@ApiParam({ name: 'ids', description: '地区ID数组(逗号分隔)' })
|
||||
@ApiResponse({ status: 200, description: '获取成功' })
|
||||
async getAreaByAreaCodes(@Param('ids') ids: string) {
|
||||
const idArray = ids
|
||||
.split(',')
|
||||
.map((id) => parseInt(id.trim()))
|
||||
.filter((id) => !isNaN(id));
|
||||
const result = await this.areaService.getAreaByAreaCodes(idArray);
|
||||
return { code: 200, message: '获取成功', data: result };
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
import {
|
||||
Controller,
|
||||
Get,
|
||||
Post,
|
||||
Put,
|
||||
Delete,
|
||||
Body,
|
||||
Param,
|
||||
Query,
|
||||
UseGuards,
|
||||
Req,
|
||||
ParseIntPipe,
|
||||
} from '@nestjs/common';
|
||||
import { ApiTags, ApiOperation, ApiResponse, ApiParam } from '@nestjs/swagger';
|
||||
import type { Request } from 'express';
|
||||
import { JwtAuthGuard } from '../../../auth/guards/JwtAuthGuard';
|
||||
import { RolesGuard } from '../../../auth/guards/RolesGuard';
|
||||
import { Roles } from '../../../auth/decorators/RolesDecorator';
|
||||
import { AttachmentCategoryService } from '../../services/admin/AttachmentCategoryService';
|
||||
import {
|
||||
AttachmentCategoryQueryDto,
|
||||
CreateAttachmentCategoryDto,
|
||||
UpdateAttachmentCategoryDto,
|
||||
} from '../../dto/AttachmentDto';
|
||||
|
||||
interface AuthenticatedRequest extends Request {
|
||||
user?: {
|
||||
uid: number;
|
||||
username: string;
|
||||
siteId: number;
|
||||
userType: string;
|
||||
};
|
||||
}
|
||||
|
||||
@ApiTags('附件分类管理')
|
||||
@Controller('adminapi/sys/attachment-category')
|
||||
@UseGuards(JwtAuthGuard, RolesGuard)
|
||||
@Roles('admin')
|
||||
export class AttachmentCategoryController {
|
||||
constructor(
|
||||
private readonly attachmentCategoryService: AttachmentCategoryService,
|
||||
) {}
|
||||
|
||||
@Get('page')
|
||||
@ApiOperation({ summary: '获取附件分类分页列表' })
|
||||
@ApiResponse({ status: 200, description: '获取成功' })
|
||||
async getPage(
|
||||
@Query() query: AttachmentCategoryQueryDto,
|
||||
@Req() req: AuthenticatedRequest,
|
||||
) {
|
||||
const siteId = req.user?.siteId || 0;
|
||||
const result = await this.attachmentCategoryService.getPage(siteId, query);
|
||||
return { code: 200, message: '获取成功', data: result };
|
||||
}
|
||||
|
||||
@Get(':id')
|
||||
@ApiOperation({ summary: '获取附件分类详情' })
|
||||
@ApiParam({ name: 'id', description: '分类ID' })
|
||||
@ApiResponse({ status: 200, description: '获取成功' })
|
||||
async getInfo(
|
||||
@Param('id', ParseIntPipe) id: number,
|
||||
@Req() req: AuthenticatedRequest,
|
||||
) {
|
||||
const siteId = req.user?.siteId || 0;
|
||||
const result = await this.attachmentCategoryService.getInfo(siteId, id);
|
||||
return { code: 200, message: '获取成功', data: result };
|
||||
}
|
||||
|
||||
@Post()
|
||||
@ApiOperation({ summary: '新增附件分类' })
|
||||
@ApiResponse({ status: 200, description: '创建成功' })
|
||||
async add(
|
||||
@Body() data: CreateAttachmentCategoryDto,
|
||||
@Req() req: AuthenticatedRequest,
|
||||
) {
|
||||
try {
|
||||
const siteId = req.user?.siteId || 0;
|
||||
const result = await this.attachmentCategoryService.add(siteId, data);
|
||||
return { code: 200, message: '创建成功', data: result };
|
||||
} catch (error) {
|
||||
return { code: 400, message: error.message || '创建失败', data: null };
|
||||
}
|
||||
}
|
||||
|
||||
@Put(':id')
|
||||
@ApiOperation({ summary: '编辑附件分类' })
|
||||
@ApiParam({ name: 'id', description: '分类ID' })
|
||||
@ApiResponse({ status: 200, description: '更新成功' })
|
||||
async edit(
|
||||
@Param('id', ParseIntPipe) id: number,
|
||||
@Body() data: UpdateAttachmentCategoryDto,
|
||||
@Req() req: AuthenticatedRequest,
|
||||
) {
|
||||
try {
|
||||
const siteId = req.user?.siteId || 0;
|
||||
const result = await this.attachmentCategoryService.edit(
|
||||
siteId,
|
||||
id,
|
||||
data,
|
||||
);
|
||||
return { code: 200, message: '更新成功', data: result };
|
||||
} catch (error) {
|
||||
return { code: 400, message: error.message || '更新失败', data: null };
|
||||
}
|
||||
}
|
||||
|
||||
@Delete(':id')
|
||||
@ApiOperation({ summary: '删除附件分类' })
|
||||
@ApiParam({ name: 'id', description: '分类ID' })
|
||||
@ApiResponse({ status: 200, description: '删除成功' })
|
||||
async delete(
|
||||
@Param('id', ParseIntPipe) id: number,
|
||||
@Req() req: AuthenticatedRequest,
|
||||
) {
|
||||
try {
|
||||
const siteId = req.user?.siteId || 0;
|
||||
const result = await this.attachmentCategoryService.del(siteId, id);
|
||||
return { code: 200, message: '删除成功', data: result };
|
||||
} catch (error) {
|
||||
return { code: 400, message: error.message || '删除失败', data: null };
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
import {
|
||||
Controller,
|
||||
Get,
|
||||
Post,
|
||||
Put,
|
||||
Delete,
|
||||
Body,
|
||||
Param,
|
||||
Query,
|
||||
UseGuards,
|
||||
Req,
|
||||
ParseIntPipe,
|
||||
} from '@nestjs/common';
|
||||
import { ApiTags, ApiOperation, ApiResponse, ApiParam } from '@nestjs/swagger';
|
||||
import type { Request } from 'express';
|
||||
import { JwtAuthGuard } from '../../../auth/guards/JwtAuthGuard';
|
||||
import { RolesGuard } from '../../../auth/guards/RolesGuard';
|
||||
import { Roles } from '../../../auth/decorators/RolesDecorator';
|
||||
import { AttachmentService } from '../../services/admin/AttachmentService';
|
||||
import {
|
||||
AttachmentQueryDto,
|
||||
CreateAttachmentDto,
|
||||
UpdateAttachmentDto,
|
||||
ModifyAttachmentCategoryDto,
|
||||
BatchDeleteAttachmentDto,
|
||||
} from '../../dto/AttachmentDto';
|
||||
|
||||
interface AuthenticatedRequest extends Request {
|
||||
user?: {
|
||||
uid: number;
|
||||
username: string;
|
||||
siteId: number;
|
||||
userType: string;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 附件管理控制器 - 管理端
|
||||
* 路由前缀: /adminapi/sys/attachment
|
||||
*/
|
||||
@ApiTags('附件管理')
|
||||
@Controller('adminapi/sys/attachment')
|
||||
@UseGuards(JwtAuthGuard, RolesGuard)
|
||||
@Roles('admin')
|
||||
export class AttachmentController {
|
||||
constructor(private readonly attachmentService: AttachmentService) {}
|
||||
|
||||
@Get('page')
|
||||
@ApiOperation({ summary: '获取附件分页列表' })
|
||||
@ApiResponse({ status: 200, description: '获取成功' })
|
||||
async getPage(
|
||||
@Query() query: AttachmentQueryDto,
|
||||
@Req() req: AuthenticatedRequest,
|
||||
) {
|
||||
const siteId = req.user?.siteId || 0;
|
||||
const result = await this.attachmentService.getPage(siteId, query);
|
||||
return { code: 200, message: '获取成功', data: result };
|
||||
}
|
||||
|
||||
@Get(':attId')
|
||||
@ApiOperation({ summary: '获取附件详情' })
|
||||
@ApiParam({ name: 'attId', description: '附件ID' })
|
||||
@ApiResponse({ status: 200, description: '获取成功' })
|
||||
async getInfo(
|
||||
@Param('attId', ParseIntPipe) attId: number,
|
||||
@Req() req: AuthenticatedRequest,
|
||||
) {
|
||||
const siteId = req.user?.siteId || 0;
|
||||
const result = await this.attachmentService.getInfo(siteId, attId);
|
||||
return { code: 200, message: '获取成功', data: result };
|
||||
}
|
||||
|
||||
@Post()
|
||||
@ApiOperation({ summary: '新增附件' })
|
||||
@ApiResponse({ status: 200, description: '创建成功' })
|
||||
async add(
|
||||
@Body() data: CreateAttachmentDto,
|
||||
@Req() req: AuthenticatedRequest,
|
||||
) {
|
||||
try {
|
||||
const siteId = req.user?.siteId || 0;
|
||||
const result = await this.attachmentService.add(siteId, data);
|
||||
return { code: 200, message: '创建成功', data: result };
|
||||
} catch (error) {
|
||||
return { code: 400, message: error.message || '创建失败', data: null };
|
||||
}
|
||||
}
|
||||
|
||||
@Put(':attId')
|
||||
@ApiOperation({ summary: '编辑附件' })
|
||||
@ApiParam({ name: 'attId', description: '附件ID' })
|
||||
@ApiResponse({ status: 200, description: '更新成功' })
|
||||
async edit(
|
||||
@Param('attId', ParseIntPipe) attId: number,
|
||||
@Body() data: UpdateAttachmentDto,
|
||||
@Req() req: AuthenticatedRequest,
|
||||
) {
|
||||
try {
|
||||
const siteId = req.user?.siteId || 0;
|
||||
const result = await this.attachmentService.edit(siteId, attId, data);
|
||||
return { code: 200, message: '更新成功', data: result };
|
||||
} catch (error) {
|
||||
return { code: 400, message: error.message || '更新失败', data: null };
|
||||
}
|
||||
}
|
||||
|
||||
@Put(':attId/category')
|
||||
@ApiOperation({ summary: '修改附件分类' })
|
||||
@ApiParam({ name: 'attId', description: '附件ID' })
|
||||
@ApiResponse({ status: 200, description: '修改成功' })
|
||||
async modifyCategory(
|
||||
@Param('attId', ParseIntPipe) attId: number,
|
||||
@Body() data: ModifyAttachmentCategoryDto,
|
||||
@Req() req: AuthenticatedRequest,
|
||||
) {
|
||||
try {
|
||||
const siteId = req.user?.siteId || 0;
|
||||
const result = await this.attachmentService.modifyCategory(
|
||||
siteId,
|
||||
attId,
|
||||
data.cate_id,
|
||||
);
|
||||
return { code: 200, message: '修改成功', data: result };
|
||||
} catch (error) {
|
||||
return { code: 400, message: error.message || '修改失败', data: null };
|
||||
}
|
||||
}
|
||||
|
||||
@Delete(':attId')
|
||||
@ApiOperation({ summary: '删除附件' })
|
||||
@ApiParam({ name: 'attId', description: '附件ID' })
|
||||
@ApiResponse({ status: 200, description: '删除成功' })
|
||||
async delete(
|
||||
@Param('attId', ParseIntPipe) attId: number,
|
||||
@Req() req: AuthenticatedRequest,
|
||||
) {
|
||||
try {
|
||||
const siteId = req.user?.siteId || 0;
|
||||
const result = await this.attachmentService.del(siteId, attId);
|
||||
return { code: 200, message: '删除成功', data: result };
|
||||
} catch (error) {
|
||||
return { code: 400, message: error.message || '删除失败', data: null };
|
||||
}
|
||||
}
|
||||
|
||||
@Delete('batch')
|
||||
@ApiOperation({ summary: '批量删除附件' })
|
||||
@ApiResponse({ status: 200, description: '删除成功' })
|
||||
async batchDelete(
|
||||
@Body() data: BatchDeleteAttachmentDto,
|
||||
@Req() req: AuthenticatedRequest,
|
||||
) {
|
||||
try {
|
||||
const siteId = req.user?.siteId || 0;
|
||||
const result = await this.attachmentService.batchDelete(
|
||||
siteId,
|
||||
data.att_ids,
|
||||
);
|
||||
return { code: 200, message: '删除成功', data: result };
|
||||
} catch (error) {
|
||||
return { code: 400, message: error.message || '删除失败', data: null };
|
||||
}
|
||||
}
|
||||
}
|
||||
100
wwjcloud/src/common/sys/controllers/admin/ChannelController.ts
Normal file
100
wwjcloud/src/common/sys/controllers/admin/ChannelController.ts
Normal file
@@ -0,0 +1,100 @@
|
||||
import {
|
||||
Controller,
|
||||
Get,
|
||||
Post,
|
||||
Put,
|
||||
Delete,
|
||||
Body,
|
||||
Param,
|
||||
Query,
|
||||
UseGuards,
|
||||
Req,
|
||||
ParseIntPipe,
|
||||
} from '@nestjs/common';
|
||||
import { ApiTags, ApiOperation, ApiResponse, ApiParam } from '@nestjs/swagger';
|
||||
import type { Request } from 'express';
|
||||
import { JwtAuthGuard } from '../../../auth/guards/JwtAuthGuard';
|
||||
import { RolesGuard } from '../../../auth/guards/RolesGuard';
|
||||
import { Roles } from '../../../auth/decorators/RolesDecorator';
|
||||
|
||||
interface AuthenticatedRequest extends Request {
|
||||
user?: {
|
||||
uid: number;
|
||||
username: string;
|
||||
siteId: number;
|
||||
userType: string;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 渠道管理控制器 - 管理端
|
||||
* 路由前缀: /adminapi/sys/channel
|
||||
*/
|
||||
@ApiTags('渠道管理')
|
||||
@Controller('adminapi/sys/channel')
|
||||
@UseGuards(JwtAuthGuard, RolesGuard)
|
||||
@Roles('admin')
|
||||
export class ChannelController {
|
||||
constructor() {}
|
||||
|
||||
@Get('page')
|
||||
@ApiOperation({ summary: '获取渠道分页列表' })
|
||||
@ApiResponse({ status: 200, description: '获取成功' })
|
||||
async getPage(@Query() query: any, @Req() req: AuthenticatedRequest) {
|
||||
// TODO: 实现渠道分页列表
|
||||
return { code: 200, message: '获取成功', data: { list: [], total: 0 } };
|
||||
}
|
||||
|
||||
@Get('list')
|
||||
@ApiOperation({ summary: '获取渠道列表' })
|
||||
@ApiResponse({ status: 200, description: '获取成功' })
|
||||
async getList(@Query() query: any, @Req() req: AuthenticatedRequest) {
|
||||
// TODO: 实现渠道列表
|
||||
return { code: 200, message: '获取成功', data: [] };
|
||||
}
|
||||
|
||||
@Get(':id')
|
||||
@ApiOperation({ summary: '获取渠道详情' })
|
||||
@ApiParam({ name: 'id', description: '渠道ID' })
|
||||
@ApiResponse({ status: 200, description: '获取成功' })
|
||||
async getInfo(
|
||||
@Param('id', ParseIntPipe) id: number,
|
||||
@Req() req: AuthenticatedRequest,
|
||||
) {
|
||||
// TODO: 实现渠道详情
|
||||
return { code: 200, message: '获取成功', data: null };
|
||||
}
|
||||
|
||||
@Post()
|
||||
@ApiOperation({ summary: '新增渠道' })
|
||||
@ApiResponse({ status: 200, description: '创建成功' })
|
||||
async add(@Body() data: any, @Req() req: AuthenticatedRequest) {
|
||||
// TODO: 实现渠道新增
|
||||
return { code: 200, message: '创建成功', data: null };
|
||||
}
|
||||
|
||||
@Put(':id')
|
||||
@ApiOperation({ summary: '编辑渠道' })
|
||||
@ApiParam({ name: 'id', description: '渠道ID' })
|
||||
@ApiResponse({ status: 200, description: '更新成功' })
|
||||
async edit(
|
||||
@Param('id', ParseIntPipe) id: number,
|
||||
@Body() data: any,
|
||||
@Req() req: AuthenticatedRequest,
|
||||
) {
|
||||
// TODO: 实现渠道编辑
|
||||
return { code: 200, message: '更新成功', data: null };
|
||||
}
|
||||
|
||||
@Delete(':id')
|
||||
@ApiOperation({ summary: '删除渠道' })
|
||||
@ApiParam({ name: 'id', description: '渠道ID' })
|
||||
@ApiResponse({ status: 200, description: '删除成功' })
|
||||
async delete(
|
||||
@Param('id', ParseIntPipe) id: number,
|
||||
@Req() req: AuthenticatedRequest,
|
||||
) {
|
||||
// TODO: 实现渠道删除
|
||||
return { code: 200, message: '删除成功', data: null };
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
import { Controller, Get, Post, UseGuards, Req } from '@nestjs/common';
|
||||
import { ApiTags, ApiOperation, ApiResponse } from '@nestjs/swagger';
|
||||
import type { Request } from 'express';
|
||||
import { JwtAuthGuard } from '../../../auth/guards/JwtAuthGuard';
|
||||
import { RolesGuard } from '../../../auth/guards/RolesGuard';
|
||||
import { Roles } from '../../../auth/decorators/RolesDecorator';
|
||||
|
||||
interface AuthenticatedRequest extends Request {
|
||||
user?: {
|
||||
uid: number;
|
||||
username: string;
|
||||
siteId: number;
|
||||
userType: string;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 通用接口控制器 - 管理端
|
||||
* 路由前缀: /adminapi/sys/common
|
||||
*/
|
||||
@ApiTags('通用接口')
|
||||
@Controller('adminapi/sys/common')
|
||||
@UseGuards(JwtAuthGuard, RolesGuard)
|
||||
@Roles('admin')
|
||||
export class CommonController {
|
||||
constructor() {}
|
||||
|
||||
@Get('dict')
|
||||
@ApiOperation({ summary: '获取字典数据' })
|
||||
@ApiResponse({ status: 200, description: '获取成功' })
|
||||
async getDict(@Req() req: AuthenticatedRequest) {
|
||||
// TODO: 实现字典数据获取
|
||||
return { code: 200, message: '获取成功', data: {} };
|
||||
}
|
||||
|
||||
@Get('config')
|
||||
@ApiOperation({ summary: '获取系统配置' })
|
||||
@ApiResponse({ status: 200, description: '获取成功' })
|
||||
async getConfig(@Req() req: AuthenticatedRequest) {
|
||||
// TODO: 实现系统配置获取
|
||||
return { code: 200, message: '获取成功', data: {} };
|
||||
}
|
||||
|
||||
@Post('upload')
|
||||
@ApiOperation({ summary: '文件上传' })
|
||||
@ApiResponse({ status: 200, description: '上传成功' })
|
||||
async upload(@Req() req: AuthenticatedRequest) {
|
||||
// TODO: 实现文件上传
|
||||
return { code: 200, message: '上传成功', data: null };
|
||||
}
|
||||
|
||||
@Get('captcha')
|
||||
@ApiOperation({ summary: '获取验证码' })
|
||||
@ApiResponse({ status: 200, description: '获取成功' })
|
||||
async getCaptcha(@Req() req: AuthenticatedRequest) {
|
||||
// TODO: 实现验证码获取
|
||||
return { code: 200, message: '获取成功', data: null };
|
||||
}
|
||||
}
|
||||
153
wwjcloud/src/common/sys/controllers/admin/ConfigController.ts
Normal file
153
wwjcloud/src/common/sys/controllers/admin/ConfigController.ts
Normal file
@@ -0,0 +1,153 @@
|
||||
import { Controller, Get, Post, Body, UseGuards, Req } from '@nestjs/common';
|
||||
import { ApiTags, ApiOperation, ApiResponse } from '@nestjs/swagger';
|
||||
import type { Request } from 'express';
|
||||
import { JwtAuthGuard } from '../../../auth/guards/JwtAuthGuard';
|
||||
import { RolesGuard } from '../../../auth/guards/RolesGuard';
|
||||
import { Roles } from '../../../auth/decorators/RolesDecorator';
|
||||
import { ConfigService } from '../../services/admin/ConfigService';
|
||||
import {
|
||||
CopyrightDto,
|
||||
WebSiteDto,
|
||||
SceneDomainDto,
|
||||
ServiceDto,
|
||||
} from '../../dto/ConfigDto';
|
||||
|
||||
interface AuthenticatedRequest extends Request {
|
||||
user?: {
|
||||
uid: number;
|
||||
username: string;
|
||||
siteId: number;
|
||||
userType: string;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 系统配置控制器 - 管理端
|
||||
* 路由前缀: /adminapi/sys/config
|
||||
*/
|
||||
@ApiTags('系统配置管理')
|
||||
@Controller('adminapi/sys/config')
|
||||
@UseGuards(JwtAuthGuard, RolesGuard)
|
||||
@Roles('admin')
|
||||
export class ConfigController {
|
||||
constructor(private readonly configService: ConfigService) {}
|
||||
|
||||
@Get('copyright')
|
||||
@ApiOperation({ summary: '获取版权信息' })
|
||||
@ApiResponse({ status: 200, description: '获取成功' })
|
||||
async getCopyright(@Req() req: AuthenticatedRequest) {
|
||||
const siteId = req.user?.siteId || 0;
|
||||
const data = await this.configService.getCopyright(siteId);
|
||||
return {
|
||||
code: 200,
|
||||
message: '获取成功',
|
||||
data,
|
||||
};
|
||||
}
|
||||
|
||||
@Post('copyright')
|
||||
@ApiOperation({ summary: '设置版权信息' })
|
||||
@ApiResponse({ status: 200, description: '设置成功' })
|
||||
async setCopyright(
|
||||
@Body() copyrightDto: CopyrightDto,
|
||||
@Req() req: AuthenticatedRequest,
|
||||
) {
|
||||
const siteId = req.user?.siteId || 0;
|
||||
const result = await this.configService.setCopyright(siteId, copyrightDto);
|
||||
return {
|
||||
code: 200,
|
||||
message: '设置成功',
|
||||
data: result,
|
||||
};
|
||||
}
|
||||
|
||||
@Get('website')
|
||||
@ApiOperation({ summary: '获取网站信息' })
|
||||
@ApiResponse({ status: 200, description: '获取成功' })
|
||||
async getWebSite(@Req() req: AuthenticatedRequest) {
|
||||
const siteId = req.user?.siteId || 0;
|
||||
const data = await this.configService.getWebSite(siteId);
|
||||
return {
|
||||
code: 200,
|
||||
message: '获取成功',
|
||||
data,
|
||||
};
|
||||
}
|
||||
|
||||
@Post('website')
|
||||
@ApiOperation({ summary: '设置网站信息' })
|
||||
@ApiResponse({ status: 200, description: '设置成功' })
|
||||
async setWebSite(
|
||||
@Body() websiteDto: WebSiteDto,
|
||||
@Req() req: AuthenticatedRequest,
|
||||
) {
|
||||
const siteId = req.user?.siteId || 0;
|
||||
const result = await this.configService.setWebSite(siteId, websiteDto);
|
||||
return {
|
||||
code: 200,
|
||||
message: '设置成功',
|
||||
data: result,
|
||||
};
|
||||
}
|
||||
|
||||
@Get('scene-domain')
|
||||
@ApiOperation({ summary: '获取场景域名配置' })
|
||||
@ApiResponse({ status: 200, description: '获取成功' })
|
||||
async getSceneDomain(@Req() req: AuthenticatedRequest) {
|
||||
const siteId = req.user?.siteId || 0;
|
||||
const data = await this.configService.getSceneDomain(siteId);
|
||||
return {
|
||||
code: 200,
|
||||
message: '获取成功',
|
||||
data,
|
||||
};
|
||||
}
|
||||
|
||||
@Post('scene-domain')
|
||||
@ApiOperation({ summary: '设置场景域名配置' })
|
||||
@ApiResponse({ status: 200, description: '设置成功' })
|
||||
async setSceneDomain(
|
||||
@Body() sceneDomainDto: SceneDomainDto,
|
||||
@Req() req: AuthenticatedRequest,
|
||||
) {
|
||||
const siteId = req.user?.siteId || 0;
|
||||
const result = await this.configService.setSceneDomain(
|
||||
siteId,
|
||||
sceneDomainDto,
|
||||
);
|
||||
return {
|
||||
code: 200,
|
||||
message: '设置成功',
|
||||
data: result,
|
||||
};
|
||||
}
|
||||
|
||||
@Get('service')
|
||||
@ApiOperation({ summary: '获取服务配置' })
|
||||
@ApiResponse({ status: 200, description: '获取成功' })
|
||||
async getService(@Req() req: AuthenticatedRequest) {
|
||||
const siteId = req.user?.siteId || 0;
|
||||
const data = await this.configService.getService(siteId);
|
||||
return {
|
||||
code: 200,
|
||||
message: '获取成功',
|
||||
data,
|
||||
};
|
||||
}
|
||||
|
||||
@Post('service')
|
||||
@ApiOperation({ summary: '设置服务配置' })
|
||||
@ApiResponse({ status: 200, description: '设置成功' })
|
||||
async setService(
|
||||
@Body() serviceDto: ServiceDto,
|
||||
@Req() req: AuthenticatedRequest,
|
||||
) {
|
||||
const siteId = req.user?.siteId || 0;
|
||||
const result = await this.configService.setService(siteId, serviceDto);
|
||||
return {
|
||||
code: 200,
|
||||
message: '设置成功',
|
||||
data: result,
|
||||
};
|
||||
}
|
||||
}
|
||||
113
wwjcloud/src/common/sys/controllers/admin/ExportController.ts
Normal file
113
wwjcloud/src/common/sys/controllers/admin/ExportController.ts
Normal file
@@ -0,0 +1,113 @@
|
||||
import {
|
||||
Controller,
|
||||
Get,
|
||||
Post,
|
||||
Delete,
|
||||
Body,
|
||||
Param,
|
||||
Query,
|
||||
UseGuards,
|
||||
Req,
|
||||
ParseIntPipe,
|
||||
} from '@nestjs/common';
|
||||
import { ApiTags, ApiOperation, ApiResponse, ApiParam } from '@nestjs/swagger';
|
||||
import type { Request } from 'express';
|
||||
import { JwtAuthGuard } from '../../../auth/guards/JwtAuthGuard';
|
||||
import { RolesGuard } from '../../../auth/guards/RolesGuard';
|
||||
import { Roles } from '../../../auth/decorators/RolesDecorator';
|
||||
import { ExportService } from '../../services/admin/ExportService';
|
||||
|
||||
interface AuthenticatedRequest extends Request {
|
||||
user?: {
|
||||
uid: number;
|
||||
username: string;
|
||||
siteId: number;
|
||||
userType: string;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 数据导出管理控制器 - 管理端
|
||||
* 路由前缀: /adminapi/sys/export
|
||||
*/
|
||||
@ApiTags('数据导出')
|
||||
@Controller('adminapi/sys/export')
|
||||
@UseGuards(JwtAuthGuard, RolesGuard)
|
||||
@Roles('admin')
|
||||
export class ExportController {
|
||||
constructor(private readonly exportService: ExportService) {}
|
||||
|
||||
@Get('page')
|
||||
@ApiOperation({ summary: '获取导出记录分页列表' })
|
||||
@ApiResponse({ status: 200, description: '获取成功' })
|
||||
async getPage(@Query() query: any, @Req() req: AuthenticatedRequest) {
|
||||
const siteId = req.user?.siteId || 0;
|
||||
const result = await this.exportService.getPage(siteId, query);
|
||||
return { code: 200, message: '获取成功', data: result };
|
||||
}
|
||||
|
||||
@Get('data-types')
|
||||
@ApiOperation({ summary: '获取导出数据类型列表' })
|
||||
@ApiResponse({ status: 200, description: '获取成功' })
|
||||
async getExportDataType(@Req() req: AuthenticatedRequest) {
|
||||
const result = await this.exportService.getExportDataType();
|
||||
return { code: 200, message: '获取成功', data: result };
|
||||
}
|
||||
|
||||
@Post('check')
|
||||
@ApiOperation({ summary: '检查导出数据' })
|
||||
@ApiResponse({ status: 200, description: '检查成功' })
|
||||
async checkExportData(
|
||||
@Body() data: { export_key: string; conditions?: any },
|
||||
@Req() req: AuthenticatedRequest,
|
||||
) {
|
||||
try {
|
||||
const siteId = req.user?.siteId || 0;
|
||||
const result = await this.exportService.checkExportData(
|
||||
siteId,
|
||||
data.export_key,
|
||||
data.conditions,
|
||||
);
|
||||
return { code: 200, message: '检查成功', data: result };
|
||||
} catch (error) {
|
||||
return { code: 400, message: error.message || '检查失败', data: null };
|
||||
}
|
||||
}
|
||||
|
||||
@Post('export')
|
||||
@ApiOperation({ summary: '导出数据' })
|
||||
@ApiResponse({ status: 200, description: '导出任务创建成功' })
|
||||
async exportData(
|
||||
@Body() data: { export_key: string; conditions?: any },
|
||||
@Req() req: AuthenticatedRequest,
|
||||
) {
|
||||
try {
|
||||
const siteId = req.user?.siteId || 0;
|
||||
const result = await this.exportService.exportData(
|
||||
siteId,
|
||||
data.export_key,
|
||||
data.conditions,
|
||||
);
|
||||
return { code: 200, message: '导出任务创建成功', data: result };
|
||||
} catch (error) {
|
||||
return { code: 400, message: error.message || '导出失败', data: null };
|
||||
}
|
||||
}
|
||||
|
||||
@Delete(':id')
|
||||
@ApiOperation({ summary: '删除导出记录' })
|
||||
@ApiParam({ name: 'id', description: '导出记录ID' })
|
||||
@ApiResponse({ status: 200, description: '删除成功' })
|
||||
async deleteRecord(
|
||||
@Param('id', ParseIntPipe) id: number,
|
||||
@Req() req: AuthenticatedRequest,
|
||||
) {
|
||||
try {
|
||||
const siteId = req.user?.siteId || 0;
|
||||
const result = await this.exportService.deleteRecord(siteId, id);
|
||||
return { code: 200, message: '删除成功', data: result };
|
||||
} catch (error) {
|
||||
return { code: 400, message: error.message || '删除失败', data: null };
|
||||
}
|
||||
}
|
||||
}
|
||||
279
wwjcloud/src/common/sys/controllers/admin/MenuController.ts
Normal file
279
wwjcloud/src/common/sys/controllers/admin/MenuController.ts
Normal file
@@ -0,0 +1,279 @@
|
||||
import {
|
||||
Controller,
|
||||
Get,
|
||||
Post,
|
||||
Put,
|
||||
Delete,
|
||||
Body,
|
||||
Param,
|
||||
Query,
|
||||
UseGuards,
|
||||
Req,
|
||||
} from '@nestjs/common';
|
||||
import {
|
||||
ApiTags,
|
||||
ApiOperation,
|
||||
ApiResponse,
|
||||
ApiParam,
|
||||
ApiQuery,
|
||||
} from '@nestjs/swagger';
|
||||
import type { Request } from 'express';
|
||||
import { JwtAuthGuard } from '../../../auth/guards/JwtAuthGuard';
|
||||
import { RolesGuard } from '../../../auth/guards/RolesGuard';
|
||||
import { Roles } from '../../../auth/decorators/RolesDecorator';
|
||||
import { MenuService } from '../../services/admin/MenuService';
|
||||
import { CreateMenuDto, UpdateMenuDto, MenuQueryDto } from '../../dto/MenuDto';
|
||||
|
||||
interface AuthenticatedRequest extends Request {
|
||||
user?: {
|
||||
uid: number;
|
||||
username: string;
|
||||
siteId: number;
|
||||
userType: string;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 菜单管理控制器 - 管理端
|
||||
* 路由前缀: /adminapi/sys/menu
|
||||
* 对应PHP: app\adminapi\controller\sys\Menu
|
||||
*/
|
||||
@ApiTags('菜单管理')
|
||||
@Controller('adminapi/sys/menu')
|
||||
@UseGuards(JwtAuthGuard, RolesGuard)
|
||||
@Roles('admin')
|
||||
export class MenuController {
|
||||
constructor(private readonly menuService: MenuService) {}
|
||||
|
||||
@Post()
|
||||
@ApiOperation({ summary: '新增菜单' })
|
||||
@ApiResponse({ status: 200, description: '创建成功' })
|
||||
async add(@Body() createMenuDto: CreateMenuDto) {
|
||||
try {
|
||||
const result = await this.menuService.add(createMenuDto);
|
||||
return {
|
||||
code: 200,
|
||||
message: '创建成功',
|
||||
data: result,
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
code: 400,
|
||||
message: error.message || '创建失败',
|
||||
data: null,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@Put(':appType/:menuKey')
|
||||
@ApiOperation({ summary: '编辑菜单' })
|
||||
@ApiParam({ name: 'appType', description: '应用类型' })
|
||||
@ApiParam({ name: 'menuKey', description: '菜单键' })
|
||||
@ApiResponse({ status: 200, description: '更新成功' })
|
||||
async edit(
|
||||
@Param('appType') appType: string,
|
||||
@Param('menuKey') menuKey: string,
|
||||
@Body() updateMenuDto: UpdateMenuDto,
|
||||
) {
|
||||
try {
|
||||
const result = await this.menuService.edit(
|
||||
appType,
|
||||
menuKey,
|
||||
updateMenuDto,
|
||||
);
|
||||
return {
|
||||
code: 200,
|
||||
message: '更新成功',
|
||||
data: result,
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
code: 400,
|
||||
message: error.message || '更新失败',
|
||||
data: null,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@Get(':appType/:menuKey')
|
||||
@ApiOperation({ summary: '获取菜单详情' })
|
||||
@ApiParam({ name: 'appType', description: '应用类型' })
|
||||
@ApiParam({ name: 'menuKey', description: '菜单键' })
|
||||
@ApiResponse({ status: 200, description: '获取成功' })
|
||||
async get(
|
||||
@Param('appType') appType: string,
|
||||
@Param('menuKey') menuKey: string,
|
||||
) {
|
||||
const result = await this.menuService.get(appType, menuKey);
|
||||
return {
|
||||
code: 200,
|
||||
message: '获取成功',
|
||||
data: result,
|
||||
};
|
||||
}
|
||||
|
||||
@Delete(':appType/:menuKey')
|
||||
@ApiOperation({ summary: '删除菜单' })
|
||||
@ApiParam({ name: 'appType', description: '应用类型' })
|
||||
@ApiParam({ name: 'menuKey', description: '菜单键' })
|
||||
@ApiResponse({ status: 200, description: '删除成功' })
|
||||
async delete(
|
||||
@Param('appType') appType: string,
|
||||
@Param('menuKey') menuKey: string,
|
||||
) {
|
||||
try {
|
||||
const result = await this.menuService.del(appType, menuKey);
|
||||
return {
|
||||
code: 200,
|
||||
message: '删除成功',
|
||||
data: result,
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
code: 400,
|
||||
message: error.message || '删除失败',
|
||||
data: null,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@Get('list/system')
|
||||
@ApiOperation({ summary: '获取系统菜单列表' })
|
||||
@ApiQuery({ name: 'status', description: '状态过滤', required: false })
|
||||
@ApiQuery({ name: 'is_tree', description: '是否树形结构', required: false })
|
||||
@ApiQuery({ name: 'is_button', description: '是否包含按钮', required: false })
|
||||
@ApiResponse({ status: 200, description: '获取成功' })
|
||||
async getSystemMenu(
|
||||
@Query('status') status: string = 'all',
|
||||
@Query('is_tree') isTree: string = '0',
|
||||
@Query('is_button') isButton: string = '0',
|
||||
) {
|
||||
const result = await this.menuService.getSystemMenu(
|
||||
status,
|
||||
parseInt(isTree),
|
||||
parseInt(isButton),
|
||||
);
|
||||
return {
|
||||
code: 200,
|
||||
message: '获取成功',
|
||||
data: result,
|
||||
};
|
||||
}
|
||||
|
||||
@Get('list/addon/:appKey')
|
||||
@ApiOperation({ summary: '获取插件菜单列表' })
|
||||
@ApiParam({ name: 'appKey', description: '插件键' })
|
||||
@ApiQuery({ name: 'status', description: '状态过滤', required: false })
|
||||
@ApiQuery({ name: 'is_tree', description: '是否树形结构', required: false })
|
||||
@ApiQuery({ name: 'is_button', description: '是否包含按钮', required: false })
|
||||
@ApiResponse({ status: 200, description: '获取成功' })
|
||||
async getAddonMenu(
|
||||
@Param('appKey') appKey: string,
|
||||
@Query('status') status: string = 'all',
|
||||
@Query('is_tree') isTree: string = '0',
|
||||
@Query('is_button') isButton: string = '0',
|
||||
) {
|
||||
const result = await this.menuService.getAddonMenu(
|
||||
appKey,
|
||||
status,
|
||||
parseInt(isTree),
|
||||
parseInt(isButton),
|
||||
);
|
||||
return {
|
||||
code: 200,
|
||||
message: '获取成功',
|
||||
data: result,
|
||||
};
|
||||
}
|
||||
|
||||
@Get('list/by-keys')
|
||||
@ApiOperation({ summary: '根据菜单键获取菜单列表' })
|
||||
@ApiQuery({ name: 'menu_keys', description: '菜单键数组(逗号分隔)' })
|
||||
@ApiQuery({ name: 'app_type', description: '应用类型' })
|
||||
@ApiQuery({ name: 'is_tree', description: '是否树形结构', required: false })
|
||||
@ApiQuery({ name: 'addon', description: '插件标识', required: false })
|
||||
@ApiQuery({ name: 'is_button', description: '是否包含按钮', required: false })
|
||||
@ApiResponse({ status: 200, description: '获取成功' })
|
||||
async getMenuListByKeys(
|
||||
@Query('menu_keys') menuKeys: string,
|
||||
@Query('app_type') appType: string,
|
||||
@Query('is_tree') isTree: string = '0',
|
||||
@Query('addon') addon: string = 'all',
|
||||
@Query('is_button') isButton: string = '1',
|
||||
@Req() req: AuthenticatedRequest,
|
||||
) {
|
||||
const siteId = req.user?.siteId || 0;
|
||||
const menuKeyArray = menuKeys.split(',').filter((key) => key.trim());
|
||||
|
||||
const result = await this.menuService.getMenuListByMenuKeys(
|
||||
siteId,
|
||||
menuKeyArray,
|
||||
appType,
|
||||
parseInt(isTree),
|
||||
addon,
|
||||
parseInt(isButton),
|
||||
);
|
||||
return {
|
||||
code: 200,
|
||||
message: '获取成功',
|
||||
data: result,
|
||||
};
|
||||
}
|
||||
|
||||
@Get('api/all')
|
||||
@ApiOperation({ summary: '获取所有API菜单' })
|
||||
@ApiQuery({ name: 'app_type', description: '应用类型', required: false })
|
||||
@ApiQuery({ name: 'addon', description: '插件标识', required: false })
|
||||
@ApiResponse({ status: 200, description: '获取成功' })
|
||||
async getAllApiMenus(
|
||||
@Query('app_type') appType: string = 'admin',
|
||||
@Query('addon') addon: string = '',
|
||||
) {
|
||||
const result = await this.menuService.getAllApiMenus(appType, addon);
|
||||
return {
|
||||
code: 200,
|
||||
message: '获取成功',
|
||||
data: result,
|
||||
};
|
||||
}
|
||||
|
||||
@Get('type/dir')
|
||||
@ApiOperation({ summary: '获取目录类型菜单' })
|
||||
@ApiQuery({ name: 'addon', description: '插件标识', required: false })
|
||||
@ApiResponse({ status: 200, description: '获取成功' })
|
||||
async getMenuByTypeDir(@Query('addon') addon: string = 'system') {
|
||||
const result = await this.menuService.getMenuByTypeDir(addon);
|
||||
return {
|
||||
code: 200,
|
||||
message: '获取成功',
|
||||
data: result,
|
||||
};
|
||||
}
|
||||
|
||||
@Get('keys/system')
|
||||
@ApiOperation({ summary: '根据系统配置获取菜单键' })
|
||||
@ApiQuery({ name: 'app_type', description: '应用类型' })
|
||||
@ApiQuery({
|
||||
name: 'addons',
|
||||
description: '插件列表(逗号分隔)',
|
||||
required: false,
|
||||
})
|
||||
@ApiResponse({ status: 200, description: '获取成功' })
|
||||
async getMenuKeysBySystem(
|
||||
@Query('app_type') appType: string,
|
||||
@Query('addons') addons: string = '',
|
||||
) {
|
||||
const addonArray = addons
|
||||
? addons.split(',').filter((addon) => addon.trim())
|
||||
: [];
|
||||
const result = await this.menuService.getMenuKeysBySystem(
|
||||
appType,
|
||||
addonArray,
|
||||
);
|
||||
return {
|
||||
code: 200,
|
||||
message: '获取成功',
|
||||
data: result,
|
||||
};
|
||||
}
|
||||
}
|
||||
158
wwjcloud/src/common/sys/controllers/admin/PosterController.ts
Normal file
158
wwjcloud/src/common/sys/controllers/admin/PosterController.ts
Normal file
@@ -0,0 +1,158 @@
|
||||
import {
|
||||
Controller,
|
||||
Get,
|
||||
Post,
|
||||
Put,
|
||||
Delete,
|
||||
Body,
|
||||
Param,
|
||||
Query,
|
||||
UseGuards,
|
||||
Req,
|
||||
ParseIntPipe,
|
||||
} from '@nestjs/common';
|
||||
import { ApiTags, ApiOperation, ApiResponse, ApiParam } from '@nestjs/swagger';
|
||||
import type { Request } from 'express';
|
||||
import { JwtAuthGuard } from '../../../auth/guards/JwtAuthGuard';
|
||||
import { RolesGuard } from '../../../auth/guards/RolesGuard';
|
||||
import { Roles } from '../../../auth/decorators/RolesDecorator';
|
||||
import { PosterService } from '../../services/admin/PosterService';
|
||||
|
||||
interface AuthenticatedRequest extends Request {
|
||||
user?: {
|
||||
uid: number;
|
||||
username: string;
|
||||
siteId: number;
|
||||
userType: string;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 海报管理控制器 - 管理端
|
||||
* 路由前缀: /adminapi/sys/poster
|
||||
*/
|
||||
@ApiTags('海报管理')
|
||||
@Controller('adminapi/sys/poster')
|
||||
@UseGuards(JwtAuthGuard, RolesGuard)
|
||||
@Roles('admin')
|
||||
export class PosterController {
|
||||
constructor(private readonly posterService: PosterService) {}
|
||||
|
||||
@Get('page')
|
||||
@ApiOperation({ summary: '获取海报分页列表' })
|
||||
@ApiResponse({ status: 200, description: '获取成功' })
|
||||
async getPage(@Query() query: any, @Req() req: AuthenticatedRequest) {
|
||||
const siteId = req.user?.siteId || 0;
|
||||
const result = await this.posterService.getPage(siteId, query);
|
||||
return { code: 200, message: '获取成功', data: result };
|
||||
}
|
||||
|
||||
@Get('list')
|
||||
@ApiOperation({ summary: '获取海报列表' })
|
||||
@ApiResponse({ status: 200, description: '获取成功' })
|
||||
async getList(@Query() query: any, @Req() req: AuthenticatedRequest) {
|
||||
const siteId = req.user?.siteId || 0;
|
||||
const result = await this.posterService.getList(siteId, query);
|
||||
return { code: 200, message: '获取成功', data: result };
|
||||
}
|
||||
|
||||
@Get('types')
|
||||
@ApiOperation({ summary: '获取海报类型列表' })
|
||||
@ApiResponse({ status: 200, description: '获取成功' })
|
||||
async getPosterTypes(@Req() req: AuthenticatedRequest) {
|
||||
const result = await this.posterService.getPosterTypes();
|
||||
return { code: 200, message: '获取成功', data: result };
|
||||
}
|
||||
|
||||
@Get('default/:type')
|
||||
@ApiOperation({ summary: '获取默认海报' })
|
||||
@ApiParam({ name: 'type', description: '海报类型' })
|
||||
@ApiResponse({ status: 200, description: '获取成功' })
|
||||
async getDefaultByType(
|
||||
@Param('type') type: string,
|
||||
@Req() req: AuthenticatedRequest,
|
||||
) {
|
||||
const siteId = req.user?.siteId || 0;
|
||||
const result = await this.posterService.getDefaultByType(siteId, type);
|
||||
return { code: 200, message: '获取成功', data: result };
|
||||
}
|
||||
|
||||
@Get(':id')
|
||||
@ApiOperation({ summary: '获取海报详情' })
|
||||
@ApiParam({ name: 'id', description: '海报ID' })
|
||||
@ApiResponse({ status: 200, description: '获取成功' })
|
||||
async getInfo(
|
||||
@Param('id', ParseIntPipe) id: number,
|
||||
@Req() req: AuthenticatedRequest,
|
||||
) {
|
||||
const siteId = req.user?.siteId || 0;
|
||||
const result = await this.posterService.getInfo(siteId, id);
|
||||
return { code: 200, message: '获取成功', data: result };
|
||||
}
|
||||
|
||||
@Post()
|
||||
@ApiOperation({ summary: '新增海报' })
|
||||
@ApiResponse({ status: 200, description: '创建成功' })
|
||||
async add(@Body() data: any, @Req() req: AuthenticatedRequest) {
|
||||
try {
|
||||
const siteId = req.user?.siteId || 0;
|
||||
const result = await this.posterService.add(siteId, data);
|
||||
return { code: 200, message: '创建成功', data: result };
|
||||
} catch (error) {
|
||||
return { code: 400, message: error.message || '创建失败', data: null };
|
||||
}
|
||||
}
|
||||
|
||||
@Put(':id')
|
||||
@ApiOperation({ summary: '编辑海报' })
|
||||
@ApiParam({ name: 'id', description: '海报ID' })
|
||||
@ApiResponse({ status: 200, description: '更新成功' })
|
||||
async edit(
|
||||
@Param('id', ParseIntPipe) id: number,
|
||||
@Body() data: any,
|
||||
@Req() req: AuthenticatedRequest,
|
||||
) {
|
||||
try {
|
||||
const siteId = req.user?.siteId || 0;
|
||||
const result = await this.posterService.edit(siteId, id, data);
|
||||
return { code: 200, message: '更新成功', data: result };
|
||||
} catch (error) {
|
||||
return { code: 400, message: error.message || '更新失败', data: null };
|
||||
}
|
||||
}
|
||||
|
||||
@Put(':id/default')
|
||||
@ApiOperation({ summary: '设置默认海报' })
|
||||
@ApiParam({ name: 'id', description: '海报ID' })
|
||||
@ApiResponse({ status: 200, description: '设置成功' })
|
||||
async setDefault(
|
||||
@Param('id', ParseIntPipe) id: number,
|
||||
@Body() data: { type: string },
|
||||
@Req() req: AuthenticatedRequest,
|
||||
) {
|
||||
try {
|
||||
const siteId = req.user?.siteId || 0;
|
||||
const result = await this.posterService.setDefault(siteId, id, data.type);
|
||||
return { code: 200, message: '设置成功', data: result };
|
||||
} catch (error) {
|
||||
return { code: 400, message: error.message || '设置失败', data: null };
|
||||
}
|
||||
}
|
||||
|
||||
@Delete(':id')
|
||||
@ApiOperation({ summary: '删除海报' })
|
||||
@ApiParam({ name: 'id', description: '海报ID' })
|
||||
@ApiResponse({ status: 200, description: '删除成功' })
|
||||
async delete(
|
||||
@Param('id', ParseIntPipe) id: number,
|
||||
@Req() req: AuthenticatedRequest,
|
||||
) {
|
||||
try {
|
||||
const siteId = req.user?.siteId || 0;
|
||||
const result = await this.posterService.del(siteId, id);
|
||||
return { code: 200, message: '删除成功', data: result };
|
||||
} catch (error) {
|
||||
return { code: 400, message: error.message || '删除失败', data: null };
|
||||
}
|
||||
}
|
||||
}
|
||||
191
wwjcloud/src/common/sys/controllers/admin/PrinterController.ts
Normal file
191
wwjcloud/src/common/sys/controllers/admin/PrinterController.ts
Normal file
@@ -0,0 +1,191 @@
|
||||
import {
|
||||
Controller,
|
||||
Get,
|
||||
Post,
|
||||
Put,
|
||||
Delete,
|
||||
Body,
|
||||
Param,
|
||||
Query,
|
||||
UseGuards,
|
||||
Req,
|
||||
ParseIntPipe,
|
||||
} from '@nestjs/common';
|
||||
import { ApiTags, ApiOperation, ApiResponse, ApiParam } from '@nestjs/swagger';
|
||||
import type { Request } from 'express';
|
||||
import { JwtAuthGuard } from '../../../auth/guards/JwtAuthGuard';
|
||||
import { RolesGuard } from '../../../auth/guards/RolesGuard';
|
||||
import { Roles } from '../../../auth/decorators/RolesDecorator';
|
||||
import { PrinterService } from '../../services/admin/PrinterService';
|
||||
|
||||
interface AuthenticatedRequest extends Request {
|
||||
user?: {
|
||||
uid: number;
|
||||
username: string;
|
||||
siteId: number;
|
||||
userType: string;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 打印机管理控制器 - 管理端
|
||||
* 路由前缀: /adminapi/sys/printer
|
||||
*/
|
||||
@ApiTags('打印机管理')
|
||||
@Controller('adminapi/sys/printer')
|
||||
@UseGuards(JwtAuthGuard, RolesGuard)
|
||||
@Roles('admin')
|
||||
export class PrinterController {
|
||||
constructor(private readonly printerService: PrinterService) {}
|
||||
|
||||
@Get('page')
|
||||
@ApiOperation({ summary: '获取打印机分页列表' })
|
||||
@ApiResponse({ status: 200, description: '获取成功' })
|
||||
async getPage(@Query() query: any, @Req() req: AuthenticatedRequest) {
|
||||
const siteId = req.user?.siteId || 0;
|
||||
const result = await this.printerService.getPage(siteId, query);
|
||||
return { code: 200, message: '获取成功', data: result };
|
||||
}
|
||||
|
||||
@Get('list')
|
||||
@ApiOperation({ summary: '获取打印机列表' })
|
||||
@ApiResponse({ status: 200, description: '获取成功' })
|
||||
async getList(@Query() query: any, @Req() req: AuthenticatedRequest) {
|
||||
const siteId = req.user?.siteId || 0;
|
||||
const result = await this.printerService.getList(siteId, query);
|
||||
return { code: 200, message: '获取成功', data: result };
|
||||
}
|
||||
|
||||
@Get('brands')
|
||||
@ApiOperation({ summary: '获取打印机品牌列表' })
|
||||
@ApiResponse({ status: 200, description: '获取成功' })
|
||||
async getBrandList() {
|
||||
const result = this.printerService.getBrandList();
|
||||
return { code: 200, message: '获取成功', data: result };
|
||||
}
|
||||
|
||||
@Get(':printerId')
|
||||
@ApiOperation({ summary: '获取打印机详情' })
|
||||
@ApiParam({ name: 'printerId', description: '打印机ID' })
|
||||
@ApiResponse({ status: 200, description: '获取成功' })
|
||||
async getInfo(
|
||||
@Param('printerId', ParseIntPipe) printerId: number,
|
||||
@Req() req: AuthenticatedRequest,
|
||||
) {
|
||||
const siteId = req.user?.siteId || 0;
|
||||
const result = await this.printerService.getInfo(siteId, printerId);
|
||||
return { code: 200, message: '获取成功', data: result };
|
||||
}
|
||||
|
||||
@Post()
|
||||
@ApiOperation({ summary: '新增打印机' })
|
||||
@ApiResponse({ status: 200, description: '创建成功' })
|
||||
async add(@Body() data: any, @Req() req: AuthenticatedRequest) {
|
||||
try {
|
||||
const siteId = req.user?.siteId || 0;
|
||||
const result = await this.printerService.add(siteId, data);
|
||||
return { code: 200, message: '创建成功', data: result };
|
||||
} catch (error) {
|
||||
return { code: 400, message: error.message || '创建失败', data: null };
|
||||
}
|
||||
}
|
||||
|
||||
@Put(':printerId')
|
||||
@ApiOperation({ summary: '编辑打印机' })
|
||||
@ApiParam({ name: 'printerId', description: '打印机ID' })
|
||||
@ApiResponse({ status: 200, description: '更新成功' })
|
||||
async edit(
|
||||
@Param('printerId', ParseIntPipe) printerId: number,
|
||||
@Body() data: any,
|
||||
@Req() req: AuthenticatedRequest,
|
||||
) {
|
||||
try {
|
||||
const siteId = req.user?.siteId || 0;
|
||||
const result = await this.printerService.edit(siteId, printerId, data);
|
||||
return { code: 200, message: '更新成功', data: result };
|
||||
} catch (error) {
|
||||
return { code: 400, message: error.message || '更新失败', data: null };
|
||||
}
|
||||
}
|
||||
|
||||
@Put(':printerId/status')
|
||||
@ApiOperation({ summary: '修改打印机状态' })
|
||||
@ApiParam({ name: 'printerId', description: '打印机ID' })
|
||||
@ApiResponse({ status: 200, description: '修改成功' })
|
||||
async modifyStatus(
|
||||
@Param('printerId', ParseIntPipe) printerId: number,
|
||||
@Body() data: { status: number },
|
||||
@Req() req: AuthenticatedRequest,
|
||||
) {
|
||||
try {
|
||||
const siteId = req.user?.siteId || 0;
|
||||
const result = await this.printerService.modifyStatus(
|
||||
siteId,
|
||||
printerId,
|
||||
data.status,
|
||||
);
|
||||
return { code: 200, message: '修改成功', data: result };
|
||||
} catch (error) {
|
||||
return { code: 400, message: error.message || '修改失败', data: null };
|
||||
}
|
||||
}
|
||||
|
||||
@Post(':printerId/test')
|
||||
@ApiOperation({ summary: '测试打印机连接' })
|
||||
@ApiParam({ name: 'printerId', description: '打印机ID' })
|
||||
@ApiResponse({ status: 200, description: '测试完成' })
|
||||
async testConnection(
|
||||
@Param('printerId', ParseIntPipe) printerId: number,
|
||||
@Req() req: AuthenticatedRequest,
|
||||
) {
|
||||
try {
|
||||
const siteId = req.user?.siteId || 0;
|
||||
const result = await this.printerService.testConnection(
|
||||
siteId,
|
||||
printerId,
|
||||
);
|
||||
return { code: 200, message: '测试完成', data: result };
|
||||
} catch (error) {
|
||||
return { code: 400, message: error.message || '测试失败', data: null };
|
||||
}
|
||||
}
|
||||
|
||||
@Post(':printerId/print')
|
||||
@ApiOperation({ summary: '打印内容' })
|
||||
@ApiParam({ name: 'printerId', description: '打印机ID' })
|
||||
@ApiResponse({ status: 200, description: '打印完成' })
|
||||
async print(
|
||||
@Param('printerId', ParseIntPipe) printerId: number,
|
||||
@Body() data: { content: string },
|
||||
@Req() req: AuthenticatedRequest,
|
||||
) {
|
||||
try {
|
||||
const siteId = req.user?.siteId || 0;
|
||||
const result = await this.printerService.print(
|
||||
siteId,
|
||||
printerId,
|
||||
data.content,
|
||||
);
|
||||
return { code: 200, message: '打印完成', data: result };
|
||||
} catch (error) {
|
||||
return { code: 400, message: error.message || '打印失败', data: null };
|
||||
}
|
||||
}
|
||||
|
||||
@Delete(':printerId')
|
||||
@ApiOperation({ summary: '删除打印机' })
|
||||
@ApiParam({ name: 'printerId', description: '打印机ID' })
|
||||
@ApiResponse({ status: 200, description: '删除成功' })
|
||||
async delete(
|
||||
@Param('printerId', ParseIntPipe) printerId: number,
|
||||
@Req() req: AuthenticatedRequest,
|
||||
) {
|
||||
try {
|
||||
const siteId = req.user?.siteId || 0;
|
||||
const result = await this.printerService.del(siteId, printerId);
|
||||
return { code: 200, message: '删除成功', data: result };
|
||||
} catch (error) {
|
||||
return { code: 400, message: error.message || '删除失败', data: null };
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
import {
|
||||
Controller,
|
||||
Get,
|
||||
Post,
|
||||
Put,
|
||||
Delete,
|
||||
Body,
|
||||
Param,
|
||||
Query,
|
||||
UseGuards,
|
||||
Req,
|
||||
ParseIntPipe,
|
||||
} from '@nestjs/common';
|
||||
import { ApiTags, ApiOperation, ApiResponse, ApiParam } from '@nestjs/swagger';
|
||||
import type { Request } from 'express';
|
||||
import { JwtAuthGuard } from '../../../auth/guards/JwtAuthGuard';
|
||||
import { RolesGuard } from '../../../auth/guards/RolesGuard';
|
||||
import { Roles } from '../../../auth/decorators/RolesDecorator';
|
||||
import { PrinterTemplateService } from '../../services/admin/PrinterTemplateService';
|
||||
|
||||
interface AuthenticatedRequest extends Request {
|
||||
user?: {
|
||||
uid: number;
|
||||
username: string;
|
||||
siteId: number;
|
||||
userType: string;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 打印模板管理控制器 - 管理端
|
||||
* 路由前缀: /adminapi/sys/printer-template
|
||||
*/
|
||||
@ApiTags('打印模板管理')
|
||||
@Controller('adminapi/sys/printer-template')
|
||||
@UseGuards(JwtAuthGuard, RolesGuard)
|
||||
@Roles('admin')
|
||||
export class PrinterTemplateController {
|
||||
constructor(
|
||||
private readonly printerTemplateService: PrinterTemplateService,
|
||||
) {}
|
||||
|
||||
@Get('page')
|
||||
@ApiOperation({ summary: '获取打印模板分页列表' })
|
||||
@ApiResponse({ status: 200, description: '获取成功' })
|
||||
async getPage(@Query() query: any, @Req() req: AuthenticatedRequest) {
|
||||
const siteId = req.user?.siteId || 0;
|
||||
const result = await this.printerTemplateService.getPage(siteId, query);
|
||||
return { code: 200, message: '获取成功', data: result };
|
||||
}
|
||||
|
||||
@Get('list')
|
||||
@ApiOperation({ summary: '获取打印模板列表' })
|
||||
@ApiResponse({ status: 200, description: '获取成功' })
|
||||
async getList(@Query() query: any, @Req() req: AuthenticatedRequest) {
|
||||
const siteId = req.user?.siteId || 0;
|
||||
const result = await this.printerTemplateService.getList(siteId, query);
|
||||
return { code: 200, message: '获取成功', data: result };
|
||||
}
|
||||
|
||||
@Get('types')
|
||||
@ApiOperation({ summary: '获取模板类型列表' })
|
||||
@ApiResponse({ status: 200, description: '获取成功' })
|
||||
async getTemplateTypes(@Req() req: AuthenticatedRequest) {
|
||||
const result = await this.printerTemplateService.getTemplateTypes();
|
||||
return { code: 200, message: '获取成功', data: result };
|
||||
}
|
||||
|
||||
@Get('by-type/:type')
|
||||
@ApiOperation({ summary: '根据类型获取模板' })
|
||||
@ApiParam({ name: 'type', description: '模板类型' })
|
||||
@ApiResponse({ status: 200, description: '获取成功' })
|
||||
async getTemplatesByType(
|
||||
@Param('type') type: string,
|
||||
@Req() req: AuthenticatedRequest,
|
||||
) {
|
||||
const siteId = req.user?.siteId || 0;
|
||||
const result = await this.printerTemplateService.getTemplatesByType(
|
||||
siteId,
|
||||
type,
|
||||
);
|
||||
return { code: 200, message: '获取成功', data: result };
|
||||
}
|
||||
|
||||
@Get(':templateId')
|
||||
@ApiOperation({ summary: '获取打印模板详情' })
|
||||
@ApiParam({ name: 'templateId', description: '模板ID' })
|
||||
@ApiResponse({ status: 200, description: '获取成功' })
|
||||
async getInfo(
|
||||
@Param('templateId', ParseIntPipe) templateId: number,
|
||||
@Req() req: AuthenticatedRequest,
|
||||
) {
|
||||
const siteId = req.user?.siteId || 0;
|
||||
const result = await this.printerTemplateService.getInfo(
|
||||
siteId,
|
||||
templateId,
|
||||
);
|
||||
return { code: 200, message: '获取成功', data: result };
|
||||
}
|
||||
|
||||
@Post()
|
||||
@ApiOperation({ summary: '新增打印模板' })
|
||||
@ApiResponse({ status: 200, description: '创建成功' })
|
||||
async add(@Body() data: any, @Req() req: AuthenticatedRequest) {
|
||||
try {
|
||||
const siteId = req.user?.siteId || 0;
|
||||
const result = await this.printerTemplateService.add(siteId, data);
|
||||
return { code: 200, message: '创建成功', data: result };
|
||||
} catch (error) {
|
||||
return { code: 400, message: error.message || '创建失败', data: null };
|
||||
}
|
||||
}
|
||||
|
||||
@Put(':templateId')
|
||||
@ApiOperation({ summary: '编辑打印模板' })
|
||||
@ApiParam({ name: 'templateId', description: '模板ID' })
|
||||
@ApiResponse({ status: 200, description: '更新成功' })
|
||||
async edit(
|
||||
@Param('templateId', ParseIntPipe) templateId: number,
|
||||
@Body() data: any,
|
||||
@Req() req: AuthenticatedRequest,
|
||||
) {
|
||||
try {
|
||||
const siteId = req.user?.siteId || 0;
|
||||
const result = await this.printerTemplateService.edit(
|
||||
siteId,
|
||||
templateId,
|
||||
data,
|
||||
);
|
||||
return { code: 200, message: '更新成功', data: result };
|
||||
} catch (error) {
|
||||
return { code: 400, message: error.message || '更新失败', data: null };
|
||||
}
|
||||
}
|
||||
|
||||
@Post(':templateId/preview')
|
||||
@ApiOperation({ summary: '预览打印模板' })
|
||||
@ApiParam({ name: 'templateId', description: '模板ID' })
|
||||
@ApiResponse({ status: 200, description: '预览成功' })
|
||||
async previewTemplate(
|
||||
@Param('templateId', ParseIntPipe) templateId: number,
|
||||
@Body() data: { preview_data?: any },
|
||||
@Req() req: AuthenticatedRequest,
|
||||
) {
|
||||
try {
|
||||
const siteId = req.user?.siteId || 0;
|
||||
const result = await this.printerTemplateService.previewTemplate(
|
||||
siteId,
|
||||
templateId,
|
||||
data.preview_data,
|
||||
);
|
||||
return { code: 200, message: '预览成功', data: result };
|
||||
} catch (error) {
|
||||
return { code: 400, message: error.message || '预览失败', data: null };
|
||||
}
|
||||
}
|
||||
|
||||
@Delete(':templateId')
|
||||
@ApiOperation({ summary: '删除打印模板' })
|
||||
@ApiParam({ name: 'templateId', description: '模板ID' })
|
||||
@ApiResponse({ status: 200, description: '删除成功' })
|
||||
async delete(
|
||||
@Param('templateId', ParseIntPipe) templateId: number,
|
||||
@Req() req: AuthenticatedRequest,
|
||||
) {
|
||||
try {
|
||||
const siteId = req.user?.siteId || 0;
|
||||
const result = await this.printerTemplateService.del(siteId, templateId);
|
||||
return { code: 200, message: '删除成功', data: result };
|
||||
} catch (error) {
|
||||
return { code: 400, message: error.message || '删除失败', data: null };
|
||||
}
|
||||
}
|
||||
}
|
||||
277
wwjcloud/src/common/sys/controllers/admin/RoleController.ts
Normal file
277
wwjcloud/src/common/sys/controllers/admin/RoleController.ts
Normal file
@@ -0,0 +1,277 @@
|
||||
import {
|
||||
Controller,
|
||||
Get,
|
||||
Post,
|
||||
Put,
|
||||
Delete,
|
||||
Body,
|
||||
Param,
|
||||
Query,
|
||||
UseGuards,
|
||||
Req,
|
||||
ParseIntPipe,
|
||||
} from '@nestjs/common';
|
||||
import {
|
||||
ApiTags,
|
||||
ApiOperation,
|
||||
ApiResponse,
|
||||
ApiParam,
|
||||
ApiQuery,
|
||||
} from '@nestjs/swagger';
|
||||
import type { Request } from 'express';
|
||||
import { JwtAuthGuard } from '../../../auth/guards/JwtAuthGuard';
|
||||
import { RolesGuard } from '../../../auth/guards/RolesGuard';
|
||||
import { Roles } from '../../../auth/decorators/RolesDecorator';
|
||||
import { RoleService } from '../../services/admin/RoleService';
|
||||
import {
|
||||
CreateRoleDto,
|
||||
UpdateRoleDto,
|
||||
RoleQueryDto,
|
||||
ModifyRoleStatusDto,
|
||||
} from '../../dto/RoleDto';
|
||||
|
||||
interface AuthenticatedRequest extends Request {
|
||||
user?: {
|
||||
uid: number;
|
||||
username: string;
|
||||
siteId: number;
|
||||
userType: string;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 角色管理控制器 - 管理端
|
||||
* 路由前缀: /adminapi/sys/role
|
||||
* 对应PHP: app\adminapi\controller\sys\Role
|
||||
*/
|
||||
@ApiTags('角色管理')
|
||||
@Controller('adminapi/sys/role')
|
||||
@UseGuards(JwtAuthGuard, RolesGuard)
|
||||
@Roles('admin')
|
||||
export class RoleController {
|
||||
constructor(private readonly roleService: RoleService) {}
|
||||
|
||||
@Get('page')
|
||||
@ApiOperation({ summary: '获取角色分页列表' })
|
||||
@ApiResponse({ status: 200, description: '获取成功' })
|
||||
async getPage(
|
||||
@Query() query: RoleQueryDto,
|
||||
@Req() req: AuthenticatedRequest,
|
||||
) {
|
||||
const siteId = req.user?.siteId || 0;
|
||||
const result = await this.roleService.getPage(siteId, query);
|
||||
return {
|
||||
code: 200,
|
||||
message: '获取成功',
|
||||
data: result,
|
||||
};
|
||||
}
|
||||
|
||||
@Get('all')
|
||||
@ApiOperation({ summary: '获取所有角色列表' })
|
||||
@ApiResponse({ status: 200, description: '获取成功' })
|
||||
async getAll(@Req() req: AuthenticatedRequest) {
|
||||
const siteId = req.user?.siteId || 0;
|
||||
const userId = req.user?.uid || 0;
|
||||
|
||||
// TODO: 实现用户权限检查
|
||||
// 暂时假设为超级管理员,后续完善权限模块时补充
|
||||
const isAdmin = true;
|
||||
const userRoleIds: number[] = [];
|
||||
|
||||
const result = await this.roleService.getAll(siteId, userRoleIds, isAdmin);
|
||||
return {
|
||||
code: 200,
|
||||
message: '获取成功',
|
||||
data: result,
|
||||
};
|
||||
}
|
||||
|
||||
@Get('column')
|
||||
@ApiOperation({ summary: '获取角色键值对' })
|
||||
@ApiResponse({ status: 200, description: '获取成功' })
|
||||
async getColumn(@Req() req: AuthenticatedRequest) {
|
||||
const siteId = req.user?.siteId || 0;
|
||||
const result = await this.roleService.getColumn(siteId);
|
||||
return {
|
||||
code: 200,
|
||||
message: '获取成功',
|
||||
data: result,
|
||||
};
|
||||
}
|
||||
|
||||
@Get(':roleId')
|
||||
@ApiOperation({ summary: '获取角色详情' })
|
||||
@ApiParam({ name: 'roleId', description: '角色ID' })
|
||||
@ApiResponse({ status: 200, description: '获取成功' })
|
||||
async getInfo(@Param('roleId', ParseIntPipe) roleId: number) {
|
||||
const result = await this.roleService.getInfo(roleId);
|
||||
return {
|
||||
code: 200,
|
||||
message: '获取成功',
|
||||
data: result,
|
||||
};
|
||||
}
|
||||
|
||||
@Post()
|
||||
@ApiOperation({ summary: '新增角色' })
|
||||
@ApiResponse({ status: 200, description: '创建成功' })
|
||||
async add(
|
||||
@Body() createRoleDto: CreateRoleDto,
|
||||
@Req() req: AuthenticatedRequest,
|
||||
) {
|
||||
try {
|
||||
const siteId = req.user?.siteId || 0;
|
||||
const appType = 'admin'; // 默认为admin类型
|
||||
|
||||
// 处理rules字段
|
||||
const roleData = {
|
||||
...createRoleDto,
|
||||
rules: createRoleDto.rules
|
||||
? JSON.stringify(createRoleDto.rules)
|
||||
: undefined,
|
||||
};
|
||||
|
||||
const result = await this.roleService.add(siteId, appType, roleData);
|
||||
return {
|
||||
code: 200,
|
||||
message: '创建成功',
|
||||
data: result,
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
code: 400,
|
||||
message: error.message || '创建失败',
|
||||
data: null,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@Put(':roleId')
|
||||
@ApiOperation({ summary: '编辑角色' })
|
||||
@ApiParam({ name: 'roleId', description: '角色ID' })
|
||||
@ApiResponse({ status: 200, description: '更新成功' })
|
||||
async edit(
|
||||
@Param('roleId', ParseIntPipe) roleId: number,
|
||||
@Body() updateRoleDto: UpdateRoleDto,
|
||||
@Req() req: AuthenticatedRequest,
|
||||
) {
|
||||
try {
|
||||
const siteId = req.user?.siteId || 0;
|
||||
|
||||
// 处理rules字段
|
||||
const roleData = {
|
||||
...updateRoleDto,
|
||||
rules: updateRoleDto.rules
|
||||
? JSON.stringify(updateRoleDto.rules)
|
||||
: undefined,
|
||||
};
|
||||
|
||||
const result = await this.roleService.edit(roleId, siteId, roleData);
|
||||
return {
|
||||
code: 200,
|
||||
message: '更新成功',
|
||||
data: result,
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
code: 400,
|
||||
message: error.message || '更新失败',
|
||||
data: null,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@Put('status/:roleId')
|
||||
@ApiOperation({ summary: '修改角色状态' })
|
||||
@ApiParam({ name: 'roleId', description: '角色ID' })
|
||||
@ApiResponse({ status: 200, description: '修改成功' })
|
||||
async modifyStatus(
|
||||
@Param('roleId', ParseIntPipe) roleId: number,
|
||||
@Body() modifyStatusDto: ModifyRoleStatusDto,
|
||||
@Req() req: AuthenticatedRequest,
|
||||
) {
|
||||
try {
|
||||
const siteId = req.user?.siteId || 0;
|
||||
const result = await this.roleService.modifyStatus(
|
||||
roleId,
|
||||
siteId,
|
||||
modifyStatusDto.status,
|
||||
);
|
||||
return {
|
||||
code: 200,
|
||||
message: '修改成功',
|
||||
data: result,
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
code: 400,
|
||||
message: error.message || '修改失败',
|
||||
data: null,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@Delete(':roleId')
|
||||
@ApiOperation({ summary: '删除角色' })
|
||||
@ApiParam({ name: 'roleId', description: '角色ID' })
|
||||
@ApiResponse({ status: 200, description: '删除成功' })
|
||||
async delete(
|
||||
@Param('roleId', ParseIntPipe) roleId: number,
|
||||
@Req() req: AuthenticatedRequest,
|
||||
) {
|
||||
try {
|
||||
const siteId = req.user?.siteId || 0;
|
||||
const result = await this.roleService.del(roleId, siteId);
|
||||
return {
|
||||
code: 200,
|
||||
message: '删除成功',
|
||||
data: result,
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
code: 400,
|
||||
message: error.message || '删除失败',
|
||||
data: null,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@Get('menu-ids/:roleIds')
|
||||
@ApiOperation({ summary: '根据角色ID获取菜单权限' })
|
||||
@ApiParam({ name: 'roleIds', description: '角色ID数组(逗号分隔)' })
|
||||
@ApiQuery({
|
||||
name: 'allow_menu_keys',
|
||||
description: '允许的菜单键(逗号分隔)',
|
||||
required: false,
|
||||
})
|
||||
@ApiResponse({ status: 200, description: '获取成功' })
|
||||
async getMenuIdsByRoleIds(
|
||||
@Param('roleIds') roleIds: string,
|
||||
@Query('allow_menu_keys') allowMenuKeys: string = '',
|
||||
@Req() req: AuthenticatedRequest,
|
||||
) {
|
||||
const siteId = req.user?.siteId || 0;
|
||||
const roleIdArray = roleIds
|
||||
.split(',')
|
||||
.map((id) => parseInt(id.trim()))
|
||||
.filter((id) => !isNaN(id));
|
||||
const allowMenuKeyArray = allowMenuKeys
|
||||
? allowMenuKeys
|
||||
.split(',')
|
||||
.map((key) => key.trim())
|
||||
.filter((key) => key)
|
||||
: [];
|
||||
|
||||
const result = await this.roleService.getMenuIdsByRoleIds(
|
||||
siteId,
|
||||
roleIdArray,
|
||||
allowMenuKeyArray,
|
||||
);
|
||||
return {
|
||||
code: 200,
|
||||
message: '获取成功',
|
||||
data: result,
|
||||
};
|
||||
}
|
||||
}
|
||||
153
wwjcloud/src/common/sys/controllers/admin/ScheduleController.ts
Normal file
153
wwjcloud/src/common/sys/controllers/admin/ScheduleController.ts
Normal file
@@ -0,0 +1,153 @@
|
||||
import {
|
||||
Controller,
|
||||
Get,
|
||||
Post,
|
||||
Put,
|
||||
Delete,
|
||||
Body,
|
||||
Param,
|
||||
Query,
|
||||
UseGuards,
|
||||
Req,
|
||||
ParseIntPipe,
|
||||
} from '@nestjs/common';
|
||||
import { ApiTags, ApiOperation, ApiResponse, ApiParam } from '@nestjs/swagger';
|
||||
import type { Request } from 'express';
|
||||
import { JwtAuthGuard } from '../../../auth/guards/JwtAuthGuard';
|
||||
import { RolesGuard } from '../../../auth/guards/RolesGuard';
|
||||
import { Roles } from '../../../auth/decorators/RolesDecorator';
|
||||
import { ScheduleService } from '../../services/admin/ScheduleService';
|
||||
|
||||
interface AuthenticatedRequest extends Request {
|
||||
user?: {
|
||||
uid: number;
|
||||
username: string;
|
||||
siteId: number;
|
||||
userType: string;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 定时任务管理控制器 - 管理端
|
||||
* 路由前缀: /adminapi/sys/schedule
|
||||
*/
|
||||
@ApiTags('定时任务管理')
|
||||
@Controller('adminapi/sys/schedule')
|
||||
@UseGuards(JwtAuthGuard, RolesGuard)
|
||||
@Roles('admin')
|
||||
export class ScheduleController {
|
||||
constructor(private readonly scheduleService: ScheduleService) {}
|
||||
|
||||
@Get('page')
|
||||
@ApiOperation({ summary: '获取定时任务分页列表' })
|
||||
@ApiResponse({ status: 200, description: '获取成功' })
|
||||
async getPage(@Query() query: any, @Req() req: AuthenticatedRequest) {
|
||||
const siteId = req.user?.siteId || 0;
|
||||
const result = await this.scheduleService.getPage(siteId, query);
|
||||
return { code: 200, message: '获取成功', data: result };
|
||||
}
|
||||
|
||||
@Get('list')
|
||||
@ApiOperation({ summary: '获取定时任务列表' })
|
||||
@ApiResponse({ status: 200, description: '获取成功' })
|
||||
async getList(@Query() query: any, @Req() req: AuthenticatedRequest) {
|
||||
const siteId = req.user?.siteId || 0;
|
||||
const result = await this.scheduleService.getList(siteId, query);
|
||||
return { code: 200, message: '获取成功', data: result };
|
||||
}
|
||||
|
||||
@Get(':id')
|
||||
@ApiOperation({ summary: '获取定时任务详情' })
|
||||
@ApiParam({ name: 'id', description: '任务ID' })
|
||||
@ApiResponse({ status: 200, description: '获取成功' })
|
||||
async getInfo(
|
||||
@Param('id', ParseIntPipe) id: number,
|
||||
@Req() req: AuthenticatedRequest,
|
||||
) {
|
||||
const siteId = req.user?.siteId || 0;
|
||||
const result = await this.scheduleService.getInfo(siteId, id);
|
||||
return { code: 200, message: '获取成功', data: result };
|
||||
}
|
||||
|
||||
@Post()
|
||||
@ApiOperation({ summary: '新增定时任务' })
|
||||
@ApiResponse({ status: 200, description: '创建成功' })
|
||||
async add(@Body() data: any, @Req() req: AuthenticatedRequest) {
|
||||
try {
|
||||
const siteId = req.user?.siteId || 0;
|
||||
const result = await this.scheduleService.add(siteId, data);
|
||||
return { code: 200, message: '创建成功', data: result };
|
||||
} catch (error) {
|
||||
return { code: 400, message: error.message || '创建失败', data: null };
|
||||
}
|
||||
}
|
||||
|
||||
@Put(':id')
|
||||
@ApiOperation({ summary: '编辑定时任务' })
|
||||
@ApiParam({ name: 'id', description: '任务ID' })
|
||||
@ApiResponse({ status: 200, description: '更新成功' })
|
||||
async edit(
|
||||
@Param('id', ParseIntPipe) id: number,
|
||||
@Body() data: any,
|
||||
@Req() req: AuthenticatedRequest,
|
||||
) {
|
||||
try {
|
||||
const siteId = req.user?.siteId || 0;
|
||||
const result = await this.scheduleService.edit(siteId, id, data);
|
||||
return { code: 200, message: '更新成功', data: result };
|
||||
} catch (error) {
|
||||
return { code: 400, message: error.message || '更新失败', data: null };
|
||||
}
|
||||
}
|
||||
|
||||
@Put(':id/start')
|
||||
@ApiOperation({ summary: '启动定时任务' })
|
||||
@ApiParam({ name: 'id', description: '任务ID' })
|
||||
@ApiResponse({ status: 200, description: '启动成功' })
|
||||
async start(
|
||||
@Param('id', ParseIntPipe) id: number,
|
||||
@Req() req: AuthenticatedRequest,
|
||||
) {
|
||||
try {
|
||||
const siteId = req.user?.siteId || 0;
|
||||
const result = await this.scheduleService.start(siteId, id);
|
||||
return { code: 200, message: '启动成功', data: result };
|
||||
} catch (error) {
|
||||
return { code: 400, message: error.message || '启动失败', data: null };
|
||||
}
|
||||
}
|
||||
|
||||
@Put(':id/stop')
|
||||
@ApiOperation({ summary: '停止定时任务' })
|
||||
@ApiParam({ name: 'id', description: '任务ID' })
|
||||
@ApiResponse({ status: 200, description: '停止成功' })
|
||||
async stop(
|
||||
@Param('id', ParseIntPipe) id: number,
|
||||
@Req() req: AuthenticatedRequest,
|
||||
) {
|
||||
try {
|
||||
const siteId = req.user?.siteId || 0;
|
||||
const result = await this.scheduleService.stop(siteId, id);
|
||||
return { code: 200, message: '停止成功', data: result };
|
||||
} catch (error) {
|
||||
return { code: 400, message: error.message || '停止失败', data: null };
|
||||
}
|
||||
}
|
||||
|
||||
@Delete(':id')
|
||||
@ApiOperation({ summary: '删除定时任务' })
|
||||
@ApiParam({ name: 'id', description: '任务ID' })
|
||||
@ApiResponse({ status: 200, description: '删除成功' })
|
||||
async delete(
|
||||
@Param('id', ParseIntPipe) id: number,
|
||||
@Req() req: AuthenticatedRequest,
|
||||
) {
|
||||
try {
|
||||
const siteId = req.user?.siteId || 0;
|
||||
const result = await this.scheduleService.del(siteId, id);
|
||||
return { code: 200, message: '删除成功', data: result };
|
||||
} catch (error) {
|
||||
return { code: 400, message: error.message || '删除失败', data: null };
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
import { Controller, Get, Query, UseGuards, Req } from '@nestjs/common';
|
||||
import { ApiTags, ApiOperation, ApiResponse } from '@nestjs/swagger';
|
||||
import type { Request } from 'express';
|
||||
import { JwtAuthGuard } from '../../../auth/guards/JwtAuthGuard';
|
||||
import { RolesGuard } from '../../../auth/guards/RolesGuard';
|
||||
import { Roles } from '../../../auth/decorators/RolesDecorator';
|
||||
|
||||
interface AuthenticatedRequest extends Request {
|
||||
user?: {
|
||||
uid: number;
|
||||
username: string;
|
||||
siteId: number;
|
||||
userType: string;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 定时任务日志控制器 - 管理端
|
||||
* 路由前缀: /adminapi/sys/schedule-log
|
||||
*/
|
||||
@ApiTags('定时任务日志')
|
||||
@Controller('adminapi/sys/schedule-log')
|
||||
@UseGuards(JwtAuthGuard, RolesGuard)
|
||||
@Roles('admin')
|
||||
export class ScheduleLogController {
|
||||
constructor() {}
|
||||
|
||||
@Get('page')
|
||||
@ApiOperation({ summary: '获取定时任务日志分页列表' })
|
||||
@ApiResponse({ status: 200, description: '获取成功' })
|
||||
async getPage(@Query() query: any, @Req() req: AuthenticatedRequest) {
|
||||
// TODO: 实现定时任务日志分页列表
|
||||
return { code: 200, message: '获取成功', data: { list: [], total: 0 } };
|
||||
}
|
||||
|
||||
@Get('list')
|
||||
@ApiOperation({ summary: '获取定时任务日志列表' })
|
||||
@ApiResponse({ status: 200, description: '获取成功' })
|
||||
async getList(@Query() query: any, @Req() req: AuthenticatedRequest) {
|
||||
// TODO: 实现定时任务日志列表
|
||||
return { code: 200, message: '获取成功', data: [] };
|
||||
}
|
||||
|
||||
@Get('stats')
|
||||
@ApiOperation({ summary: '获取定时任务统计信息' })
|
||||
@ApiResponse({ status: 200, description: '获取成功' })
|
||||
async getStats(@Req() req: AuthenticatedRequest) {
|
||||
// TODO: 实现定时任务统计信息
|
||||
return {
|
||||
code: 200,
|
||||
message: '获取成功',
|
||||
data: { total: 0, success: 0, failed: 0 },
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
import { Controller, Get, Post, UseGuards, Req } from '@nestjs/common';
|
||||
import { ApiTags, ApiOperation, ApiResponse } from '@nestjs/swagger';
|
||||
import type { Request } from 'express';
|
||||
import { JwtAuthGuard } from '../../../auth/guards/JwtAuthGuard';
|
||||
import { RolesGuard } from '../../../auth/guards/RolesGuard';
|
||||
import { Roles } from '../../../auth/decorators/RolesDecorator';
|
||||
import { SystemService } from '../../services/admin/SystemService';
|
||||
|
||||
interface AuthenticatedRequest extends Request {
|
||||
user?: {
|
||||
uid: number;
|
||||
username: string;
|
||||
siteId: number;
|
||||
userType: string;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 系统信息管理控制器 - 管理端
|
||||
* 路由前缀: /adminapi/sys/system
|
||||
*/
|
||||
@ApiTags('系统信息')
|
||||
@Controller('adminapi/sys/system')
|
||||
@UseGuards(JwtAuthGuard, RolesGuard)
|
||||
@Roles('admin')
|
||||
export class SystemController {
|
||||
constructor(private readonly systemService: SystemService) {}
|
||||
|
||||
@Get('info')
|
||||
@ApiOperation({ summary: '获取系统信息' })
|
||||
@ApiResponse({ status: 200, description: '获取成功' })
|
||||
async getInfo(@Req() req: AuthenticatedRequest) {
|
||||
const result = await this.systemService.getInfo();
|
||||
return { code: 200, message: '获取成功', data: result };
|
||||
}
|
||||
|
||||
@Get('url')
|
||||
@ApiOperation({ summary: '获取系统URL信息' })
|
||||
@ApiResponse({ status: 200, description: '获取成功' })
|
||||
async getUrl(@Req() req: AuthenticatedRequest) {
|
||||
const siteId = req.user?.siteId || 0;
|
||||
const result = await this.systemService.getUrl(siteId);
|
||||
return { code: 200, message: '获取成功', data: result };
|
||||
}
|
||||
|
||||
@Get('stats')
|
||||
@ApiOperation({ summary: '获取系统统计信息' })
|
||||
@ApiResponse({ status: 200, description: '获取成功' })
|
||||
async getSystemStats(@Req() req: AuthenticatedRequest) {
|
||||
const result = await this.systemService.getSystemStats();
|
||||
return { code: 200, message: '获取成功', data: result };
|
||||
}
|
||||
|
||||
@Get('system-info')
|
||||
@ApiOperation({ summary: '获取详细系统信息' })
|
||||
@ApiResponse({ status: 200, description: '获取成功' })
|
||||
async getSystemInfo(@Req() req: AuthenticatedRequest) {
|
||||
const result = await this.systemService.getSystemInfo();
|
||||
return { code: 200, message: '获取成功', data: result };
|
||||
}
|
||||
|
||||
@Post('clear-cache')
|
||||
@ApiOperation({ summary: '清理系统缓存' })
|
||||
@ApiResponse({ status: 200, description: '清理成功' })
|
||||
async clearCache(@Req() req: AuthenticatedRequest) {
|
||||
try {
|
||||
const result = await this.systemService.clearCache();
|
||||
return { code: 200, message: '清理成功', data: result };
|
||||
} catch (error) {
|
||||
return { code: 400, message: error.message || '清理失败', data: null };
|
||||
}
|
||||
}
|
||||
|
||||
@Get('check-config')
|
||||
@ApiOperation({ summary: '检查系统配置' })
|
||||
@ApiResponse({ status: 200, description: '检查完成' })
|
||||
async checkSystemConfig(@Req() req: AuthenticatedRequest) {
|
||||
const result = await this.systemService.checkSystemConfig();
|
||||
return { code: 200, message: '检查完成', data: result };
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
import { Controller, Get, Post, UseGuards, Req, Query } from '@nestjs/common';
|
||||
import { ApiTags, ApiOperation, ApiResponse } from '@nestjs/swagger';
|
||||
import type { Request } from 'express';
|
||||
import { JwtAuthGuard } from '../../../auth/guards/JwtAuthGuard';
|
||||
import { RolesGuard } from '../../../auth/guards/RolesGuard';
|
||||
import { Roles } from '../../../auth/decorators/RolesDecorator';
|
||||
|
||||
interface AuthenticatedRequest extends Request {
|
||||
user?: {
|
||||
uid: number;
|
||||
username: string;
|
||||
siteId: number;
|
||||
userType: string;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 富文本编辑器控制器 - 管理端
|
||||
* 路由前缀: /adminapi/sys/ueditor
|
||||
*/
|
||||
@ApiTags('富文本编辑器')
|
||||
@Controller('adminapi/sys/ueditor')
|
||||
@UseGuards(JwtAuthGuard, RolesGuard)
|
||||
@Roles('admin')
|
||||
export class UeditorController {
|
||||
constructor() {}
|
||||
|
||||
@Get('config')
|
||||
@ApiOperation({ summary: '获取编辑器配置' })
|
||||
@ApiResponse({ status: 200, description: '获取成功' })
|
||||
async getConfig(@Req() req: AuthenticatedRequest) {
|
||||
// TODO: 实现编辑器配置获取
|
||||
return {
|
||||
imageActionName: 'uploadimage',
|
||||
imageFieldName: 'upfile',
|
||||
imageMaxSize: 2048000,
|
||||
imageAllowFiles: ['.png', '.jpg', '.jpeg', '.gif', '.bmp'],
|
||||
imageCompressEnable: true,
|
||||
imageCompressBorder: 1600,
|
||||
imageInsertAlign: 'none',
|
||||
imageUrlPrefix: '',
|
||||
imagePathFormat:
|
||||
'/ueditor/php/upload/image/{yyyy}{mm}{dd}/{time}{rand:6}',
|
||||
};
|
||||
}
|
||||
|
||||
@Post('upload')
|
||||
@ApiOperation({ summary: '编辑器文件上传' })
|
||||
@ApiResponse({ status: 200, description: '上传成功' })
|
||||
async upload(@Req() req: AuthenticatedRequest) {
|
||||
// TODO: 实现编辑器文件上传
|
||||
return { code: 200, message: '上传成功', data: null };
|
||||
}
|
||||
|
||||
@Get('list')
|
||||
@ApiOperation({ summary: '获取文件列表' })
|
||||
@ApiResponse({ status: 200, description: '获取成功' })
|
||||
async getFileList(@Query() query: any, @Req() req: AuthenticatedRequest) {
|
||||
// TODO: 实现文件列表获取
|
||||
return { code: 200, message: '获取成功', data: { list: [], total: 0 } };
|
||||
}
|
||||
}
|
||||
54
wwjcloud/src/common/sys/controllers/api/ApiAreaController.ts
Normal file
54
wwjcloud/src/common/sys/controllers/api/ApiAreaController.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
import {
|
||||
Controller,
|
||||
Get,
|
||||
Param,
|
||||
UseGuards,
|
||||
Req,
|
||||
ParseIntPipe,
|
||||
Query,
|
||||
} from '@nestjs/common';
|
||||
import { ApiTags, ApiOperation, ApiResponse, ApiParam } from '@nestjs/swagger';
|
||||
import type { Request } from 'express';
|
||||
import { JwtAuthGuard } from '../../../auth/guards/JwtAuthGuard';
|
||||
import { ApiAreaService } from '../../services/api/ApiAreaService';
|
||||
|
||||
interface AuthenticatedRequest extends Request {
|
||||
user?: {
|
||||
uid: number;
|
||||
username: string;
|
||||
siteId: number;
|
||||
userType: string;
|
||||
};
|
||||
}
|
||||
|
||||
@ApiTags('API区域')
|
||||
@Controller('api/sys/area')
|
||||
@UseGuards(JwtAuthGuard)
|
||||
export class ApiAreaController {
|
||||
constructor(private readonly apiAreaService: ApiAreaService) {}
|
||||
|
||||
@Get('list')
|
||||
@ApiOperation({ summary: '获取区域列表' })
|
||||
@ApiResponse({ status: 200, description: '获取成功' })
|
||||
async getAreaList(
|
||||
@Req() req: AuthenticatedRequest,
|
||||
@Query('parent_id') parentId?: number,
|
||||
) {
|
||||
const siteId = req.user?.siteId || 0;
|
||||
const result = await this.apiAreaService.getAreaList(siteId, parentId);
|
||||
return { code: 200, message: '获取成功', data: result };
|
||||
}
|
||||
|
||||
@Get(':areaId')
|
||||
@ApiOperation({ summary: '获取区域详情' })
|
||||
@ApiParam({ name: 'areaId', description: '区域ID' })
|
||||
@ApiResponse({ status: 200, description: '获取成功' })
|
||||
async getAreaInfo(
|
||||
@Param('areaId', ParseIntPipe) areaId: number,
|
||||
@Req() req: AuthenticatedRequest,
|
||||
) {
|
||||
const siteId = req.user?.siteId || 0;
|
||||
const result = await this.apiAreaService.getAreaInfo(siteId, areaId);
|
||||
return { code: 200, message: '获取成功', data: result };
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
import {
|
||||
Controller,
|
||||
Get,
|
||||
Post,
|
||||
Body,
|
||||
Query,
|
||||
UseGuards,
|
||||
Req,
|
||||
} from '@nestjs/common';
|
||||
import { ApiTags, ApiOperation, ApiResponse } from '@nestjs/swagger';
|
||||
import type { Request } from 'express';
|
||||
import { JwtAuthGuard } from '../../../auth/guards/JwtAuthGuard';
|
||||
import { ApiConfigService } from '../../services/api/ApiConfigService';
|
||||
|
||||
interface AuthenticatedRequest extends Request {
|
||||
user?: {
|
||||
uid: number;
|
||||
username: string;
|
||||
siteId: number;
|
||||
userType: string;
|
||||
};
|
||||
}
|
||||
|
||||
@ApiTags('API配置')
|
||||
@Controller('api/sys/config')
|
||||
@UseGuards(JwtAuthGuard)
|
||||
export class ApiConfigController {
|
||||
constructor(private readonly apiConfigService: ApiConfigService) {}
|
||||
|
||||
@Get()
|
||||
@ApiOperation({ summary: '获取配置' })
|
||||
@ApiResponse({ status: 200, description: '获取成功' })
|
||||
async getConfig(@Query('key') key: string, @Req() req: AuthenticatedRequest) {
|
||||
const siteId = req.user?.siteId || 0;
|
||||
const result = await this.apiConfigService.getConfig(siteId, key);
|
||||
return { code: 200, message: '获取成功', data: result };
|
||||
}
|
||||
|
||||
@Post('batch')
|
||||
@ApiOperation({ summary: '批量获取配置' })
|
||||
@ApiResponse({ status: 200, description: '获取成功' })
|
||||
async getConfigs(
|
||||
@Body() body: { keys: string[] },
|
||||
@Req() req: AuthenticatedRequest,
|
||||
) {
|
||||
const siteId = req.user?.siteId || 0;
|
||||
const result = await this.apiConfigService.getConfigs(siteId, body.keys);
|
||||
return { code: 200, message: '获取成功', data: result };
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
import { Controller, Get, UseGuards, Req } from '@nestjs/common';
|
||||
import { ApiTags, ApiOperation, ApiResponse } from '@nestjs/swagger';
|
||||
import type { Request } from 'express';
|
||||
import { JwtAuthGuard } from '../../../auth/guards/JwtAuthGuard';
|
||||
import { ApiIndexService } from '../../services/api/ApiIndexService';
|
||||
|
||||
interface AuthenticatedRequest extends Request {
|
||||
user?: {
|
||||
uid: number;
|
||||
username: string;
|
||||
siteId: number;
|
||||
userType: string;
|
||||
};
|
||||
}
|
||||
|
||||
@ApiTags('API首页')
|
||||
@Controller('api/sys/index')
|
||||
@UseGuards(JwtAuthGuard)
|
||||
export class ApiIndexController {
|
||||
constructor(private readonly apiIndexService: ApiIndexService) {}
|
||||
|
||||
@Get()
|
||||
@ApiOperation({ summary: '获取首页信息' })
|
||||
@ApiResponse({ status: 200, description: '获取成功' })
|
||||
async getIndexInfo(@Req() req: AuthenticatedRequest) {
|
||||
const siteId = req.user?.siteId || 0;
|
||||
const result = await this.apiIndexService.getIndexInfo(siteId);
|
||||
return { code: 200, message: '获取成功', data: result };
|
||||
}
|
||||
|
||||
@Get('system')
|
||||
@ApiOperation({ summary: '获取系统信息' })
|
||||
@ApiResponse({ status: 200, description: '获取成功' })
|
||||
async getSystemInfo(@Req() req: AuthenticatedRequest) {
|
||||
const result = await this.apiIndexService.getSystemInfo();
|
||||
return { code: 200, message: '获取成功', data: result };
|
||||
}
|
||||
}
|
||||
43
wwjcloud/src/common/sys/controllers/api/ApiScanController.ts
Normal file
43
wwjcloud/src/common/sys/controllers/api/ApiScanController.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
import { Controller, Post, Body, UseGuards, Req } from '@nestjs/common';
|
||||
import { ApiTags, ApiOperation, ApiResponse } from '@nestjs/swagger';
|
||||
import type { Request } from 'express';
|
||||
import { JwtAuthGuard } from '../../../auth/guards/JwtAuthGuard';
|
||||
import { ApiScanService } from '../../services/api/ApiScanService';
|
||||
|
||||
interface AuthenticatedRequest extends Request {
|
||||
user?: {
|
||||
uid: number;
|
||||
username: string;
|
||||
siteId: number;
|
||||
userType: string;
|
||||
};
|
||||
}
|
||||
|
||||
@ApiTags('API扫描')
|
||||
@Controller('api/sys/scan')
|
||||
@UseGuards(JwtAuthGuard)
|
||||
export class ApiScanController {
|
||||
constructor(private readonly apiScanService: ApiScanService) {}
|
||||
|
||||
@Post('qr')
|
||||
@ApiOperation({ summary: '扫描二维码' })
|
||||
@ApiResponse({ status: 200, description: '扫描成功' })
|
||||
async scanQrCode(
|
||||
@Body() body: { code: string },
|
||||
@Req() req: AuthenticatedRequest,
|
||||
) {
|
||||
const result = await this.apiScanService.scanQrCode(body.code);
|
||||
return { code: 200, message: '扫描成功', data: result };
|
||||
}
|
||||
|
||||
@Post('barcode')
|
||||
@ApiOperation({ summary: '扫描条码' })
|
||||
@ApiResponse({ status: 200, description: '扫描成功' })
|
||||
async scanBarcode(
|
||||
@Body() body: { code: string },
|
||||
@Req() req: AuthenticatedRequest,
|
||||
) {
|
||||
const result = await this.apiScanService.scanBarcode(body.code);
|
||||
return { code: 200, message: '扫描成功', data: result };
|
||||
}
|
||||
}
|
||||
65
wwjcloud/src/common/sys/controllers/api/ApiTaskController.ts
Normal file
65
wwjcloud/src/common/sys/controllers/api/ApiTaskController.ts
Normal file
@@ -0,0 +1,65 @@
|
||||
import {
|
||||
Controller,
|
||||
Get,
|
||||
Post,
|
||||
Body,
|
||||
Put,
|
||||
Param,
|
||||
UseGuards,
|
||||
Req,
|
||||
ParseIntPipe,
|
||||
} from '@nestjs/common';
|
||||
import { ApiTags, ApiOperation, ApiResponse, ApiParam } from '@nestjs/swagger';
|
||||
import type { Request } from 'express';
|
||||
import { JwtAuthGuard } from '../../../auth/guards/JwtAuthGuard';
|
||||
import { ApiTaskService } from '../../services/api/ApiTaskService';
|
||||
|
||||
interface AuthenticatedRequest extends Request {
|
||||
user?: {
|
||||
uid: number;
|
||||
username: string;
|
||||
siteId: number;
|
||||
userType: string;
|
||||
};
|
||||
}
|
||||
|
||||
@ApiTags('API任务')
|
||||
@Controller('api/sys/task')
|
||||
@UseGuards(JwtAuthGuard)
|
||||
export class ApiTaskController {
|
||||
constructor(private readonly apiTaskService: ApiTaskService) {}
|
||||
|
||||
@Get('list')
|
||||
@ApiOperation({ summary: '获取任务列表' })
|
||||
@ApiResponse({ status: 200, description: '获取成功' })
|
||||
async getTaskList(@Req() req: AuthenticatedRequest) {
|
||||
const siteId = req.user?.siteId || 0;
|
||||
const result = await this.apiTaskService.getTaskList(siteId);
|
||||
return { code: 200, message: '获取成功', data: result };
|
||||
}
|
||||
|
||||
@Post()
|
||||
@ApiOperation({ summary: '创建任务' })
|
||||
@ApiResponse({ status: 200, description: '创建成功' })
|
||||
async createTask(@Body() body: any, @Req() req: AuthenticatedRequest) {
|
||||
const siteId = req.user?.siteId || 0;
|
||||
const result = await this.apiTaskService.createTask(siteId, body);
|
||||
return { code: 200, message: '创建成功', data: result };
|
||||
}
|
||||
|
||||
@Put(':taskId/status')
|
||||
@ApiOperation({ summary: '更新任务状态' })
|
||||
@ApiParam({ name: 'taskId', description: '任务ID' })
|
||||
@ApiResponse({ status: 200, description: '更新成功' })
|
||||
async updateTaskStatus(
|
||||
@Param('taskId', ParseIntPipe) taskId: number,
|
||||
@Body() body: { status: string },
|
||||
@Req() req: AuthenticatedRequest,
|
||||
) {
|
||||
const result = await this.apiTaskService.updateTaskStatus(
|
||||
taskId,
|
||||
body.status,
|
||||
);
|
||||
return { code: 200, message: '更新成功', data: result };
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
import { Controller, Post, Body, UseGuards, Req } from '@nestjs/common';
|
||||
import { ApiTags, ApiOperation, ApiResponse } from '@nestjs/swagger';
|
||||
import type { Request } from 'express';
|
||||
import { JwtAuthGuard } from '../../../auth/guards/JwtAuthGuard';
|
||||
import { ApiVerifyService } from '../../services/api/ApiVerifyService';
|
||||
|
||||
interface AuthenticatedRequest extends Request {
|
||||
user?: {
|
||||
uid: number;
|
||||
username: string;
|
||||
siteId: number;
|
||||
userType: string;
|
||||
};
|
||||
}
|
||||
|
||||
@ApiTags('API验证')
|
||||
@Controller('api/sys/verify')
|
||||
@UseGuards(JwtAuthGuard)
|
||||
export class ApiVerifyController {
|
||||
constructor(private readonly apiVerifyService: ApiVerifyService) {}
|
||||
|
||||
@Post('code')
|
||||
@ApiOperation({ summary: '验证码验证' })
|
||||
@ApiResponse({ status: 200, description: '验证成功' })
|
||||
async verifyCode(
|
||||
@Body() body: { code: string },
|
||||
@Req() req: AuthenticatedRequest,
|
||||
) {
|
||||
const result = await this.apiVerifyService.verifyCode(body.code);
|
||||
return {
|
||||
code: 200,
|
||||
message: result ? '验证成功' : '验证失败',
|
||||
data: result,
|
||||
};
|
||||
}
|
||||
|
||||
@Post('sms/send')
|
||||
@ApiOperation({ summary: '发送短信验证码' })
|
||||
@ApiResponse({ status: 200, description: '发送成功' })
|
||||
async sendSms(
|
||||
@Body() body: { phone: string },
|
||||
@Req() req: AuthenticatedRequest,
|
||||
) {
|
||||
const result = await this.apiVerifyService.sendSms(body.phone);
|
||||
return {
|
||||
code: 200,
|
||||
message: result ? '发送成功' : '发送失败',
|
||||
data: result,
|
||||
};
|
||||
}
|
||||
|
||||
@Post('sms/verify')
|
||||
@ApiOperation({ summary: '验证短信验证码' })
|
||||
@ApiResponse({ status: 200, description: '验证成功' })
|
||||
async verifySms(
|
||||
@Body() body: { phone: string; code: string },
|
||||
@Req() req: AuthenticatedRequest,
|
||||
) {
|
||||
const result = await this.apiVerifyService.verifySms(body.phone, body.code);
|
||||
return {
|
||||
code: 200,
|
||||
message: result ? '验证成功' : '验证失败',
|
||||
data: result,
|
||||
};
|
||||
}
|
||||
}
|
||||
57
wwjcloud/src/common/sys/controllers/api/SysApiController.ts
Normal file
57
wwjcloud/src/common/sys/controllers/api/SysApiController.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
import { Controller, Get, Post, Body, Query, UseGuards } from '@nestjs/common';
|
||||
import { JwtAuthGuard } from '../../../auth/guards/JwtAuthGuard';
|
||||
import { SysApiService } from '../../services/api/SysApiService';
|
||||
|
||||
@Controller('api/sys')
|
||||
@UseGuards(JwtAuthGuard)
|
||||
export class SysApiController {
|
||||
constructor(private readonly sysApiService: SysApiService) {}
|
||||
|
||||
/**
|
||||
* 获取系统信息
|
||||
*/
|
||||
@Get('index')
|
||||
async index(@Query() query: { site_id: number }) {
|
||||
return this.sysApiService.getIndex(query.site_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取地区列表
|
||||
*/
|
||||
@Get('area')
|
||||
async getArea(@Query() query: { parent_id?: number }) {
|
||||
return this.sysApiService.getArea(query.parent_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取系统配置
|
||||
*/
|
||||
@Get('config')
|
||||
async getConfig(@Query() query: { site_id: number, keys?: string }) {
|
||||
return this.sysApiService.getConfig(query.site_id, query.keys);
|
||||
}
|
||||
|
||||
/**
|
||||
* 扫码登录
|
||||
*/
|
||||
@Post('scan')
|
||||
async scan(@Body() dto: { qr_code: string }) {
|
||||
return this.sysApiService.scan(dto.qr_code);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取任务状态
|
||||
*/
|
||||
@Get('task')
|
||||
async getTask(@Query() query: { task_id: string }) {
|
||||
return this.sysApiService.getTask(query.task_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证码验证
|
||||
*/
|
||||
@Post('verify')
|
||||
async verify(@Body() dto: { verify_key: string; verify_code: string }) {
|
||||
return this.sysApiService.verify(dto.verify_key, dto.verify_code);
|
||||
}
|
||||
}
|
||||
249
wwjcloud/src/common/sys/dto/AttachmentDto.ts
Normal file
249
wwjcloud/src/common/sys/dto/AttachmentDto.ts
Normal file
@@ -0,0 +1,249 @@
|
||||
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
|
||||
import {
|
||||
IsString,
|
||||
IsOptional,
|
||||
IsNumber,
|
||||
IsArray,
|
||||
Min,
|
||||
Max,
|
||||
} from 'class-validator';
|
||||
import { Transform } from 'class-transformer';
|
||||
|
||||
/**
|
||||
* 附件查询DTO
|
||||
*/
|
||||
export class AttachmentQueryDto {
|
||||
@ApiPropertyOptional({ description: '附件名称', example: 'logo' })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
name?: string;
|
||||
|
||||
@ApiPropertyOptional({ description: '原始文件名', example: 'logo.png' })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
real_name?: string;
|
||||
|
||||
@ApiPropertyOptional({ description: '分类ID', example: 1 })
|
||||
@IsOptional()
|
||||
@Transform(({ value }) => parseInt(value))
|
||||
@IsNumber()
|
||||
cate_id?: number;
|
||||
|
||||
@ApiPropertyOptional({ description: '附件类型', example: 'image' })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
att_type?: string;
|
||||
|
||||
@ApiPropertyOptional({ description: '页码', example: 1, minimum: 1 })
|
||||
@IsOptional()
|
||||
@Transform(({ value }) => parseInt(value))
|
||||
@IsNumber()
|
||||
@Min(1)
|
||||
page?: number = 1;
|
||||
|
||||
@ApiPropertyOptional({
|
||||
description: '每页数量',
|
||||
example: 10,
|
||||
minimum: 1,
|
||||
maximum: 100,
|
||||
})
|
||||
@IsOptional()
|
||||
@Transform(({ value }) => parseInt(value))
|
||||
@IsNumber()
|
||||
@Min(1)
|
||||
@Max(100)
|
||||
limit?: number = 10;
|
||||
}
|
||||
|
||||
/**
|
||||
* 附件创建DTO
|
||||
*/
|
||||
export class CreateAttachmentDto {
|
||||
@ApiProperty({ description: '附件名称', example: 'logo' })
|
||||
@IsString()
|
||||
name: string;
|
||||
|
||||
@ApiProperty({ description: '原始文件名', example: 'logo.png' })
|
||||
@IsString()
|
||||
real_name: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: '完整路径',
|
||||
example: '/storage/attachment/2024/01/01/logo.png',
|
||||
})
|
||||
@IsString()
|
||||
path: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: '附件路径',
|
||||
example: '/storage/attachment/2024/01/01/',
|
||||
})
|
||||
@IsString()
|
||||
dir: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: '网络地址',
|
||||
example: 'https://example.com/storage/attachment/2024/01/01/logo.png',
|
||||
})
|
||||
@IsString()
|
||||
url: string;
|
||||
|
||||
@ApiPropertyOptional({ description: '分类ID', example: 1 })
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
cate_id?: number = 0;
|
||||
|
||||
@ApiProperty({ description: '附件大小', example: '102400' })
|
||||
@IsString()
|
||||
att_size: string;
|
||||
|
||||
@ApiProperty({ description: '附件类型', example: 'image' })
|
||||
@IsString()
|
||||
att_type: string;
|
||||
|
||||
@ApiPropertyOptional({ description: '存储类型', example: 'local' })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
storage_type?: string = 'local';
|
||||
}
|
||||
|
||||
/**
|
||||
* 附件更新DTO
|
||||
*/
|
||||
export class UpdateAttachmentDto {
|
||||
@ApiPropertyOptional({ description: '附件名称', example: 'logo' })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
name?: string;
|
||||
|
||||
@ApiPropertyOptional({ description: '分类ID', example: 1 })
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
cate_id?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改附件分类DTO
|
||||
*/
|
||||
export class ModifyAttachmentCategoryDto {
|
||||
@ApiProperty({ description: '分类ID', example: 1 })
|
||||
@IsNumber()
|
||||
cate_id: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除附件DTO
|
||||
*/
|
||||
export class BatchDeleteAttachmentDto {
|
||||
@ApiProperty({ description: '附件ID数组', example: [1, 2, 3] })
|
||||
@IsArray()
|
||||
@IsNumber({}, { each: true })
|
||||
att_ids: number[];
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量修改分类DTO
|
||||
*/
|
||||
export class BatchModifyCategoryDto {
|
||||
@ApiProperty({ description: '附件ID数组', example: [1, 2, 3] })
|
||||
@IsArray()
|
||||
@IsNumber({}, { each: true })
|
||||
att_ids: number[];
|
||||
|
||||
@ApiProperty({ description: '分类ID', example: 1 })
|
||||
@IsNumber()
|
||||
cate_id: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* 附件分类查询DTO
|
||||
*/
|
||||
export class AttachmentCategoryQueryDto {
|
||||
@ApiPropertyOptional({ description: '分类名称', example: '图片' })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
name?: string;
|
||||
|
||||
@ApiPropertyOptional({ description: '页码', example: 1, minimum: 1 })
|
||||
@IsOptional()
|
||||
@Transform(({ value }) => parseInt(value))
|
||||
@IsNumber()
|
||||
@Min(1)
|
||||
page?: number = 1;
|
||||
|
||||
@ApiPropertyOptional({
|
||||
description: '每页数量',
|
||||
example: 10,
|
||||
minimum: 1,
|
||||
maximum: 100,
|
||||
})
|
||||
@IsOptional()
|
||||
@Transform(({ value }) => parseInt(value))
|
||||
@IsNumber()
|
||||
@Min(1)
|
||||
@Max(100)
|
||||
limit?: number = 10;
|
||||
}
|
||||
|
||||
/**
|
||||
* 附件分类创建DTO
|
||||
*/
|
||||
export class CreateAttachmentCategoryDto {
|
||||
@ApiProperty({ description: '分类名称', example: '图片' })
|
||||
@IsString()
|
||||
name: string;
|
||||
|
||||
@ApiPropertyOptional({ description: '分类描述', example: '图片分类' })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
description?: string;
|
||||
|
||||
@ApiPropertyOptional({ description: '排序', example: 0 })
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
sort?: number = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 附件分类更新DTO
|
||||
*/
|
||||
export class UpdateAttachmentCategoryDto {
|
||||
@ApiPropertyOptional({ description: '分类名称', example: '图片' })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
name?: string;
|
||||
|
||||
@ApiPropertyOptional({ description: '分类描述', example: '图片分类' })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
description?: string;
|
||||
|
||||
@ApiPropertyOptional({ description: '排序', example: 0 })
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
sort?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Base64上传DTO
|
||||
*/
|
||||
export class Base64UploadDto {
|
||||
@ApiProperty({
|
||||
description: 'Base64编码的图片内容',
|
||||
example: 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD...',
|
||||
})
|
||||
@IsString()
|
||||
content: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 远程图片拉取DTO
|
||||
*/
|
||||
export class FetchImageDto {
|
||||
@ApiProperty({
|
||||
description: '远程图片URL',
|
||||
example: 'https://example.com/image.jpg',
|
||||
})
|
||||
@IsString()
|
||||
url: string;
|
||||
}
|
||||
116
wwjcloud/src/common/sys/dto/ConfigDto.ts
Normal file
116
wwjcloud/src/common/sys/dto/ConfigDto.ts
Normal file
@@ -0,0 +1,116 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { IsString, IsOptional, IsObject } from 'class-validator';
|
||||
|
||||
/**
|
||||
* 版权信息DTO
|
||||
*/
|
||||
export class CopyrightDto {
|
||||
@ApiProperty({ description: 'ICP备案号', required: false })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
icp?: string;
|
||||
|
||||
@ApiProperty({ description: '公安备案号', required: false })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
gov_record?: string;
|
||||
|
||||
@ApiProperty({ description: '公安备案链接', required: false })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
gov_url?: string;
|
||||
|
||||
@ApiProperty({ description: '市场监督管理局链接', required: false })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
market_supervision_url?: string;
|
||||
|
||||
@ApiProperty({ description: '版权Logo', required: false })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
logo?: string;
|
||||
|
||||
@ApiProperty({ description: '公司名称', required: false })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
company_name?: string;
|
||||
|
||||
@ApiProperty({ description: '版权链接', required: false })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
copyright_link?: string;
|
||||
|
||||
@ApiProperty({ description: '版权描述', required: false })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
copyright_desc?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 网站信息DTO
|
||||
*/
|
||||
export class WebSiteDto {
|
||||
@ApiProperty({ description: '网站名称', required: false })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
site_name?: string;
|
||||
|
||||
@ApiProperty({ description: '网站Logo', required: false })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
logo?: string;
|
||||
|
||||
@ApiProperty({ description: '网站图标', required: false })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
icon?: string;
|
||||
|
||||
@ApiProperty({ description: '网站关键词', required: false })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
keywords?: string;
|
||||
|
||||
@ApiProperty({ description: '网站描述', required: false })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
desc?: string;
|
||||
|
||||
@ApiProperty({ description: '网站状态', required: false })
|
||||
@IsOptional()
|
||||
status?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* 场景域名配置DTO
|
||||
*/
|
||||
export class SceneDomainDto {
|
||||
@ApiProperty({ description: 'WAP域名', required: false })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
wap_domain?: string;
|
||||
|
||||
@ApiProperty({ description: 'WEB域名', required: false })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
web_domain?: string;
|
||||
|
||||
@ApiProperty({ description: 'H5域名', required: false })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
h5_domain?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 服务配置DTO
|
||||
*/
|
||||
export class ServiceDto {
|
||||
@ApiProperty({ description: '登录页Logo', required: false })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
site_login_logo?: string;
|
||||
|
||||
@ApiProperty({ description: '登录页背景图', required: false })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
site_login_bg_img?: string;
|
||||
}
|
||||
174
wwjcloud/src/common/sys/dto/MenuDto.ts
Normal file
174
wwjcloud/src/common/sys/dto/MenuDto.ts
Normal file
@@ -0,0 +1,174 @@
|
||||
import {
|
||||
IsString,
|
||||
IsNumber,
|
||||
IsOptional,
|
||||
IsBoolean,
|
||||
MinLength,
|
||||
MaxLength,
|
||||
} from 'class-validator';
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
|
||||
export class CreateMenuDto {
|
||||
@ApiProperty({ description: '菜单名称', example: '系统管理' })
|
||||
@IsString()
|
||||
@MinLength(1)
|
||||
@MaxLength(100)
|
||||
menuName: string;
|
||||
|
||||
@ApiProperty({ description: '菜单简称', example: '系统', required: false })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@MaxLength(50)
|
||||
menuShortName?: string;
|
||||
|
||||
@ApiProperty({ description: '菜单类型', example: 1 })
|
||||
@IsNumber()
|
||||
menuType: number;
|
||||
|
||||
@ApiProperty({ description: '父级菜单ID', example: 0 })
|
||||
@IsNumber()
|
||||
parentId: number;
|
||||
|
||||
@ApiProperty({ description: '菜单标识', example: 'sys', required: false })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@MaxLength(100)
|
||||
menuKey?: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: '菜单链接',
|
||||
example: '/adminapi/sys',
|
||||
required: false,
|
||||
})
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@MaxLength(255)
|
||||
menuUrl?: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: '菜单图标',
|
||||
example: 'icon-sys',
|
||||
required: false,
|
||||
})
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@MaxLength(100)
|
||||
menuIcon?: string;
|
||||
|
||||
@ApiProperty({ description: '排序', example: 0 })
|
||||
@IsNumber()
|
||||
sort: number;
|
||||
|
||||
@ApiProperty({ description: '状态', example: 1 })
|
||||
@IsNumber()
|
||||
status: number;
|
||||
|
||||
@ApiProperty({ description: '是否显示', example: 1 })
|
||||
@IsNumber()
|
||||
isShow: number;
|
||||
}
|
||||
|
||||
export class UpdateMenuDto {
|
||||
@ApiProperty({ description: '菜单ID', example: 1 })
|
||||
@IsNumber()
|
||||
id: number;
|
||||
|
||||
@ApiProperty({
|
||||
description: '菜单名称',
|
||||
example: '系统管理',
|
||||
required: false,
|
||||
})
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@MinLength(1)
|
||||
@MaxLength(100)
|
||||
menuName?: string;
|
||||
|
||||
@ApiProperty({ description: '菜单简称', example: '系统', required: false })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@MaxLength(50)
|
||||
menuShortName?: string;
|
||||
|
||||
@ApiProperty({ description: '菜单类型', example: 1, required: false })
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
menuType?: number;
|
||||
|
||||
@ApiProperty({ description: '父级菜单ID', example: 0, required: false })
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
parentId?: number;
|
||||
|
||||
@ApiProperty({ description: '菜单标识', example: 'sys', required: false })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@MaxLength(100)
|
||||
menuKey?: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: '菜单链接',
|
||||
example: '/adminapi/sys',
|
||||
required: false,
|
||||
})
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@MaxLength(255)
|
||||
menuUrl?: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: '菜单图标',
|
||||
example: 'icon-sys',
|
||||
required: false,
|
||||
})
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@MaxLength(100)
|
||||
menuIcon?: string;
|
||||
|
||||
@ApiProperty({ description: '排序', example: 0, required: false })
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
sort?: number;
|
||||
|
||||
@ApiProperty({ description: '状态', example: 1, required: false })
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
status?: number;
|
||||
|
||||
@ApiProperty({ description: '是否显示', example: 1, required: false })
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
isShow?: number;
|
||||
}
|
||||
|
||||
export class MenuQueryDto {
|
||||
@ApiProperty({
|
||||
description: '菜单名称',
|
||||
example: '系统管理',
|
||||
required: false,
|
||||
})
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
menuName?: string;
|
||||
|
||||
@ApiProperty({ description: '菜单类型', example: 1, required: false })
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
menuType?: number;
|
||||
|
||||
@ApiProperty({ description: '状态', example: 1, required: false })
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
status?: number;
|
||||
|
||||
@ApiProperty({ description: '页码', example: 1, required: false })
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
page?: number;
|
||||
|
||||
@ApiProperty({ description: '每页数量', example: 10, required: false })
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
limit?: number;
|
||||
}
|
||||
88
wwjcloud/src/common/sys/dto/RoleDto.ts
Normal file
88
wwjcloud/src/common/sys/dto/RoleDto.ts
Normal file
@@ -0,0 +1,88 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { IsString, IsOptional, IsNumber, IsIn, IsArray } from 'class-validator';
|
||||
|
||||
/**
|
||||
* 创建角色DTO
|
||||
*/
|
||||
export class CreateRoleDto {
|
||||
@ApiProperty({ description: '角色名称', example: '管理员' })
|
||||
@IsString()
|
||||
role_name: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: '角色权限(菜单键数组)',
|
||||
required: false,
|
||||
type: [String],
|
||||
})
|
||||
@IsOptional()
|
||||
@IsArray()
|
||||
@IsString({ each: true })
|
||||
rules?: string[];
|
||||
|
||||
@ApiProperty({
|
||||
description: '状态:0=禁用,1=启用',
|
||||
required: false,
|
||||
default: 1,
|
||||
})
|
||||
@IsOptional()
|
||||
@IsIn([0, 1])
|
||||
status?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新角色DTO
|
||||
*/
|
||||
export class UpdateRoleDto {
|
||||
@ApiProperty({ description: '角色名称', required: false })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
role_name?: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: '角色权限(菜单键数组)',
|
||||
required: false,
|
||||
type: [String],
|
||||
})
|
||||
@IsOptional()
|
||||
@IsArray()
|
||||
@IsString({ each: true })
|
||||
rules?: string[];
|
||||
|
||||
@ApiProperty({ description: '状态:0=禁用,1=启用', required: false })
|
||||
@IsOptional()
|
||||
@IsIn([0, 1])
|
||||
status?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* 角色查询DTO
|
||||
*/
|
||||
export class RoleQueryDto {
|
||||
@ApiProperty({ description: '角色名称', required: false })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
role_name?: string;
|
||||
|
||||
@ApiProperty({ description: '页码', required: false, default: 1 })
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
page?: number;
|
||||
|
||||
@ApiProperty({ description: '每页数量', required: false, default: 10 })
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
limit?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改角色状态DTO
|
||||
*/
|
||||
export class ModifyRoleStatusDto {
|
||||
@ApiProperty({ description: '角色ID' })
|
||||
@IsNumber()
|
||||
role_id: number;
|
||||
|
||||
@ApiProperty({ description: '状态:0=禁用,1=启用' })
|
||||
@IsIn([0, 1])
|
||||
status: number;
|
||||
}
|
||||
121
wwjcloud/src/common/sys/dto/ScheduleDto.ts
Normal file
121
wwjcloud/src/common/sys/dto/ScheduleDto.ts
Normal file
@@ -0,0 +1,121 @@
|
||||
import {
|
||||
IsString,
|
||||
IsNumber,
|
||||
IsOptional,
|
||||
IsObject,
|
||||
MinLength,
|
||||
MaxLength,
|
||||
} from 'class-validator';
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
|
||||
export class CreateScheduleDto {
|
||||
@ApiProperty({ description: '任务标识', example: 'test_task' })
|
||||
@IsString()
|
||||
@MinLength(1)
|
||||
@MaxLength(100)
|
||||
key: string;
|
||||
|
||||
@ApiProperty({ description: '任务标题', example: '测试任务' })
|
||||
@IsString()
|
||||
@MinLength(1)
|
||||
@MaxLength(100)
|
||||
title: string;
|
||||
|
||||
@ApiProperty({ description: '执行命令', example: 'php artisan test' })
|
||||
@IsString()
|
||||
@MinLength(1)
|
||||
@MaxLength(500)
|
||||
command: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: '执行时间配置',
|
||||
example: { type: 'cron', value: '0 0 * * *' },
|
||||
required: false,
|
||||
})
|
||||
@IsOptional()
|
||||
@IsObject()
|
||||
time?: any;
|
||||
|
||||
@ApiProperty({ description: '状态', example: 1 })
|
||||
@IsNumber()
|
||||
status: number;
|
||||
}
|
||||
|
||||
export class UpdateScheduleDto {
|
||||
@ApiProperty({ description: '任务ID', example: 1 })
|
||||
@IsNumber()
|
||||
id: number;
|
||||
|
||||
@ApiProperty({
|
||||
description: '任务标识',
|
||||
example: 'test_task',
|
||||
required: false,
|
||||
})
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@MinLength(1)
|
||||
@MaxLength(100)
|
||||
key?: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: '任务标题',
|
||||
example: '测试任务',
|
||||
required: false,
|
||||
})
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@MinLength(1)
|
||||
@MaxLength(100)
|
||||
title?: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: '执行命令',
|
||||
example: 'php artisan test',
|
||||
required: false,
|
||||
})
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@MinLength(1)
|
||||
@MaxLength(500)
|
||||
command?: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: '执行时间配置',
|
||||
example: { type: 'cron', value: '0 0 * * *' },
|
||||
required: false,
|
||||
})
|
||||
@IsOptional()
|
||||
@IsObject()
|
||||
time?: any;
|
||||
|
||||
@ApiProperty({ description: '状态', example: 1, required: false })
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
status?: number;
|
||||
}
|
||||
|
||||
export class ScheduleQueryDto {
|
||||
@ApiProperty({
|
||||
description: '任务标识',
|
||||
example: 'test_task',
|
||||
required: false,
|
||||
})
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
key?: string;
|
||||
|
||||
@ApiProperty({ description: '状态', example: 1, required: false })
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
status?: number;
|
||||
|
||||
@ApiProperty({ description: '页码', example: 1, required: false })
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
page?: number;
|
||||
|
||||
@ApiProperty({ description: '每页数量', example: 10, required: false })
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
limit?: number;
|
||||
}
|
||||
138
wwjcloud/src/common/sys/dto/UserDto.ts
Normal file
138
wwjcloud/src/common/sys/dto/UserDto.ts
Normal file
@@ -0,0 +1,138 @@
|
||||
import {
|
||||
IsString,
|
||||
IsNumber,
|
||||
IsOptional,
|
||||
IsEmail,
|
||||
MinLength,
|
||||
MaxLength,
|
||||
} from 'class-validator';
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
|
||||
export class CreateUserDto {
|
||||
@ApiProperty({ description: '用户名', example: 'admin' })
|
||||
@IsString()
|
||||
@MinLength(3)
|
||||
@MaxLength(50)
|
||||
username: string;
|
||||
|
||||
@ApiProperty({ description: '密码', example: '123456' })
|
||||
@IsString()
|
||||
@MinLength(6)
|
||||
@MaxLength(255)
|
||||
password: string;
|
||||
|
||||
@ApiProperty({ description: '真实姓名', example: '管理员', required: false })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@MaxLength(50)
|
||||
realName?: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: '头像',
|
||||
example: '/uploads/avatar.jpg',
|
||||
required: false,
|
||||
})
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@MaxLength(255)
|
||||
headImg?: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: '手机号',
|
||||
example: '13800138000',
|
||||
required: false,
|
||||
})
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@MaxLength(20)
|
||||
phone?: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: '邮箱',
|
||||
example: 'admin@example.com',
|
||||
required: false,
|
||||
})
|
||||
@IsOptional()
|
||||
@IsEmail()
|
||||
@MaxLength(100)
|
||||
email?: string;
|
||||
|
||||
@ApiProperty({ description: '状态', example: 1 })
|
||||
@IsNumber()
|
||||
status: number;
|
||||
}
|
||||
|
||||
export class UpdateUserDto {
|
||||
@ApiProperty({ description: '用户ID', example: 1 })
|
||||
@IsNumber()
|
||||
uid: number;
|
||||
|
||||
@ApiProperty({ description: '用户名', example: 'admin', required: false })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@MinLength(3)
|
||||
@MaxLength(50)
|
||||
username?: string;
|
||||
|
||||
@ApiProperty({ description: '密码', example: '123456', required: false })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@MinLength(6)
|
||||
@MaxLength(255)
|
||||
password?: string;
|
||||
|
||||
@ApiProperty({ description: '真实姓名', example: '管理员', required: false })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@MaxLength(50)
|
||||
realName?: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: '头像',
|
||||
example: '/uploads/avatar.jpg',
|
||||
required: false,
|
||||
})
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@MaxLength(255)
|
||||
headImg?: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: '手机号',
|
||||
example: '13800138000',
|
||||
required: false,
|
||||
})
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@MaxLength(20)
|
||||
phone?: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: '邮箱',
|
||||
example: 'admin@example.com',
|
||||
required: false,
|
||||
})
|
||||
@IsOptional()
|
||||
@IsEmail()
|
||||
@MaxLength(100)
|
||||
email?: string;
|
||||
|
||||
@ApiProperty({ description: '状态', example: 1, required: false })
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
status?: number;
|
||||
}
|
||||
|
||||
export class LoginDto {
|
||||
@ApiProperty({ description: '用户名', example: 'admin' })
|
||||
@IsString()
|
||||
@MinLength(3)
|
||||
@MaxLength(50)
|
||||
username: string;
|
||||
|
||||
@ApiProperty({ description: '密码', example: '123456' })
|
||||
@IsString()
|
||||
@MinLength(6)
|
||||
@MaxLength(255)
|
||||
password: string;
|
||||
}
|
||||
48
wwjcloud/src/common/sys/dto/api/SysApiDto.ts
Normal file
48
wwjcloud/src/common/sys/dto/api/SysApiDto.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
import { IsString, IsNumber, IsOptional, IsArray } from 'class-validator';
|
||||
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
|
||||
|
||||
export class AreaQueryDto {
|
||||
@ApiPropertyOptional({ description: '父级ID', example: 0 })
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
parent_id?: number;
|
||||
}
|
||||
|
||||
export class ConfigQueryDto {
|
||||
@ApiProperty({ description: '站点ID', example: 0 })
|
||||
@IsNumber()
|
||||
site_id: number;
|
||||
|
||||
@ApiPropertyOptional({ description: '配置键,多个用逗号分隔', example: 'site_name,logo' })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
keys?: string;
|
||||
}
|
||||
|
||||
export class ScanDto {
|
||||
@ApiProperty({ description: '二维码内容', example: 'qr_code_content' })
|
||||
@IsString()
|
||||
qr_code: string;
|
||||
}
|
||||
|
||||
export class TaskQueryDto {
|
||||
@ApiProperty({ description: '任务ID', example: 'task_123456' })
|
||||
@IsString()
|
||||
task_id: string;
|
||||
}
|
||||
|
||||
export class VerifyDto {
|
||||
@ApiProperty({ description: '验证键', example: 'verify_key_123' })
|
||||
@IsString()
|
||||
verify_key: string;
|
||||
|
||||
@ApiProperty({ description: '验证码', example: '123456' })
|
||||
@IsString()
|
||||
verify_code: string;
|
||||
}
|
||||
|
||||
export class IndexQueryDto {
|
||||
@ApiProperty({ description: '站点ID', example: 0 })
|
||||
@IsNumber()
|
||||
site_id: number;
|
||||
}
|
||||
43
wwjcloud/src/common/sys/entities/NiuSmsTemplate.ts
Normal file
43
wwjcloud/src/common/sys/entities/NiuSmsTemplate.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
import {
|
||||
Entity,
|
||||
PrimaryGeneratedColumn,
|
||||
Column,
|
||||
CreateDateColumn,
|
||||
UpdateDateColumn,
|
||||
} from 'typeorm';
|
||||
import { BaseEntity } from '../../../core/base/BaseEntity';
|
||||
|
||||
/**
|
||||
* 牛云短信模板实体
|
||||
*/
|
||||
@Entity('niu_sms_template')
|
||||
export class NiuSmsTemplate extends BaseEntity {
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
|
||||
@Column({ name: 'template_name', length: 100, comment: '模板名称' })
|
||||
templateName: string;
|
||||
|
||||
@Column({ name: 'template_key', length: 100, comment: '模板标识' })
|
||||
templateKey: string;
|
||||
|
||||
@Column({ name: 'template_content', type: 'text', comment: '模板内容' })
|
||||
templateContent: string;
|
||||
|
||||
@Column({ name: 'template_type', type: 'tinyint', comment: '模板类型' })
|
||||
templateType: number;
|
||||
|
||||
@Column({
|
||||
name: 'status',
|
||||
type: 'tinyint',
|
||||
default: 1,
|
||||
comment: '状态 0禁用 1启用',
|
||||
})
|
||||
status: number;
|
||||
|
||||
@CreateDateColumn({ name: 'create_time', comment: '创建时间' })
|
||||
createTime: Date;
|
||||
|
||||
@UpdateDateColumn({ name: 'update_time', comment: '更新时间' })
|
||||
updateTime: Date;
|
||||
}
|
||||
45
wwjcloud/src/common/sys/entities/SysAgreement.ts
Normal file
45
wwjcloud/src/common/sys/entities/SysAgreement.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';
|
||||
import { BaseEntity } from '../../../core/base/BaseEntity';
|
||||
|
||||
@Entity('sys_agreement')
|
||||
export class SysAgreement extends BaseEntity {
|
||||
@PrimaryGeneratedColumn({ name: 'id' })
|
||||
id: number;
|
||||
|
||||
@Column({
|
||||
name: 'agreement_key',
|
||||
type: 'varchar',
|
||||
length: 255,
|
||||
default: '',
|
||||
comment: '协议关键字',
|
||||
})
|
||||
agreement_key: string;
|
||||
|
||||
@Column({
|
||||
name: 'title',
|
||||
type: 'varchar',
|
||||
length: 255,
|
||||
default: '',
|
||||
comment: '协议标题',
|
||||
})
|
||||
title: string;
|
||||
|
||||
@Column({
|
||||
name: 'content',
|
||||
type: 'text',
|
||||
nullable: true,
|
||||
comment: '协议内容',
|
||||
})
|
||||
content: string;
|
||||
|
||||
// 获取协议类型名称
|
||||
getTypeName(): string {
|
||||
const typeMap: { [key: string]: string } = {
|
||||
privacy: '隐私政策',
|
||||
service: '服务协议',
|
||||
user: '用户协议',
|
||||
member: '会员协议',
|
||||
};
|
||||
return typeMap[this.agreement_key] || this.agreement_key;
|
||||
}
|
||||
}
|
||||
28
wwjcloud/src/common/sys/entities/SysApp.ts
Normal file
28
wwjcloud/src/common/sys/entities/SysApp.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';
|
||||
import { BaseEntity } from '../../../core/base/BaseEntity';
|
||||
|
||||
@Entity('sys_app')
|
||||
export class SysApp extends BaseEntity {
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
|
||||
@Column({ name: 'app_name', length: 100, comment: '应用名称' })
|
||||
app_name: string;
|
||||
|
||||
@Column({ name: 'app_key', length: 100, comment: '应用密钥' })
|
||||
app_key: string;
|
||||
|
||||
@Column({ name: 'app_secret', length: 255, comment: '应用秘钥' })
|
||||
app_secret: string;
|
||||
|
||||
@Column({
|
||||
name: 'status',
|
||||
type: 'tinyint',
|
||||
default: 1,
|
||||
comment: '状态 0禁用 1启用',
|
||||
})
|
||||
status: number;
|
||||
|
||||
@Column({ name: 'remark', type: 'text', nullable: true, comment: '备注' })
|
||||
remark: string;
|
||||
}
|
||||
75
wwjcloud/src/common/sys/entities/SysArea.ts
Normal file
75
wwjcloud/src/common/sys/entities/SysArea.ts
Normal file
@@ -0,0 +1,75 @@
|
||||
import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';
|
||||
|
||||
@Entity('sys_area')
|
||||
export class SysArea {
|
||||
@PrimaryGeneratedColumn({ name: 'id' })
|
||||
id: number;
|
||||
|
||||
@Column({ name: 'pid', type: 'int', default: 0, comment: '父级ID' })
|
||||
pid: number;
|
||||
|
||||
@Column({
|
||||
name: 'name',
|
||||
type: 'varchar',
|
||||
length: 50,
|
||||
default: '',
|
||||
comment: '名称',
|
||||
})
|
||||
name: string;
|
||||
|
||||
@Column({
|
||||
name: 'shortname',
|
||||
type: 'varchar',
|
||||
length: 30,
|
||||
default: '',
|
||||
comment: '简称',
|
||||
})
|
||||
shortname: string;
|
||||
|
||||
@Column({
|
||||
name: 'longitude',
|
||||
type: 'varchar',
|
||||
length: 30,
|
||||
default: '',
|
||||
comment: '经度',
|
||||
})
|
||||
longitude: string;
|
||||
|
||||
@Column({
|
||||
name: 'latitude',
|
||||
type: 'varchar',
|
||||
length: 30,
|
||||
default: '',
|
||||
comment: '纬度',
|
||||
})
|
||||
latitude: string;
|
||||
|
||||
@Column({ name: 'level', type: 'tinyint', default: 1, comment: '层级' })
|
||||
level: number;
|
||||
|
||||
@Column({ name: 'sort', type: 'int', default: 0, comment: '排序' })
|
||||
sort: number;
|
||||
|
||||
@Column({
|
||||
name: 'status',
|
||||
type: 'tinyint',
|
||||
default: 1,
|
||||
comment: '状态:1=有效,0=无效',
|
||||
})
|
||||
status: number;
|
||||
|
||||
// 获取层级文本
|
||||
getLevelText(): string {
|
||||
const levelMap: { [key: number]: string } = {
|
||||
1: '省',
|
||||
2: '市',
|
||||
3: '区/县',
|
||||
};
|
||||
return levelMap[this.level] || '未知';
|
||||
}
|
||||
|
||||
// 检查是否为叶子节点
|
||||
isLeafNode(): boolean {
|
||||
return this.level >= 3;
|
||||
}
|
||||
}
|
||||
97
wwjcloud/src/common/sys/entities/SysAttachment.ts
Normal file
97
wwjcloud/src/common/sys/entities/SysAttachment.ts
Normal file
@@ -0,0 +1,97 @@
|
||||
import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';
|
||||
import { BaseEntity } from '../../../core/base/BaseEntity';
|
||||
|
||||
@Entity('sys_attachment')
|
||||
export class SysAttachment extends BaseEntity {
|
||||
@PrimaryGeneratedColumn({ name: 'att_id' })
|
||||
att_id: number;
|
||||
|
||||
@Column({
|
||||
name: 'name',
|
||||
type: 'varchar',
|
||||
length: 100,
|
||||
default: '',
|
||||
comment: '附件名称',
|
||||
})
|
||||
name: string;
|
||||
|
||||
@Column({
|
||||
name: 'real_name',
|
||||
type: 'varchar',
|
||||
length: 255,
|
||||
default: '',
|
||||
comment: '原始文件名',
|
||||
})
|
||||
real_name: string;
|
||||
|
||||
@Column({
|
||||
name: 'path',
|
||||
type: 'varchar',
|
||||
length: 255,
|
||||
default: '',
|
||||
comment: '完整地址',
|
||||
})
|
||||
path: string;
|
||||
|
||||
@Column({
|
||||
name: 'dir',
|
||||
type: 'varchar',
|
||||
length: 200,
|
||||
default: '',
|
||||
comment: '附件路径',
|
||||
})
|
||||
dir: string;
|
||||
|
||||
@Column({
|
||||
name: 'url',
|
||||
type: 'varchar',
|
||||
length: 255,
|
||||
default: '',
|
||||
comment: '网络地址',
|
||||
})
|
||||
url: string;
|
||||
|
||||
@Column({ name: 'cate_id', type: 'int', default: 0, comment: '分类ID' })
|
||||
cate_id: number;
|
||||
|
||||
@Column({
|
||||
name: 'att_size',
|
||||
type: 'char',
|
||||
length: 30,
|
||||
default: '',
|
||||
comment: '附件大小',
|
||||
})
|
||||
att_size: string;
|
||||
|
||||
@Column({
|
||||
name: 'att_type',
|
||||
type: 'char',
|
||||
length: 30,
|
||||
default: '',
|
||||
comment: '附件类型image,video',
|
||||
})
|
||||
att_type: string;
|
||||
|
||||
@Column({
|
||||
name: 'storage_type',
|
||||
type: 'varchar',
|
||||
length: 20,
|
||||
default: 'local',
|
||||
comment: '存储类型',
|
||||
})
|
||||
storage_type: string;
|
||||
|
||||
// 获取文件扩展名
|
||||
getFileExtension(): string {
|
||||
return this.real_name.split('.').pop() || '';
|
||||
}
|
||||
|
||||
// 获取可读的文件大小
|
||||
getReadableFileSize(): string {
|
||||
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
|
||||
const size = parseInt(this.att_size) || 0;
|
||||
if (size === 0) return '0 Byte';
|
||||
const i = Math.floor(Math.log(size) / Math.log(1024));
|
||||
return Math.round((size / Math.pow(1024, i)) * 100) / 100 + ' ' + sizes[i];
|
||||
}
|
||||
}
|
||||
BIN
wwjcloud/src/common/sys/entities/SysAttachmentCategory.ts
Normal file
BIN
wwjcloud/src/common/sys/entities/SysAttachmentCategory.ts
Normal file
Binary file not shown.
55
wwjcloud/src/common/sys/entities/SysBackupRecords.ts
Normal file
55
wwjcloud/src/common/sys/entities/SysBackupRecords.ts
Normal file
@@ -0,0 +1,55 @@
|
||||
import {
|
||||
Entity,
|
||||
PrimaryGeneratedColumn,
|
||||
Column,
|
||||
CreateDateColumn,
|
||||
UpdateDateColumn,
|
||||
} from 'typeorm';
|
||||
import { BaseEntity } from '../../../core/base/BaseEntity';
|
||||
|
||||
/**
|
||||
* 系统备份记录实体
|
||||
*/
|
||||
@Entity('sys_backup_records')
|
||||
export class SysBackupRecords extends BaseEntity {
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
|
||||
@Column({ name: 'backup_name', length: 200, comment: '备份名称' })
|
||||
backupName: string;
|
||||
|
||||
@Column({
|
||||
name: 'backup_type',
|
||||
type: 'tinyint',
|
||||
comment: '备份类型 1数据库 2文件',
|
||||
})
|
||||
backupType: number;
|
||||
|
||||
@Column({ name: 'file_path', length: 500, comment: '文件路径' })
|
||||
filePath: string;
|
||||
|
||||
@Column({
|
||||
name: 'file_size',
|
||||
type: 'bigint',
|
||||
default: 0,
|
||||
comment: '文件大小',
|
||||
})
|
||||
fileSize: number;
|
||||
|
||||
@Column({
|
||||
name: 'status',
|
||||
type: 'tinyint',
|
||||
default: 1,
|
||||
comment: '状态 0失败 1成功',
|
||||
})
|
||||
status: number;
|
||||
|
||||
@Column({ name: 'remark', length: 500, nullable: true, comment: '备注' })
|
||||
remark: string;
|
||||
|
||||
@CreateDateColumn({ name: 'create_time', comment: '创建时间' })
|
||||
createTime: Date;
|
||||
|
||||
@UpdateDateColumn({ name: 'update_time', comment: '更新时间' })
|
||||
updateTime: Date;
|
||||
}
|
||||
31
wwjcloud/src/common/sys/entities/SysChannel.ts
Normal file
31
wwjcloud/src/common/sys/entities/SysChannel.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';
|
||||
import { BaseEntity } from '../../../core/base/BaseEntity';
|
||||
|
||||
@Entity('sys_channel')
|
||||
export class SysChannel extends BaseEntity {
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
|
||||
@Column({ name: 'channel_name', length: 100, comment: '渠道名称' })
|
||||
channel_name: string;
|
||||
|
||||
@Column({ name: 'channel_code', length: 50, comment: '渠道编码' })
|
||||
channel_code: string;
|
||||
|
||||
@Column({ name: 'channel_type', length: 50, comment: '渠道类型' })
|
||||
channel_type: string;
|
||||
|
||||
@Column({
|
||||
name: 'status',
|
||||
type: 'tinyint',
|
||||
default: 1,
|
||||
comment: '状态 0禁用 1启用',
|
||||
})
|
||||
status: number;
|
||||
|
||||
@Column({ name: 'sort', type: 'int', default: 0, comment: '排序' })
|
||||
sort: number;
|
||||
|
||||
@Column({ name: 'remark', type: 'text', nullable: true, comment: '备注' })
|
||||
remark: string;
|
||||
}
|
||||
44
wwjcloud/src/common/sys/entities/SysConfig.ts
Normal file
44
wwjcloud/src/common/sys/entities/SysConfig.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
import { Entity, PrimaryGeneratedColumn, Column, Index } from 'typeorm';
|
||||
import { BaseEntity } from '../../../core/base/BaseEntity';
|
||||
|
||||
/**
|
||||
* 系统配置实体
|
||||
* 对应数据表: sys_config
|
||||
*/
|
||||
@Entity('sys_config')
|
||||
@Index(['siteId', 'key'], { unique: true })
|
||||
export class SysConfig extends BaseEntity {
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
|
||||
@Column({ name: 'site_id', type: 'int', default: 0, comment: '站点ID' })
|
||||
siteId: number;
|
||||
|
||||
@Column({ name: 'key', type: 'varchar', length: 100, comment: '配置键' })
|
||||
key: string;
|
||||
|
||||
@Column({
|
||||
name: 'value',
|
||||
type: 'text',
|
||||
nullable: true,
|
||||
comment: '配置值(JSON格式)',
|
||||
})
|
||||
value: string;
|
||||
|
||||
@Column({
|
||||
name: 'desc',
|
||||
type: 'varchar',
|
||||
length: 255,
|
||||
nullable: true,
|
||||
comment: '配置描述',
|
||||
})
|
||||
desc?: string;
|
||||
|
||||
@Column({
|
||||
name: 'is_use',
|
||||
type: 'tinyint',
|
||||
default: 1,
|
||||
comment: '是否启用:0=否,1=是',
|
||||
})
|
||||
isUse: number;
|
||||
}
|
||||
77
wwjcloud/src/common/sys/entities/SysExport.ts
Normal file
77
wwjcloud/src/common/sys/entities/SysExport.ts
Normal file
@@ -0,0 +1,77 @@
|
||||
import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';
|
||||
import { BaseEntity } from '../../../core/base/BaseEntity';
|
||||
|
||||
@Entity('sys_export')
|
||||
export class SysExport extends BaseEntity {
|
||||
@PrimaryGeneratedColumn({ name: 'id' })
|
||||
id: number;
|
||||
|
||||
@Column({
|
||||
name: 'export_key',
|
||||
type: 'varchar',
|
||||
length: 255,
|
||||
default: '',
|
||||
comment: '导出类型关键字',
|
||||
})
|
||||
export_key: string;
|
||||
|
||||
@Column({
|
||||
name: 'export_num',
|
||||
type: 'int',
|
||||
default: 0,
|
||||
comment: '导出数据数量',
|
||||
})
|
||||
export_num: number;
|
||||
|
||||
@Column({
|
||||
name: 'file_path',
|
||||
type: 'varchar',
|
||||
length: 255,
|
||||
default: '',
|
||||
comment: '文件存储路径',
|
||||
})
|
||||
file_path: string;
|
||||
|
||||
@Column({ name: 'file_size', type: 'int', default: 0, comment: '文件大小' })
|
||||
file_size: number;
|
||||
|
||||
@Column({
|
||||
name: 'export_status',
|
||||
type: 'tinyint',
|
||||
default: 0,
|
||||
comment: '导出状态:0=处理中,1=成功,2=失败',
|
||||
})
|
||||
export_status: number;
|
||||
|
||||
// 获取导出状态文本
|
||||
getExportStatusText(): string {
|
||||
const statusMap: { [key: number]: string } = {
|
||||
0: '处理中',
|
||||
1: '成功',
|
||||
2: '失败',
|
||||
};
|
||||
return statusMap[this.export_status] || '未知';
|
||||
}
|
||||
|
||||
// 获取导出类型名称
|
||||
getExportKeyName(): string {
|
||||
const keyMap: { [key: string]: string } = {
|
||||
member: '会员数据',
|
||||
order: '订单数据',
|
||||
product: '商品数据',
|
||||
};
|
||||
return keyMap[this.export_key] || this.export_key;
|
||||
}
|
||||
|
||||
// 获取可读的文件大小
|
||||
getReadableFileSize(): string {
|
||||
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
|
||||
if (this.file_size === 0) return '0 Byte';
|
||||
const i = Math.floor(Math.log(this.file_size) / Math.log(1024));
|
||||
return (
|
||||
Math.round((this.file_size / Math.pow(1024, i)) * 100) / 100 +
|
||||
' ' +
|
||||
sizes[i]
|
||||
);
|
||||
}
|
||||
}
|
||||
104
wwjcloud/src/common/sys/entities/SysMenu.ts
Normal file
104
wwjcloud/src/common/sys/entities/SysMenu.ts
Normal file
@@ -0,0 +1,104 @@
|
||||
import {
|
||||
Entity,
|
||||
PrimaryGeneratedColumn,
|
||||
Column,
|
||||
CreateDateColumn,
|
||||
UpdateDateColumn,
|
||||
DeleteDateColumn,
|
||||
} from 'typeorm';
|
||||
import { BaseEntity } from '../../../core/base/BaseEntity';
|
||||
|
||||
/**
|
||||
* 系统菜单实体
|
||||
*/
|
||||
@Entity('sys_menu')
|
||||
export class SysMenu extends BaseEntity {
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
|
||||
@Column({ name: 'menu_name', length: 100, comment: '菜单名称' })
|
||||
menuName: string;
|
||||
|
||||
@Column({
|
||||
name: 'menu_short_name',
|
||||
length: 50,
|
||||
nullable: true,
|
||||
comment: '菜单简称',
|
||||
})
|
||||
menuShortName: string;
|
||||
|
||||
@Column({
|
||||
name: 'menu_type',
|
||||
type: 'tinyint',
|
||||
default: 1,
|
||||
comment: '菜单类型 1目录 2菜单 3按钮',
|
||||
})
|
||||
menuType: number;
|
||||
|
||||
@Column({ name: 'parent_id', type: 'int', default: 0, comment: '父级菜单ID' })
|
||||
parentId: number;
|
||||
|
||||
@Column({
|
||||
name: 'menu_key',
|
||||
length: 100,
|
||||
nullable: true,
|
||||
comment: '菜单标识',
|
||||
})
|
||||
menuKey: string;
|
||||
|
||||
@Column({
|
||||
name: 'menu_url',
|
||||
length: 255,
|
||||
nullable: true,
|
||||
comment: '菜单链接',
|
||||
})
|
||||
menuUrl: string;
|
||||
|
||||
@Column({
|
||||
name: 'menu_icon',
|
||||
length: 100,
|
||||
nullable: true,
|
||||
comment: '菜单图标',
|
||||
})
|
||||
menuIcon: string;
|
||||
|
||||
@Column({ name: 'sort', type: 'int', default: 0, comment: '排序' })
|
||||
sort: number;
|
||||
|
||||
@Column({
|
||||
name: 'status',
|
||||
type: 'tinyint',
|
||||
default: 1,
|
||||
comment: '状态 0禁用 1启用',
|
||||
})
|
||||
status: number;
|
||||
|
||||
@Column({
|
||||
name: 'is_show',
|
||||
type: 'tinyint',
|
||||
default: 1,
|
||||
comment: '是否显示 0不显示 1显示',
|
||||
})
|
||||
isShow: number;
|
||||
|
||||
@Column({
|
||||
name: 'is_del',
|
||||
type: 'tinyint',
|
||||
default: 0,
|
||||
comment: '是否删除 0未删除 1已删除',
|
||||
})
|
||||
isDel: number;
|
||||
|
||||
@CreateDateColumn({ name: 'create_time', comment: '创建时间' })
|
||||
createTime: Date;
|
||||
|
||||
@UpdateDateColumn({ name: 'update_time', comment: '更新时间' })
|
||||
updateTime: Date;
|
||||
|
||||
@DeleteDateColumn({ name: 'delete_time', comment: '删除时间' })
|
||||
deleteTime: Date;
|
||||
|
||||
// 虚拟字段
|
||||
statusName?: string;
|
||||
menuTypeName?: string;
|
||||
}
|
||||
45
wwjcloud/src/common/sys/entities/SysNotice.ts
Normal file
45
wwjcloud/src/common/sys/entities/SysNotice.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
import {
|
||||
Entity,
|
||||
PrimaryGeneratedColumn,
|
||||
Column,
|
||||
CreateDateColumn,
|
||||
UpdateDateColumn,
|
||||
} from 'typeorm';
|
||||
import { BaseEntity } from '../../../core/base/BaseEntity';
|
||||
|
||||
/**
|
||||
* 系统通知实体
|
||||
*/
|
||||
@Entity('sys_notice')
|
||||
export class SysNotice extends BaseEntity {
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
|
||||
@Column({ name: 'title', length: 200, comment: '通知标题' })
|
||||
title: string;
|
||||
|
||||
@Column({ name: 'content', type: 'text', comment: '通知内容' })
|
||||
content: string;
|
||||
|
||||
@Column({
|
||||
name: 'type',
|
||||
type: 'tinyint',
|
||||
default: 1,
|
||||
comment: '通知类型 1系统通知 2用户通知',
|
||||
})
|
||||
type: number;
|
||||
|
||||
@Column({
|
||||
name: 'status',
|
||||
type: 'tinyint',
|
||||
default: 1,
|
||||
comment: '状态 0禁用 1启用',
|
||||
})
|
||||
status: number;
|
||||
|
||||
@CreateDateColumn({ name: 'create_time', comment: '创建时间' })
|
||||
createTime: Date;
|
||||
|
||||
@UpdateDateColumn({ name: 'update_time', comment: '更新时间' })
|
||||
updateTime: Date;
|
||||
}
|
||||
58
wwjcloud/src/common/sys/entities/SysNoticeLog.ts
Normal file
58
wwjcloud/src/common/sys/entities/SysNoticeLog.ts
Normal file
@@ -0,0 +1,58 @@
|
||||
import {
|
||||
Entity,
|
||||
PrimaryGeneratedColumn,
|
||||
Column,
|
||||
CreateDateColumn,
|
||||
UpdateDateColumn,
|
||||
} from 'typeorm';
|
||||
import { BaseEntity } from '../../../core/base/BaseEntity';
|
||||
|
||||
/**
|
||||
* 系统通知日志实体
|
||||
*/
|
||||
@Entity('sys_notice_log')
|
||||
export class SysNoticeLog extends BaseEntity {
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
|
||||
@Column({ name: 'key', length: 100, comment: '通知标识' })
|
||||
key: string;
|
||||
|
||||
@Column({ name: 'notice_type', type: 'tinyint', comment: '通知类型' })
|
||||
noticeType: number;
|
||||
|
||||
@Column({ name: 'receiver', length: 100, comment: '接收人' })
|
||||
receiver: string;
|
||||
|
||||
@Column({ name: 'params', type: 'json', nullable: true, comment: '参数' })
|
||||
params: any;
|
||||
|
||||
@Column({ name: 'content', type: 'json', nullable: true, comment: '内容' })
|
||||
content: any;
|
||||
|
||||
@Column({
|
||||
name: 'send_time',
|
||||
type: 'timestamp',
|
||||
nullable: true,
|
||||
comment: '发送时间',
|
||||
})
|
||||
sendTime: Date;
|
||||
|
||||
@Column({
|
||||
name: 'status',
|
||||
type: 'tinyint',
|
||||
default: 1,
|
||||
comment: '发送状态 0失败 1成功',
|
||||
})
|
||||
status: number;
|
||||
|
||||
@CreateDateColumn({ name: 'create_time', comment: '创建时间' })
|
||||
createTime: Date;
|
||||
|
||||
@UpdateDateColumn({ name: 'update_time', comment: '更新时间' })
|
||||
updateTime: Date;
|
||||
|
||||
// 虚拟字段
|
||||
name?: string;
|
||||
noticeTypeName?: string;
|
||||
}
|
||||
59
wwjcloud/src/common/sys/entities/SysNoticeSmsLog.ts
Normal file
59
wwjcloud/src/common/sys/entities/SysNoticeSmsLog.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
import {
|
||||
Entity,
|
||||
PrimaryGeneratedColumn,
|
||||
Column,
|
||||
CreateDateColumn,
|
||||
UpdateDateColumn,
|
||||
} from 'typeorm';
|
||||
import { BaseEntity } from '../../../core/base/BaseEntity';
|
||||
|
||||
/**
|
||||
* 系统短信通知日志实体
|
||||
*/
|
||||
@Entity('sys_notice_sms_log')
|
||||
export class SysNoticeSmsLog extends BaseEntity {
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
|
||||
@Column({ name: 'key', length: 100, comment: '通知标识' })
|
||||
key: string;
|
||||
|
||||
@Column({ name: 'mobile', length: 20, comment: '手机号' })
|
||||
mobile: string;
|
||||
|
||||
@Column({ name: 'sms_type', type: 'tinyint', comment: '短信类型' })
|
||||
smsType: number;
|
||||
|
||||
@Column({ name: 'params', type: 'json', nullable: true, comment: '参数' })
|
||||
params: any;
|
||||
|
||||
@Column({ name: 'result', type: 'json', nullable: true, comment: '发送结果' })
|
||||
result: any;
|
||||
|
||||
@Column({
|
||||
name: 'send_time',
|
||||
type: 'timestamp',
|
||||
nullable: true,
|
||||
comment: '发送时间',
|
||||
})
|
||||
sendTime: Date;
|
||||
|
||||
@Column({
|
||||
name: 'status',
|
||||
type: 'tinyint',
|
||||
default: 1,
|
||||
comment: '发送状态 0失败 1成功',
|
||||
})
|
||||
status: number;
|
||||
|
||||
@CreateDateColumn({ name: 'create_time', comment: '创建时间' })
|
||||
createTime: Date;
|
||||
|
||||
@UpdateDateColumn({ name: 'update_time', comment: '更新时间' })
|
||||
updateTime: Date;
|
||||
|
||||
// 虚拟字段
|
||||
name?: string;
|
||||
statusName?: string;
|
||||
smsTypeName?: string;
|
||||
}
|
||||
93
wwjcloud/src/common/sys/entities/SysPoster.ts
Normal file
93
wwjcloud/src/common/sys/entities/SysPoster.ts
Normal file
@@ -0,0 +1,93 @@
|
||||
import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';
|
||||
import { BaseEntity } from '../../../core/base/BaseEntity';
|
||||
|
||||
@Entity('sys_poster')
|
||||
export class SysPoster extends BaseEntity {
|
||||
@PrimaryGeneratedColumn({ name: 'id' })
|
||||
id: number;
|
||||
|
||||
@Column({
|
||||
name: 'name',
|
||||
type: 'varchar',
|
||||
length: 255,
|
||||
default: '',
|
||||
comment: '海报名称',
|
||||
})
|
||||
name: string;
|
||||
|
||||
@Column({
|
||||
name: 'type',
|
||||
type: 'varchar',
|
||||
length: 255,
|
||||
default: '',
|
||||
comment: '海报类型',
|
||||
})
|
||||
type: string;
|
||||
|
||||
@Column({
|
||||
name: 'channel',
|
||||
type: 'varchar',
|
||||
length: 255,
|
||||
default: '',
|
||||
comment: '海报支持渠道',
|
||||
})
|
||||
channel: string;
|
||||
|
||||
@Column({
|
||||
name: 'value',
|
||||
type: 'longtext',
|
||||
nullable: true,
|
||||
comment: '海报数据JSON',
|
||||
})
|
||||
value: string;
|
||||
|
||||
@Column({
|
||||
name: 'status',
|
||||
type: 'tinyint',
|
||||
default: 1,
|
||||
comment: '状态:0=禁用,1=启用',
|
||||
})
|
||||
status: number;
|
||||
|
||||
@Column({
|
||||
name: 'is_default',
|
||||
type: 'tinyint',
|
||||
default: 0,
|
||||
comment: '是否默认:0=否,1=是',
|
||||
})
|
||||
is_default: number;
|
||||
|
||||
@Column({
|
||||
name: 'addon',
|
||||
type: 'varchar',
|
||||
length: 50,
|
||||
default: '',
|
||||
comment: '所属插件',
|
||||
})
|
||||
addon: string;
|
||||
|
||||
// 获取海报类型名称
|
||||
getTypeName(): string {
|
||||
const typeMap: { [key: string]: string } = {
|
||||
member_card: '会员卡',
|
||||
goods_poster: '商品海报',
|
||||
share_poster: '分享海报',
|
||||
};
|
||||
return typeMap[this.type] || this.type;
|
||||
}
|
||||
|
||||
// 获取海报数据对象
|
||||
getValueObject(): any {
|
||||
if (!this.value) return {};
|
||||
try {
|
||||
return JSON.parse(this.value);
|
||||
} catch {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
// 设置海报数据
|
||||
setValueObject(value: any): void {
|
||||
this.value = JSON.stringify(value);
|
||||
}
|
||||
}
|
||||
118
wwjcloud/src/common/sys/entities/SysPrinter.ts
Normal file
118
wwjcloud/src/common/sys/entities/SysPrinter.ts
Normal file
@@ -0,0 +1,118 @@
|
||||
import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';
|
||||
import { BaseEntity } from '../../../core/base/BaseEntity';
|
||||
|
||||
@Entity('sys_printer')
|
||||
export class SysPrinter extends BaseEntity {
|
||||
@PrimaryGeneratedColumn({ name: 'printer_id' })
|
||||
printer_id: number;
|
||||
|
||||
@Column({
|
||||
name: 'brand',
|
||||
type: 'varchar',
|
||||
length: 255,
|
||||
default: '',
|
||||
comment: '设备品牌(易联云,365,飞鹅)',
|
||||
})
|
||||
brand: string;
|
||||
|
||||
@Column({
|
||||
name: 'printer_name',
|
||||
type: 'varchar',
|
||||
length: 255,
|
||||
default: '',
|
||||
comment: '打印机名称',
|
||||
})
|
||||
printer_name: string;
|
||||
|
||||
@Column({
|
||||
name: 'printer_code',
|
||||
type: 'varchar',
|
||||
length: 255,
|
||||
default: '',
|
||||
comment: '打印机编号',
|
||||
})
|
||||
printer_code: string;
|
||||
|
||||
@Column({
|
||||
name: 'printer_key',
|
||||
type: 'varchar',
|
||||
length: 255,
|
||||
default: '',
|
||||
comment: '打印机密钥',
|
||||
})
|
||||
printer_key: string;
|
||||
|
||||
@Column({
|
||||
name: 'open_id',
|
||||
type: 'varchar',
|
||||
length: 255,
|
||||
default: '',
|
||||
comment: '开发者ID',
|
||||
})
|
||||
open_id: string;
|
||||
|
||||
@Column({
|
||||
name: 'apikey',
|
||||
type: 'varchar',
|
||||
length: 255,
|
||||
default: '',
|
||||
comment: 'API密钥',
|
||||
})
|
||||
apikey: string;
|
||||
|
||||
@Column({
|
||||
name: 'value',
|
||||
type: 'text',
|
||||
nullable: true,
|
||||
comment: '打印机配置JSON',
|
||||
})
|
||||
value: string;
|
||||
|
||||
@Column({
|
||||
name: 'print_width',
|
||||
type: 'int',
|
||||
default: 58,
|
||||
comment: '打印宽度',
|
||||
})
|
||||
print_width: number;
|
||||
|
||||
@Column({
|
||||
name: 'status',
|
||||
type: 'tinyint',
|
||||
default: 1,
|
||||
comment: '状态:0=禁用,1=启用',
|
||||
})
|
||||
status: number;
|
||||
|
||||
// 获取品牌名称
|
||||
getBrandName(): string {
|
||||
const brandMap: { [key: string]: string } = {
|
||||
yilianyun: '易联云',
|
||||
feie: '飞鹅',
|
||||
xpyun: '芯烨云',
|
||||
'365': '365云打印',
|
||||
};
|
||||
return brandMap[this.brand] || this.brand;
|
||||
}
|
||||
|
||||
// 获取配置对象
|
||||
getValueObject(): any {
|
||||
if (!this.value) return {};
|
||||
try {
|
||||
return JSON.parse(this.value);
|
||||
} catch {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
// 设置配置对象
|
||||
setValueObject(value: any): void {
|
||||
this.value = JSON.stringify(value);
|
||||
}
|
||||
|
||||
// 获取状态文本
|
||||
getStatusText(): string {
|
||||
const statusMap: { [key: number]: string } = { 0: '禁用', 1: '启用' };
|
||||
return statusMap[this.status] || '未知';
|
||||
}
|
||||
}
|
||||
60
wwjcloud/src/common/sys/entities/SysPrinterTemplate.ts
Normal file
60
wwjcloud/src/common/sys/entities/SysPrinterTemplate.ts
Normal file
@@ -0,0 +1,60 @@
|
||||
import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';
|
||||
import { BaseEntity } from '../../../core/base/BaseEntity';
|
||||
|
||||
@Entity('sys_printer_template')
|
||||
export class SysPrinterTemplate extends BaseEntity {
|
||||
@PrimaryGeneratedColumn({ name: 'template_id' })
|
||||
template_id: number;
|
||||
|
||||
@Column({
|
||||
name: 'template_name',
|
||||
type: 'varchar',
|
||||
length: 255,
|
||||
default: '',
|
||||
comment: '模板名称',
|
||||
})
|
||||
template_name: string;
|
||||
|
||||
@Column({
|
||||
name: 'template_type',
|
||||
type: 'varchar',
|
||||
length: 255,
|
||||
default: '',
|
||||
comment: '模板类型',
|
||||
})
|
||||
template_type: string;
|
||||
|
||||
@Column({
|
||||
name: 'value',
|
||||
type: 'longtext',
|
||||
nullable: true,
|
||||
comment: '模板数据,json格式',
|
||||
})
|
||||
value: string;
|
||||
|
||||
// 获取模板类型名称
|
||||
getTemplateTypeName(): string {
|
||||
const typeMap: { [key: string]: string } = {
|
||||
order: '订单模板',
|
||||
receipt: '收据模板',
|
||||
refund: '退款模板',
|
||||
custom: '自定义模板',
|
||||
};
|
||||
return typeMap[this.template_type] || this.template_type;
|
||||
}
|
||||
|
||||
// 获取模板数据对象
|
||||
getValueObject(): any {
|
||||
if (!this.value) return {};
|
||||
try {
|
||||
return JSON.parse(this.value);
|
||||
} catch {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
// 设置模板数据
|
||||
setValueObject(value: any): void {
|
||||
this.value = JSON.stringify(value);
|
||||
}
|
||||
}
|
||||
49
wwjcloud/src/common/sys/entities/SysRole.ts
Normal file
49
wwjcloud/src/common/sys/entities/SysRole.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
import {
|
||||
Entity,
|
||||
PrimaryGeneratedColumn,
|
||||
Column,
|
||||
CreateDateColumn,
|
||||
UpdateDateColumn,
|
||||
} from 'typeorm';
|
||||
import { BaseEntity } from '../../../core/base/BaseEntity';
|
||||
|
||||
/**
|
||||
* 系统角色实体
|
||||
*/
|
||||
@Entity('sys_role')
|
||||
export class SysRole extends BaseEntity {
|
||||
@PrimaryGeneratedColumn({ name: 'role_id' })
|
||||
roleId: number;
|
||||
|
||||
@Column({ name: 'role_name', length: 50, comment: '角色名称' })
|
||||
roleName: string;
|
||||
|
||||
@Column({ name: 'role_key', length: 50, comment: '角色标识' })
|
||||
roleKey: string;
|
||||
|
||||
@Column({ name: 'sort', type: 'int', default: 0, comment: '排序' })
|
||||
sort: number;
|
||||
|
||||
@Column({
|
||||
name: 'status',
|
||||
type: 'tinyint',
|
||||
default: 1,
|
||||
comment: '状态 0禁用 1启用',
|
||||
})
|
||||
status: number;
|
||||
|
||||
@Column({ name: 'remark', length: 500, nullable: true, comment: '备注' })
|
||||
remark: string;
|
||||
|
||||
@Column({ name: 'rules', type: 'json', nullable: true, comment: '权限规则' })
|
||||
rules: string[];
|
||||
|
||||
@CreateDateColumn({ name: 'create_time', comment: '创建时间' })
|
||||
createTime: Date;
|
||||
|
||||
@UpdateDateColumn({ name: 'update_time', comment: '更新时间' })
|
||||
updateTime: Date;
|
||||
|
||||
// 虚拟字段
|
||||
statusName?: string;
|
||||
}
|
||||
67
wwjcloud/src/common/sys/entities/SysSchedule.ts
Normal file
67
wwjcloud/src/common/sys/entities/SysSchedule.ts
Normal file
@@ -0,0 +1,67 @@
|
||||
import {
|
||||
Entity,
|
||||
PrimaryGeneratedColumn,
|
||||
Column,
|
||||
CreateDateColumn,
|
||||
UpdateDateColumn,
|
||||
} from 'typeorm';
|
||||
import { BaseEntity } from '../../../core/base/BaseEntity';
|
||||
|
||||
/**
|
||||
* 定时任务实体
|
||||
*/
|
||||
@Entity('sys_schedule')
|
||||
export class SysSchedule extends BaseEntity {
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
|
||||
@Column({ name: 'key', length: 100, comment: '任务标识' })
|
||||
key: string;
|
||||
|
||||
@Column({ name: 'title', length: 100, comment: '任务标题' })
|
||||
title: string;
|
||||
|
||||
@Column({ name: 'command', length: 500, comment: '执行命令' })
|
||||
command: string;
|
||||
|
||||
@Column({
|
||||
name: 'time',
|
||||
type: 'json',
|
||||
nullable: true,
|
||||
comment: '执行时间配置',
|
||||
})
|
||||
time: any;
|
||||
|
||||
@Column({
|
||||
name: 'last_time',
|
||||
type: 'timestamp',
|
||||
nullable: true,
|
||||
comment: '最后执行时间',
|
||||
})
|
||||
lastTime: Date;
|
||||
|
||||
@Column({
|
||||
name: 'next_time',
|
||||
type: 'timestamp',
|
||||
nullable: true,
|
||||
comment: '下次执行时间',
|
||||
})
|
||||
nextTime: Date;
|
||||
|
||||
@Column({
|
||||
name: 'status',
|
||||
type: 'tinyint',
|
||||
default: 1,
|
||||
comment: '状态 0禁用 1启用',
|
||||
})
|
||||
status: number;
|
||||
|
||||
@CreateDateColumn({ name: 'create_time', comment: '创建时间' })
|
||||
createTime: Date;
|
||||
|
||||
@UpdateDateColumn({ name: 'update_time', comment: '更新时间' })
|
||||
updateTime: Date;
|
||||
|
||||
// 虚拟字段
|
||||
statusName?: string;
|
||||
}
|
||||
60
wwjcloud/src/common/sys/entities/SysScheduleLog.ts
Normal file
60
wwjcloud/src/common/sys/entities/SysScheduleLog.ts
Normal file
@@ -0,0 +1,60 @@
|
||||
import {
|
||||
Entity,
|
||||
PrimaryGeneratedColumn,
|
||||
Column,
|
||||
CreateDateColumn,
|
||||
UpdateDateColumn,
|
||||
} from 'typeorm';
|
||||
import { BaseEntity } from '../../../core/base/BaseEntity';
|
||||
|
||||
/**
|
||||
* 定时任务日志实体
|
||||
*/
|
||||
@Entity('sys_schedule_log')
|
||||
export class SysScheduleLog extends BaseEntity {
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
|
||||
@Column({ name: 'schedule_id', type: 'int', comment: '任务ID' })
|
||||
scheduleId: number;
|
||||
|
||||
@Column({ name: 'key', length: 100, comment: '任务标识' })
|
||||
key: string;
|
||||
|
||||
@Column({ name: 'title', length: 100, comment: '任务标题' })
|
||||
title: string;
|
||||
|
||||
@Column({ name: 'command', length: 500, comment: '执行命令' })
|
||||
command: string;
|
||||
|
||||
@Column({
|
||||
name: 'execute_time',
|
||||
type: 'timestamp',
|
||||
nullable: true,
|
||||
comment: '执行时间',
|
||||
})
|
||||
executeTime: Date;
|
||||
|
||||
@Column({
|
||||
name: 'status',
|
||||
type: 'tinyint',
|
||||
default: 1,
|
||||
comment: '执行状态 0失败 1成功',
|
||||
})
|
||||
status: number;
|
||||
|
||||
@Column({ name: 'result', type: 'text', nullable: true, comment: '执行结果' })
|
||||
result: string;
|
||||
|
||||
@Column({ name: 'error', type: 'text', nullable: true, comment: '错误信息' })
|
||||
error: string;
|
||||
|
||||
@CreateDateColumn({ name: 'create_time', comment: '创建时间' })
|
||||
createTime: Date;
|
||||
|
||||
@UpdateDateColumn({ name: 'update_time', comment: '更新时间' })
|
||||
updateTime: Date;
|
||||
|
||||
// 虚拟字段
|
||||
statusName?: string;
|
||||
}
|
||||
31
wwjcloud/src/common/sys/entities/SysSystem.ts
Normal file
31
wwjcloud/src/common/sys/entities/SysSystem.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';
|
||||
import { BaseEntity } from '../../../core/base/BaseEntity';
|
||||
|
||||
@Entity('sys_system')
|
||||
export class SysSystem extends BaseEntity {
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
|
||||
@Column({ name: 'system_name', length: 100, comment: '系统名称' })
|
||||
system_name: string;
|
||||
|
||||
@Column({ name: 'system_version', length: 50, comment: '系统版本' })
|
||||
system_version: string;
|
||||
|
||||
@Column({ name: 'system_type', length: 50, comment: '系统类型' })
|
||||
system_type: string;
|
||||
|
||||
@Column({
|
||||
name: 'status',
|
||||
type: 'tinyint',
|
||||
default: 1,
|
||||
comment: '状态 0禁用 1启用',
|
||||
})
|
||||
status: number;
|
||||
|
||||
@Column({ name: 'config', type: 'text', nullable: true, comment: '系统配置' })
|
||||
config: string;
|
||||
|
||||
@Column({ name: 'remark', type: 'text', nullable: true, comment: '备注' })
|
||||
remark: string;
|
||||
}
|
||||
70
wwjcloud/src/common/sys/entities/SysUpgradeRecords.ts
Normal file
70
wwjcloud/src/common/sys/entities/SysUpgradeRecords.ts
Normal file
@@ -0,0 +1,70 @@
|
||||
import {
|
||||
Entity,
|
||||
PrimaryGeneratedColumn,
|
||||
Column,
|
||||
CreateDateColumn,
|
||||
UpdateDateColumn,
|
||||
} from 'typeorm';
|
||||
import { BaseEntity } from '../../../core/base/BaseEntity';
|
||||
|
||||
/**
|
||||
* 系统升级记录实体
|
||||
*/
|
||||
@Entity('sys_upgrade_records')
|
||||
export class SysUpgradeRecords extends BaseEntity {
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
|
||||
@Column({ name: 'upgrade_key', length: 100, comment: '升级标识' })
|
||||
upgradeKey: string;
|
||||
|
||||
@Column({ name: 'name', length: 200, comment: '升级名称' })
|
||||
name: string;
|
||||
|
||||
@Column({ name: 'version', length: 50, comment: '版本号' })
|
||||
version: string;
|
||||
|
||||
@Column({
|
||||
name: 'content',
|
||||
type: 'text',
|
||||
nullable: true,
|
||||
comment: '升级内容',
|
||||
})
|
||||
content: string;
|
||||
|
||||
@Column({
|
||||
name: 'status',
|
||||
type: 'tinyint',
|
||||
default: 0,
|
||||
comment: '状态 0待升级 1升级中 2升级成功 3升级失败',
|
||||
})
|
||||
status: number;
|
||||
|
||||
@Column({
|
||||
name: 'fail_reason',
|
||||
type: 'json',
|
||||
nullable: true,
|
||||
comment: '失败原因',
|
||||
})
|
||||
failReason: any;
|
||||
|
||||
@Column({
|
||||
name: 'complete_time',
|
||||
type: 'timestamp',
|
||||
nullable: true,
|
||||
comment: '完成时间',
|
||||
})
|
||||
completeTime: Date;
|
||||
|
||||
@CreateDateColumn({ name: 'create_time', comment: '创建时间' })
|
||||
createTime: Date;
|
||||
|
||||
@UpdateDateColumn({ name: 'update_time', comment: '更新时间' })
|
||||
updateTime: Date;
|
||||
|
||||
// 虚拟字段
|
||||
statusName?: string;
|
||||
backupDir?: string;
|
||||
backupCodeDir?: string;
|
||||
backupSqlDir?: string;
|
||||
}
|
||||
88
wwjcloud/src/common/sys/entities/SysUser.ts
Normal file
88
wwjcloud/src/common/sys/entities/SysUser.ts
Normal file
@@ -0,0 +1,88 @@
|
||||
import {
|
||||
Entity,
|
||||
PrimaryGeneratedColumn,
|
||||
Column,
|
||||
CreateDateColumn,
|
||||
UpdateDateColumn,
|
||||
DeleteDateColumn,
|
||||
} from 'typeorm';
|
||||
import { BaseEntity } from '../../../core/base/BaseEntity';
|
||||
|
||||
/**
|
||||
* 系统用户实体
|
||||
*/
|
||||
@Entity('sys_user')
|
||||
export class SysUser extends BaseEntity {
|
||||
@PrimaryGeneratedColumn({ name: 'uid' })
|
||||
uid: number;
|
||||
|
||||
@Column({ name: 'username', length: 50, comment: '用户名' })
|
||||
username: string;
|
||||
|
||||
@Column({ name: 'password', length: 255, comment: '密码' })
|
||||
password: string;
|
||||
|
||||
@Column({
|
||||
name: 'real_name',
|
||||
length: 50,
|
||||
nullable: true,
|
||||
comment: '真实姓名',
|
||||
})
|
||||
realName: string;
|
||||
|
||||
@Column({ name: 'head_img', length: 255, nullable: true, comment: '头像' })
|
||||
headImg: string;
|
||||
|
||||
@Column({ name: 'phone', length: 20, nullable: true, comment: '手机号' })
|
||||
phone: string;
|
||||
|
||||
@Column({ name: 'email', length: 100, nullable: true, comment: '邮箱' })
|
||||
email: string;
|
||||
|
||||
@Column({
|
||||
name: 'last_ip',
|
||||
length: 50,
|
||||
nullable: true,
|
||||
comment: '最后登录IP',
|
||||
})
|
||||
lastIp: string;
|
||||
|
||||
@Column({
|
||||
name: 'last_time',
|
||||
type: 'timestamp',
|
||||
nullable: true,
|
||||
comment: '最后登录时间',
|
||||
})
|
||||
lastTime: Date;
|
||||
|
||||
@Column({ name: 'login_count', type: 'int', default: 0, comment: '登录次数' })
|
||||
loginCount: number;
|
||||
|
||||
@Column({
|
||||
name: 'status',
|
||||
type: 'tinyint',
|
||||
default: 1,
|
||||
comment: '状态 0禁用 1启用',
|
||||
})
|
||||
status: number;
|
||||
|
||||
@Column({
|
||||
name: 'is_del',
|
||||
type: 'tinyint',
|
||||
default: 0,
|
||||
comment: '是否删除 0未删除 1已删除',
|
||||
})
|
||||
isDel: number;
|
||||
|
||||
@CreateDateColumn({ name: 'create_time', comment: '创建时间' })
|
||||
createTime: Date;
|
||||
|
||||
@UpdateDateColumn({ name: 'update_time', comment: '更新时间' })
|
||||
updateTime: Date;
|
||||
|
||||
@DeleteDateColumn({ name: 'delete_time', comment: '删除时间' })
|
||||
deleteTime: Date;
|
||||
|
||||
// 虚拟字段
|
||||
statusName?: string;
|
||||
}
|
||||
49
wwjcloud/src/common/sys/entities/SysUserRole.ts
Normal file
49
wwjcloud/src/common/sys/entities/SysUserRole.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
import {
|
||||
Entity,
|
||||
PrimaryGeneratedColumn,
|
||||
Column,
|
||||
CreateDateColumn,
|
||||
UpdateDateColumn,
|
||||
DeleteDateColumn,
|
||||
} from 'typeorm';
|
||||
import { BaseEntity } from '../../../core/base/BaseEntity';
|
||||
|
||||
/**
|
||||
* 用户角色关联实体
|
||||
*/
|
||||
@Entity('sys_user_role')
|
||||
export class SysUserRole extends BaseEntity {
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
|
||||
@Column({ name: 'uid', type: 'int', comment: '用户ID' })
|
||||
uid: number;
|
||||
|
||||
@Column({
|
||||
name: 'role_ids',
|
||||
type: 'json',
|
||||
nullable: true,
|
||||
comment: '角色ID数组',
|
||||
})
|
||||
roleIds: number[];
|
||||
|
||||
@Column({
|
||||
name: 'status',
|
||||
type: 'tinyint',
|
||||
default: 1,
|
||||
comment: '状态 0禁用 1启用',
|
||||
})
|
||||
status: number;
|
||||
|
||||
@CreateDateColumn({ name: 'create_time', comment: '创建时间' })
|
||||
createTime: Date;
|
||||
|
||||
@UpdateDateColumn({ name: 'update_time', comment: '更新时间' })
|
||||
updateTime: Date;
|
||||
|
||||
@DeleteDateColumn({ name: 'delete_time', comment: '删除时间' })
|
||||
deleteTime: Date;
|
||||
|
||||
// 虚拟字段
|
||||
statusName?: string;
|
||||
}
|
||||
43
wwjcloud/src/common/sys/entities/UserCreateSiteLimit.ts
Normal file
43
wwjcloud/src/common/sys/entities/UserCreateSiteLimit.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
import {
|
||||
Entity,
|
||||
PrimaryGeneratedColumn,
|
||||
Column,
|
||||
CreateDateColumn,
|
||||
UpdateDateColumn,
|
||||
} from 'typeorm';
|
||||
import { BaseEntity } from '../../../core/base/BaseEntity';
|
||||
|
||||
/**
|
||||
* 用户创建站点限制实体
|
||||
*/
|
||||
@Entity('user_create_site_limit')
|
||||
export class UserCreateSiteLimit extends BaseEntity {
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
|
||||
@Column({ name: 'uid', type: 'int', comment: '用户ID' })
|
||||
uid: number;
|
||||
|
||||
@Column({ name: 'group_id', type: 'int', comment: '站点分组ID' })
|
||||
groupId: number;
|
||||
|
||||
@Column({ name: 'limit_num', type: 'int', default: 0, comment: '限制数量' })
|
||||
limitNum: number;
|
||||
|
||||
@Column({ name: 'used_num', type: 'int', default: 0, comment: '已使用数量' })
|
||||
usedNum: number;
|
||||
|
||||
@Column({
|
||||
name: 'status',
|
||||
type: 'tinyint',
|
||||
default: 1,
|
||||
comment: '状态 0禁用 1启用',
|
||||
})
|
||||
status: number;
|
||||
|
||||
@CreateDateColumn({ name: 'create_time', comment: '创建时间' })
|
||||
createTime: Date;
|
||||
|
||||
@UpdateDateColumn({ name: 'update_time', comment: '更新时间' })
|
||||
updateTime: Date;
|
||||
}
|
||||
65
wwjcloud/src/common/sys/entities/WxOplatfromWeappVersion.ts
Normal file
65
wwjcloud/src/common/sys/entities/WxOplatfromWeappVersion.ts
Normal file
@@ -0,0 +1,65 @@
|
||||
import {
|
||||
Entity,
|
||||
PrimaryGeneratedColumn,
|
||||
Column,
|
||||
CreateDateColumn,
|
||||
UpdateDateColumn,
|
||||
} from 'typeorm';
|
||||
import { BaseEntity } from '../../../core/base/BaseEntity';
|
||||
|
||||
/**
|
||||
* 微信开放平台小程序版本实体
|
||||
*/
|
||||
@Entity('wx_oplatfrom_weapp_version')
|
||||
export class WxOplatfromWeappVersion extends BaseEntity {
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
|
||||
@Column({ name: 'site_group_id', type: 'int', comment: '站点分组ID' })
|
||||
siteGroupId: number;
|
||||
|
||||
@Column({ name: 'version', length: 50, comment: '版本号' })
|
||||
version: string;
|
||||
|
||||
@Column({
|
||||
name: 'version_desc',
|
||||
length: 500,
|
||||
nullable: true,
|
||||
comment: '版本描述',
|
||||
})
|
||||
versionDesc: string;
|
||||
|
||||
@Column({
|
||||
name: 'template_id',
|
||||
length: 100,
|
||||
nullable: true,
|
||||
comment: '模板ID',
|
||||
})
|
||||
templateId: string;
|
||||
|
||||
@Column({
|
||||
name: 'ext_json',
|
||||
type: 'text',
|
||||
nullable: true,
|
||||
comment: '扩展配置',
|
||||
})
|
||||
extJson: string;
|
||||
|
||||
@Column({
|
||||
name: 'status',
|
||||
type: 'tinyint',
|
||||
default: 1,
|
||||
comment: '状态 0禁用 1启用',
|
||||
})
|
||||
status: number;
|
||||
|
||||
@CreateDateColumn({ name: 'create_time', comment: '创建时间' })
|
||||
createTime: Date;
|
||||
|
||||
@UpdateDateColumn({ name: 'update_time', comment: '更新时间' })
|
||||
updateTime: Date;
|
||||
|
||||
// 虚拟字段
|
||||
statusName?: string;
|
||||
siteGroupName?: string;
|
||||
}
|
||||
83
wwjcloud/src/common/sys/services/admin/AgreementService.ts
Normal file
83
wwjcloud/src/common/sys/services/admin/AgreementService.ts
Normal file
@@ -0,0 +1,83 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { CoreAgreementService } from '../core/CoreAgreementService';
|
||||
|
||||
/**
|
||||
* 协议服务 - Admin层
|
||||
* 对应PHP: app\service\admin\sys\AgreementService
|
||||
*/
|
||||
@Injectable()
|
||||
export class AgreementService {
|
||||
constructor(private readonly coreAgreementService: CoreAgreementService) {}
|
||||
|
||||
/**
|
||||
* 协议列表(不分页)
|
||||
* @param siteId 站点ID
|
||||
* @returns 协议列表
|
||||
*/
|
||||
async getList(siteId: number) {
|
||||
const agreementTypes = this.getAgreementTypes();
|
||||
const list: any = {};
|
||||
|
||||
for (const [key, typeName] of Object.entries(agreementTypes)) {
|
||||
const agreement = await this.getAgreement(siteId, key);
|
||||
list[key] = {
|
||||
...agreement,
|
||||
type_name: typeName,
|
||||
};
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取协议内容
|
||||
* @param siteId 站点ID
|
||||
* @param key 协议关键字
|
||||
* @returns 协议信息
|
||||
*/
|
||||
async getAgreement(siteId: number, key: string) {
|
||||
const agreement = await this.coreAgreementService.getAgreement(siteId, key);
|
||||
return (
|
||||
agreement || {
|
||||
agreement_key: key,
|
||||
title: '',
|
||||
content: '',
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置协议
|
||||
* @param siteId 站点ID
|
||||
* @param key 协议关键字
|
||||
* @param title 协议标题
|
||||
* @param content 协议内容
|
||||
* @returns 是否成功
|
||||
*/
|
||||
async setAgreement(
|
||||
siteId: number,
|
||||
key: string,
|
||||
title: string,
|
||||
content: string,
|
||||
) {
|
||||
return await this.coreAgreementService.setAgreement(
|
||||
siteId,
|
||||
key,
|
||||
title,
|
||||
content,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取协议类型列表
|
||||
* @returns 协议类型映射
|
||||
*/
|
||||
private getAgreementTypes(): Record<string, string> {
|
||||
return {
|
||||
privacy: '隐私政策',
|
||||
service: '服务协议',
|
||||
user: '用户协议',
|
||||
member: '会员协议',
|
||||
};
|
||||
}
|
||||
}
|
||||
130
wwjcloud/src/common/sys/services/admin/AppService.ts
Normal file
130
wwjcloud/src/common/sys/services/admin/AppService.ts
Normal file
@@ -0,0 +1,130 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
/**
|
||||
* 应用管理服务 - Admin层
|
||||
* 对应PHP: app\service\admin\sys\AppService
|
||||
*/
|
||||
@Injectable()
|
||||
export class AppService {
|
||||
constructor() {}
|
||||
|
||||
/**
|
||||
* 获取应用列表
|
||||
* @returns 应用分类列表
|
||||
*/
|
||||
async getAppList() {
|
||||
// TODO: 实现事件系统来获取应用列表
|
||||
// 对应PHP的 event('AppManage')
|
||||
|
||||
// 临时返回基础应用分类
|
||||
const categoryList = [
|
||||
{
|
||||
key: 'basic',
|
||||
name: '基础应用',
|
||||
sort: 1,
|
||||
app_list: [
|
||||
{
|
||||
key: 'member',
|
||||
name: '会员管理',
|
||||
desc: '会员注册、登录、信息管理',
|
||||
category: 'basic',
|
||||
icon: 'user',
|
||||
status: 1,
|
||||
},
|
||||
{
|
||||
key: 'order',
|
||||
name: '订单管理',
|
||||
desc: '订单创建、支付、发货、售后',
|
||||
category: 'basic',
|
||||
icon: 'shopping-cart',
|
||||
status: 1,
|
||||
},
|
||||
{
|
||||
key: 'goods',
|
||||
name: '商品管理',
|
||||
desc: '商品分类、商品信息、库存管理',
|
||||
category: 'basic',
|
||||
icon: 'package',
|
||||
status: 1,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'marketing',
|
||||
name: '营销应用',
|
||||
sort: 2,
|
||||
app_list: [
|
||||
{
|
||||
key: 'coupon',
|
||||
name: '优惠券',
|
||||
desc: '优惠券发放、使用、统计',
|
||||
category: 'marketing',
|
||||
icon: 'gift',
|
||||
status: 1,
|
||||
},
|
||||
{
|
||||
key: 'points',
|
||||
name: '积分系统',
|
||||
desc: '积分获取、消费、兑换',
|
||||
category: 'marketing',
|
||||
icon: 'star',
|
||||
status: 1,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'system',
|
||||
name: '系统管理',
|
||||
sort: 3,
|
||||
app_list: [
|
||||
{
|
||||
key: 'sys',
|
||||
name: '系统设置',
|
||||
desc: '系统配置、菜单管理、权限管理',
|
||||
category: 'system',
|
||||
icon: 'settings',
|
||||
status: 1,
|
||||
},
|
||||
{
|
||||
key: 'site',
|
||||
name: '站点管理',
|
||||
desc: '多站点管理、域名配置',
|
||||
category: 'system',
|
||||
icon: 'globe',
|
||||
status: 1,
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
return categoryList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取应用详情
|
||||
* @param appKey 应用标识
|
||||
* @returns 应用信息
|
||||
*/
|
||||
async getAppInfo(appKey: string) {
|
||||
const appList = await this.getAppList();
|
||||
|
||||
for (const category of appList) {
|
||||
const app = category.app_list.find((item) => item.key === appKey);
|
||||
if (app) {
|
||||
return app;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查应用是否存在
|
||||
* @param appKey 应用标识
|
||||
* @returns 是否存在
|
||||
*/
|
||||
async checkAppExists(appKey: string): Promise<boolean> {
|
||||
const app = await this.getAppInfo(appKey);
|
||||
return !!app;
|
||||
}
|
||||
}
|
||||
66
wwjcloud/src/common/sys/services/admin/AreaService.ts
Normal file
66
wwjcloud/src/common/sys/services/admin/AreaService.ts
Normal file
@@ -0,0 +1,66 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { CoreAreaService } from '../core/CoreAreaService';
|
||||
|
||||
/**
|
||||
* 地区服务 - Admin层
|
||||
* 对应PHP: app\service\admin\sys\AreaService
|
||||
*/
|
||||
@Injectable()
|
||||
export class AreaService {
|
||||
constructor(private readonly coreAreaService: CoreAreaService) {}
|
||||
|
||||
/**
|
||||
* 根据父级ID获取地区列表
|
||||
* @param pid 父级ID
|
||||
* @returns 地区列表
|
||||
*/
|
||||
async getListByPid(pid: number = 0) {
|
||||
return await this.coreAreaService.getListByPid(pid);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询地区树列表
|
||||
* @param level 最大层级
|
||||
* @returns 树形地区列表
|
||||
*/
|
||||
async getAreaTree(level: number = 3) {
|
||||
return await this.coreAreaService.getAreaTree(level);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据地区ID获取地区信息
|
||||
* @param id 地区ID
|
||||
* @returns 地区信息
|
||||
*/
|
||||
async getAreaByAreaCode(id: number) {
|
||||
return await this.coreAreaService.getAreaByAreaCode(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据地区ID数组获取地区信息
|
||||
* @param ids 地区ID数组
|
||||
* @returns 地区信息数组
|
||||
*/
|
||||
async getAreaByAreaCodes(ids: number[]) {
|
||||
return await this.coreAreaService.getAreaByAreaCodes(ids);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取省市区完整路径
|
||||
* @param id 地区ID
|
||||
* @returns 完整路径字符串
|
||||
*/
|
||||
async getFullPath(id: number) {
|
||||
return await this.coreAreaService.getFullPath(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 搜索地区
|
||||
* @param keyword 关键词
|
||||
* @param level 层级过滤
|
||||
* @returns 地区列表
|
||||
*/
|
||||
async searchArea(keyword: string, level?: number) {
|
||||
return await this.coreAreaService.searchArea(keyword, level);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { CoreAttachmentCategoryService } from '../core/CoreAttachmentCategoryService';
|
||||
import { SysAttachmentCategory } from '../../entities/SysAttachmentCategory';
|
||||
|
||||
@Injectable()
|
||||
export class AttachmentCategoryService {
|
||||
constructor(
|
||||
private readonly coreAttachmentCategoryService: CoreAttachmentCategoryService,
|
||||
) {}
|
||||
|
||||
async add(siteId: number, data: Partial<SysAttachmentCategory>) {
|
||||
const categoryData = { ...data, site_id: siteId };
|
||||
return await this.coreAttachmentCategoryService.add(categoryData);
|
||||
}
|
||||
|
||||
async edit(siteId: number, id: number, data: Partial<SysAttachmentCategory>) {
|
||||
return await this.coreAttachmentCategoryService.edit(siteId, id, data);
|
||||
}
|
||||
|
||||
async getPage(siteId: number, data: any = {}) {
|
||||
const { name, page = 1, limit = 10 } = data;
|
||||
return await this.coreAttachmentCategoryService.getPage(
|
||||
siteId,
|
||||
name,
|
||||
page,
|
||||
limit,
|
||||
);
|
||||
}
|
||||
|
||||
async getInfo(siteId: number, id: number) {
|
||||
return await this.coreAttachmentCategoryService.getInfo(siteId, id);
|
||||
}
|
||||
|
||||
async del(siteId: number, id: number) {
|
||||
return await this.coreAttachmentCategoryService.del(siteId, id);
|
||||
}
|
||||
}
|
||||
96
wwjcloud/src/common/sys/services/admin/AttachmentService.ts
Normal file
96
wwjcloud/src/common/sys/services/admin/AttachmentService.ts
Normal file
@@ -0,0 +1,96 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { CoreAttachmentService } from '../core/CoreAttachmentService';
|
||||
import { SysAttachment } from '../../entities/SysAttachment';
|
||||
|
||||
/**
|
||||
* 附件服务 - Admin层
|
||||
* 对应PHP: app\service\admin\sys\AttachmentService
|
||||
*/
|
||||
@Injectable()
|
||||
export class AttachmentService {
|
||||
constructor(private readonly coreAttachmentService: CoreAttachmentService) {}
|
||||
|
||||
/**
|
||||
* 新增素材
|
||||
* @param siteId 站点ID
|
||||
* @param data 附件数据
|
||||
* @returns 创建的附件
|
||||
*/
|
||||
async add(siteId: number, data: Partial<SysAttachment>) {
|
||||
const attachmentData = { ...data, site_id: siteId };
|
||||
return await this.coreAttachmentService.add(attachmentData);
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑素材
|
||||
* @param siteId 站点ID
|
||||
* @param attId 附件ID
|
||||
* @param data 更新数据
|
||||
* @returns 是否成功
|
||||
*/
|
||||
async edit(siteId: number, attId: number, data: Partial<SysAttachment>) {
|
||||
return await this.coreAttachmentService.edit(siteId, attId, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改附件分组
|
||||
* @param siteId 站点ID
|
||||
* @param attId 附件ID
|
||||
* @param cateId 分类ID
|
||||
* @returns 是否成功
|
||||
*/
|
||||
async modifyCategory(siteId: number, attId: number, cateId: number) {
|
||||
return await this.coreAttachmentService.modifyCategory(
|
||||
siteId,
|
||||
attId,
|
||||
cateId,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取附件分页列表
|
||||
* @param siteId 站点ID
|
||||
* @param data 查询参数
|
||||
* @returns 分页结果
|
||||
*/
|
||||
async getPage(siteId: number, data: any = {}) {
|
||||
const { name, cate_id, page = 1, limit = 10 } = data;
|
||||
return await this.coreAttachmentService.getPage(
|
||||
siteId,
|
||||
name,
|
||||
cate_id,
|
||||
page,
|
||||
limit,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取附件详情
|
||||
* @param siteId 站点ID
|
||||
* @param attId 附件ID
|
||||
* @returns 附件信息
|
||||
*/
|
||||
async getInfo(siteId: number, attId: number) {
|
||||
return await this.coreAttachmentService.getInfo(siteId, attId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除附件
|
||||
* @param siteId 站点ID
|
||||
* @param attId 附件ID
|
||||
* @returns 是否成功
|
||||
*/
|
||||
async del(siteId: number, attId: number) {
|
||||
return await this.coreAttachmentService.del(siteId, attId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除附件
|
||||
* @param siteId 站点ID
|
||||
* @param attIds 附件ID数组
|
||||
* @returns 是否成功
|
||||
*/
|
||||
async batchDelete(siteId: number, attIds: number[]) {
|
||||
return await this.coreAttachmentService.batchDelete(siteId, attIds);
|
||||
}
|
||||
}
|
||||
112
wwjcloud/src/common/sys/services/admin/ChannelService.ts
Normal file
112
wwjcloud/src/common/sys/services/admin/ChannelService.ts
Normal file
@@ -0,0 +1,112 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { CoreChannelService } from '../core/CoreChannelService';
|
||||
|
||||
/**
|
||||
* 渠道服务 - Admin层
|
||||
* 对应PHP: app\service\admin\sys\ChannelService
|
||||
*/
|
||||
@Injectable()
|
||||
export class ChannelService {
|
||||
constructor(
|
||||
private readonly coreChannelService: CoreChannelService,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* 获取渠道列表
|
||||
* @param params 查询参数
|
||||
* @returns 渠道列表
|
||||
*/
|
||||
async getList(params: any) {
|
||||
return await this.coreChannelService.getList(params);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取渠道详情
|
||||
* @param id 渠道ID
|
||||
* @returns 渠道详情
|
||||
*/
|
||||
async getInfo(id: number) {
|
||||
return await this.coreChannelService.getInfo(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加渠道
|
||||
* @param data 渠道数据
|
||||
* @returns 是否成功
|
||||
*/
|
||||
async add(data: any) {
|
||||
return await this.coreChannelService.add(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑渠道
|
||||
* @param id 渠道ID
|
||||
* @param data 渠道数据
|
||||
* @returns 是否成功
|
||||
*/
|
||||
async edit(id: number, data: any) {
|
||||
return await this.coreChannelService.edit(id, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除渠道
|
||||
* @param id 渠道ID
|
||||
* @returns 是否成功
|
||||
*/
|
||||
async delete(id: number) {
|
||||
return await this.coreChannelService.delete(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取渠道类型列表
|
||||
* @returns 渠道类型列表
|
||||
*/
|
||||
async getChannelTypes() {
|
||||
return await this.coreChannelService.getChannelTypes();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取渠道状态列表
|
||||
* @returns 渠道状态列表
|
||||
*/
|
||||
async getChannelStatuses() {
|
||||
return await this.coreChannelService.getChannelStatuses();
|
||||
}
|
||||
|
||||
/**
|
||||
* 启用渠道
|
||||
* @param id 渠道ID
|
||||
* @returns 是否成功
|
||||
*/
|
||||
async enable(id: number) {
|
||||
return await this.coreChannelService.updateStatus(id, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 禁用渠道
|
||||
* @param id 渠道ID
|
||||
* @returns 是否成功
|
||||
*/
|
||||
async disable(id: number) {
|
||||
return await this.coreChannelService.updateStatus(id, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取渠道配置
|
||||
* @param id 渠道ID
|
||||
* @returns 渠道配置
|
||||
*/
|
||||
async getConfig(id: number) {
|
||||
return await this.coreChannelService.getConfig(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置渠道配置
|
||||
* @param id 渠道ID
|
||||
* @param config 配置数据
|
||||
* @returns 是否成功
|
||||
*/
|
||||
async setConfig(id: number, config: any) {
|
||||
return await this.coreChannelService.setConfig(id, config);
|
||||
}
|
||||
}
|
||||
100
wwjcloud/src/common/sys/services/admin/CommonService.ts
Normal file
100
wwjcloud/src/common/sys/services/admin/CommonService.ts
Normal file
@@ -0,0 +1,100 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { CoreCommonService } from '../core/CoreCommonService';
|
||||
|
||||
/**
|
||||
* 通用服务 - Admin层
|
||||
* 对应PHP: app\service\admin\sys\CommonService
|
||||
*/
|
||||
@Injectable()
|
||||
export class CommonService {
|
||||
constructor(
|
||||
private readonly coreCommonService: CoreCommonService,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* 获取系统字典
|
||||
* @param type 字典类型
|
||||
* @returns 字典数据
|
||||
*/
|
||||
async getDict(type: string) {
|
||||
return await this.coreCommonService.getDict(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取系统配置
|
||||
* @param key 配置键
|
||||
* @returns 配置值
|
||||
*/
|
||||
async getConfig(key: string) {
|
||||
return await this.coreCommonService.getConfig(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置系统配置
|
||||
* @param key 配置键
|
||||
* @param value 配置值
|
||||
* @returns 是否成功
|
||||
*/
|
||||
async setConfig(key: string, value: any) {
|
||||
return await this.coreCommonService.setConfig(key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取系统信息
|
||||
* @returns 系统信息
|
||||
*/
|
||||
async getSystemInfo() {
|
||||
return await this.coreCommonService.getSystemInfo();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取系统统计
|
||||
* @returns 统计信息
|
||||
*/
|
||||
async getSystemStats() {
|
||||
return await this.coreCommonService.getSystemStats();
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理系统缓存
|
||||
* @returns 是否成功
|
||||
*/
|
||||
async clearCache() {
|
||||
return await this.coreCommonService.clearCache();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取系统日志
|
||||
* @param params 查询参数
|
||||
* @returns 日志列表
|
||||
*/
|
||||
async getLogs(params: any) {
|
||||
return await this.coreCommonService.getLogs(params);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理系统日志
|
||||
* @param days 保留天数
|
||||
* @returns 是否成功
|
||||
*/
|
||||
async clearLogs(days: number = 30) {
|
||||
return await this.coreCommonService.clearLogs(days);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取系统健康状态
|
||||
* @returns 健康状态
|
||||
*/
|
||||
async getHealthStatus() {
|
||||
return await this.coreCommonService.getHealthStatus();
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行系统维护
|
||||
* @param action 维护动作
|
||||
* @returns 维护结果
|
||||
*/
|
||||
async performMaintenance(action: string) {
|
||||
return await this.coreCommonService.performMaintenance(action);
|
||||
}
|
||||
}
|
||||
156
wwjcloud/src/common/sys/services/admin/ConfigService.ts
Normal file
156
wwjcloud/src/common/sys/services/admin/ConfigService.ts
Normal file
@@ -0,0 +1,156 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { CoreConfigService } from '../core/CoreConfigService';
|
||||
import { ConfigCenterService } from '../../../../config/services/configCenterService';
|
||||
|
||||
/**
|
||||
* 系统配置服务 - Admin层
|
||||
* 对应PHP: app\service\admin\sys\ConfigService
|
||||
*/
|
||||
@Injectable()
|
||||
export class ConfigService {
|
||||
constructor(
|
||||
private readonly coreConfigService: CoreConfigService,
|
||||
private readonly configCenter: ConfigCenterService,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* 获取版权信息
|
||||
* @param siteId 站点ID
|
||||
* @returns 版权配置信息
|
||||
*/
|
||||
async getCopyright(siteId: number = 0) {
|
||||
return await this.coreConfigService.getCopyright(siteId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置版权信息
|
||||
* @param siteId 站点ID
|
||||
* @param value 版权信息
|
||||
* @returns 是否成功
|
||||
*/
|
||||
async setCopyright(siteId: number, value: any) {
|
||||
const data = {
|
||||
icp: value.icp || '',
|
||||
gov_record: value.gov_record || '',
|
||||
gov_url: value.gov_url || '',
|
||||
market_supervision_url: value.market_supervision_url || '',
|
||||
logo: value.logo || '',
|
||||
company_name: value.company_name || '',
|
||||
copyright_link: value.copyright_link || '',
|
||||
copyright_desc: value.copyright_desc || '',
|
||||
};
|
||||
|
||||
return await this.coreConfigService.setConfig(
|
||||
siteId,
|
||||
'COPYRIGHT',
|
||||
data,
|
||||
'版权信息配置',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取网站信息
|
||||
* @param siteId 站点ID
|
||||
* @returns 网站配置信息
|
||||
*/
|
||||
async getWebSite(siteId: number) {
|
||||
const websiteInfo = await this.coreConfigService.getConfig(
|
||||
siteId,
|
||||
'WEBSITE',
|
||||
{},
|
||||
);
|
||||
const serviceInfo = await this.getService(siteId);
|
||||
|
||||
return {
|
||||
...websiteInfo,
|
||||
site_login_logo: serviceInfo.site_login_logo,
|
||||
site_login_bg_img: serviceInfo.site_login_bg_img,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置网站信息
|
||||
* @param siteId 站点ID
|
||||
* @param data 网站信息
|
||||
* @returns 是否成功
|
||||
*/
|
||||
async setWebSite(siteId: number, data: any) {
|
||||
return await this.coreConfigService.setConfig(
|
||||
siteId,
|
||||
'WEBSITE',
|
||||
data,
|
||||
'网站信息配置',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取服务配置信息
|
||||
* @param siteId 站点ID
|
||||
* @returns 服务配置
|
||||
*/
|
||||
async getService(siteId: number) {
|
||||
return await this.coreConfigService.getConfig(siteId, 'SERVICE', {
|
||||
site_login_logo: '',
|
||||
site_login_bg_img: '',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置服务配置信息
|
||||
* @param siteId 站点ID
|
||||
* @param data 服务配置
|
||||
* @returns 是否成功
|
||||
*/
|
||||
async setService(siteId: number, data: any) {
|
||||
return await this.coreConfigService.setConfig(
|
||||
siteId,
|
||||
'SERVICE',
|
||||
data,
|
||||
'服务配置',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取场景域名配置
|
||||
* @param siteId 站点ID
|
||||
* @returns 域名配置
|
||||
*/
|
||||
async getSceneDomain(siteId: number) {
|
||||
return await this.coreConfigService.getSceneDomain(siteId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置场景域名配置
|
||||
* @param siteId 站点ID
|
||||
* @param data 域名配置
|
||||
* @returns 是否成功
|
||||
*/
|
||||
async setSceneDomain(siteId: number, data: any) {
|
||||
return await this.coreConfigService.setConfig(
|
||||
siteId,
|
||||
'SCENE_DOMAIN',
|
||||
data,
|
||||
'场景域名配置',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取系统配置列表
|
||||
* @param siteId 站点ID
|
||||
* @param keys 配置键数组
|
||||
* @returns 配置列表
|
||||
*/
|
||||
async getConfigList(siteId: number, keys: string[] = []) {
|
||||
return await this.coreConfigService.getConfigs(siteId, keys);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量设置配置
|
||||
* @param siteId 站点ID
|
||||
* @param configs 配置对象
|
||||
* @returns 是否成功
|
||||
*/
|
||||
async setConfigList(siteId: number, configs: Record<string, any>) {
|
||||
return await this.coreConfigService.setConfigs(siteId, configs);
|
||||
}
|
||||
}
|
||||
127
wwjcloud/src/common/sys/services/admin/ExportService.ts
Normal file
127
wwjcloud/src/common/sys/services/admin/ExportService.ts
Normal file
@@ -0,0 +1,127 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { CoreExportService } from '../core/CoreExportService';
|
||||
|
||||
/**
|
||||
* 导出服务 - Admin层
|
||||
* 对应PHP: app\service\admin\sys\ExportService
|
||||
*/
|
||||
@Injectable()
|
||||
export class ExportService {
|
||||
constructor(private readonly coreExportService: CoreExportService) {}
|
||||
|
||||
/**
|
||||
* 报表导出列表
|
||||
* @param siteId 站点ID
|
||||
* @param data 查询参数
|
||||
* @returns 分页结果
|
||||
*/
|
||||
async getPage(siteId: number, data: any = {}) {
|
||||
const {
|
||||
export_key,
|
||||
export_status,
|
||||
create_time,
|
||||
page = 1,
|
||||
limit = 10,
|
||||
} = data;
|
||||
return await this.coreExportService.getPage(
|
||||
siteId,
|
||||
export_key,
|
||||
export_status,
|
||||
create_time,
|
||||
page,
|
||||
limit,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取导出数据类型列表
|
||||
* @returns 数据类型列表
|
||||
*/
|
||||
getExportDataType() {
|
||||
return this.coreExportService.getExportDataType();
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查导出数据源是否为空
|
||||
* @param siteId 站点ID
|
||||
* @param type 导出类型
|
||||
* @param where 查询条件
|
||||
* @param page 分页参数
|
||||
* @returns 是否有数据
|
||||
*/
|
||||
async checkExportData(
|
||||
siteId: number,
|
||||
type: string,
|
||||
where: any,
|
||||
page: any = { page: 0, limit: 0 },
|
||||
) {
|
||||
const data = await this.coreExportService.getExportData(
|
||||
siteId,
|
||||
type,
|
||||
where,
|
||||
page,
|
||||
);
|
||||
return data.length > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 报表导出
|
||||
* @param siteId 站点ID
|
||||
* @param type 导出类型
|
||||
* @param where 查询条件
|
||||
* @param page 分页参数
|
||||
* @returns 是否成功
|
||||
*/
|
||||
async exportData(
|
||||
siteId: number,
|
||||
type: string,
|
||||
where: any,
|
||||
page: any = { page: 0, limit: 0 },
|
||||
) {
|
||||
// 创建导出记录
|
||||
const exportRecord = await this.coreExportService.createExportRecord(
|
||||
siteId,
|
||||
type,
|
||||
0,
|
||||
);
|
||||
|
||||
try {
|
||||
// 获取导出数据
|
||||
const data = await this.coreExportService.getExportData(
|
||||
siteId,
|
||||
type,
|
||||
where,
|
||||
page,
|
||||
);
|
||||
|
||||
// TODO: 实际的文件导出逻辑
|
||||
// 这里应该生成Excel文件并保存
|
||||
|
||||
// 更新导出记录
|
||||
await this.coreExportService.updateExportRecord(exportRecord.id, {
|
||||
export_num: data.length,
|
||||
export_status: 1, // 成功
|
||||
file_path: `/exports/${type}_${Date.now()}.xlsx`,
|
||||
file_size: 1024, // 临时值
|
||||
});
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
// 更新为失败状态
|
||||
await this.coreExportService.updateExportRecord(exportRecord.id, {
|
||||
export_status: 2, // 失败
|
||||
});
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除导出记录
|
||||
* @param siteId 站点ID
|
||||
* @param id 导出记录ID
|
||||
* @returns 是否成功
|
||||
*/
|
||||
async deleteRecord(siteId: number, id: number) {
|
||||
return await this.coreExportService.deleteExportRecord(siteId, id);
|
||||
}
|
||||
}
|
||||
270
wwjcloud/src/common/sys/services/admin/MenuService.ts
Normal file
270
wwjcloud/src/common/sys/services/admin/MenuService.ts
Normal file
@@ -0,0 +1,270 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { CoreMenuService } from '../core/CoreMenuService';
|
||||
import { SysMenu } from '../../../rbac/entities/SysMenu';
|
||||
|
||||
/**
|
||||
* 菜单服务 - Admin层
|
||||
* 对应PHP: app\service\admin\sys\MenuService
|
||||
*/
|
||||
@Injectable()
|
||||
export class MenuService {
|
||||
constructor(private readonly coreMenuService: CoreMenuService) {}
|
||||
|
||||
/**
|
||||
* 新增菜单
|
||||
* @param data 菜单数据
|
||||
* @returns 创建的菜单
|
||||
*/
|
||||
async add(data: Partial<SysMenu>): Promise<SysMenu> {
|
||||
return await this.coreMenuService.createMenu(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新菜单
|
||||
* @param appType 应用类型
|
||||
* @param menuKey 菜单键
|
||||
* @param data 更新数据
|
||||
* @returns 是否成功
|
||||
*/
|
||||
async edit(
|
||||
appType: string,
|
||||
menuKey: string,
|
||||
data: Partial<SysMenu>,
|
||||
): Promise<boolean> {
|
||||
return await this.coreMenuService.updateMenu(appType, menuKey, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取菜单信息
|
||||
* @param appType 应用类型
|
||||
* @param menuKey 菜单键
|
||||
* @returns 菜单信息
|
||||
*/
|
||||
async get(appType: string, menuKey: string): Promise<SysMenu | null> {
|
||||
return await this.coreMenuService.findByMenuKey(menuKey, appType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找菜单
|
||||
* @param menuKey 菜单键
|
||||
* @param appType 应用类型
|
||||
* @returns 菜单实体
|
||||
*/
|
||||
async find(menuKey: string, appType?: string): Promise<SysMenu | null> {
|
||||
return await this.coreMenuService.findByMenuKey(menuKey, appType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除菜单
|
||||
* @param appType 应用类型
|
||||
* @param menuKey 菜单键
|
||||
* @returns 是否成功
|
||||
*/
|
||||
async del(appType: string, menuKey: string): Promise<boolean> {
|
||||
return await this.coreMenuService.deleteMenu(appType, menuKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过菜单键数组获取菜单列表
|
||||
* @param siteId 站点ID
|
||||
* @param menuKeys 菜单键数组
|
||||
* @param appType 应用类型
|
||||
* @param isTree 是否返回树形结构
|
||||
* @param addon 插件标识
|
||||
* @param isButton 是否包含按钮
|
||||
* @returns 菜单列表
|
||||
*/
|
||||
async getMenuListByMenuKeys(
|
||||
siteId: number,
|
||||
menuKeys: string[],
|
||||
appType: string,
|
||||
isTree: number = 0,
|
||||
addon: string = 'all',
|
||||
isButton: number = 1,
|
||||
): Promise<any[]> {
|
||||
// TODO: 这里需要实现插件服务来获取站点的插件列表
|
||||
// 暂时使用空数组,后续完善插件模块时补充
|
||||
const addons: string[] = [''];
|
||||
|
||||
const menuList = await this.coreMenuService.getMenusByKeys(
|
||||
siteId,
|
||||
menuKeys,
|
||||
appType,
|
||||
addon,
|
||||
addons,
|
||||
);
|
||||
|
||||
// 处理多语言 - 暂时跳过,后续完善多语言模块时补充
|
||||
// TODO: 实现多语言处理逻辑
|
||||
|
||||
if (isTree) {
|
||||
return this.coreMenuService.buildMenuTree(
|
||||
menuList,
|
||||
'menu_key',
|
||||
'parent_key',
|
||||
'children',
|
||||
'',
|
||||
isButton,
|
||||
);
|
||||
}
|
||||
|
||||
return menuList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有API菜单
|
||||
* @param appType 应用类型
|
||||
* @param addon 插件标识
|
||||
* @returns API菜单列表
|
||||
*/
|
||||
async getAllApiMenus(
|
||||
appType: string = 'admin',
|
||||
addon: string = '',
|
||||
): Promise<SysMenu[]> {
|
||||
return await this.coreMenuService.getAllApiMenus(appType, addon);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取系统菜单
|
||||
* @param status 状态过滤
|
||||
* @param isTree 是否返回树形结构
|
||||
* @param isButton 是否包含按钮
|
||||
* @returns 系统菜单
|
||||
*/
|
||||
async getSystemMenu(
|
||||
status: string | number = 'all',
|
||||
isTree: number = 0,
|
||||
isButton: number = 0,
|
||||
): Promise<any[]> {
|
||||
const menuList = await this.coreMenuService.getSystemMenus(
|
||||
status,
|
||||
isButton,
|
||||
);
|
||||
|
||||
// 处理多语言 - 暂时跳过,后续完善多语言模块时补充
|
||||
// TODO: 实现多语言处理逻辑
|
||||
|
||||
if (isTree) {
|
||||
const treeMenus = this.coreMenuService.buildMenuTree(
|
||||
menuList,
|
||||
'menu_key',
|
||||
'parent_key',
|
||||
'children',
|
||||
'',
|
||||
isButton,
|
||||
);
|
||||
return this.moveChildrenToParent(treeMenus);
|
||||
}
|
||||
|
||||
return menuList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取插件菜单
|
||||
* @param appKey 插件键
|
||||
* @param status 状态过滤
|
||||
* @param isTree 是否返回树形结构
|
||||
* @param isButton 是否包含按钮
|
||||
* @returns 插件菜单
|
||||
*/
|
||||
async getAddonMenu(
|
||||
appKey: string,
|
||||
status: string | number = 'all',
|
||||
isTree: number = 0,
|
||||
isButton: number = 0,
|
||||
): Promise<any[]> {
|
||||
const menuList = await this.coreMenuService.getAddonMenus(
|
||||
appKey,
|
||||
status,
|
||||
isButton,
|
||||
);
|
||||
|
||||
if (isTree) {
|
||||
return this.coreMenuService.buildMenuTree(
|
||||
menuList,
|
||||
'menu_key',
|
||||
'parent_key',
|
||||
'children',
|
||||
'',
|
||||
isButton,
|
||||
);
|
||||
}
|
||||
|
||||
return menuList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取目录类型菜单
|
||||
* @param addon 插件标识
|
||||
* @returns 目录菜单树形结构
|
||||
*/
|
||||
async getMenuByTypeDir(addon: string = 'system'): Promise<any[]> {
|
||||
const menuList = await this.coreMenuService.getMenusByTypeDir(addon);
|
||||
|
||||
// 处理多语言 - 暂时跳过,后续完善多语言模块时补充
|
||||
// TODO: 实现多语言处理逻辑
|
||||
|
||||
return this.coreMenuService.buildMenuTree(
|
||||
menuList,
|
||||
'menu_key',
|
||||
'parent_key',
|
||||
'children',
|
||||
'',
|
||||
0,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据系统配置获取菜单键列表
|
||||
* @param appType 应用类型
|
||||
* @param addons 插件列表
|
||||
* @returns 菜单键数组
|
||||
*/
|
||||
async getMenuKeysBySystem(
|
||||
appType: string,
|
||||
addons: string[],
|
||||
): Promise<string[]> {
|
||||
return await this.coreMenuService.getMenuKeysBySystem(appType, addons);
|
||||
}
|
||||
|
||||
/**
|
||||
* 移动子节点到父节点 - 辅助方法
|
||||
* @param menuList 菜单列表
|
||||
* @returns 处理后的菜单列表
|
||||
*/
|
||||
private moveChildrenToParent(menuList: any[]): any[] {
|
||||
// 这个方法的具体实现需要根据PHP代码的逻辑来完善
|
||||
// 暂时返回原始数据,后续根据需求完善
|
||||
return menuList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建菜单树形结构 - 对外接口
|
||||
* @param menus 菜单列表
|
||||
* @param keyField 键字段
|
||||
* @param parentKeyField 父键字段
|
||||
* @param childrenField 子节点字段名
|
||||
* @param authField 权限字段
|
||||
* @param parentKey 父键值
|
||||
* @param isButton 是否包含按钮
|
||||
* @returns 树形菜单结构
|
||||
*/
|
||||
menuToTree(
|
||||
menus: any[],
|
||||
keyField: string = 'menu_key',
|
||||
parentKeyField: string = 'parent_key',
|
||||
childrenField: string = 'children',
|
||||
authField: string = 'auth',
|
||||
parentKey: string = '',
|
||||
isButton: number = 1,
|
||||
): any[] {
|
||||
return this.coreMenuService.buildMenuTree(
|
||||
menus,
|
||||
keyField,
|
||||
parentKeyField,
|
||||
childrenField,
|
||||
parentKey,
|
||||
isButton,
|
||||
);
|
||||
}
|
||||
}
|
||||
111
wwjcloud/src/common/sys/services/admin/PosterService.ts
Normal file
111
wwjcloud/src/common/sys/services/admin/PosterService.ts
Normal file
@@ -0,0 +1,111 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { CorePosterService } from '../core/CorePosterService';
|
||||
import { SysPoster } from '../../entities/SysPoster';
|
||||
|
||||
/**
|
||||
* 海报服务 - Admin层
|
||||
* 对应PHP: app\service\admin\sys\PosterService
|
||||
*/
|
||||
@Injectable()
|
||||
export class PosterService {
|
||||
constructor(private readonly corePosterService: CorePosterService) {}
|
||||
|
||||
/**
|
||||
* 获取海报分页列表
|
||||
* @param siteId 站点ID
|
||||
* @param data 查询参数
|
||||
* @returns 分页结果
|
||||
*/
|
||||
async getPage(siteId: number, data: any = {}) {
|
||||
const { name, type, page = 1, limit = 10 } = data;
|
||||
return await this.corePosterService.getPage(
|
||||
siteId,
|
||||
name,
|
||||
type,
|
||||
page,
|
||||
limit,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取海报列表
|
||||
* @param siteId 站点ID
|
||||
* @param data 查询参数
|
||||
* @returns 海报列表
|
||||
*/
|
||||
async getList(siteId: number, data: any = {}) {
|
||||
const { name, type } = data;
|
||||
return await this.corePosterService.getList(siteId, name, type);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取海报信息
|
||||
* @param siteId 站点ID
|
||||
* @param id 海报ID
|
||||
* @returns 海报信息
|
||||
*/
|
||||
async getInfo(siteId: number, id: number) {
|
||||
return await this.corePosterService.getInfo(siteId, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加海报
|
||||
* @param siteId 站点ID
|
||||
* @param data 海报数据
|
||||
* @returns 创建的海报
|
||||
*/
|
||||
async add(siteId: number, data: Partial<SysPoster>) {
|
||||
const posterData = { ...data, site_id: siteId };
|
||||
return await this.corePosterService.add(posterData);
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑海报
|
||||
* @param siteId 站点ID
|
||||
* @param id 海报ID
|
||||
* @param data 更新数据
|
||||
* @returns 是否成功
|
||||
*/
|
||||
async edit(siteId: number, id: number, data: Partial<SysPoster>) {
|
||||
return await this.corePosterService.edit(siteId, id, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除海报
|
||||
* @param siteId 站点ID
|
||||
* @param id 海报ID
|
||||
* @returns 是否成功
|
||||
*/
|
||||
async del(siteId: number, id: number) {
|
||||
return await this.corePosterService.del(siteId, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置默认海报
|
||||
* @param siteId 站点ID
|
||||
* @param id 海报ID
|
||||
* @param type 海报类型
|
||||
* @returns 是否成功
|
||||
*/
|
||||
async setDefault(siteId: number, id: number, type: string) {
|
||||
return await this.corePosterService.setDefault(siteId, id, type);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据类型获取默认海报
|
||||
* @param siteId 站点ID
|
||||
* @param type 海报类型
|
||||
* @returns 默认海报
|
||||
*/
|
||||
async getDefaultByType(siteId: number, type: string) {
|
||||
return await this.corePosterService.getDefaultByType(siteId, type);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取海报类型列表
|
||||
* @returns 海报类型映射
|
||||
*/
|
||||
getPosterTypes() {
|
||||
return this.corePosterService.getPosterTypes();
|
||||
}
|
||||
}
|
||||
129
wwjcloud/src/common/sys/services/admin/PrinterService.ts
Normal file
129
wwjcloud/src/common/sys/services/admin/PrinterService.ts
Normal file
@@ -0,0 +1,129 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { CorePrinterService } from '../core/CorePrinterService';
|
||||
import { SysPrinter } from '../../entities/SysPrinter';
|
||||
|
||||
/**
|
||||
* 打印机服务 - Admin层
|
||||
* 对应PHP: app\service\admin\sys\PrinterService
|
||||
*/
|
||||
@Injectable()
|
||||
export class PrinterService {
|
||||
constructor(private readonly corePrinterService: CorePrinterService) {}
|
||||
|
||||
/**
|
||||
* 获取小票打印机分页列表
|
||||
* @param siteId 站点ID
|
||||
* @param data 查询参数
|
||||
* @returns 分页结果
|
||||
*/
|
||||
async getPage(siteId: number, data: any = {}) {
|
||||
const { printer_name, page = 1, limit = 10 } = data;
|
||||
return await this.corePrinterService.getPage(
|
||||
siteId,
|
||||
printer_name,
|
||||
page,
|
||||
limit,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取小票打印机列表
|
||||
* @param siteId 站点ID
|
||||
* @param data 查询参数
|
||||
* @returns 打印机列表
|
||||
*/
|
||||
async getList(siteId: number, data: any = {}) {
|
||||
return await this.corePrinterService.getList(siteId, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取小票打印机信息
|
||||
* @param siteId 站点ID
|
||||
* @param printerId 打印机ID
|
||||
* @returns 打印机信息
|
||||
*/
|
||||
async getInfo(siteId: number, printerId: number) {
|
||||
return await this.corePrinterService.getInfo(siteId, printerId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加小票打印机
|
||||
* @param siteId 站点ID
|
||||
* @param data 打印机数据
|
||||
* @returns 创建的打印机
|
||||
*/
|
||||
async add(siteId: number, data: Partial<SysPrinter>) {
|
||||
const printerData = { ...data, site_id: siteId };
|
||||
return await this.corePrinterService.add(printerData);
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑小票打印机
|
||||
* @param siteId 站点ID
|
||||
* @param printerId 打印机ID
|
||||
* @param data 更新数据
|
||||
* @returns 是否成功
|
||||
*/
|
||||
async edit(siteId: number, printerId: number, data: Partial<SysPrinter>) {
|
||||
return await this.corePrinterService.edit(siteId, printerId, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除小票打印机
|
||||
* @param siteId 站点ID
|
||||
* @param printerId 打印机ID
|
||||
* @returns 是否成功
|
||||
*/
|
||||
async del(siteId: number, printerId: number) {
|
||||
return await this.corePrinterService.del(siteId, printerId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改打印机状态
|
||||
* @param siteId 站点ID
|
||||
* @param printerId 打印机ID
|
||||
* @param status 状态
|
||||
* @returns 是否成功
|
||||
*/
|
||||
async modifyStatus(siteId: number, printerId: number, status: number) {
|
||||
return await this.corePrinterService.modifyStatus(
|
||||
siteId,
|
||||
printerId,
|
||||
status,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试打印机连接
|
||||
* @param siteId 站点ID
|
||||
* @param printerId 打印机ID
|
||||
* @returns 测试结果
|
||||
*/
|
||||
async testConnection(siteId: number, printerId: number) {
|
||||
return await this.corePrinterService.testPrinter(siteId, printerId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 打印内容
|
||||
* @param siteId 站点ID
|
||||
* @param printerId 打印机ID
|
||||
* @param content 打印内容
|
||||
* @returns 打印结果
|
||||
*/
|
||||
async print(siteId: number, printerId: number, content: string) {
|
||||
return await this.corePrinterService.print(siteId, printerId, content);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取打印机品牌列表
|
||||
* @returns 品牌列表
|
||||
*/
|
||||
getBrandList() {
|
||||
return {
|
||||
yilianyun: '易联云',
|
||||
feie: '飞鹅',
|
||||
xpyun: '芯烨云',
|
||||
'365': '365云打印',
|
||||
};
|
||||
}
|
||||
}
|
||||
141
wwjcloud/src/common/sys/services/admin/PrinterTemplateService.ts
Normal file
141
wwjcloud/src/common/sys/services/admin/PrinterTemplateService.ts
Normal file
@@ -0,0 +1,141 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { CorePrinterTemplateService } from '../core/CorePrinterTemplateService';
|
||||
import { SysPrinterTemplate } from '../../entities/SysPrinterTemplate';
|
||||
|
||||
/**
|
||||
* 打印模板服务 - Admin层
|
||||
* 对应PHP: app\service\admin\sys\PrinterTemplateService
|
||||
*/
|
||||
@Injectable()
|
||||
export class PrinterTemplateService {
|
||||
constructor(
|
||||
private readonly coreTemplateService: CorePrinterTemplateService,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* 获取小票打印模板分页列表
|
||||
* @param siteId 站点ID
|
||||
* @param data 查询参数
|
||||
* @returns 分页结果
|
||||
*/
|
||||
async getPage(siteId: number, data: any = {}) {
|
||||
const {
|
||||
template_id,
|
||||
template_type,
|
||||
template_name,
|
||||
page = 1,
|
||||
limit = 10,
|
||||
} = data;
|
||||
return await this.coreTemplateService.getPage(
|
||||
siteId,
|
||||
template_id,
|
||||
template_type,
|
||||
template_name,
|
||||
page,
|
||||
limit,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取小票打印模板列表
|
||||
* @param siteId 站点ID
|
||||
* @param data 查询参数
|
||||
* @returns 模板列表
|
||||
*/
|
||||
async getList(siteId: number, data: any = {}) {
|
||||
return await this.coreTemplateService.getList(siteId, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取小票打印模板信息
|
||||
* @param siteId 站点ID
|
||||
* @param templateId 模板ID
|
||||
* @returns 模板信息
|
||||
*/
|
||||
async getInfo(siteId: number, templateId: number) {
|
||||
return await this.coreTemplateService.getInfo(siteId, templateId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加小票打印模板
|
||||
* @param siteId 站点ID
|
||||
* @param data 模板数据
|
||||
* @returns 创建的模板
|
||||
*/
|
||||
async add(siteId: number, data: Partial<SysPrinterTemplate>) {
|
||||
const templateData = { ...data, site_id: siteId };
|
||||
return await this.coreTemplateService.add(templateData);
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑小票打印模板
|
||||
* @param siteId 站点ID
|
||||
* @param templateId 模板ID
|
||||
* @param data 更新数据
|
||||
* @returns 是否成功
|
||||
*/
|
||||
async edit(
|
||||
siteId: number,
|
||||
templateId: number,
|
||||
data: Partial<SysPrinterTemplate>,
|
||||
) {
|
||||
return await this.coreTemplateService.edit(siteId, templateId, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除小票打印模板
|
||||
* @param siteId 站点ID
|
||||
* @param templateId 模板ID
|
||||
* @returns 是否成功
|
||||
*/
|
||||
async del(siteId: number, templateId: number) {
|
||||
return await this.coreTemplateService.del(siteId, templateId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据类型获取模板
|
||||
* @param siteId 站点ID
|
||||
* @param templateType 模板类型
|
||||
* @returns 模板列表
|
||||
*/
|
||||
async getTemplatesByType(siteId: number, templateType: string) {
|
||||
return await this.coreTemplateService.getTemplatesByType(
|
||||
siteId,
|
||||
templateType,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取模板类型列表
|
||||
* @returns 模板类型映射
|
||||
*/
|
||||
getTemplateTypes() {
|
||||
return this.coreTemplateService.getTemplateTypes();
|
||||
}
|
||||
|
||||
/**
|
||||
* 预览模板
|
||||
* @param siteId 站点ID
|
||||
* @param templateId 模板ID
|
||||
* @param data 预览数据
|
||||
* @returns 预览结果
|
||||
*/
|
||||
async previewTemplate(siteId: number, templateId: number, data: any = {}) {
|
||||
const template = await this.getInfo(siteId, templateId);
|
||||
if (!template) {
|
||||
throw new Error('模板不存在');
|
||||
}
|
||||
|
||||
const templateData = template.getValueObject();
|
||||
|
||||
// TODO: 实现模板预览逻辑
|
||||
// 根据模板配置和数据生成预览内容
|
||||
|
||||
return {
|
||||
template_id: templateId,
|
||||
template_name: template.template_name,
|
||||
template_type: template.template_type,
|
||||
preview_content: '预览内容', // 实际应该根据模板和数据生成
|
||||
};
|
||||
}
|
||||
}
|
||||
216
wwjcloud/src/common/sys/services/admin/RoleService.ts
Normal file
216
wwjcloud/src/common/sys/services/admin/RoleService.ts
Normal file
@@ -0,0 +1,216 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { CoreRoleService } from '../core/CoreRoleService';
|
||||
import { SysRole } from '../../../rbac/entities/SysRole';
|
||||
|
||||
/**
|
||||
* 角色服务 - Admin层
|
||||
* 对应PHP: app\service\admin\sys\RoleService
|
||||
*/
|
||||
@Injectable()
|
||||
export class RoleService {
|
||||
constructor(private readonly coreRoleService: CoreRoleService) {}
|
||||
|
||||
/**
|
||||
* 管理端获取角色列表
|
||||
* @param siteId 站点ID
|
||||
* @param data 查询参数
|
||||
* @returns 分页结果
|
||||
*/
|
||||
async getPage(siteId: number, data: any = {}) {
|
||||
const { role_name, page = 1, limit = 10 } = data;
|
||||
return await this.coreRoleService.getPage(siteId, role_name, page, limit);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取角色信息
|
||||
* @param roleId 角色ID
|
||||
* @returns 角色信息
|
||||
*/
|
||||
async getInfo(roleId: number): Promise<SysRole | null> {
|
||||
return await this.coreRoleService.getInfo(roleId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取站点下的所有角色
|
||||
* @param siteId 站点ID
|
||||
* @param userRoleIds 当前用户的角色ID数组(用于权限过滤)
|
||||
* @param isAdmin 是否是超级管理员
|
||||
* @returns 角色列表
|
||||
*/
|
||||
async getAll(
|
||||
siteId: number,
|
||||
userRoleIds: number[] = [],
|
||||
isAdmin: boolean = false,
|
||||
): Promise<any[]> {
|
||||
const siteRoleAll = await this.coreRoleService.getAll(siteId);
|
||||
|
||||
// 为每个角色添加disabled字段
|
||||
const result = siteRoleAll.map((role) => ({
|
||||
...role,
|
||||
disabled: false,
|
||||
}));
|
||||
|
||||
// 如果不是超级管理员,需要检查权限
|
||||
if (!isAdmin && userRoleIds.length > 0) {
|
||||
// TODO: 实现菜单权限检查逻辑
|
||||
// 暂时跳过权限检查,后续完善权限模块时补充
|
||||
// const menuKeys = await this.getMenuIdsByRoleIds(siteId, userRoleIds);
|
||||
// 检查每个角色的权限是否超出当前用户权限
|
||||
}
|
||||
|
||||
// 移除rules字段,不返回给前端
|
||||
return result.map((role) => {
|
||||
const { rules, ...roleWithoutRules } = role;
|
||||
return roleWithoutRules;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增角色
|
||||
* @param siteId 站点ID
|
||||
* @param appType 应用类型
|
||||
* @param data 角色数据
|
||||
* @returns 是否成功
|
||||
*/
|
||||
async add(
|
||||
siteId: number,
|
||||
appType: string,
|
||||
data: Partial<SysRole>,
|
||||
): Promise<boolean> {
|
||||
const roleData = {
|
||||
...data,
|
||||
site_id: siteId,
|
||||
// app_type: appType, // 根据数据表结构,暂时不添加app_type字段
|
||||
};
|
||||
|
||||
await this.coreRoleService.add(roleData);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新角色
|
||||
* @param roleId 角色ID
|
||||
* @param siteId 站点ID
|
||||
* @param data 更新数据
|
||||
* @returns 是否成功
|
||||
*/
|
||||
async edit(
|
||||
roleId: number,
|
||||
siteId: number,
|
||||
data: Partial<SysRole>,
|
||||
): Promise<boolean> {
|
||||
return await this.coreRoleService.edit(roleId, siteId, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改角色状态
|
||||
* @param roleId 角色ID
|
||||
* @param siteId 站点ID
|
||||
* @param status 状态
|
||||
* @returns 是否成功
|
||||
*/
|
||||
async modifyStatus(
|
||||
roleId: number,
|
||||
siteId: number,
|
||||
status: number,
|
||||
): Promise<boolean> {
|
||||
return await this.coreRoleService.modifyStatus(roleId, siteId, status);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找角色
|
||||
* @param siteId 站点ID
|
||||
* @param roleId 角色ID
|
||||
* @returns 角色实体
|
||||
*/
|
||||
async find(siteId: number, roleId: number): Promise<SysRole> {
|
||||
const role = await this.coreRoleService.find(siteId, roleId);
|
||||
if (!role) {
|
||||
throw new Error('角色不存在');
|
||||
}
|
||||
return role;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除角色
|
||||
* @param roleId 角色ID
|
||||
* @param siteId 站点ID
|
||||
* @returns 是否成功
|
||||
*/
|
||||
async del(roleId: number, siteId: number): Promise<boolean> {
|
||||
// 先检查角色是否存在
|
||||
await this.find(siteId, roleId);
|
||||
|
||||
// 检查是否有用户使用该角色
|
||||
// TODO: 需要检查SysUserRole表
|
||||
// 暂时跳过用户角色关联检查,后续完善用户模块时补充
|
||||
|
||||
return await this.coreRoleService.del(roleId, siteId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取角色ID和名称的键值对
|
||||
* @param siteId 站点ID
|
||||
* @returns 角色键值对
|
||||
*/
|
||||
async getColumn(siteId: number): Promise<Record<number, string>> {
|
||||
return await this.coreRoleService.getColumn(siteId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过角色ID数组获取菜单权限
|
||||
* @param siteId 站点ID
|
||||
* @param roleIds 角色ID数组
|
||||
* @param allowMenuKeys 允许的菜单键列表
|
||||
* @returns 菜单键数组
|
||||
*/
|
||||
async getMenuIdsByRoleIds(
|
||||
siteId: number,
|
||||
roleIds: number[],
|
||||
allowMenuKeys: string[] = [],
|
||||
): Promise<string[]> {
|
||||
return await this.coreRoleService.getMenuIdsByRoleIds(
|
||||
siteId,
|
||||
roleIds,
|
||||
allowMenuKeys,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据角色ID数组获取角色列表
|
||||
* @param roleIds 角色ID数组
|
||||
* @returns 角色列表
|
||||
*/
|
||||
async getRolesByIds(roleIds: number[]): Promise<SysRole[]> {
|
||||
return await this.coreRoleService.getRolesByIds(roleIds);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查用户是否为超级管理员
|
||||
* @param userId 用户ID
|
||||
* @param siteId 站点ID
|
||||
* @returns 是否为超级管理员
|
||||
*/
|
||||
async isSuperAdmin(userId: number, siteId: number): Promise<boolean> {
|
||||
// TODO: 实现超级管理员检查逻辑
|
||||
// 需要与AuthService配合实现
|
||||
// 暂时返回false,后续完善权限模块时补充
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户的角色权限信息
|
||||
* @param userId 用户ID
|
||||
* @param siteId 站点ID
|
||||
* @returns 角色权限信息
|
||||
*/
|
||||
async getUserRoleInfo(userId: number, siteId: number): Promise<any> {
|
||||
// TODO: 实现用户角色信息获取逻辑
|
||||
// 需要与用户模块配合实现
|
||||
// 暂时返回空对象,后续完善用户模块时补充
|
||||
return {
|
||||
role_ids: [],
|
||||
is_admin: false,
|
||||
};
|
||||
}
|
||||
}
|
||||
75
wwjcloud/src/common/sys/services/admin/ScheduleService.ts
Normal file
75
wwjcloud/src/common/sys/services/admin/ScheduleService.ts
Normal file
@@ -0,0 +1,75 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { CoreScheduleService } from '../core/CoreScheduleService';
|
||||
import { SysSchedule } from '../../entities/SysSchedule';
|
||||
|
||||
/**
|
||||
* 定时任务服务 - Admin层
|
||||
*/
|
||||
@Injectable()
|
||||
export class ScheduleService {
|
||||
constructor(private readonly coreScheduleService: CoreScheduleService) {}
|
||||
|
||||
/**
|
||||
* 获取定时任务分页列表
|
||||
*/
|
||||
async getPage(siteId: number, data: any = {}) {
|
||||
const { key, status, page = 1, limit = 10 } = data;
|
||||
return await this.coreScheduleService.getPage(
|
||||
siteId,
|
||||
key,
|
||||
status,
|
||||
page,
|
||||
limit,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取定时任务列表
|
||||
*/
|
||||
async getList(siteId: number, data: any = {}) {
|
||||
return await this.coreScheduleService.getList(siteId, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取定时任务信息
|
||||
*/
|
||||
async getInfo(siteId: number, id: number) {
|
||||
return await this.coreScheduleService.getInfo(siteId, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加定时任务
|
||||
*/
|
||||
async add(siteId: number, data: Partial<SysSchedule>) {
|
||||
const scheduleData = { ...data, siteId };
|
||||
return await this.coreScheduleService.add(scheduleData);
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑定时任务
|
||||
*/
|
||||
async edit(siteId: number, id: number, data: Partial<SysSchedule>) {
|
||||
return await this.coreScheduleService.edit(siteId, id, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除定时任务
|
||||
*/
|
||||
async del(siteId: number, id: number) {
|
||||
return await this.coreScheduleService.del(siteId, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动定时任务
|
||||
*/
|
||||
async start(siteId: number, id: number) {
|
||||
return await this.coreScheduleService.start(siteId, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止定时任务
|
||||
*/
|
||||
async stop(siteId: number, id: number) {
|
||||
return await this.coreScheduleService.stop(siteId, id);
|
||||
}
|
||||
}
|
||||
BIN
wwjcloud/src/common/sys/services/admin/SystemService.ts
Normal file
BIN
wwjcloud/src/common/sys/services/admin/SystemService.ts
Normal file
Binary file not shown.
15
wwjcloud/src/common/sys/services/api/ApiAreaService.ts
Normal file
15
wwjcloud/src/common/sys/services/api/ApiAreaService.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { CoreAreaService } from '../core/CoreAreaService';
|
||||
|
||||
@Injectable()
|
||||
export class ApiAreaService {
|
||||
constructor(private readonly coreAreaService: CoreAreaService) {}
|
||||
|
||||
async getAreaList(siteId: number, parentId?: number) {
|
||||
return await this.coreAreaService.getListByPid(parentId || 0);
|
||||
}
|
||||
|
||||
async getAreaInfo(siteId: number, areaId: number) {
|
||||
return await this.coreAreaService.getAreaByAreaCode(areaId);
|
||||
}
|
||||
}
|
||||
33
wwjcloud/src/common/sys/services/api/ApiAttachmentService.ts
Normal file
33
wwjcloud/src/common/sys/services/api/ApiAttachmentService.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { CoreAttachmentService } from '../core/CoreAttachmentService';
|
||||
import { SysAttachment } from '../../entities/SysAttachment';
|
||||
|
||||
@Injectable()
|
||||
export class ApiAttachmentService {
|
||||
constructor(private readonly coreAttachmentService: CoreAttachmentService) {}
|
||||
|
||||
async upload(
|
||||
siteId: number,
|
||||
file: Express.Multer.File,
|
||||
cateId?: number,
|
||||
): Promise<SysAttachment> {
|
||||
const attachmentData = {
|
||||
site_id: siteId,
|
||||
name: file.filename,
|
||||
real_name: file.originalname,
|
||||
path: file.path,
|
||||
dir: file.destination || './public/upload',
|
||||
url: '/storage/' + file.filename,
|
||||
cate_id: cateId || 0,
|
||||
att_size: file.size.toString(),
|
||||
att_type: file.mimetype.startsWith('image/') ? 'image' : 'video',
|
||||
storage_type: 'local',
|
||||
};
|
||||
|
||||
return await this.coreAttachmentService.add(attachmentData);
|
||||
}
|
||||
|
||||
async getInfo(siteId: number, attId: number) {
|
||||
return await this.coreAttachmentService.getInfo(siteId, attId);
|
||||
}
|
||||
}
|
||||
15
wwjcloud/src/common/sys/services/api/ApiConfigService.ts
Normal file
15
wwjcloud/src/common/sys/services/api/ApiConfigService.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { CoreSysConfigService } from '../core/CoreSysConfigService';
|
||||
|
||||
@Injectable()
|
||||
export class ApiConfigService {
|
||||
constructor(private readonly coreSysConfigService: CoreSysConfigService) {}
|
||||
|
||||
async getConfig(siteId: number, key: string) {
|
||||
return await this.coreSysConfigService.getConfigByKey(siteId, key);
|
||||
}
|
||||
|
||||
async getConfigs(siteId: number, keys: string[]) {
|
||||
return await this.coreSysConfigService.getConfigsByKeys(siteId, keys);
|
||||
}
|
||||
}
|
||||
21
wwjcloud/src/common/sys/services/api/ApiIndexService.ts
Normal file
21
wwjcloud/src/common/sys/services/api/ApiIndexService.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
@Injectable()
|
||||
export class ApiIndexService {
|
||||
async getIndexInfo(siteId: number) {
|
||||
return {
|
||||
site_id: siteId,
|
||||
title: '系统首页',
|
||||
version: '1.0.0',
|
||||
timestamp: Date.now(),
|
||||
};
|
||||
}
|
||||
|
||||
async getSystemInfo() {
|
||||
return {
|
||||
name: 'WWJCloud',
|
||||
version: '1.0.0',
|
||||
description: '企业级SaaS管理平台',
|
||||
};
|
||||
}
|
||||
}
|
||||
22
wwjcloud/src/common/sys/services/api/ApiScanService.ts
Normal file
22
wwjcloud/src/common/sys/services/api/ApiScanService.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
@Injectable()
|
||||
export class ApiScanService {
|
||||
async scanQrCode(code: string) {
|
||||
return {
|
||||
code,
|
||||
type: 'qr',
|
||||
data: '扫描结果',
|
||||
timestamp: Date.now(),
|
||||
};
|
||||
}
|
||||
|
||||
async scanBarcode(code: string) {
|
||||
return {
|
||||
code,
|
||||
type: 'barcode',
|
||||
data: '条码扫描结果',
|
||||
timestamp: Date.now(),
|
||||
};
|
||||
}
|
||||
}
|
||||
29
wwjcloud/src/common/sys/services/api/ApiTaskService.ts
Normal file
29
wwjcloud/src/common/sys/services/api/ApiTaskService.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
@Injectable()
|
||||
export class ApiTaskService {
|
||||
async getTaskList(siteId: number) {
|
||||
return {
|
||||
site_id: siteId,
|
||||
tasks: [],
|
||||
total: 0,
|
||||
};
|
||||
}
|
||||
|
||||
async createTask(siteId: number, taskData: any) {
|
||||
return {
|
||||
site_id: siteId,
|
||||
task_id: Date.now(),
|
||||
...taskData,
|
||||
status: 'pending',
|
||||
};
|
||||
}
|
||||
|
||||
async updateTaskStatus(taskId: number, status: string) {
|
||||
return {
|
||||
task_id: taskId,
|
||||
status,
|
||||
update_time: Date.now(),
|
||||
};
|
||||
}
|
||||
}
|
||||
19
wwjcloud/src/common/sys/services/api/ApiVerifyService.ts
Normal file
19
wwjcloud/src/common/sys/services/api/ApiVerifyService.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
@Injectable()
|
||||
export class ApiVerifyService {
|
||||
async verifyCode(code: string): Promise<boolean> {
|
||||
// 验证码验证逻辑
|
||||
return code === '123456'; // 示例验证
|
||||
}
|
||||
|
||||
async sendSms(phone: string): Promise<boolean> {
|
||||
// 发送短信验证码逻辑
|
||||
return true; // 示例返回
|
||||
}
|
||||
|
||||
async verifySms(phone: string, code: string): Promise<boolean> {
|
||||
// 短信验证码验证逻辑
|
||||
return code === '123456'; // 示例验证
|
||||
}
|
||||
}
|
||||
70
wwjcloud/src/common/sys/services/api/Base64Service.ts
Normal file
70
wwjcloud/src/common/sys/services/api/Base64Service.ts
Normal file
@@ -0,0 +1,70 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { CoreAttachmentService } from '../core/CoreAttachmentService';
|
||||
import { SysAttachment } from '../../entities/SysAttachment';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
|
||||
@Injectable()
|
||||
export class Base64Service {
|
||||
constructor(private readonly coreAttachmentService: CoreAttachmentService) {}
|
||||
|
||||
async image(siteId: number, content: string): Promise<SysAttachment> {
|
||||
// 解析base64内容
|
||||
const matches = content.match(/^data:([A-Za-z-+\/]+);base64,(.+)$/);
|
||||
if (!matches || matches.length !== 3) {
|
||||
throw new Error('无效的base64格式');
|
||||
}
|
||||
|
||||
const mimeType = matches[1];
|
||||
const base64Data = matches[2];
|
||||
const buffer = Buffer.from(base64Data, 'base64');
|
||||
|
||||
// 生成文件名
|
||||
const extension = this.getExtensionFromMimeType(mimeType);
|
||||
const filename = this.generateRandomName() + extension;
|
||||
const filepath = path.join('./public/upload', filename);
|
||||
|
||||
// 确保目录存在
|
||||
const uploadDir = path.dirname(filepath);
|
||||
if (!fs.existsSync(uploadDir)) {
|
||||
fs.mkdirSync(uploadDir, { recursive: true });
|
||||
}
|
||||
|
||||
// 写入文件
|
||||
fs.writeFileSync(filepath, buffer);
|
||||
|
||||
const attachmentData = {
|
||||
site_id: siteId,
|
||||
name: filename,
|
||||
real_name: 'base64_image' + extension,
|
||||
path: filepath,
|
||||
dir: './public/upload',
|
||||
url: '/storage/' + filename,
|
||||
cate_id: 0,
|
||||
att_size: buffer.length.toString(),
|
||||
att_type: 'image',
|
||||
storage_type: 'local',
|
||||
};
|
||||
|
||||
return await this.coreAttachmentService.add(attachmentData);
|
||||
}
|
||||
|
||||
private getExtensionFromMimeType(mimeType: string): string {
|
||||
const mimeToExt: { [key: string]: string } = {
|
||||
'image/jpeg': '.jpg',
|
||||
'image/png': '.png',
|
||||
'image/gif': '.gif',
|
||||
'image/webp': '.webp',
|
||||
'image/bmp': '.bmp',
|
||||
'image/svg+xml': '.svg',
|
||||
};
|
||||
return mimeToExt[mimeType] || '.jpg';
|
||||
}
|
||||
|
||||
private generateRandomName(): string {
|
||||
return Array(32)
|
||||
.fill(null)
|
||||
.map(() => Math.round(Math.random() * 16).toString(16))
|
||||
.join('');
|
||||
}
|
||||
}
|
||||
77
wwjcloud/src/common/sys/services/api/FetchService.ts
Normal file
77
wwjcloud/src/common/sys/services/api/FetchService.ts
Normal file
@@ -0,0 +1,77 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { CoreAttachmentService } from '../core/CoreAttachmentService';
|
||||
import { SysAttachment } from '../../entities/SysAttachment';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import axios from 'axios';
|
||||
|
||||
@Injectable()
|
||||
export class FetchService {
|
||||
constructor(private readonly coreAttachmentService: CoreAttachmentService) {}
|
||||
|
||||
async image(siteId: number, url: string): Promise<SysAttachment> {
|
||||
try {
|
||||
// 下载远程图片
|
||||
const response = await axios.get(url, {
|
||||
responseType: 'arraybuffer',
|
||||
timeout: 30000,
|
||||
headers: {
|
||||
'User-Agent':
|
||||
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
|
||||
},
|
||||
});
|
||||
|
||||
const buffer = Buffer.from(response.data);
|
||||
const contentType = response.headers['content-type'] || 'image/jpeg';
|
||||
|
||||
// 生成文件名
|
||||
const extension = this.getExtensionFromMimeType(contentType);
|
||||
const filename = this.generateRandomName() + extension;
|
||||
const filepath = path.join('./public/upload', filename);
|
||||
|
||||
// 确保目录存在
|
||||
const uploadDir = path.dirname(filepath);
|
||||
if (!fs.existsSync(uploadDir)) {
|
||||
fs.mkdirSync(uploadDir, { recursive: true });
|
||||
}
|
||||
|
||||
// 写入文件
|
||||
fs.writeFileSync(filepath, buffer);
|
||||
|
||||
const attachmentData = {
|
||||
site_id: siteId,
|
||||
name: filename,
|
||||
real_name: path.basename(url) || 'remote_image' + extension,
|
||||
path: filepath,
|
||||
url: '/storage/' + filename,
|
||||
cate_id: 0,
|
||||
file_size: buffer.length,
|
||||
file_type: contentType,
|
||||
storage_type: 'local',
|
||||
};
|
||||
|
||||
return await this.coreAttachmentService.add(attachmentData);
|
||||
} catch (error) {
|
||||
throw new Error('远程图片拉取失败: ' + error.message);
|
||||
}
|
||||
}
|
||||
|
||||
private getExtensionFromMimeType(mimeType: string): string {
|
||||
const mimeToExt: { [key: string]: string } = {
|
||||
'image/jpeg': '.jpg',
|
||||
'image/png': '.png',
|
||||
'image/gif': '.gif',
|
||||
'image/webp': '.webp',
|
||||
'image/bmp': '.bmp',
|
||||
'image/svg+xml': '.svg',
|
||||
};
|
||||
return mimeToExt[mimeType] || '.jpg';
|
||||
}
|
||||
|
||||
private generateRandomName(): string {
|
||||
return Array(32)
|
||||
.fill(null)
|
||||
.map(() => Math.round(Math.random() * 16).toString(16))
|
||||
.join('');
|
||||
}
|
||||
}
|
||||
50
wwjcloud/src/common/sys/services/api/SysApiService.ts
Normal file
50
wwjcloud/src/common/sys/services/api/SysApiService.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { CoreSysService } from '../core/CoreSysService';
|
||||
|
||||
@Injectable()
|
||||
export class SysApiService {
|
||||
constructor(private readonly coreSysService: CoreSysService) {}
|
||||
|
||||
/**
|
||||
* 获取系统信息
|
||||
*/
|
||||
async getIndex(site_id: number) {
|
||||
return this.coreSysService.getSystemInfo(site_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取地区列表
|
||||
*/
|
||||
async getArea(parent_id?: number) {
|
||||
return this.coreSysService.getAreaList(parent_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取系统配置
|
||||
*/
|
||||
async getConfig(site_id: number, keys?: string) {
|
||||
const keyList = keys ? keys.split(',') : [];
|
||||
return this.coreSysService.getConfigByKeys(site_id, keyList);
|
||||
}
|
||||
|
||||
/**
|
||||
* 扫码登录
|
||||
*/
|
||||
async scan(qr_code: string) {
|
||||
return this.coreSysService.scanLogin(qr_code);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取任务状态
|
||||
*/
|
||||
async getTask(task_id: string) {
|
||||
return this.coreSysService.getTaskStatus(task_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证码验证
|
||||
*/
|
||||
async verify(verify_key: string, verify_code: string) {
|
||||
return this.coreSysService.verifyCode(verify_key, verify_code);
|
||||
}
|
||||
}
|
||||
48
wwjcloud/src/common/sys/services/api/UploadService.ts
Normal file
48
wwjcloud/src/common/sys/services/api/UploadService.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { CoreAttachmentService } from '../core/CoreAttachmentService';
|
||||
import { SysAttachment } from '../../entities/SysAttachment';
|
||||
|
||||
@Injectable()
|
||||
export class UploadService {
|
||||
constructor(private readonly coreAttachmentService: CoreAttachmentService) {}
|
||||
|
||||
async image(
|
||||
siteId: number,
|
||||
file: Express.Multer.File,
|
||||
): Promise<SysAttachment> {
|
||||
const attachmentData = {
|
||||
site_id: siteId,
|
||||
name: file.filename,
|
||||
real_name: file.originalname,
|
||||
path: file.path,
|
||||
dir: file.destination || './public/upload',
|
||||
url: '/storage/' + file.filename,
|
||||
cate_id: 0,
|
||||
att_size: file.size.toString(),
|
||||
att_type: 'image',
|
||||
storage_type: 'local',
|
||||
};
|
||||
|
||||
return await this.coreAttachmentService.add(attachmentData);
|
||||
}
|
||||
|
||||
async video(
|
||||
siteId: number,
|
||||
file: Express.Multer.File,
|
||||
): Promise<SysAttachment> {
|
||||
const attachmentData = {
|
||||
site_id: siteId,
|
||||
name: file.filename,
|
||||
real_name: file.originalname,
|
||||
path: file.path,
|
||||
dir: file.destination || './public/upload',
|
||||
url: '/storage/' + file.filename,
|
||||
cate_id: 0,
|
||||
att_size: file.size.toString(),
|
||||
att_type: 'video',
|
||||
storage_type: 'local',
|
||||
};
|
||||
|
||||
return await this.coreAttachmentService.add(attachmentData);
|
||||
}
|
||||
}
|
||||
152
wwjcloud/src/common/sys/services/core/CoreAgreementService.ts
Normal file
152
wwjcloud/src/common/sys/services/core/CoreAgreementService.ts
Normal file
@@ -0,0 +1,152 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { Repository } from 'typeorm';
|
||||
import { BaseService } from '../../../../core/base/BaseService';
|
||||
import { SysAgreement } from '../../entities/SysAgreement';
|
||||
|
||||
/**
|
||||
* 核心协议服务 - Core层
|
||||
* 对应PHP: CoreAgreementService
|
||||
*/
|
||||
@Injectable()
|
||||
export class CoreAgreementService extends BaseService<SysAgreement> {
|
||||
constructor(
|
||||
@InjectRepository(SysAgreement)
|
||||
private readonly agreementRepository: Repository<SysAgreement>,
|
||||
) {
|
||||
super(agreementRepository);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取协议内容
|
||||
* @param siteId 站点ID
|
||||
* @param key 协议关键字
|
||||
* @returns 协议信息
|
||||
*/
|
||||
async getAgreement(
|
||||
siteId: number,
|
||||
key: string,
|
||||
): Promise<SysAgreement | null> {
|
||||
return await this.agreementRepository.findOne({
|
||||
where: {
|
||||
site_id: siteId,
|
||||
agreement_key: key,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置协议
|
||||
* @param siteId 站点ID
|
||||
* @param key 协议关键字
|
||||
* @param title 协议标题
|
||||
* @param content 协议内容
|
||||
* @returns 是否成功
|
||||
*/
|
||||
async setAgreement(
|
||||
siteId: number,
|
||||
key: string,
|
||||
title: string,
|
||||
content: string,
|
||||
): Promise<boolean> {
|
||||
const existingAgreement = await this.getAgreement(siteId, key);
|
||||
|
||||
if (existingAgreement) {
|
||||
// 更新现有协议
|
||||
const result = await this.agreementRepository.update(
|
||||
{ site_id: siteId, agreement_key: key },
|
||||
{
|
||||
title,
|
||||
content,
|
||||
update_time: Math.floor(Date.now() / 1000),
|
||||
},
|
||||
);
|
||||
return (result.affected || 0) > 0;
|
||||
} else {
|
||||
// 创建新协议
|
||||
const agreement = this.agreementRepository.create({
|
||||
site_id: siteId,
|
||||
agreement_key: key,
|
||||
title,
|
||||
content,
|
||||
create_time: Math.floor(Date.now() / 1000),
|
||||
});
|
||||
await this.agreementRepository.save(agreement);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有协议列表
|
||||
* @param siteId 站点ID
|
||||
* @returns 协议列表
|
||||
*/
|
||||
async getAll(siteId: number): Promise<SysAgreement[]> {
|
||||
return await this.agreementRepository.find({
|
||||
where: { site_id: siteId },
|
||||
order: { create_time: 'DESC' },
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除协议
|
||||
* @param siteId 站点ID
|
||||
* @param key 协议关键字
|
||||
* @returns 是否成功
|
||||
*/
|
||||
async deleteAgreement(siteId: number, key: string): Promise<boolean> {
|
||||
const result = await this.agreementRepository.delete({
|
||||
site_id: siteId,
|
||||
agreement_key: key,
|
||||
});
|
||||
return (result.affected || 0) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量获取协议
|
||||
* @param siteId 站点ID
|
||||
* @param keys 协议关键字数组
|
||||
* @returns 协议映射对象
|
||||
*/
|
||||
async getAgreements(
|
||||
siteId: number,
|
||||
keys: string[],
|
||||
): Promise<Record<string, SysAgreement>> {
|
||||
if (!keys.length) return {};
|
||||
|
||||
const agreements = await this.agreementRepository.find({
|
||||
where: {
|
||||
site_id: siteId,
|
||||
agreement_key: keys.length === 1 ? keys[0] : undefined,
|
||||
},
|
||||
});
|
||||
|
||||
// 过滤指定的keys
|
||||
const filteredAgreements = agreements.filter((agreement) =>
|
||||
keys.includes(agreement.agreement_key),
|
||||
);
|
||||
|
||||
const result: Record<string, SysAgreement> = {};
|
||||
filteredAgreements.forEach((agreement) => {
|
||||
result[agreement.agreement_key] = agreement;
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查协议是否存在
|
||||
* @param siteId 站点ID
|
||||
* @param key 协议关键字
|
||||
* @returns 是否存在
|
||||
*/
|
||||
async exists(siteId: number, key: string): Promise<boolean> {
|
||||
const count = await this.agreementRepository.count({
|
||||
where: {
|
||||
site_id: siteId,
|
||||
agreement_key: key,
|
||||
},
|
||||
});
|
||||
return count > 0;
|
||||
}
|
||||
}
|
||||
217
wwjcloud/src/common/sys/services/core/CoreAreaService.ts
Normal file
217
wwjcloud/src/common/sys/services/core/CoreAreaService.ts
Normal file
@@ -0,0 +1,217 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { Repository } from 'typeorm';
|
||||
import { SysArea } from '../../entities/SysArea';
|
||||
|
||||
/**
|
||||
* 核心地区服务 - Core层
|
||||
* 对应PHP: AreaService核心逻辑
|
||||
*/
|
||||
@Injectable()
|
||||
export class CoreAreaService {
|
||||
constructor(
|
||||
@InjectRepository(SysArea)
|
||||
private readonly areaRepository: Repository<SysArea>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* 根据父级ID获取地区列表
|
||||
* @param pid 父级ID
|
||||
* @returns 地区列表
|
||||
*/
|
||||
async getListByPid(pid: number = 0): Promise<SysArea[]> {
|
||||
return await this.areaRepository.find({
|
||||
where: { pid },
|
||||
select: [
|
||||
'id',
|
||||
'pid',
|
||||
'name',
|
||||
'shortname',
|
||||
'longitude',
|
||||
'latitude',
|
||||
'level',
|
||||
'sort',
|
||||
'status',
|
||||
],
|
||||
order: { sort: 'ASC', id: 'ASC' },
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询地区树列表
|
||||
* @param level 最大层级(1,2,3)
|
||||
* @returns 树形地区列表
|
||||
*/
|
||||
async getAreaTree(level: number = 3): Promise<any[]> {
|
||||
const list = await this.areaRepository.find({
|
||||
where: { level: level <= 3 ? undefined : level },
|
||||
select: [
|
||||
'id',
|
||||
'pid',
|
||||
'name',
|
||||
'shortname',
|
||||
'longitude',
|
||||
'latitude',
|
||||
'level',
|
||||
'sort',
|
||||
'status',
|
||||
],
|
||||
order: { level: 'ASC', sort: 'ASC', id: 'ASC' },
|
||||
});
|
||||
|
||||
// 过滤指定层级
|
||||
const filteredList = list.filter((item) => item.level <= level);
|
||||
|
||||
// 构建树形结构
|
||||
return this.listToTree(filteredList);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据地区ID获取地区信息
|
||||
* @param id 地区ID
|
||||
* @returns 地区信息
|
||||
*/
|
||||
async getAreaByAreaCode(id: number): Promise<SysArea | null> {
|
||||
return await this.areaRepository.findOne({
|
||||
where: { id },
|
||||
select: [
|
||||
'id',
|
||||
'pid',
|
||||
'name',
|
||||
'shortname',
|
||||
'longitude',
|
||||
'latitude',
|
||||
'level',
|
||||
'sort',
|
||||
'status',
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据地区ID数组获取地区信息
|
||||
* @param ids 地区ID数组
|
||||
* @returns 地区信息数组
|
||||
*/
|
||||
async getAreaByAreaCodes(ids: number[]): Promise<SysArea[]> {
|
||||
if (!ids.length) return [];
|
||||
|
||||
return await this.areaRepository.find({
|
||||
where: { id: ids.length === 1 ? ids[0] : undefined },
|
||||
select: [
|
||||
'id',
|
||||
'pid',
|
||||
'name',
|
||||
'shortname',
|
||||
'longitude',
|
||||
'latitude',
|
||||
'level',
|
||||
'sort',
|
||||
'status',
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取省市区完整路径
|
||||
* @param id 地区ID
|
||||
* @returns 完整路径字符串
|
||||
*/
|
||||
async getFullPath(id: number): Promise<string> {
|
||||
const area = await this.getAreaByAreaCode(id);
|
||||
if (!area) return '';
|
||||
|
||||
const path: string[] = [area.name];
|
||||
let currentArea = area;
|
||||
|
||||
// 向上查找父级
|
||||
while (currentArea.pid > 0) {
|
||||
const parent = await this.getAreaByAreaCode(currentArea.pid);
|
||||
if (!parent) break;
|
||||
path.unshift(parent.name);
|
||||
currentArea = parent;
|
||||
}
|
||||
|
||||
return path.join(' ');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定层级的所有地区
|
||||
* @param level 层级
|
||||
* @returns 地区列表
|
||||
*/
|
||||
async getAreasByLevel(level: number): Promise<SysArea[]> {
|
||||
return await this.areaRepository.find({
|
||||
where: { level },
|
||||
select: [
|
||||
'id',
|
||||
'pid',
|
||||
'name',
|
||||
'shortname',
|
||||
'longitude',
|
||||
'latitude',
|
||||
'level',
|
||||
'sort',
|
||||
'status',
|
||||
],
|
||||
order: { sort: 'ASC', id: 'ASC' },
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 列表转树形结构
|
||||
* @param list 平面列表
|
||||
* @param pid 父级ID
|
||||
* @returns 树形结构
|
||||
*/
|
||||
private listToTree(list: SysArea[], pid: number = 0): any[] {
|
||||
const tree: any[] = [];
|
||||
|
||||
list.forEach((item) => {
|
||||
if (item.pid === pid) {
|
||||
const children = this.listToTree(list, item.id);
|
||||
const node = {
|
||||
...item,
|
||||
children: children.length > 0 ? children : undefined,
|
||||
};
|
||||
tree.push(node);
|
||||
}
|
||||
});
|
||||
|
||||
return tree;
|
||||
}
|
||||
|
||||
/**
|
||||
* 搜索地区
|
||||
* @param keyword 关键词
|
||||
* @param level 层级过滤
|
||||
* @returns 地区列表
|
||||
*/
|
||||
async searchArea(keyword: string, level?: number): Promise<SysArea[]> {
|
||||
const queryBuilder = this.areaRepository
|
||||
.createQueryBuilder('area')
|
||||
.where('area.name LIKE :keyword OR area.shortname LIKE :keyword', {
|
||||
keyword: `%${keyword}%`,
|
||||
});
|
||||
|
||||
if (level !== undefined) {
|
||||
queryBuilder.andWhere('area.level = :level', { level });
|
||||
}
|
||||
|
||||
return await queryBuilder
|
||||
.select([
|
||||
'area.id',
|
||||
'area.pid',
|
||||
'area.name',
|
||||
'area.shortname',
|
||||
'area.longitude',
|
||||
'area.latitude',
|
||||
'area.level',
|
||||
'area.sort',
|
||||
'area.status',
|
||||
])
|
||||
.orderBy('area.level', 'ASC')
|
||||
.addOrderBy('area.sort', 'ASC')
|
||||
.getMany();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { Repository } from 'typeorm';
|
||||
import { BaseService } from '../../../../core/base/BaseService';
|
||||
import { SysAttachmentCategory } from '../../entities/SysAttachmentCategory';
|
||||
|
||||
@Injectable()
|
||||
export class CoreAttachmentCategoryService extends BaseService<SysAttachmentCategory> {
|
||||
constructor(
|
||||
@InjectRepository(SysAttachmentCategory)
|
||||
private readonly categoryRepository: Repository<SysAttachmentCategory>,
|
||||
) {
|
||||
super(categoryRepository);
|
||||
}
|
||||
|
||||
async getPage(
|
||||
siteId: number,
|
||||
name?: string,
|
||||
page: number = 1,
|
||||
limit: number = 10,
|
||||
) {
|
||||
const queryBuilder = this.categoryRepository
|
||||
.createQueryBuilder('category')
|
||||
.where('category.site_id = :siteId', { siteId });
|
||||
|
||||
if (name) {
|
||||
queryBuilder.andWhere('category.categoryName LIKE :name', {
|
||||
name: '%' + name + '%',
|
||||
});
|
||||
}
|
||||
|
||||
const [data, total] = await queryBuilder
|
||||
.orderBy('category.sort', 'ASC')
|
||||
.addOrderBy('category.createTime', 'DESC')
|
||||
.skip((page - 1) * limit)
|
||||
.take(limit)
|
||||
.getManyAndCount();
|
||||
|
||||
return {
|
||||
data,
|
||||
total,
|
||||
page,
|
||||
limit,
|
||||
pages: Math.ceil(total / limit),
|
||||
};
|
||||
}
|
||||
|
||||
async add(
|
||||
data: Partial<SysAttachmentCategory>,
|
||||
): Promise<SysAttachmentCategory> {
|
||||
const category = this.categoryRepository.create(data);
|
||||
return await this.categoryRepository.save(category);
|
||||
}
|
||||
|
||||
async edit(
|
||||
siteId: number,
|
||||
id: number,
|
||||
data: Partial<SysAttachmentCategory>,
|
||||
): Promise<boolean> {
|
||||
const result = await this.categoryRepository.update(
|
||||
{ id, site_id: siteId },
|
||||
data,
|
||||
);
|
||||
return (result.affected || 0) > 0;
|
||||
}
|
||||
|
||||
async del(siteId: number, id: number): Promise<boolean> {
|
||||
const result = await this.categoryRepository.delete({
|
||||
id,
|
||||
site_id: siteId,
|
||||
});
|
||||
return (result.affected || 0) > 0;
|
||||
}
|
||||
|
||||
async getInfo(
|
||||
siteId: number,
|
||||
id: number,
|
||||
): Promise<SysAttachmentCategory | null> {
|
||||
return await this.categoryRepository.findOne({
|
||||
where: { id, site_id: siteId },
|
||||
});
|
||||
}
|
||||
}
|
||||
193
wwjcloud/src/common/sys/services/core/CoreAttachmentService.ts
Normal file
193
wwjcloud/src/common/sys/services/core/CoreAttachmentService.ts
Normal file
@@ -0,0 +1,193 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { Repository, Like } from 'typeorm';
|
||||
import { BaseService } from '../../../../core/base/BaseService';
|
||||
import { SysAttachment } from '../../entities/SysAttachment';
|
||||
|
||||
/**
|
||||
* 核心附件服务 - Core层
|
||||
* 对应PHP: CoreAttachmentService
|
||||
*/
|
||||
@Injectable()
|
||||
export class CoreAttachmentService extends BaseService<SysAttachment> {
|
||||
constructor(
|
||||
@InjectRepository(SysAttachment)
|
||||
private readonly attachmentRepository: Repository<SysAttachment>,
|
||||
) {
|
||||
super(attachmentRepository);
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询附件列表
|
||||
* @param siteId 站点ID
|
||||
* @param name 附件名称过滤
|
||||
* @param cateId 分类ID过滤
|
||||
* @param page 页码
|
||||
* @param limit 每页数量
|
||||
* @returns 分页结果
|
||||
*/
|
||||
async getPage(
|
||||
siteId: number,
|
||||
name?: string,
|
||||
cateId?: number,
|
||||
page: number = 1,
|
||||
limit: number = 10,
|
||||
) {
|
||||
const queryBuilder = this.attachmentRepository
|
||||
.createQueryBuilder('attachment')
|
||||
.where('attachment.site_id = :siteId', { siteId })
|
||||
.select([
|
||||
'attachment.att_id',
|
||||
'attachment.name',
|
||||
'attachment.real_name',
|
||||
'attachment.path',
|
||||
'attachment.url',
|
||||
'attachment.file_size',
|
||||
'attachment.file_type',
|
||||
'attachment.cate_id',
|
||||
'attachment.create_time',
|
||||
]);
|
||||
|
||||
if (name) {
|
||||
queryBuilder.andWhere('attachment.name LIKE :name', {
|
||||
name: `%${name}%`,
|
||||
});
|
||||
}
|
||||
|
||||
if (cateId !== undefined) {
|
||||
queryBuilder.andWhere('attachment.cate_id = :cateId', { cateId });
|
||||
}
|
||||
|
||||
const [data, total] = await queryBuilder
|
||||
.orderBy('attachment.create_time', 'DESC')
|
||||
.skip((page - 1) * limit)
|
||||
.take(limit)
|
||||
.getManyAndCount();
|
||||
|
||||
return {
|
||||
data,
|
||||
total,
|
||||
page,
|
||||
limit,
|
||||
pages: Math.ceil(total / limit),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加附件
|
||||
* @param data 附件数据
|
||||
* @returns 创建的附件
|
||||
*/
|
||||
async add(data: Partial<SysAttachment>): Promise<SysAttachment> {
|
||||
const attachmentData = {
|
||||
...data,
|
||||
create_time: Math.floor(Date.now() / 1000),
|
||||
};
|
||||
|
||||
const attachment = this.attachmentRepository.create(attachmentData);
|
||||
return await this.attachmentRepository.save(attachment);
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑附件
|
||||
* @param siteId 站点ID
|
||||
* @param attId 附件ID
|
||||
* @param data 更新数据
|
||||
* @returns 是否成功
|
||||
*/
|
||||
async edit(
|
||||
siteId: number,
|
||||
attId: number,
|
||||
data: Partial<SysAttachment>,
|
||||
): Promise<boolean> {
|
||||
const updateData = {
|
||||
...data,
|
||||
update_time: Math.floor(Date.now() / 1000),
|
||||
};
|
||||
|
||||
const result = await this.attachmentRepository.update(
|
||||
{ att_id: attId, site_id: siteId },
|
||||
updateData,
|
||||
);
|
||||
return (result.affected || 0) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改附件分类
|
||||
* @param siteId 站点ID
|
||||
* @param attId 附件ID
|
||||
* @param cateId 分类ID
|
||||
* @returns 是否成功
|
||||
*/
|
||||
async modifyCategory(
|
||||
siteId: number,
|
||||
attId: number,
|
||||
cateId: number,
|
||||
): Promise<boolean> {
|
||||
const result = await this.attachmentRepository.update(
|
||||
{ att_id: attId, site_id: siteId },
|
||||
{ cate_id: cateId, update_time: Math.floor(Date.now() / 1000) },
|
||||
);
|
||||
return (result.affected || 0) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除附件
|
||||
* @param siteId 站点ID
|
||||
* @param attId 附件ID
|
||||
* @returns 是否成功
|
||||
*/
|
||||
async del(siteId: number, attId: number): Promise<boolean> {
|
||||
const result = await this.attachmentRepository.delete({
|
||||
att_id: attId,
|
||||
site_id: siteId,
|
||||
});
|
||||
return (result.affected || 0) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取附件详情
|
||||
* @param siteId 站点ID
|
||||
* @param attId 附件ID
|
||||
* @returns 附件信息
|
||||
*/
|
||||
async getInfo(siteId: number, attId: number): Promise<SysAttachment | null> {
|
||||
return await this.attachmentRepository.findOne({
|
||||
where: { att_id: attId, site_id: siteId },
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据路径查找附件
|
||||
* @param siteId 站点ID
|
||||
* @param path 文件路径
|
||||
* @returns 附件信息
|
||||
*/
|
||||
async findByPath(
|
||||
siteId: number,
|
||||
path: string,
|
||||
): Promise<SysAttachment | null> {
|
||||
return await this.attachmentRepository.findOne({
|
||||
where: { site_id: siteId, path },
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除附件
|
||||
* @param siteId 站点ID
|
||||
* @param attIds 附件ID数组
|
||||
* @returns 是否成功
|
||||
*/
|
||||
async batchDelete(siteId: number, attIds: number[]): Promise<boolean> {
|
||||
if (!attIds.length) return false;
|
||||
|
||||
const result = await this.attachmentRepository
|
||||
.createQueryBuilder()
|
||||
.delete()
|
||||
.where('site_id = :siteId', { siteId })
|
||||
.andWhere('att_id IN (:...attIds)', { attIds })
|
||||
.execute();
|
||||
|
||||
return (result.affected || 0) > 0;
|
||||
}
|
||||
}
|
||||
184
wwjcloud/src/common/sys/services/core/CoreChannelService.ts
Normal file
184
wwjcloud/src/common/sys/services/core/CoreChannelService.ts
Normal file
@@ -0,0 +1,184 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { BaseService } from '../../../../core/base/BaseService';
|
||||
import { Channel } from '../../entities/Channel';
|
||||
|
||||
/**
|
||||
* 核心渠道服务 - Core层
|
||||
* 对应PHP: ChannelService核心逻辑
|
||||
*/
|
||||
@Injectable()
|
||||
export class CoreChannelService extends BaseService<Channel> {
|
||||
constructor() {
|
||||
super(Channel);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取渠道列表
|
||||
* @param params 查询参数
|
||||
* @returns 渠道列表
|
||||
*/
|
||||
async getList(params: any) {
|
||||
const { page = 1, limit = 20, keyword = '', status = '', type = '' } = params;
|
||||
|
||||
const query = this.repository.createQueryBuilder('channel');
|
||||
|
||||
if (keyword) {
|
||||
query.andWhere('channel.name LIKE :keyword', { keyword: `%${keyword}%` });
|
||||
}
|
||||
|
||||
if (status !== '') {
|
||||
query.andWhere('channel.status = :status', { status: parseInt(status) });
|
||||
}
|
||||
|
||||
if (type) {
|
||||
query.andWhere('channel.type = :type', { type });
|
||||
}
|
||||
|
||||
query.orderBy('channel.sort', 'ASC');
|
||||
query.addOrderBy('channel.create_time', 'DESC');
|
||||
|
||||
const [list, total] = await query
|
||||
.skip((page - 1) * limit)
|
||||
.take(limit)
|
||||
.getManyAndCount();
|
||||
|
||||
return {
|
||||
list,
|
||||
total,
|
||||
page,
|
||||
limit,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取渠道详情
|
||||
* @param id 渠道ID
|
||||
* @returns 渠道详情
|
||||
*/
|
||||
async getInfo(id: number) {
|
||||
return await this.repository.findOne({ where: { channel_id: id } });
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加渠道
|
||||
* @param data 渠道数据
|
||||
* @returns 是否成功
|
||||
*/
|
||||
async add(data: any) {
|
||||
const channel = this.repository.create({
|
||||
name: data.name,
|
||||
type: data.type,
|
||||
status: data.status || 1,
|
||||
sort: data.sort || 0,
|
||||
config: data.config || {},
|
||||
remark: data.remark || '',
|
||||
});
|
||||
|
||||
await this.repository.save(channel);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑渠道
|
||||
* @param id 渠道ID
|
||||
* @param data 渠道数据
|
||||
* @returns 是否成功
|
||||
*/
|
||||
async edit(id: number, data: any) {
|
||||
const result = await this.repository.update(
|
||||
{ channel_id: id },
|
||||
{
|
||||
name: data.name,
|
||||
type: data.type,
|
||||
status: data.status,
|
||||
sort: data.sort,
|
||||
config: data.config,
|
||||
remark: data.remark,
|
||||
update_time: new Date(),
|
||||
}
|
||||
);
|
||||
|
||||
return result.affected > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除渠道
|
||||
* @param id 渠道ID
|
||||
* @returns 是否成功
|
||||
*/
|
||||
async delete(id: number) {
|
||||
const result = await this.repository.delete({ channel_id: id });
|
||||
return result.affected > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取渠道类型列表
|
||||
* @returns 渠道类型列表
|
||||
*/
|
||||
async getChannelTypes() {
|
||||
return [
|
||||
{ value: 'h5', label: 'H5渠道' },
|
||||
{ value: 'pc', label: 'PC渠道' },
|
||||
{ value: 'app', label: 'APP渠道' },
|
||||
{ value: 'mini', label: '小程序渠道' },
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取渠道状态列表
|
||||
* @returns 渠道状态列表
|
||||
*/
|
||||
async getChannelStatuses() {
|
||||
return [
|
||||
{ value: 1, label: '启用' },
|
||||
{ value: 0, label: '禁用' },
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新渠道状态
|
||||
* @param id 渠道ID
|
||||
* @param status 状态
|
||||
* @returns 是否成功
|
||||
*/
|
||||
async updateStatus(id: number, status: number) {
|
||||
const result = await this.repository.update(
|
||||
{ channel_id: id },
|
||||
{ status, update_time: new Date() }
|
||||
);
|
||||
|
||||
return result.affected > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取渠道配置
|
||||
* @param id 渠道ID
|
||||
* @returns 渠道配置
|
||||
*/
|
||||
async getConfig(id: number) {
|
||||
const channel = await this.repository.findOne({
|
||||
where: { channel_id: id },
|
||||
select: ['channel_id', 'config']
|
||||
});
|
||||
|
||||
return channel?.config || {};
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置渠道配置
|
||||
* @param id 渠道ID
|
||||
* @param config 配置数据
|
||||
* @returns 是否成功
|
||||
*/
|
||||
async setConfig(id: number, config: any) {
|
||||
const result = await this.repository.update(
|
||||
{ channel_id: id },
|
||||
{
|
||||
config,
|
||||
update_time: new Date()
|
||||
}
|
||||
);
|
||||
|
||||
return result.affected > 0;
|
||||
}
|
||||
}
|
||||
190
wwjcloud/src/common/sys/services/core/CoreCommonService.ts
Normal file
190
wwjcloud/src/common/sys/services/core/CoreCommonService.ts
Normal file
@@ -0,0 +1,190 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { ConfigCenterService } from '../../../../config/services/configCenterService';
|
||||
|
||||
/**
|
||||
* 核心通用服务 - Core层
|
||||
* 对应PHP: CommonService核心逻辑
|
||||
*/
|
||||
@Injectable()
|
||||
export class CoreCommonService {
|
||||
constructor(private readonly configCenter: ConfigCenterService) {}
|
||||
|
||||
/**
|
||||
* 获取系统字典
|
||||
* @param type 字典类型
|
||||
* @returns 字典数据
|
||||
*/
|
||||
async getDict(type: string) {
|
||||
const dicts = {
|
||||
status: [
|
||||
{ value: 1, label: '启用' },
|
||||
{ value: 0, label: '禁用' },
|
||||
],
|
||||
gender: [
|
||||
{ value: 1, label: '男' },
|
||||
{ value: 2, label: '女' },
|
||||
{ value: 0, label: '未知' },
|
||||
],
|
||||
yes_no: [
|
||||
{ value: 1, label: '是' },
|
||||
{ value: 0, label: '否' },
|
||||
],
|
||||
channel_type: [
|
||||
{ value: 'h5', label: 'H5渠道' },
|
||||
{ value: 'pc', label: 'PC渠道' },
|
||||
{ value: 'app', label: 'APP渠道' },
|
||||
{ value: 'mini', label: '小程序渠道' },
|
||||
],
|
||||
};
|
||||
|
||||
return dicts[type] || [];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取系统配置
|
||||
* @param key 配置键
|
||||
* @returns 配置值
|
||||
*/
|
||||
async getConfig(key: string) {
|
||||
return this.configCenter.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置系统配置
|
||||
* @param key 配置键
|
||||
* @param value 配置值
|
||||
* @returns 是否成功
|
||||
*/
|
||||
async setConfig(key: string, value: any) {
|
||||
try {
|
||||
this.configCenter.set(key, value);
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取系统信息
|
||||
* @returns 系统信息
|
||||
*/
|
||||
async getSystemInfo() {
|
||||
return {
|
||||
version: this.configCenter.get('app.version', '1.0.0'),
|
||||
name: this.configCenter.get('app.name', 'Niucloud Admin'),
|
||||
description: this.configCenter.get('app.description', '企业快速开发的saas管理平台'),
|
||||
author: this.configCenter.get('app.author', 'Niucloud Team'),
|
||||
homepage: this.configCenter.get('app.homepage', 'https://www.niucloud.com'),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取系统统计
|
||||
* @returns 统计信息
|
||||
*/
|
||||
async getSystemStats() {
|
||||
return {
|
||||
total_sites: 0, // TODO: 实际统计站点数量
|
||||
total_users: 0, // TODO: 实际统计用户数量
|
||||
total_orders: 0, // TODO: 实际统计订单数量
|
||||
total_income: 0, // TODO: 实际统计收入
|
||||
online_users: 0, // TODO: 实际统计在线用户
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理系统缓存
|
||||
* @returns 是否成功
|
||||
*/
|
||||
async clearCache() {
|
||||
try {
|
||||
// TODO: 实现缓存清理逻辑
|
||||
// 可以清理Redis缓存、文件缓存等
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取系统日志
|
||||
* @param params 查询参数
|
||||
* @returns 日志列表
|
||||
*/
|
||||
async getLogs(params: any) {
|
||||
// TODO: 实现日志查询逻辑
|
||||
return {
|
||||
list: [],
|
||||
total: 0,
|
||||
page: params.page || 1,
|
||||
limit: params.limit || 20,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理系统日志
|
||||
* @param days 保留天数
|
||||
* @returns 是否成功
|
||||
*/
|
||||
async clearLogs(days: number = 30) {
|
||||
try {
|
||||
// TODO: 实现日志清理逻辑
|
||||
const cutoffDate = new Date();
|
||||
cutoffDate.setDate(cutoffDate.getDate() - days);
|
||||
// 清理指定日期之前的日志
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取系统健康状态
|
||||
* @returns 健康状态
|
||||
*/
|
||||
async getHealthStatus() {
|
||||
const memory = process.memoryUsage();
|
||||
const uptime = process.uptime();
|
||||
|
||||
return {
|
||||
status: 'healthy',
|
||||
timestamp: new Date().toISOString(),
|
||||
uptime: uptime,
|
||||
memory: {
|
||||
rss: memory.rss,
|
||||
heapTotal: memory.heapTotal,
|
||||
heapUsed: memory.heapUsed,
|
||||
external: memory.external,
|
||||
},
|
||||
cpu: {
|
||||
usage: process.cpuUsage(),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行系统维护
|
||||
* @param action 维护动作
|
||||
* @returns 维护结果
|
||||
*/
|
||||
async performMaintenance(action: string) {
|
||||
try {
|
||||
switch (action) {
|
||||
case 'clear_cache':
|
||||
return await this.clearCache();
|
||||
case 'clear_logs':
|
||||
return await this.clearLogs(30);
|
||||
case 'optimize_db':
|
||||
// TODO: 实现数据库优化
|
||||
return true;
|
||||
case 'backup_data':
|
||||
// TODO: 实现数据备份
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
182
wwjcloud/src/common/sys/services/core/CoreConfigService.ts
Normal file
182
wwjcloud/src/common/sys/services/core/CoreConfigService.ts
Normal file
@@ -0,0 +1,182 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { Repository } from 'typeorm';
|
||||
import { BaseService } from '../../../../core/base/BaseService';
|
||||
import { SysConfig } from '../../entities/SysConfig';
|
||||
|
||||
/**
|
||||
* 核心配置服务 - Core层
|
||||
* 对应PHP: app\service\core\sys\CoreSysConfigService
|
||||
*/
|
||||
@Injectable()
|
||||
export class CoreConfigService extends BaseService<SysConfig> {
|
||||
constructor(
|
||||
@InjectRepository(SysConfig)
|
||||
private readonly sysConfigRepository: Repository<SysConfig>,
|
||||
) {
|
||||
super(sysConfigRepository);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取配置值
|
||||
* @param siteId 站点ID
|
||||
* @param key 配置键
|
||||
* @param defaultValue 默认值
|
||||
* @returns 配置值
|
||||
*/
|
||||
async getConfig(
|
||||
siteId: number,
|
||||
key: string,
|
||||
defaultValue: any = null,
|
||||
): Promise<any> {
|
||||
const config = await this.sysConfigRepository.findOne({
|
||||
where: {
|
||||
siteId,
|
||||
key,
|
||||
isUse: 1,
|
||||
},
|
||||
});
|
||||
|
||||
if (!config || !config.value) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
try {
|
||||
return JSON.parse(config.value);
|
||||
} catch (error) {
|
||||
return config.value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置配置值
|
||||
* @param siteId 站点ID
|
||||
* @param key 配置键
|
||||
* @param value 配置值
|
||||
* @param desc 配置描述
|
||||
* @returns 是否成功
|
||||
*/
|
||||
async setConfig(
|
||||
siteId: number,
|
||||
key: string,
|
||||
value: any,
|
||||
desc?: string,
|
||||
): Promise<boolean> {
|
||||
const configValue =
|
||||
typeof value === 'object' ? JSON.stringify(value) : String(value);
|
||||
|
||||
const existingConfig = await this.sysConfigRepository.findOne({
|
||||
where: { siteId, key },
|
||||
});
|
||||
|
||||
if (existingConfig) {
|
||||
existingConfig.value = configValue;
|
||||
if (desc) {
|
||||
existingConfig.desc = desc;
|
||||
}
|
||||
await this.sysConfigRepository.save(existingConfig);
|
||||
} else {
|
||||
const newConfig = this.sysConfigRepository.create({
|
||||
siteId,
|
||||
key,
|
||||
value: configValue,
|
||||
desc: desc || '',
|
||||
isUse: 1,
|
||||
});
|
||||
await this.sysConfigRepository.save(newConfig);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除配置
|
||||
* @param siteId 站点ID
|
||||
* @param key 配置键
|
||||
* @returns 是否成功
|
||||
*/
|
||||
async deleteConfig(siteId: number, key: string): Promise<boolean> {
|
||||
const result = await this.sysConfigRepository.delete({ siteId, key });
|
||||
return (result.affected || 0) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取多个配置
|
||||
* @param siteId 站点ID
|
||||
* @param keys 配置键数组
|
||||
* @returns 配置对象
|
||||
*/
|
||||
async getConfigs(
|
||||
siteId: number,
|
||||
keys: string[],
|
||||
): Promise<Record<string, any>> {
|
||||
const queryBuilder = this.sysConfigRepository
|
||||
.createQueryBuilder('config')
|
||||
.where('config.siteId = :siteId', { siteId })
|
||||
.andWhere('config.isUse = :isUse', { isUse: 1 });
|
||||
|
||||
if (keys.length > 0) {
|
||||
queryBuilder.andWhere('config.key IN (:...keys)', { keys });
|
||||
}
|
||||
|
||||
const configs = await queryBuilder.getMany();
|
||||
|
||||
const result: Record<string, any> = {};
|
||||
for (const config of configs) {
|
||||
try {
|
||||
result[config.key] = JSON.parse(config.value);
|
||||
} catch (error) {
|
||||
result[config.key] = config.value;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量设置配置
|
||||
* @param siteId 站点ID
|
||||
* @param configs 配置对象
|
||||
* @returns 是否成功
|
||||
*/
|
||||
async setConfigs(
|
||||
siteId: number,
|
||||
configs: Record<string, any>,
|
||||
): Promise<boolean> {
|
||||
for (const [key, value] of Object.entries(configs)) {
|
||||
await this.setConfig(siteId, key, value);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取版权信息
|
||||
* @param siteId 站点ID
|
||||
* @returns 版权信息
|
||||
*/
|
||||
async getCopyright(siteId: number): Promise<any> {
|
||||
return this.getConfig(siteId, 'COPYRIGHT', {
|
||||
icp: '',
|
||||
gov_record: '',
|
||||
gov_url: '',
|
||||
market_supervision_url: '',
|
||||
logo: '',
|
||||
company_name: '',
|
||||
copyright_link: '',
|
||||
copyright_desc: '',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取场景域名配置
|
||||
* @param siteId 站点ID
|
||||
* @returns 域名配置
|
||||
*/
|
||||
async getSceneDomain(siteId: number): Promise<any> {
|
||||
return this.getConfig(siteId, 'SCENE_DOMAIN', {
|
||||
wap_domain: '',
|
||||
web_domain: '',
|
||||
h5_domain: '',
|
||||
});
|
||||
}
|
||||
}
|
||||
267
wwjcloud/src/common/sys/services/core/CoreExportService.ts
Normal file
267
wwjcloud/src/common/sys/services/core/CoreExportService.ts
Normal file
@@ -0,0 +1,267 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { Repository } from 'typeorm';
|
||||
import { BaseService } from '../../../../core/base/BaseService';
|
||||
import { SysExport } from '../../entities/SysExport';
|
||||
|
||||
/**
|
||||
* 核心导出服务 - Core层
|
||||
* 对应PHP: CoreExportService
|
||||
*/
|
||||
@Injectable()
|
||||
export class CoreExportService extends BaseService<SysExport> {
|
||||
constructor(
|
||||
@InjectRepository(SysExport)
|
||||
private readonly exportRepository: Repository<SysExport>,
|
||||
) {
|
||||
super(exportRepository);
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询导出记录
|
||||
* @param siteId 站点ID
|
||||
* @param exportKey 导出类型过滤
|
||||
* @param exportStatus 导出状态过滤
|
||||
* @param createTime 创建时间过滤
|
||||
* @param page 页码
|
||||
* @param limit 每页数量
|
||||
* @returns 分页结果
|
||||
*/
|
||||
async getPage(
|
||||
siteId: number,
|
||||
exportKey?: string,
|
||||
exportStatus?: number,
|
||||
createTime?: { start?: number; end?: number },
|
||||
page: number = 1,
|
||||
limit: number = 10,
|
||||
) {
|
||||
const queryBuilder = this.exportRepository
|
||||
.createQueryBuilder('export')
|
||||
.where('export.site_id = :siteId', { siteId })
|
||||
.select([
|
||||
'export.id',
|
||||
'export.export_key',
|
||||
'export.export_num',
|
||||
'export.file_path',
|
||||
'export.file_size',
|
||||
'export.export_status',
|
||||
'export.create_time',
|
||||
]);
|
||||
|
||||
if (exportKey) {
|
||||
queryBuilder.andWhere('export.export_key = :exportKey', { exportKey });
|
||||
}
|
||||
|
||||
if (exportStatus !== undefined) {
|
||||
queryBuilder.andWhere('export.export_status = :exportStatus', {
|
||||
exportStatus,
|
||||
});
|
||||
}
|
||||
|
||||
if (createTime?.start) {
|
||||
queryBuilder.andWhere('export.create_time >= :startTime', {
|
||||
startTime: createTime.start,
|
||||
});
|
||||
}
|
||||
|
||||
if (createTime?.end) {
|
||||
queryBuilder.andWhere('export.create_time <= :endTime', {
|
||||
endTime: createTime.end,
|
||||
});
|
||||
}
|
||||
|
||||
const [data, total] = await queryBuilder
|
||||
.orderBy('export.id', 'DESC')
|
||||
.skip((page - 1) * limit)
|
||||
.take(limit)
|
||||
.getManyAndCount();
|
||||
|
||||
// 添加扩展字段
|
||||
const dataWithExtras = data.map((item) => ({
|
||||
...item,
|
||||
export_key_name: item.getExportKeyName(),
|
||||
export_status_name: item.getExportStatusText(),
|
||||
}));
|
||||
|
||||
return {
|
||||
data: dataWithExtras,
|
||||
total,
|
||||
page,
|
||||
limit,
|
||||
pages: Math.ceil(total / limit),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建导出记录
|
||||
* @param siteId 站点ID
|
||||
* @param exportKey 导出类型
|
||||
* @param exportNum 导出数量
|
||||
* @returns 创建的导出记录
|
||||
*/
|
||||
async createExportRecord(
|
||||
siteId: number,
|
||||
exportKey: string,
|
||||
exportNum: number,
|
||||
): Promise<SysExport> {
|
||||
const exportData = {
|
||||
site_id: siteId,
|
||||
export_key: exportKey,
|
||||
export_num: exportNum,
|
||||
export_status: 0, // 处理中
|
||||
create_time: Math.floor(Date.now() / 1000),
|
||||
};
|
||||
|
||||
const exportRecord = this.exportRepository.create(exportData);
|
||||
return await this.exportRepository.save(exportRecord);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新导出记录
|
||||
* @param id 导出记录ID
|
||||
* @param data 更新数据
|
||||
* @returns 是否成功
|
||||
*/
|
||||
async updateExportRecord(
|
||||
id: number,
|
||||
data: Partial<SysExport>,
|
||||
): Promise<boolean> {
|
||||
const updateData = {
|
||||
...data,
|
||||
update_time: Math.floor(Date.now() / 1000),
|
||||
};
|
||||
|
||||
const result = await this.exportRepository.update(id, updateData);
|
||||
return (result.affected || 0) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取导出数据类型列表
|
||||
* @returns 数据类型列表
|
||||
*/
|
||||
getExportDataType(): Record<string, string> {
|
||||
return {
|
||||
member: '会员数据',
|
||||
order: '订单数据',
|
||||
product: '商品数据',
|
||||
finance: '财务数据',
|
||||
stat: '统计数据',
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取导出数据
|
||||
* @param siteId 站点ID
|
||||
* @param type 导出类型
|
||||
* @param where 查询条件
|
||||
* @param page 分页参数
|
||||
* @returns 导出数据
|
||||
*/
|
||||
async getExportData(
|
||||
siteId: number,
|
||||
type: string,
|
||||
where: any = {},
|
||||
page: { page: number; limit: number } = { page: 0, limit: 0 },
|
||||
): Promise<any[]> {
|
||||
// TODO: 根据不同的导出类型获取对应的数据
|
||||
// 这里需要与具体的业务模块配合实现
|
||||
switch (type) {
|
||||
case 'member':
|
||||
return await this.getMemberExportData(siteId, where, page);
|
||||
case 'order':
|
||||
return await this.getOrderExportData(siteId, where, page);
|
||||
case 'product':
|
||||
return await this.getProductExportData(siteId, where, page);
|
||||
default:
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取会员导出数据
|
||||
* @param siteId 站点ID
|
||||
* @param where 查询条件
|
||||
* @param page 分页参数
|
||||
* @returns 会员数据
|
||||
*/
|
||||
private async getMemberExportData(
|
||||
siteId: number,
|
||||
where: any,
|
||||
page: any,
|
||||
): Promise<any[]> {
|
||||
// TODO: 实现会员数据导出逻辑
|
||||
// 需要与member模块配合实现
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取订单导出数据
|
||||
* @param siteId 站点ID
|
||||
* @param where 查询条件
|
||||
* @param page 分页参数
|
||||
* @returns 订单数据
|
||||
*/
|
||||
private async getOrderExportData(
|
||||
siteId: number,
|
||||
where: any,
|
||||
page: any,
|
||||
): Promise<any[]> {
|
||||
// TODO: 实现订单数据导出逻辑
|
||||
// 需要与order模块配合实现
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取商品导出数据
|
||||
* @param siteId 站点ID
|
||||
* @param where 查询条件
|
||||
* @param page 分页参数
|
||||
* @returns 商品数据
|
||||
*/
|
||||
private async getProductExportData(
|
||||
siteId: number,
|
||||
where: any,
|
||||
page: any,
|
||||
): Promise<any[]> {
|
||||
// TODO: 实现商品数据导出逻辑
|
||||
// 需要与product模块配合实现
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除导出记录
|
||||
* @param siteId 站点ID
|
||||
* @param id 导出记录ID
|
||||
* @returns 是否成功
|
||||
*/
|
||||
async deleteExportRecord(siteId: number, id: number): Promise<boolean> {
|
||||
const result = await this.exportRepository.delete({
|
||||
id,
|
||||
site_id: siteId,
|
||||
});
|
||||
return (result.affected || 0) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理过期的导出记录
|
||||
* @param siteId 站点ID
|
||||
* @param expireDays 过期天数
|
||||
* @returns 清理数量
|
||||
*/
|
||||
async cleanExpiredRecords(
|
||||
siteId: number,
|
||||
expireDays: number = 7,
|
||||
): Promise<number> {
|
||||
const expireTime =
|
||||
Math.floor(Date.now() / 1000) - expireDays * 24 * 60 * 60;
|
||||
|
||||
const result = await this.exportRepository
|
||||
.createQueryBuilder()
|
||||
.delete()
|
||||
.where('site_id = :siteId', { siteId })
|
||||
.andWhere('create_time < :expireTime', { expireTime })
|
||||
.execute();
|
||||
|
||||
return result.affected || 0;
|
||||
}
|
||||
}
|
||||
335
wwjcloud/src/common/sys/services/core/CoreMenuService.ts
Normal file
335
wwjcloud/src/common/sys/services/core/CoreMenuService.ts
Normal file
@@ -0,0 +1,335 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { Repository, In, Not } from 'typeorm';
|
||||
import { BaseService } from '../../../../core/base/BaseService';
|
||||
import { SysMenu } from '../../../rbac/entities/SysMenu';
|
||||
|
||||
/**
|
||||
* 核心菜单服务 - Core层
|
||||
* 对应PHP: 菜单核心操作逻辑
|
||||
*/
|
||||
@Injectable()
|
||||
export class CoreMenuService extends BaseService<SysMenu> {
|
||||
constructor(
|
||||
@InjectRepository(SysMenu)
|
||||
private readonly menuRepository: Repository<SysMenu>,
|
||||
) {
|
||||
super(menuRepository);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据menu_key和app_type查找菜单
|
||||
* @param menuKey 菜单键
|
||||
* @param appType 应用类型
|
||||
* @returns 菜单实体或null
|
||||
*/
|
||||
async findByMenuKey(
|
||||
menuKey: string,
|
||||
appType?: string,
|
||||
): Promise<SysMenu | null> {
|
||||
const where: any = { menu_key: menuKey };
|
||||
if (appType) {
|
||||
where.app_type = appType;
|
||||
}
|
||||
return await this.menuRepository.findOne({ where });
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建菜单
|
||||
* @param data 菜单数据
|
||||
* @returns 创建的菜单
|
||||
*/
|
||||
async createMenu(data: Partial<SysMenu>): Promise<SysMenu> {
|
||||
// 检查menu_key是否已存在
|
||||
const existingMenu = await this.findByMenuKey(
|
||||
data.menu_key!,
|
||||
data.app_type,
|
||||
);
|
||||
if (existingMenu) {
|
||||
throw new Error('菜单键已存在');
|
||||
}
|
||||
|
||||
// 设置默认值
|
||||
const menuData = {
|
||||
...data,
|
||||
source: data.source || 'system',
|
||||
sort: data.sort || 1,
|
||||
status: data.status ?? 1,
|
||||
is_show: data.is_show ?? 1,
|
||||
menu_type: data.menu_type || 1,
|
||||
app_type: data.app_type || 'admin',
|
||||
};
|
||||
|
||||
const menu = this.menuRepository.create(menuData);
|
||||
return await this.menuRepository.save(menu);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新菜单
|
||||
* @param appType 应用类型
|
||||
* @param menuKey 菜单键
|
||||
* @param data 更新数据
|
||||
* @returns 是否成功
|
||||
*/
|
||||
async updateMenu(
|
||||
appType: string,
|
||||
menuKey: string,
|
||||
data: Partial<SysMenu>,
|
||||
): Promise<boolean> {
|
||||
const result = await this.menuRepository.update(
|
||||
{ app_type: appType, menu_key: menuKey },
|
||||
data,
|
||||
);
|
||||
return (result.affected || 0) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除菜单
|
||||
* @param appType 应用类型
|
||||
* @param menuKey 菜单键
|
||||
* @returns 是否成功
|
||||
*/
|
||||
async deleteMenu(appType: string, menuKey: string): Promise<boolean> {
|
||||
// 检查是否有子菜单
|
||||
const childCount = await this.menuRepository.count({
|
||||
where: { parent_key: menuKey, app_type: appType },
|
||||
});
|
||||
|
||||
if (childCount > 0) {
|
||||
throw new Error('存在子菜单,无法删除');
|
||||
}
|
||||
|
||||
const result = await this.menuRepository.delete({
|
||||
app_type: appType,
|
||||
menu_key: menuKey,
|
||||
});
|
||||
return (result.affected || 0) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据菜单键数组获取菜单列表
|
||||
* @param siteId 站点ID
|
||||
* @param menuKeys 菜单键数组
|
||||
* @param appType 应用类型
|
||||
* @param addon 插件标识
|
||||
* @param addons 允许的插件列表
|
||||
* @returns 菜单列表
|
||||
*/
|
||||
async getMenusByKeys(
|
||||
siteId: number,
|
||||
menuKeys: string[],
|
||||
appType: string,
|
||||
addon: string = 'all',
|
||||
addons: string[] = [],
|
||||
): Promise<SysMenu[]> {
|
||||
const queryBuilder = this.menuRepository
|
||||
.createQueryBuilder('menu')
|
||||
.where('menu.menu_key IN (:...menuKeys)', { menuKeys })
|
||||
.andWhere('menu.app_type = :appType', { appType });
|
||||
|
||||
// 处理插件过滤
|
||||
if (addon !== 'all') {
|
||||
queryBuilder.andWhere('menu.addon = :addon', { addon });
|
||||
} else if (addons.length > 0) {
|
||||
queryBuilder.andWhere('menu.addon IN (:...addons)', { addons });
|
||||
}
|
||||
|
||||
return await queryBuilder
|
||||
.orderBy('menu.sort', 'DESC')
|
||||
.addOrderBy('menu.id', 'ASC')
|
||||
.getMany();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有API菜单
|
||||
* @param appType 应用类型
|
||||
* @param addon 插件标识
|
||||
* @returns API菜单列表
|
||||
*/
|
||||
async getAllApiMenus(
|
||||
appType: string = 'admin',
|
||||
addon: string = '',
|
||||
): Promise<SysMenu[]> {
|
||||
const where: any = {
|
||||
app_type: appType,
|
||||
menu_type: In([1, 2]), // 菜单和按钮
|
||||
};
|
||||
|
||||
if (addon !== 'all') {
|
||||
where.addon = addon;
|
||||
}
|
||||
|
||||
return await this.menuRepository.find({
|
||||
where,
|
||||
order: { sort: 'DESC', id: 'ASC' },
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取系统菜单
|
||||
* @param status 状态过滤
|
||||
* @param isButton 是否包含按钮
|
||||
* @returns 系统菜单列表
|
||||
*/
|
||||
async getSystemMenus(
|
||||
status: string | number = 'all',
|
||||
isButton: number = 0,
|
||||
): Promise<SysMenu[]> {
|
||||
const queryBuilder = this.menuRepository
|
||||
.createQueryBuilder('menu')
|
||||
.where('menu.addon = :addon', { addon: '' });
|
||||
|
||||
// 状态过滤
|
||||
if (status !== 'all') {
|
||||
queryBuilder.andWhere('menu.status = :status', { status });
|
||||
}
|
||||
|
||||
// 按钮过滤
|
||||
if (isButton === 0) {
|
||||
queryBuilder.andWhere('menu.menu_type IN (:...types)', { types: [0, 1] });
|
||||
}
|
||||
|
||||
return await queryBuilder
|
||||
.orderBy('menu.sort', 'DESC')
|
||||
.addOrderBy('menu.id', 'ASC')
|
||||
.getMany();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取插件菜单
|
||||
* @param appKey 插件键
|
||||
* @param status 状态过滤
|
||||
* @param isButton 是否包含按钮
|
||||
* @returns 插件菜单列表
|
||||
*/
|
||||
async getAddonMenus(
|
||||
appKey: string,
|
||||
status: string | number = 'all',
|
||||
isButton: number = 0,
|
||||
): Promise<SysMenu[]> {
|
||||
const queryBuilder = this.menuRepository
|
||||
.createQueryBuilder('menu')
|
||||
.where('menu.addon = :addon', { addon: appKey });
|
||||
|
||||
// 状态过滤
|
||||
if (status !== 'all') {
|
||||
queryBuilder.andWhere('menu.status = :status', { status });
|
||||
}
|
||||
|
||||
// 按钮过滤
|
||||
if (isButton === 0) {
|
||||
queryBuilder.andWhere('menu.menu_type IN (:...types)', { types: [0, 1] });
|
||||
}
|
||||
|
||||
return await queryBuilder
|
||||
.orderBy('menu.sort', 'DESC')
|
||||
.addOrderBy('menu.id', 'ASC')
|
||||
.getMany();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取目录类型菜单
|
||||
* @param addon 插件标识
|
||||
* @returns 目录菜单列表
|
||||
*/
|
||||
async getMenusByTypeDir(addon: string = 'system'): Promise<SysMenu[]> {
|
||||
const addonValue = addon === 'system' ? '' : addon;
|
||||
|
||||
return await this.menuRepository.find({
|
||||
where: {
|
||||
menu_type: 0, // 目录类型
|
||||
app_type: 'site',
|
||||
addon: addonValue,
|
||||
},
|
||||
order: { sort: 'DESC', id: 'ASC' },
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据系统配置获取菜单键列表
|
||||
* @param appType 应用类型
|
||||
* @param addons 插件列表
|
||||
* @returns 菜单键数组
|
||||
*/
|
||||
async getMenuKeysBySystem(
|
||||
appType: string,
|
||||
addons: string[],
|
||||
): Promise<string[]> {
|
||||
const queryBuilder = this.menuRepository
|
||||
.createQueryBuilder('menu')
|
||||
.select('menu.menu_key')
|
||||
.where('menu.addon IN (:...addons)', { addons: [...addons, ''] });
|
||||
|
||||
if (appType) {
|
||||
queryBuilder.andWhere('menu.app_type = :appType', { appType });
|
||||
}
|
||||
|
||||
const menus = await queryBuilder.orderBy('menu.sort', 'DESC').getMany();
|
||||
|
||||
return menus.map((menu) => menu.menu_key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建菜单树形结构
|
||||
* @param menus 菜单列表
|
||||
* @param keyField 键字段
|
||||
* @param parentKeyField 父键字段
|
||||
* @param childrenField 子节点字段名
|
||||
* @param parentKey 父键值
|
||||
* @param isButton 是否包含按钮
|
||||
* @returns 树形菜单结构
|
||||
*/
|
||||
buildMenuTree(
|
||||
menus: any[],
|
||||
keyField: string = 'menu_key',
|
||||
parentKeyField: string = 'parent_key',
|
||||
childrenField: string = 'children',
|
||||
parentKey: string = '',
|
||||
isButton: number = 1,
|
||||
): any[] {
|
||||
const tree: any[] = [];
|
||||
const menuMap = new Map();
|
||||
|
||||
// 创建菜单映射
|
||||
menus.forEach((menu) => {
|
||||
menuMap.set(menu[keyField], { ...menu, [childrenField]: [] });
|
||||
});
|
||||
|
||||
// 构建树形结构
|
||||
menus.forEach((menu) => {
|
||||
const menuItem = menuMap.get(menu[keyField]);
|
||||
if (menu[parentKeyField] === parentKey || !menu[parentKeyField]) {
|
||||
tree.push(menuItem);
|
||||
} else {
|
||||
const parent = menuMap.get(menu[parentKeyField]);
|
||||
if (parent) {
|
||||
parent[childrenField].push(menuItem);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 如果不包含按钮,过滤掉按钮类型的菜单
|
||||
if (isButton === 0) {
|
||||
return this.filterButtonsFromTree(tree, childrenField);
|
||||
}
|
||||
|
||||
return tree;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从树形结构中过滤掉按钮
|
||||
* @param tree 树形菜单
|
||||
* @param childrenField 子节点字段名
|
||||
* @returns 过滤后的树形结构
|
||||
*/
|
||||
private filterButtonsFromTree(tree: any[], childrenField: string): any[] {
|
||||
return tree
|
||||
.filter((item) => item.menu_type !== 2) // 过滤掉按钮类型
|
||||
.map((item) => ({
|
||||
...item,
|
||||
[childrenField]: item[childrenField]
|
||||
? this.filterButtonsFromTree(item[childrenField], childrenField)
|
||||
: [],
|
||||
}));
|
||||
}
|
||||
}
|
||||
252
wwjcloud/src/common/sys/services/core/CorePosterService.ts
Normal file
252
wwjcloud/src/common/sys/services/core/CorePosterService.ts
Normal file
@@ -0,0 +1,252 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { Repository } from 'typeorm';
|
||||
import { BaseService } from '../../../../core/base/BaseService';
|
||||
import { SysPoster } from '../../entities/SysPoster';
|
||||
|
||||
/**
|
||||
* 核心海报服务 - Core层
|
||||
* 对应PHP: CorePosterService
|
||||
*/
|
||||
@Injectable()
|
||||
export class CorePosterService extends BaseService<SysPoster> {
|
||||
constructor(
|
||||
@InjectRepository(SysPoster)
|
||||
private readonly posterRepository: Repository<SysPoster>,
|
||||
) {
|
||||
super(posterRepository);
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询海报列表
|
||||
* @param siteId 站点ID
|
||||
* @param name 海报名称过滤
|
||||
* @param type 海报类型过滤
|
||||
* @param page 页码
|
||||
* @param limit 每页数量
|
||||
* @returns 分页结果
|
||||
*/
|
||||
async getPage(
|
||||
siteId: number,
|
||||
name?: string,
|
||||
type?: string,
|
||||
page: number = 1,
|
||||
limit: number = 10,
|
||||
) {
|
||||
const queryBuilder = this.posterRepository
|
||||
.createQueryBuilder('poster')
|
||||
.where('poster.site_id = :siteId', { siteId })
|
||||
.select([
|
||||
'poster.id',
|
||||
'poster.name',
|
||||
'poster.type',
|
||||
'poster.channel',
|
||||
'poster.status',
|
||||
'poster.is_default',
|
||||
'poster.create_time',
|
||||
'poster.update_time',
|
||||
'poster.addon',
|
||||
]);
|
||||
|
||||
if (name) {
|
||||
queryBuilder.andWhere('poster.name LIKE :name', { name: `%${name}%` });
|
||||
}
|
||||
|
||||
if (type) {
|
||||
queryBuilder.andWhere('poster.type = :type', { type });
|
||||
}
|
||||
|
||||
const [data, total] = await queryBuilder
|
||||
.orderBy('poster.update_time', 'DESC')
|
||||
.skip((page - 1) * limit)
|
||||
.take(limit)
|
||||
.getManyAndCount();
|
||||
|
||||
// 添加type_name字段
|
||||
const dataWithTypeName = data.map((poster) => ({
|
||||
...poster,
|
||||
type_name: poster.getTypeName(),
|
||||
}));
|
||||
|
||||
return {
|
||||
data: dataWithTypeName,
|
||||
total,
|
||||
page,
|
||||
limit,
|
||||
pages: Math.ceil(total / limit),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取海报列表(不分页)
|
||||
* @param siteId 站点ID
|
||||
* @param name 海报名称过滤
|
||||
* @param type 海报类型过滤
|
||||
* @returns 海报列表
|
||||
*/
|
||||
async getList(
|
||||
siteId: number,
|
||||
name?: string,
|
||||
type?: string,
|
||||
): Promise<SysPoster[]> {
|
||||
const queryBuilder = this.posterRepository
|
||||
.createQueryBuilder('poster')
|
||||
.where('poster.site_id = :siteId', { siteId })
|
||||
.select([
|
||||
'poster.id',
|
||||
'poster.name',
|
||||
'poster.type',
|
||||
'poster.channel',
|
||||
'poster.value',
|
||||
'poster.status',
|
||||
'poster.is_default',
|
||||
'poster.create_time',
|
||||
'poster.update_time',
|
||||
'poster.addon',
|
||||
]);
|
||||
|
||||
if (name) {
|
||||
queryBuilder.andWhere('poster.name LIKE :name', { name: `%${name}%` });
|
||||
}
|
||||
|
||||
if (type) {
|
||||
queryBuilder.andWhere('poster.type = :type', { type });
|
||||
}
|
||||
|
||||
return await queryBuilder.orderBy('poster.update_time', 'DESC').getMany();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取海报详情
|
||||
* @param siteId 站点ID
|
||||
* @param id 海报ID
|
||||
* @returns 海报信息
|
||||
*/
|
||||
async getInfo(siteId: number, id: number): Promise<SysPoster | null> {
|
||||
return await this.posterRepository.findOne({
|
||||
where: { id, site_id: siteId },
|
||||
select: [
|
||||
'id',
|
||||
'name',
|
||||
'type',
|
||||
'channel',
|
||||
'value',
|
||||
'status',
|
||||
'is_default',
|
||||
'create_time',
|
||||
'update_time',
|
||||
'addon',
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加海报
|
||||
* @param data 海报数据
|
||||
* @returns 创建的海报
|
||||
*/
|
||||
async add(data: Partial<SysPoster>): Promise<SysPoster> {
|
||||
const posterData = {
|
||||
...data,
|
||||
create_time: Math.floor(Date.now() / 1000),
|
||||
update_time: Math.floor(Date.now() / 1000),
|
||||
};
|
||||
|
||||
const poster = this.posterRepository.create(posterData);
|
||||
return await this.posterRepository.save(poster);
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑海报
|
||||
* @param siteId 站点ID
|
||||
* @param id 海报ID
|
||||
* @param data 更新数据
|
||||
* @returns 是否成功
|
||||
*/
|
||||
async edit(
|
||||
siteId: number,
|
||||
id: number,
|
||||
data: Partial<SysPoster>,
|
||||
): Promise<boolean> {
|
||||
const updateData = {
|
||||
...data,
|
||||
update_time: Math.floor(Date.now() / 1000),
|
||||
};
|
||||
|
||||
const result = await this.posterRepository.update(
|
||||
{ id, site_id: siteId },
|
||||
updateData,
|
||||
);
|
||||
return (result.affected || 0) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除海报
|
||||
* @param siteId 站点ID
|
||||
* @param id 海报ID
|
||||
* @returns 是否成功
|
||||
*/
|
||||
async del(siteId: number, id: number): Promise<boolean> {
|
||||
const result = await this.posterRepository.delete({
|
||||
id,
|
||||
site_id: siteId,
|
||||
});
|
||||
return (result.affected || 0) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置默认海报
|
||||
* @param siteId 站点ID
|
||||
* @param id 海报ID
|
||||
* @param type 海报类型
|
||||
* @returns 是否成功
|
||||
*/
|
||||
async setDefault(siteId: number, id: number, type: string): Promise<boolean> {
|
||||
// 先取消该类型的所有默认设置
|
||||
await this.posterRepository.update(
|
||||
{ site_id: siteId, type },
|
||||
{ is_default: 0, update_time: Math.floor(Date.now() / 1000) },
|
||||
);
|
||||
|
||||
// 设置新的默认海报
|
||||
const result = await this.posterRepository.update(
|
||||
{ id, site_id: siteId },
|
||||
{ is_default: 1, update_time: Math.floor(Date.now() / 1000) },
|
||||
);
|
||||
|
||||
return (result.affected || 0) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据类型获取默认海报
|
||||
* @param siteId 站点ID
|
||||
* @param type 海报类型
|
||||
* @returns 默认海报
|
||||
*/
|
||||
async getDefaultByType(
|
||||
siteId: number,
|
||||
type: string,
|
||||
): Promise<SysPoster | null> {
|
||||
return await this.posterRepository.findOne({
|
||||
where: {
|
||||
site_id: siteId,
|
||||
type,
|
||||
is_default: 1,
|
||||
status: 1,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取海报类型列表
|
||||
* @returns 海报类型映射
|
||||
*/
|
||||
getPosterTypes(): Record<string, string> {
|
||||
return {
|
||||
member_card: '会员卡',
|
||||
goods_poster: '商品海报',
|
||||
share_poster: '分享海报',
|
||||
qrcode_poster: '二维码海报',
|
||||
};
|
||||
}
|
||||
}
|
||||
252
wwjcloud/src/common/sys/services/core/CorePrinterService.ts
Normal file
252
wwjcloud/src/common/sys/services/core/CorePrinterService.ts
Normal file
@@ -0,0 +1,252 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { Repository } from 'typeorm';
|
||||
import { BaseService } from '../../../../core/base/BaseService';
|
||||
import { SysPrinter } from '../../entities/SysPrinter';
|
||||
|
||||
/**
|
||||
* 核心打印机服务 - Core层
|
||||
* 对应PHP: CorePrinterService
|
||||
*/
|
||||
@Injectable()
|
||||
export class CorePrinterService extends BaseService<SysPrinter> {
|
||||
constructor(
|
||||
@InjectRepository(SysPrinter)
|
||||
private readonly printerRepository: Repository<SysPrinter>,
|
||||
) {
|
||||
super(printerRepository);
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询打印机列表
|
||||
* @param siteId 站点ID
|
||||
* @param printerName 打印机名称过滤
|
||||
* @param page 页码
|
||||
* @param limit 每页数量
|
||||
* @returns 分页结果
|
||||
*/
|
||||
async getPage(
|
||||
siteId: number,
|
||||
printerName?: string,
|
||||
page: number = 1,
|
||||
limit: number = 10,
|
||||
) {
|
||||
const queryBuilder = this.printerRepository
|
||||
.createQueryBuilder('printer')
|
||||
.where('printer.site_id = :siteId', { siteId })
|
||||
.select([
|
||||
'printer.printer_id',
|
||||
'printer.brand',
|
||||
'printer.printer_name',
|
||||
'printer.printer_code',
|
||||
'printer.printer_key',
|
||||
'printer.open_id',
|
||||
'printer.apikey',
|
||||
'printer.print_width',
|
||||
'printer.status',
|
||||
'printer.create_time',
|
||||
]);
|
||||
|
||||
if (printerName) {
|
||||
queryBuilder.andWhere('printer.printer_name LIKE :printerName', {
|
||||
printerName: `%${printerName}%`,
|
||||
});
|
||||
}
|
||||
|
||||
const [data, total] = await queryBuilder
|
||||
.orderBy('printer.create_time', 'DESC')
|
||||
.skip((page - 1) * limit)
|
||||
.take(limit)
|
||||
.getManyAndCount();
|
||||
|
||||
// 添加brand_name字段
|
||||
const dataWithBrandName = data.map((printer) => ({
|
||||
...printer,
|
||||
brand_name: printer.getBrandName(),
|
||||
}));
|
||||
|
||||
return {
|
||||
data: dataWithBrandName,
|
||||
total,
|
||||
page,
|
||||
limit,
|
||||
pages: Math.ceil(total / limit),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取打印机列表(不分页)
|
||||
* @param siteId 站点ID
|
||||
* @param where 查询条件
|
||||
* @returns 打印机列表
|
||||
*/
|
||||
async getList(siteId: number, where: any = {}): Promise<SysPrinter[]> {
|
||||
const queryBuilder = this.printerRepository
|
||||
.createQueryBuilder('printer')
|
||||
.where('printer.site_id = :siteId', { siteId })
|
||||
.select([
|
||||
'printer.printer_id',
|
||||
'printer.brand',
|
||||
'printer.printer_name',
|
||||
'printer.printer_code',
|
||||
'printer.printer_key',
|
||||
'printer.open_id',
|
||||
'printer.apikey',
|
||||
'printer.print_width',
|
||||
'printer.status',
|
||||
'printer.create_time',
|
||||
]);
|
||||
|
||||
if (where.printer_name) {
|
||||
queryBuilder.andWhere('printer.printer_name LIKE :printerName', {
|
||||
printerName: `%${where.printer_name}%`,
|
||||
});
|
||||
}
|
||||
|
||||
return await queryBuilder.orderBy('printer.create_time', 'DESC').getMany();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取打印机详情
|
||||
* @param siteId 站点ID
|
||||
* @param printerId 打印机ID
|
||||
* @returns 打印机信息
|
||||
*/
|
||||
async getInfo(siteId: number, printerId: number): Promise<SysPrinter | null> {
|
||||
return await this.printerRepository.findOne({
|
||||
where: { printer_id: printerId, site_id: siteId },
|
||||
select: [
|
||||
'printer_id',
|
||||
'brand',
|
||||
'printer_name',
|
||||
'printer_code',
|
||||
'printer_key',
|
||||
'open_id',
|
||||
'apikey',
|
||||
'value',
|
||||
'print_width',
|
||||
'status',
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加打印机
|
||||
* @param data 打印机数据
|
||||
* @returns 创建的打印机
|
||||
*/
|
||||
async add(data: Partial<SysPrinter>): Promise<SysPrinter> {
|
||||
const printerData = {
|
||||
...data,
|
||||
create_time: Math.floor(Date.now() / 1000),
|
||||
};
|
||||
|
||||
const printer = this.printerRepository.create(printerData);
|
||||
return await this.printerRepository.save(printer);
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑打印机
|
||||
* @param siteId 站点ID
|
||||
* @param printerId 打印机ID
|
||||
* @param data 更新数据
|
||||
* @returns 是否成功
|
||||
*/
|
||||
async edit(
|
||||
siteId: number,
|
||||
printerId: number,
|
||||
data: Partial<SysPrinter>,
|
||||
): Promise<boolean> {
|
||||
const updateData = {
|
||||
...data,
|
||||
update_time: Math.floor(Date.now() / 1000),
|
||||
};
|
||||
|
||||
const result = await this.printerRepository.update(
|
||||
{ printer_id: printerId, site_id: siteId },
|
||||
updateData,
|
||||
);
|
||||
return (result.affected || 0) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除打印机
|
||||
* @param siteId 站点ID
|
||||
* @param printerId 打印机ID
|
||||
* @returns 是否成功
|
||||
*/
|
||||
async del(siteId: number, printerId: number): Promise<boolean> {
|
||||
const result = await this.printerRepository.delete({
|
||||
printer_id: printerId,
|
||||
site_id: siteId,
|
||||
});
|
||||
return (result.affected || 0) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改打印机状态
|
||||
* @param siteId 站点ID
|
||||
* @param printerId 打印机ID
|
||||
* @param status 状态
|
||||
* @returns 是否成功
|
||||
*/
|
||||
async modifyStatus(
|
||||
siteId: number,
|
||||
printerId: number,
|
||||
status: number,
|
||||
): Promise<boolean> {
|
||||
const result = await this.printerRepository.update(
|
||||
{ printer_id: printerId, site_id: siteId },
|
||||
{ status, update_time: Math.floor(Date.now() / 1000) },
|
||||
);
|
||||
return (result.affected || 0) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试打印机连接
|
||||
* @param siteId 站点ID
|
||||
* @param printerId 打印机ID
|
||||
* @returns 测试结果
|
||||
*/
|
||||
async testPrinter(
|
||||
siteId: number,
|
||||
printerId: number,
|
||||
): Promise<{ success: boolean; message: string }> {
|
||||
const printer = await this.getInfo(siteId, printerId);
|
||||
if (!printer) {
|
||||
return { success: false, message: '打印机不存在' };
|
||||
}
|
||||
|
||||
// TODO: 实现实际的打印机连接测试逻辑
|
||||
// 根据不同品牌调用相应的API进行测试
|
||||
|
||||
return { success: true, message: '连接成功' };
|
||||
}
|
||||
|
||||
/**
|
||||
* 打印内容
|
||||
* @param siteId 站点ID
|
||||
* @param printerId 打印机ID
|
||||
* @param content 打印内容
|
||||
* @returns 打印结果
|
||||
*/
|
||||
async print(
|
||||
siteId: number,
|
||||
printerId: number,
|
||||
content: string,
|
||||
): Promise<{ success: boolean; message: string }> {
|
||||
const printer = await this.getInfo(siteId, printerId);
|
||||
if (!printer) {
|
||||
return { success: false, message: '打印机不存在' };
|
||||
}
|
||||
|
||||
if (printer.status !== 1) {
|
||||
return { success: false, message: '打印机已禁用' };
|
||||
}
|
||||
|
||||
// TODO: 实现实际的打印逻辑
|
||||
// 根据不同品牌调用相应的API进行打印
|
||||
|
||||
return { success: true, message: '打印成功' };
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,239 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { Repository } from 'typeorm';
|
||||
import { BaseService } from '../../../../core/base/BaseService';
|
||||
import { SysPrinterTemplate } from '../../entities/SysPrinterTemplate';
|
||||
|
||||
/**
|
||||
* 核心打印模板服务 - Core层
|
||||
* 对应PHP: 打印模板核心逻辑
|
||||
*/
|
||||
@Injectable()
|
||||
export class CorePrinterTemplateService extends BaseService<SysPrinterTemplate> {
|
||||
constructor(
|
||||
@InjectRepository(SysPrinterTemplate)
|
||||
private readonly templateRepository: Repository<SysPrinterTemplate>,
|
||||
) {
|
||||
super(templateRepository);
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询打印模板列表
|
||||
* @param siteId 站点ID
|
||||
* @param templateId 模板ID过滤
|
||||
* @param templateType 模板类型过滤
|
||||
* @param templateName 模板名称过滤
|
||||
* @param page 页码
|
||||
* @param limit 每页数量
|
||||
* @returns 分页结果
|
||||
*/
|
||||
async getPage(
|
||||
siteId: number,
|
||||
templateId?: number,
|
||||
templateType?: string,
|
||||
templateName?: string,
|
||||
page: number = 1,
|
||||
limit: number = 10,
|
||||
) {
|
||||
const queryBuilder = this.templateRepository
|
||||
.createQueryBuilder('template')
|
||||
.where('template.site_id = :siteId', { siteId })
|
||||
.select([
|
||||
'template.template_id',
|
||||
'template.template_type',
|
||||
'template.template_name',
|
||||
'template.value',
|
||||
'template.create_time',
|
||||
]);
|
||||
|
||||
if (templateId) {
|
||||
queryBuilder.andWhere('template.template_id = :templateId', {
|
||||
templateId,
|
||||
});
|
||||
}
|
||||
|
||||
if (templateType) {
|
||||
queryBuilder.andWhere('template.template_type = :templateType', {
|
||||
templateType,
|
||||
});
|
||||
}
|
||||
|
||||
if (templateName) {
|
||||
queryBuilder.andWhere('template.template_name LIKE :templateName', {
|
||||
templateName: `%${templateName}%`,
|
||||
});
|
||||
}
|
||||
|
||||
const [data, total] = await queryBuilder
|
||||
.orderBy('template.create_time', 'DESC')
|
||||
.skip((page - 1) * limit)
|
||||
.take(limit)
|
||||
.getManyAndCount();
|
||||
|
||||
// 添加template_type_name字段
|
||||
const dataWithTypeName = data.map((template) => ({
|
||||
...template,
|
||||
template_type_name: template.getTemplateTypeName(),
|
||||
}));
|
||||
|
||||
return {
|
||||
data: dataWithTypeName,
|
||||
total,
|
||||
page,
|
||||
limit,
|
||||
pages: Math.ceil(total / limit),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取打印模板列表(不分页)
|
||||
* @param siteId 站点ID
|
||||
* @param where 查询条件
|
||||
* @returns 模板列表
|
||||
*/
|
||||
async getList(
|
||||
siteId: number,
|
||||
where: any = {},
|
||||
): Promise<SysPrinterTemplate[]> {
|
||||
const queryBuilder = this.templateRepository
|
||||
.createQueryBuilder('template')
|
||||
.where('template.site_id = :siteId', { siteId })
|
||||
.select([
|
||||
'template.template_id',
|
||||
'template.template_type',
|
||||
'template.template_name',
|
||||
'template.value',
|
||||
'template.create_time',
|
||||
]);
|
||||
|
||||
if (where.template_id) {
|
||||
queryBuilder.andWhere('template.template_id = :templateId', {
|
||||
templateId: where.template_id,
|
||||
});
|
||||
}
|
||||
|
||||
if (where.template_type) {
|
||||
queryBuilder.andWhere('template.template_type = :templateType', {
|
||||
templateType: where.template_type,
|
||||
});
|
||||
}
|
||||
|
||||
if (where.template_name) {
|
||||
queryBuilder.andWhere('template.template_name LIKE :templateName', {
|
||||
templateName: `%${where.template_name}%`,
|
||||
});
|
||||
}
|
||||
|
||||
const templates = await queryBuilder
|
||||
.orderBy('template.create_time', 'DESC')
|
||||
.getMany();
|
||||
|
||||
// 添加template_type_name字段
|
||||
return templates.map((template) => ({
|
||||
...template,
|
||||
template_type_name: template.getTemplateTypeName(),
|
||||
})) as any;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取打印模板详情
|
||||
* @param siteId 站点ID
|
||||
* @param templateId 模板ID
|
||||
* @returns 模板信息
|
||||
*/
|
||||
async getInfo(
|
||||
siteId: number,
|
||||
templateId: number,
|
||||
): Promise<SysPrinterTemplate | null> {
|
||||
return await this.templateRepository.findOne({
|
||||
where: { template_id: templateId, site_id: siteId },
|
||||
select: ['template_id', 'template_type', 'template_name', 'value'],
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加打印模板
|
||||
* @param data 模板数据
|
||||
* @returns 创建的模板
|
||||
*/
|
||||
async add(data: Partial<SysPrinterTemplate>): Promise<SysPrinterTemplate> {
|
||||
const templateData = {
|
||||
...data,
|
||||
create_time: Math.floor(Date.now() / 1000),
|
||||
};
|
||||
|
||||
const template = this.templateRepository.create(templateData);
|
||||
return await this.templateRepository.save(template);
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑打印模板
|
||||
* @param siteId 站点ID
|
||||
* @param templateId 模板ID
|
||||
* @param data 更新数据
|
||||
* @returns 是否成功
|
||||
*/
|
||||
async edit(
|
||||
siteId: number,
|
||||
templateId: number,
|
||||
data: Partial<SysPrinterTemplate>,
|
||||
): Promise<boolean> {
|
||||
const updateData = {
|
||||
...data,
|
||||
update_time: Math.floor(Date.now() / 1000),
|
||||
};
|
||||
|
||||
const result = await this.templateRepository.update(
|
||||
{ template_id: templateId, site_id: siteId },
|
||||
updateData,
|
||||
);
|
||||
return (result.affected || 0) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除打印模板
|
||||
* @param siteId 站点ID
|
||||
* @param templateId 模板ID
|
||||
* @returns 是否成功
|
||||
*/
|
||||
async del(siteId: number, templateId: number): Promise<boolean> {
|
||||
const result = await this.templateRepository.delete({
|
||||
template_id: templateId,
|
||||
site_id: siteId,
|
||||
});
|
||||
return (result.affected || 0) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据类型获取模板
|
||||
* @param siteId 站点ID
|
||||
* @param templateType 模板类型
|
||||
* @returns 模板列表
|
||||
*/
|
||||
async getTemplatesByType(
|
||||
siteId: number,
|
||||
templateType: string,
|
||||
): Promise<SysPrinterTemplate[]> {
|
||||
return await this.templateRepository.find({
|
||||
where: {
|
||||
site_id: siteId,
|
||||
template_type: templateType,
|
||||
},
|
||||
select: ['template_id', 'template_name', 'template_type', 'value'],
|
||||
order: { create_time: 'DESC' },
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取模板类型列表
|
||||
* @returns 模板类型映射
|
||||
*/
|
||||
getTemplateTypes(): Record<string, string> {
|
||||
return {
|
||||
order: '订单模板',
|
||||
receipt: '收据模板',
|
||||
refund: '退款模板',
|
||||
custom: '自定义模板',
|
||||
};
|
||||
}
|
||||
}
|
||||
275
wwjcloud/src/common/sys/services/core/CoreRoleService.ts
Normal file
275
wwjcloud/src/common/sys/services/core/CoreRoleService.ts
Normal file
@@ -0,0 +1,275 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { Repository, In } from 'typeorm';
|
||||
import { BaseService } from '../../../../core/base/BaseService';
|
||||
import { SysRole } from '../../../rbac/entities/SysRole';
|
||||
|
||||
/**
|
||||
* 核心角色服务 - Core层
|
||||
* 对应PHP: 角色核心操作逻辑
|
||||
*/
|
||||
@Injectable()
|
||||
export class CoreRoleService extends BaseService<SysRole> {
|
||||
constructor(
|
||||
@InjectRepository(SysRole)
|
||||
private readonly roleRepository: Repository<SysRole>,
|
||||
) {
|
||||
super(roleRepository);
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询角色列表
|
||||
* @param siteId 站点ID
|
||||
* @param roleName 角色名称过滤
|
||||
* @param page 页码
|
||||
* @param limit 每页数量
|
||||
* @returns 分页结果
|
||||
*/
|
||||
async getPage(
|
||||
siteId: number,
|
||||
roleName?: string,
|
||||
page: number = 1,
|
||||
limit: number = 10,
|
||||
) {
|
||||
const queryBuilder = this.roleRepository
|
||||
.createQueryBuilder('role')
|
||||
.where('role.site_id = :siteId', { siteId })
|
||||
.select([
|
||||
'role.role_id',
|
||||
'role.role_name',
|
||||
'role.status',
|
||||
'role.create_time',
|
||||
]);
|
||||
|
||||
if (roleName) {
|
||||
queryBuilder.andWhere('role.role_name LIKE :roleName', {
|
||||
roleName: `%${roleName}%`,
|
||||
});
|
||||
}
|
||||
|
||||
const [data, total] = await queryBuilder
|
||||
.orderBy('role.create_time', 'DESC')
|
||||
.skip((page - 1) * limit)
|
||||
.take(limit)
|
||||
.getManyAndCount();
|
||||
|
||||
// 添加status_name字段
|
||||
const dataWithStatus = data.map((role) => ({
|
||||
...role,
|
||||
status_name: role.getStatusText(),
|
||||
}));
|
||||
|
||||
return {
|
||||
data: dataWithStatus,
|
||||
total,
|
||||
page,
|
||||
limit,
|
||||
pages: Math.ceil(total / limit),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取角色详情
|
||||
* @param roleId 角色ID
|
||||
* @returns 角色信息
|
||||
*/
|
||||
async getInfo(roleId: number): Promise<SysRole | null> {
|
||||
const role = await this.roleRepository.findOne({
|
||||
where: { role_id: roleId },
|
||||
});
|
||||
if (role) {
|
||||
// 添加status_name字段
|
||||
(role as any).status_name = role.getStatusText();
|
||||
}
|
||||
return role;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取站点下的所有启用角色
|
||||
* @param siteId 站点ID
|
||||
* @returns 角色列表
|
||||
*/
|
||||
async getAll(siteId: number): Promise<SysRole[]> {
|
||||
return await this.roleRepository.find({
|
||||
where: {
|
||||
site_id: siteId,
|
||||
status: 1,
|
||||
},
|
||||
select: ['role_id', 'role_name', 'rules', 'status', 'create_time'],
|
||||
order: { create_time: 'DESC' },
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建角色
|
||||
* @param data 角色数据
|
||||
* @returns 创建的角色
|
||||
*/
|
||||
async add(data: Partial<SysRole>): Promise<SysRole> {
|
||||
const roleData = {
|
||||
...data,
|
||||
create_time: Math.floor(Date.now() / 1000),
|
||||
};
|
||||
|
||||
const role = this.roleRepository.create(roleData);
|
||||
return await this.roleRepository.save(role);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新角色
|
||||
* @param roleId 角色ID
|
||||
* @param siteId 站点ID
|
||||
* @param data 更新数据
|
||||
* @returns 是否成功
|
||||
*/
|
||||
async edit(
|
||||
roleId: number,
|
||||
siteId: number,
|
||||
data: Partial<SysRole>,
|
||||
): Promise<boolean> {
|
||||
const updateData = {
|
||||
...data,
|
||||
update_time: Math.floor(Date.now() / 1000),
|
||||
};
|
||||
|
||||
const result = await this.roleRepository.update(
|
||||
{ role_id: roleId, site_id: siteId },
|
||||
updateData,
|
||||
);
|
||||
return (result.affected || 0) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改角色状态
|
||||
* @param roleId 角色ID
|
||||
* @param siteId 站点ID
|
||||
* @param status 状态
|
||||
* @returns 是否成功
|
||||
*/
|
||||
async modifyStatus(
|
||||
roleId: number,
|
||||
siteId: number,
|
||||
status: number,
|
||||
): Promise<boolean> {
|
||||
const result = await this.roleRepository.update(
|
||||
{ role_id: roleId, site_id: siteId },
|
||||
{ status },
|
||||
);
|
||||
return (result.affected || 0) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找角色
|
||||
* @param siteId 站点ID
|
||||
* @param roleId 角色ID
|
||||
* @returns 角色实体
|
||||
*/
|
||||
async find(siteId: number, roleId: number): Promise<SysRole | null> {
|
||||
return await this.roleRepository.findOne({
|
||||
where: { role_id: roleId, site_id: siteId },
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除角色
|
||||
* @param roleId 角色ID
|
||||
* @param siteId 站点ID
|
||||
* @returns 是否成功
|
||||
*/
|
||||
async del(roleId: number, siteId: number): Promise<boolean> {
|
||||
// 检查是否有用户使用该角色
|
||||
// TODO: 需要实现SysUserRole实体和检查逻辑
|
||||
// 暂时跳过用户角色关联检查,后续完善用户模块时补充
|
||||
|
||||
const result = await this.roleRepository.delete({
|
||||
role_id: roleId,
|
||||
site_id: siteId,
|
||||
});
|
||||
return (result.affected || 0) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取角色ID和名称的键值对
|
||||
* @param siteId 站点ID
|
||||
* @returns 角色键值对
|
||||
*/
|
||||
async getColumn(siteId: number): Promise<Record<number, string>> {
|
||||
const roles = await this.roleRepository.find({
|
||||
where: { site_id: siteId },
|
||||
select: ['role_id', 'role_name'],
|
||||
});
|
||||
|
||||
const result: Record<number, string> = {};
|
||||
roles.forEach((role) => {
|
||||
result[role.role_id] = role.role_name;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过角色ID数组获取菜单权限
|
||||
* @param siteId 站点ID
|
||||
* @param roleIds 角色ID数组
|
||||
* @param allowMenuKeys 允许的菜单键列表
|
||||
* @returns 菜单键数组
|
||||
*/
|
||||
async getMenuIdsByRoleIds(
|
||||
siteId: number,
|
||||
roleIds: number[],
|
||||
allowMenuKeys: string[] = [],
|
||||
): Promise<string[]> {
|
||||
const roles = await this.roleRepository.find({
|
||||
where: {
|
||||
role_id: In(roleIds),
|
||||
status: 1,
|
||||
},
|
||||
select: ['rules'],
|
||||
});
|
||||
|
||||
if (!roles.length) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// 合并所有角色的权限
|
||||
let allRules: string[] = [];
|
||||
roles.forEach((role) => {
|
||||
if (role.rules) {
|
||||
try {
|
||||
const rules = JSON.parse(role.rules);
|
||||
if (Array.isArray(rules)) {
|
||||
allRules = allRules.concat(rules);
|
||||
}
|
||||
} catch (error) {
|
||||
// 忽略JSON解析错误
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 去重
|
||||
allRules = Array.from(new Set(allRules));
|
||||
|
||||
// 如果没有允许的菜单键列表,直接返回
|
||||
if (!allowMenuKeys.length) {
|
||||
return allRules;
|
||||
}
|
||||
|
||||
// 取交集,只返回允许的菜单键
|
||||
return allRules.filter((rule) => allowMenuKeys.includes(rule));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据角色ID数组获取角色列表
|
||||
* @param roleIds 角色ID数组
|
||||
* @returns 角色列表
|
||||
*/
|
||||
async getRolesByIds(roleIds: number[]): Promise<SysRole[]> {
|
||||
if (!roleIds.length) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return await this.roleRepository.find({
|
||||
where: { role_id: In(roleIds) },
|
||||
select: ['role_id', 'role_name', 'rules', 'status'],
|
||||
});
|
||||
}
|
||||
}
|
||||
125
wwjcloud/src/common/sys/services/core/CoreScheduleService.ts
Normal file
125
wwjcloud/src/common/sys/services/core/CoreScheduleService.ts
Normal file
@@ -0,0 +1,125 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { Repository } from 'typeorm';
|
||||
import { SysSchedule } from '../../entities/SysSchedule';
|
||||
|
||||
/**
|
||||
* 定时任务核心服务 - Core层
|
||||
*/
|
||||
@Injectable()
|
||||
export class CoreScheduleService {
|
||||
constructor(
|
||||
@InjectRepository(SysSchedule)
|
||||
private readonly scheduleRepository: Repository<SysSchedule>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* 获取定时任务分页列表
|
||||
*/
|
||||
async getPage(
|
||||
siteId: number,
|
||||
key?: string,
|
||||
status?: number,
|
||||
page: number = 1,
|
||||
limit: number = 10,
|
||||
) {
|
||||
const queryBuilder = this.scheduleRepository
|
||||
.createQueryBuilder('schedule')
|
||||
.where('schedule.site_id = :siteId', { siteId });
|
||||
|
||||
if (key) {
|
||||
queryBuilder.andWhere('schedule.key = :key', { key });
|
||||
}
|
||||
if (status !== undefined) {
|
||||
queryBuilder.andWhere('schedule.status = :status', { status });
|
||||
}
|
||||
|
||||
const [items, total] = await queryBuilder
|
||||
.orderBy('schedule.create_time', 'DESC')
|
||||
.skip((page - 1) * limit)
|
||||
.take(limit)
|
||||
.getManyAndCount();
|
||||
|
||||
return {
|
||||
list: items,
|
||||
total,
|
||||
page,
|
||||
limit,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取定时任务列表
|
||||
*/
|
||||
async getList(siteId: number, data: any = {}) {
|
||||
const queryBuilder = this.scheduleRepository
|
||||
.createQueryBuilder('schedule')
|
||||
.where('schedule.site_id = :siteId', { siteId });
|
||||
|
||||
if (data.key) {
|
||||
queryBuilder.andWhere('schedule.key = :key', { key: data.key });
|
||||
}
|
||||
if (data.status !== undefined) {
|
||||
queryBuilder.andWhere('schedule.status = :status', {
|
||||
status: data.status,
|
||||
});
|
||||
}
|
||||
|
||||
return await queryBuilder.orderBy('schedule.create_time', 'DESC').getMany();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取定时任务信息
|
||||
*/
|
||||
async getInfo(siteId: number, id: number) {
|
||||
return await this.scheduleRepository.findOne({
|
||||
where: { id, site_id: siteId },
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加定时任务
|
||||
*/
|
||||
async add(data: Partial<SysSchedule>) {
|
||||
const schedule = this.scheduleRepository.create(data);
|
||||
return await this.scheduleRepository.save(schedule);
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑定时任务
|
||||
*/
|
||||
async edit(siteId: number, id: number, data: Partial<SysSchedule>) {
|
||||
await this.scheduleRepository.update({ id, site_id: siteId }, data);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除定时任务
|
||||
*/
|
||||
async del(siteId: number, id: number) {
|
||||
await this.scheduleRepository.delete({ id, site_id: siteId });
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动定时任务
|
||||
*/
|
||||
async start(siteId: number, id: number) {
|
||||
await this.scheduleRepository.update(
|
||||
{ id, site_id: siteId },
|
||||
{ status: 1 },
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止定时任务
|
||||
*/
|
||||
async stop(siteId: number, id: number) {
|
||||
await this.scheduleRepository.update(
|
||||
{ id, site_id: siteId },
|
||||
{ status: 0 },
|
||||
);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { Repository } from 'typeorm';
|
||||
import { BaseService } from '../../../../core/base/BaseService';
|
||||
import { SysConfig } from '../../entities/SysConfig';
|
||||
|
||||
@Injectable()
|
||||
export class CoreSysConfigService extends BaseService<SysConfig> {
|
||||
constructor(
|
||||
@InjectRepository(SysConfig)
|
||||
private readonly configRepository: Repository<SysConfig>,
|
||||
) {
|
||||
super(configRepository);
|
||||
}
|
||||
|
||||
async getConfigByKey(siteId: number, key: string): Promise<string | null> {
|
||||
const config = await this.configRepository.findOne({
|
||||
where: { site_id: siteId, key },
|
||||
});
|
||||
return config?.value || null;
|
||||
}
|
||||
|
||||
async setConfig(
|
||||
siteId: number,
|
||||
key: string,
|
||||
value: string,
|
||||
): Promise<boolean> {
|
||||
const existingConfig = await this.configRepository.findOne({
|
||||
where: { site_id: siteId, key },
|
||||
});
|
||||
|
||||
if (existingConfig) {
|
||||
const result = await this.configRepository.update(
|
||||
{ site_id: siteId, key },
|
||||
{ value, update_time: Math.floor(Date.now() / 1000) },
|
||||
);
|
||||
return (result.affected || 0) > 0;
|
||||
} else {
|
||||
const config = this.configRepository.create({
|
||||
site_id: siteId,
|
||||
key,
|
||||
value,
|
||||
create_time: Math.floor(Date.now() / 1000),
|
||||
});
|
||||
await this.configRepository.save(config);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
async getConfigsByKeys(
|
||||
siteId: number,
|
||||
keys: string[],
|
||||
): Promise<Record<string, string>> {
|
||||
const configs = await this.configRepository.find({
|
||||
where: { site_id: siteId, key: keys as any },
|
||||
});
|
||||
|
||||
const result: Record<string, string> = {};
|
||||
configs.forEach((config) => {
|
||||
result[config.key] = config.value;
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
async deleteConfig(siteId: number, key: string): Promise<boolean> {
|
||||
const result = await this.configRepository.delete({
|
||||
site_id: siteId,
|
||||
key,
|
||||
});
|
||||
return (result.affected || 0) > 0;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user