feat: 初始化 WWJ Cloud 企业级框架项目
- 后端:基于 NestJS 的分层架构设计 - 前端:基于 VbenAdmin + Element Plus 的管理系统 - 支持 SaaS + 独立版双架构模式 - 完整的用户权限管理系统 - 系统设置、文件上传、通知等核心功能 - 多租户支持和插件化扩展架构
This commit is contained in:
30
wwjcloud/src/common/settings/sms/sms-settings.controller.ts
Normal file
30
wwjcloud/src/common/settings/sms/sms-settings.controller.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import { Body, Controller, Get, Put, UseGuards } from '@nestjs/common';
|
||||
import { ApiBearerAuth, ApiOperation, ApiTags } from '@nestjs/swagger';
|
||||
import { SmsSettingsService } from './sms-settings.service';
|
||||
import { UpdateSmsSettingsDto, type SmsSettingsVo } from './sms-settings.dto';
|
||||
import { JwtAuthGuard } from '../../auth/guards/jwt-auth.guard';
|
||||
import { Roles } from '../../auth/roles.decorator';
|
||||
import { RolesGuard } from '../../auth/guards/roles.guard';
|
||||
|
||||
@ApiTags('Settings/Sms')
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(JwtAuthGuard, RolesGuard)
|
||||
@Roles('super', 'admin')
|
||||
@Controller('settings/sms')
|
||||
export class SmsSettingsController {
|
||||
constructor(private readonly service: SmsSettingsService) {}
|
||||
|
||||
@Get()
|
||||
@ApiOperation({ summary: '获取短信设置' })
|
||||
async get(): Promise<{ code: number; data: SmsSettingsVo }> {
|
||||
const data = await this.service.getSettings();
|
||||
return { code: 0, data };
|
||||
}
|
||||
|
||||
@Put()
|
||||
@ApiOperation({ summary: '更新短信设置' })
|
||||
async update(@Body() dto: UpdateSmsSettingsDto): Promise<{ code: number; data: SmsSettingsVo }> {
|
||||
const data = await this.service.updateSettings(dto);
|
||||
return { code: 0, data };
|
||||
}
|
||||
}
|
||||
39
wwjcloud/src/common/settings/sms/sms-settings.dto.ts
Normal file
39
wwjcloud/src/common/settings/sms/sms-settings.dto.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
import { IsBoolean, IsIn, IsObject, IsOptional, IsString } from 'class-validator';
|
||||
|
||||
export class UpdateSmsSettingsDto {
|
||||
@IsBoolean()
|
||||
enabled!: boolean;
|
||||
|
||||
@IsIn(['mock', 'aliyun', 'tencent'])
|
||||
provider!: 'mock' | 'aliyun' | 'tencent';
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
signName?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
accessKeyId?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
accessKeySecret?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
region?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsObject()
|
||||
templates?: Record<string, string>;
|
||||
}
|
||||
|
||||
export interface SmsSettingsVo {
|
||||
enabled: boolean;
|
||||
provider: 'mock' | 'aliyun' | 'tencent';
|
||||
signName?: string;
|
||||
accessKeyId?: string;
|
||||
accessKeySecret?: string;
|
||||
region?: string;
|
||||
templates?: Record<string, string>;
|
||||
}
|
||||
42
wwjcloud/src/common/settings/sms/sms-settings.service.ts
Normal file
42
wwjcloud/src/common/settings/sms/sms-settings.service.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import type { SmsSettingsVo } from './sms-settings.dto';
|
||||
|
||||
const SETTINGS_DIR = path.resolve(process.cwd(), 'config', 'runtime');
|
||||
const SETTINGS_FILE = path.resolve(SETTINGS_DIR, 'sms.settings.json');
|
||||
|
||||
const DEFAULT_SETTINGS: SmsSettingsVo = {
|
||||
enabled: false,
|
||||
provider: 'mock',
|
||||
signName: '',
|
||||
accessKeyId: '',
|
||||
accessKeySecret: '',
|
||||
region: 'cn-hangzhou',
|
||||
templates: {},
|
||||
};
|
||||
|
||||
@Injectable()
|
||||
export class SmsSettingsService {
|
||||
async getSettings(): Promise<SmsSettingsVo> {
|
||||
try {
|
||||
const buf = await fs.promises.readFile(SETTINGS_FILE, 'utf8');
|
||||
const json = JSON.parse(buf);
|
||||
return { ...DEFAULT_SETTINGS, ...json };
|
||||
} catch {
|
||||
return { ...DEFAULT_SETTINGS };
|
||||
}
|
||||
}
|
||||
|
||||
async updateSettings(patch: Partial<SmsSettingsVo>): Promise<SmsSettingsVo> {
|
||||
const current = await this.getSettings();
|
||||
const next: SmsSettingsVo = { ...current, ...patch };
|
||||
await fs.promises.mkdir(SETTINGS_DIR, { recursive: true });
|
||||
await fs.promises.writeFile(SETTINGS_FILE, JSON.stringify(next, null, 2), 'utf8');
|
||||
return next;
|
||||
}
|
||||
|
||||
static getSettingsPath() {
|
||||
return SETTINGS_FILE;
|
||||
}
|
||||
}
|
||||
11
wwjcloud/src/common/settings/sms/sms.module.ts
Normal file
11
wwjcloud/src/common/settings/sms/sms.module.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { SmsService } from './sms.service';
|
||||
import { SmsSettingsService } from './sms-settings.service';
|
||||
import { SmsSettingsController } from './sms-settings.controller';
|
||||
|
||||
@Module({
|
||||
providers: [SmsService, SmsSettingsService],
|
||||
controllers: [SmsSettingsController],
|
||||
exports: [SmsService, SmsSettingsService],
|
||||
})
|
||||
export class SmsModule {}
|
||||
16
wwjcloud/src/common/settings/sms/sms.service.ts
Normal file
16
wwjcloud/src/common/settings/sms/sms.service.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { Injectable, Logger } from '@nestjs/common';
|
||||
|
||||
@Injectable()
|
||||
export class SmsService {
|
||||
private readonly logger = new Logger(SmsService.name);
|
||||
|
||||
async send(
|
||||
to: string,
|
||||
templateId: string,
|
||||
params: Record<string, any> = {},
|
||||
): Promise<void> {
|
||||
this.logger.log(
|
||||
`Mock send sms to ${to} templateId=${templateId} params=${JSON.stringify(params)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user