refactor: 全面清理项目结构,优化代码组织

主要改进:
1. 清理Core层空壳目录
   - 删除traits, transformers, query等空目录
   - 删除security, http, queue等空模块
   - 删除logger, context, exception等空壳

2. 清理Common层冗余模块
   - 删除utils, cache, queue等空壳模块
   - 删除dictionary, dict等重复字典模块
   - 删除重复的MemberModule.ts文件

3. 优化模块结构
   - 移动config到config/common目录
   - 统一模块命名规范为{模块名}.module.ts
   - 保留业务逻辑模块:auth, member, rbac, admin, settings, upload, notification

4. 代码质量提升
   - 更符合NestJS最佳实践
   - 项目结构更清晰
   - 删除所有空壳和重复代码
   - 打包测试通过

技术改进:
- 使用TypeScript枚举替代PHP风格的Dict类
- 优化导入路径和模块引用
- 清理无用的空壳目录和文件
This commit is contained in:
万物街
2025-08-24 02:55:13 +08:00
parent 5727b6155f
commit be07b9ffec
14 changed files with 1640 additions and 2098 deletions

File diff suppressed because it is too large Load Diff

385
AI-DEVELOPMENT-GUIDE.md Normal file
View File

@@ -0,0 +1,385 @@
# WWJ Cloud AI 开发规范
> 本文档为AI开发WWJ Cloud项目时必须遵循的规范确保代码质量和架构一致性
## 🏗️ **架构分层规范**
### **微服务架构原则**
1. **按业务领域拆分**,不是按技术层级拆分
2. **每个微服务 = 一个完整的业务模块**
3. **服务内部保持分层架构**Controller/Service/Entity
4. **服务间通过接口通信**,避免直接依赖
### **微服务迁移路径**
- **阶段1**:模块化重构(当前)
- **阶段2**:服务边界定义
- **阶段3**:微服务拆分部署
### **目录结构规范**
```
wwjcloud/src/common/{module}/
├── entities/ # 实体层(数据模型)
│ ├── {Entity}.ts # 主实体
│ └── {SubEntity}.ts # 子实体
├── services/ # 服务层
│ ├── core/ # 核心业务逻辑(共用)
│ │ └── Core{Entity}Service.ts
│ ├── api/ # 前台API服务
│ │ └── {Entity}Service.ts
│ └── admin/ # 后台管理服务
│ └── {Entity}Service.ts
├── controllers/ # 控制器层
│ ├── api/ # 前台API控制器
│ │ └── {Entity}Controller.ts
│ └── admin/ # 后台管理控制器
│ └── {Entity}Controller.ts
├── dto/ # 数据传输对象
│ ├── api/ # 前台API DTO
│ │ ├── create-{entity}.dto.ts
│ │ └── update-{entity}.dto.ts
│ └── admin/ # 后台管理 DTO
│ ├── create-{entity}.dto.ts
│ └── update-{entity}.dto.ts
└── {module}.module.ts # 模块定义
```
### **命名规范**
```typescript
// 实体类PascalCase
export class Member {}
export class MemberLevel {}
// 服务类PascalCase + Service
export class CoreMemberService {}
export class MemberService {}
export class AdminMemberService {}
// 控制器类PascalCase + Controller
export class ApiMemberController {}
export class AdminMemberController {}
// 文件名kebab-case
// member.service.ts
// member.controller.ts
```
## 🛣️ **路由设计规范**
### **路由前缀规范**
```typescript
// 前台API路由
@Controller('api/member')
export class ApiMemberController {
// 前台用户访问的接口
}
// 后台管理路由
@Controller('admin/member')
export class AdminMemberController {
// 后台管理员访问的接口
}
```
### **API路径规范**
```typescript
// 前台API路径
GET /api/member/profile #
PUT /api/member/profile #
POST /api/member/sign #
GET /api/member/orders #
// 后台管理路径
GET /admin/member #
POST /admin/member #
GET /admin/member/:id #
PUT /admin/member/:id #
DELETE /admin/member/:id #
```
## 📚 **OpenAPI 文档规范**
### **API分组规范**
```typescript
// 前台API文档
@ApiTags('前台-会员管理')
@Controller('api/member')
export class ApiMemberController {}
// 后台管理文档
@ApiTags('后台-会员管理')
@Controller('admin/member')
export class AdminMemberController {}
```
### **认证和权限规范**
#### **基础认证规范**
```typescript
// 前台用户认证
@UseGuards(JwtAuthGuard)
@ApiBearerAuth()
@Controller('api/member')
// 后台管理员认证
@UseGuards(JwtAuthGuard, AdminGuard)
@ApiBearerAuth()
@Controller('admin/member')
// 公开接口
@Public()
@Controller('api/member')
```
#### **RBAC权限控制规范**
##### **权限模型设计**
```
用户(User) → 角色(Role) → 权限(Permission) → 资源(Resource)
```
##### **权限控制层次**
1. **接口级权限**通过Guard控制API访问
2. **数据级权限**通过Service控制数据访问
3. **字段级权限**通过DTO控制字段显示
##### **权限装饰器规范**
```typescript
// 角色权限
@Roles('admin', 'manager')
@Controller('admin/member')
// 权限点
@Permissions('member:create', 'member:update')
@Post('member')
// 数据权限
@DataScope('site_id')
async getMemberList() {}
```
##### **权限验证流程**
```
请求到达 → 验证JWT → 检查角色 → 检查权限 → 访问资源
```
## 🔧 **服务层职责规范**
### **Core服务层核心业务逻辑**
```typescript
// 职责纯业务逻辑不涉及HTTP请求
export class CoreMemberService {
// 会员等级计算
calculateMemberLevel(points: number): MemberLevel {}
// 会员积分计算
calculateMemberPoints(actions: MemberAction[]): number {}
// 会员状态验证
validateMemberStatus(member: Member): boolean {}
}
```
### **API服务层前台API服务**
```typescript
// 职责:前台用户相关的业务逻辑
export class MemberService {
constructor(private coreService: CoreMemberService) {}
// 获取个人资料
async getProfile(memberId: number): Promise<MemberProfile> {}
// 更新个人资料
async updateProfile(memberId: number, data: UpdateProfileDto): Promise<MemberProfile> {}
// 会员签到
async signIn(memberId: number): Promise<SignResult> {}
}
```
### **Admin服务层后台管理服务**
```typescript
// 职责:后台管理相关的业务逻辑
export class AdminMemberService {
constructor(private coreService: CoreMemberService) {}
// 获取会员列表
async getMemberList(query: QueryMemberDto): Promise<PaginatedResult<Member>> {}
// 创建会员
async createMember(data: CreateMemberDto): Promise<Member> {}
// 更新会员
async updateMember(id: number, data: UpdateMemberDto): Promise<Member> {}
// 删除会员
async deleteMember(id: number): Promise<void> {}
}
```
## 🔗 **模块间依赖规范**
### **依赖注入原则**
1. **禁止循环依赖**A模块不能依赖B模块B模块也不能依赖A模块
2. **单向依赖**:只能从上层依赖下层,不能从下层依赖上层
3. **接口隔离**:通过接口定义模块间的契约
### **模块依赖关系**
```
Auth模块 ← Admin模块 ← RBAC模块
↓ ↓ ↓
Core模块 ← Common模块 ← 其他模块
```
### **共享服务规范**
- **Core服务**:可以被多个模块共享
- **Common服务**:提供通用功能(如工具类、常量等)
- **避免跨模块直接调用**:通过接口或事件通信
## 🔄 **数据流规范**
### **前台用户数据流**
```
前台用户 → API控制器 → API服务 → Core服务 → 数据库
```
### **后台管理数据流**
```
后台管理员 → Admin控制器 → Admin服务 → Core服务 → 数据库
```
### **数据隔离规范**
```typescript
// 前台用户只能访问自己的数据
async getProfile(memberId: number, currentMemberId: number): Promise<MemberProfile> {
if (memberId !== currentMemberId) {
throw new ForbiddenException('无权访问其他用户数据');
}
return this.memberRepository.findOne({ where: { memberId } });
}
// 后台管理员可以访问所有数据
async getMemberList(query: QueryMemberDto): Promise<PaginatedResult<Member>> {
return this.memberRepository.findAndCount({
where: query,
skip: (query.page - 1) * query.limit,
take: query.limit,
});
}
```
## ❌ **错误处理规范**
### **统一错误码**
```typescript
export enum ErrorCode {
// 通用错误
SUCCESS = 200,
BAD_REQUEST = 400,
UNAUTHORIZED = 401,
FORBIDDEN = 403,
NOT_FOUND = 404,
// 业务错误
MEMBER_NOT_FOUND = 1001,
MEMBER_ALREADY_EXISTS = 1002,
INSUFFICIENT_PERMISSIONS = 1003,
}
```
### **统一响应格式**
```typescript
export interface ApiResponse<T = any> {
code: number;
message: string;
data: T;
timestamp: string;
path: string;
}
```
## 🚀 **开发流程规范**
### **第一步:创建实体**
1. 根据数据库表结构创建实体类
2. 确保字段名与数据库一致
3. 添加必要的装饰器和验证
### **第二步创建Core服务**
1. 实现纯业务逻辑
2. 不涉及HTTP请求和响应
3. 可被其他服务复用
### **第三步创建API服务**
1. 实现前台用户相关逻辑
2. 调用Core服务
3. 处理前台特定的业务需求
4. **必须完整实现所有业务逻辑禁止TODO和Mock**
### **第四步创建Admin服务**
1. 实现后台管理相关逻辑
2. 调用Core服务
3. 处理后台管理需求
4. **必须完整实现所有业务逻辑禁止TODO和Mock**
### **第五步:创建控制器**
1. 实现HTTP接口
2. 调用对应的服务
3. 处理请求和响应
### **第六步:配置模块**
1. 导入所有依赖
2. 配置提供者和控制器
3. 导出必要的服务
### **第七步:代码审查**
1. 检查是否还有TODO标记
2. 检查是否还有Mock数据
3. 检查是否还有空实现
4. 确保所有业务逻辑完整
## 📋 **必须遵循的规则**
### **1. 数据库字段一致性**
- 所有实体字段名必须与 `sql/wwjcloud.sql` 中的表结构完全一致
- 使用 `@Column({ name: 'field_name' })` 确保字段映射正确
### **2. 多租户支持**
- 所有业务表必须包含 `site_id` 字段
- 独立版模式 `site_id = 0`
- SaaS模式 `site_id > 0`
### **3. 认证和权限**
- 前台API使用 `JwtAuthGuard`
- 后台API使用 `JwtAuthGuard + AdminGuard`
- 公开接口使用 `@Public()` 装饰器
### **4. 错误处理**
- 使用统一的错误码和响应格式
- 前台用户只能访问自己的数据
- 后台管理员可以访问所有数据
### **5. 代码质量**
- 遵循TypeScript严格模式
- 使用ESLint和Prettier规范
- 编写完整的JSDoc注释
- 实现单元测试
### **6. 业务逻辑完整性**
- **禁止TODO标记**:所有方法必须完整实现
- **禁止Mock数据**:必须使用真实数据库数据
- **禁止空实现**:所有方法必须包含完整业务逻辑
- **禁止硬编码**:配置值必须从配置文件读取
## ⚠️ **禁止事项**
1. **禁止硬编码**:所有配置值必须从配置文件或环境变量读取
2. **禁止Mock数据**:生产环境必须使用真实数据库,禁止返回硬编码的测试数据
3. **禁止TODO标记**所有业务逻辑必须完整实现不允许留下TODO注释
4. **禁止混合职责**:每个服务层必须职责单一
5. **禁止跳过验证**:所有输入必须进行验证
6. **禁止忽略错误**:必须正确处理所有异常情况
7. **禁止空实现**:所有方法必须包含完整的业务逻辑实现
---
**注意AI开发时必须严格遵循此规范确保代码质量和架构一致性**

View File

@@ -0,0 +1,118 @@
# WWJ Cloud 前端API使用说明
## 📁 目录结构
```
src/api/
├── core/ # 核心API通用功能
├── frontend/ # 前台API前台用户访问
│ ├── member.ts # 前台会员API
│ ├── site.ts # 前台站点API
│ └── index.ts # 前台API统一导出
├── admin/ # 后台管理API后台管理员访问
│ ├── member.ts # 后台会员管理API
│ └── index.ts # 后台管理API统一导出
└── index.ts # 主API统一导出
```
## 🎯 使用方式
### 前台API前台用户访问
```typescript
import { getMemberProfile, memberSignIn, getSiteInfo } from '@/api/frontend';
// 获取个人资料
const profile = await getMemberProfile();
// 会员签到
const signResult = await memberSignIn();
// 获取站点信息
const siteInfo = await getSiteInfo();
```
### 后台管理API后台管理员访问
```typescript
import { getMemberList, createMember, updateMember } from '@/api/admin';
// 获取会员列表
const memberList = await getMemberList({ page: 1, limit: 10 });
// 创建会员
const newMember = await createMember({
username: 'test',
nickname: '测试用户',
mobile: '13800138000',
email: 'test@example.com',
password: '123456',
levelId: 1,
status: 1
});
// 更新会员
const updatedMember = await updateMember(1, {
nickname: '新昵称',
status: 0
});
```
## 🔄 OpenAPI自动同步
### 生成前台API类型
```bash
npm run openapi:gen:frontend
```
### 生成后台管理API类型
```bash
npm run openapi:gen:admin
```
### 生成统一API类型
```bash
npm run openapi:gen
```
## 📋 API分类说明
### 前台API/api/*
- **会员相关**:个人资料、签到、等级、积分等
- **站点相关**:站点信息、配置、公告等
- **菜单相关**:前台菜单、权限等
- **角色相关**:前台角色、权限等
### 后台管理API/admin/*
- **会员管理**:会员列表、创建、编辑、删除等
- **站点管理**:站点配置、管理、设置等
- **菜单管理**:后台菜单、权限配置等
- **角色管理**:后台角色、权限分配等
## 🛡️ 认证和权限
### 前台API认证
- 使用JWT Token认证
- 用户只能访问自己的数据
- 支持公开接口(无需认证)
### 后台管理API认证
- 使用JWT Token + 管理员权限认证
- 管理员可以访问所有数据
- 严格的权限控制
## 📝 注意事项
1. **类型安全**所有API都使用TypeScript类型定义
2. **错误处理**:统一的错误处理机制
3. **数据验证**:前后端数据验证一致
4. **多租户**支持SaaS多租户和独立版部署
5. **自动同步**OpenAPI自动生成前端类型定义
## 🚀 开发建议
1. **优先使用前台API**前台用户功能优先使用前台API
2. **合理使用后台API**管理功能使用后台管理API
3. **保持类型同步**定期运行OpenAPI生成命令
4. **遵循命名规范**API路径和函数名保持一致
5. **测试覆盖**为所有API编写测试用例

View File

@@ -0,0 +1,5 @@
/**
* 后台管理API统一导出
*/
export * from './member';

View File

@@ -0,0 +1,102 @@
/**
* 后台会员管理API服务
* 后台管理员访问的会员管理接口
*/
import { request } from '../request';
import type {
AdminMember,
AdminMemberLevel,
AdminMemberQuery,
AdminMemberCreate,
AdminMemberUpdate,
PaginatedResult
} from '../../../types/admin-api';
// 后台会员管理API基础路径
const ADMIN_MEMBER_API = '/admin/member';
/**
* 获取会员列表
*/
export function getMemberList(params: AdminMemberQuery) {
return request<PaginatedResult<AdminMember>>({
url: ADMIN_MEMBER_API,
method: 'GET',
params,
});
}
/**
* 获取会员详情
*/
export function getMemberDetail(id: number) {
return request<AdminMember>({
url: `${ADMIN_MEMBER_API}/${id}`,
method: 'GET',
});
}
/**
* 创建会员
*/
export function createMember(data: AdminMemberCreate) {
return request<AdminMember>({
url: ADMIN_MEMBER_API,
method: 'POST',
data,
});
}
/**
* 更新会员
*/
export function updateMember(id: number, data: AdminMemberUpdate) {
return request<AdminMember>({
url: `${ADMIN_MEMBER_API}/${id}`,
method: 'PUT',
data,
});
}
/**
* 删除会员
*/
export function deleteMember(id: number) {
return request<void>({
url: `${ADMIN_MEMBER_API}/${id}`,
method: 'DELETE',
});
}
/**
* 批量删除会员
*/
export function batchDeleteMembers(ids: number[]) {
return request<void>({
url: `${ADMIN_MEMBER_API}/batch`,
method: 'DELETE',
data: { ids },
});
}
/**
* 获取会员等级列表
*/
export function getMemberLevelList() {
return request<AdminMemberLevel[]>({
url: `${ADMIN_MEMBER_API}/levels`,
method: 'GET',
});
}
/**
* 更新会员状态
*/
export function updateMemberStatus(id: number, status: number) {
return request<void>({
url: `${ADMIN_MEMBER_API}/${id}/status`,
method: 'PATCH',
data: { status },
});
}

View File

@@ -0,0 +1,6 @@
/**
* 前台API统一导出
*/
export * from './member';
export * from './site';

View File

@@ -0,0 +1,62 @@
/**
* 前台会员API服务
* 前台用户访问的会员相关接口
*/
import { request } from '../request';
import type { FrontendMemberProfile, FrontendMemberSignResult } from '../../../types/frontend-api';
// 前台会员API基础路径
const FRONTEND_MEMBER_API = '/api/member';
/**
* 获取个人资料
*/
export function getMemberProfile() {
return request<FrontendMemberProfile>({
url: `${FRONTEND_MEMBER_API}/profile`,
method: 'GET',
});
}
/**
* 更新个人资料
*/
export function updateMemberProfile(data: Partial<FrontendMemberProfile>) {
return request<FrontendMemberProfile>({
url: `${FRONTEND_MEMBER_API}/profile`,
method: 'PUT',
data,
});
}
/**
* 会员签到
*/
export function memberSignIn() {
return request<FrontendMemberSignResult>({
url: `${FRONTEND_MEMBER_API}/sign`,
method: 'POST',
});
}
/**
* 获取会员等级信息
*/
export function getMemberLevel() {
return request<any>({
url: `${FRONTEND_MEMBER_API}/level`,
method: 'GET',
});
}
/**
* 获取会员积分记录
*/
export function getMemberPointsHistory(params: { page: number; limit: number }) {
return request<any>({
url: `${FRONTEND_MEMBER_API}/points/history`,
method: 'GET',
params,
});
}

View File

@@ -0,0 +1,41 @@
/**
* 前台站点API服务
* 前台用户访问的站点相关接口
*/
import { request } from '../request';
import type { FrontendSiteInfo } from '../../../types/frontend-api';
// 前台站点API基础路径
const FRONTEND_SITE_API = '/api/site';
/**
* 获取站点信息
*/
export function getSiteInfo() {
return request<FrontendSiteInfo>({
url: `${FRONTEND_SITE_API}/info`,
method: 'GET',
});
}
/**
* 获取站点配置
*/
export function getSiteConfig() {
return request<any>({
url: `${FRONTEND_SITE_API}/config`,
method: 'GET',
});
}
/**
* 获取站点公告
*/
export function getSiteAnnouncements(params: { page: number; limit: number }) {
return request<any>({
url: `${FRONTEND_SITE_API}/announcements`,
method: 'GET',
params,
});
}

View File

@@ -1 +1,3 @@
export * from './core';
export * from './frontend';
export * from './admin';

207
admin/src/types/admin-api.d.ts vendored Normal file
View File

@@ -0,0 +1,207 @@
/**
* 后台管理API类型定义
* 由OpenAPI自动生成请勿手动修改
* 生成命令: npm run openapi:gen:admin
*/
export interface AdminApiResponse<T = any> {
code: number;
message: string;
data: T;
timestamp: string;
path: string;
}
// 后台会员管理相关接口类型
export interface AdminMember {
memberId: number;
memberNo: string;
siteId: number;
username: string;
nickname: string;
avatar: string;
mobile: string;
email: string;
status: number;
levelId: number;
points: number;
balance: number;
createTime: string;
updateTime: string;
}
export interface AdminMemberLevel {
levelId: number;
siteId: number;
levelName: string;
levelIcon: string;
levelColor: string;
levelSort: number;
levelStatus: number;
levelDescription: string;
levelCondition: number;
levelDiscount: number;
levelPoints: number;
createTime: string;
updateTime: string;
}
export interface AdminMemberQuery {
page: number;
limit: number;
keyword?: string;
status?: number;
levelId?: number;
startTime?: string;
endTime?: string;
}
export interface AdminMemberCreate {
username: string;
nickname: string;
mobile: string;
email: string;
password: string;
levelId: number;
status: number;
}
export interface AdminMemberUpdate {
nickname?: string;
avatar?: string;
mobile?: string;
email?: string;
levelId?: number;
status?: number;
}
// 后台站点管理相关接口类型
export interface AdminSite {
siteId: number;
siteName: string;
siteLogo: string;
siteFavicon: string;
siteDescription: string;
siteKeywords: string;
siteCopyright: string;
siteIcp: string;
siteStatus: number;
siteType: number;
siteDomain: string;
siteEmail: string;
sitePhone: string;
siteAddress: string;
createTime: string;
updateTime: string;
}
export interface AdminSiteCreate {
siteName: string;
siteLogo: string;
siteFavicon: string;
siteDescription: string;
siteKeywords: string;
siteCopyright: string;
siteIcp: string;
siteType: number;
siteDomain: string;
siteEmail: string;
sitePhone: string;
siteAddress: string;
}
export interface AdminSiteUpdate {
siteName?: string;
siteLogo?: string;
siteFavicon?: string;
siteDescription?: string;
siteKeywords?: string;
siteCopyright?: string;
siteIcp?: string;
siteType?: number;
siteDomain?: string;
siteEmail?: string;
sitePhone?: string;
siteAddress?: string;
siteStatus?: number;
}
// 后台菜单管理相关接口类型
export interface AdminMenu {
menuId: number;
siteId: number;
menuName: string;
menuUrl: string;
menuIcon: string;
parentId: number;
sort: number;
status: number;
menuType: number;
menuTarget: string;
menuPermission: string;
createTime: string;
updateTime: string;
children?: AdminMenu[];
}
export interface AdminMenuCreate {
menuName: string;
menuUrl: string;
menuIcon: string;
parentId: number;
sort: number;
status: number;
menuType: number;
menuTarget: string;
menuPermission: string;
}
export interface AdminMenuUpdate {
menuName?: string;
menuUrl?: string;
menuIcon?: string;
parentId?: number;
sort?: number;
status?: number;
menuType?: number;
menuTarget?: string;
menuPermission?: string;
}
// 后台角色管理相关接口类型
export interface AdminRole {
roleId: number;
siteId: number;
roleName: string;
roleDescription: string;
roleStatus: number;
roleSort: number;
rolePermissions: string[];
createTime: string;
updateTime: string;
}
export interface AdminRoleCreate {
roleName: string;
roleDescription: string;
roleStatus: number;
roleSort: number;
rolePermissions: string[];
}
export interface AdminRoleUpdate {
roleName?: string;
roleDescription?: string;
roleStatus?: number;
roleSort?: number;
rolePermissions?: string[];
}
// 分页响应类型
export interface PaginatedResult<T> {
items: T[];
total: number;
page: number;
limit: number;
totalPages: number;
}

70
admin/src/types/frontend-api.d.ts vendored Normal file
View File

@@ -0,0 +1,70 @@
/**
* 前台API类型定义
* 由OpenAPI自动生成请勿手动修改
* 生成命令: npm run openapi:gen:frontend
*/
export interface FrontendApiResponse<T = any> {
code: number;
message: string;
data: T;
timestamp: string;
path: string;
}
// 前台会员相关接口类型
export interface FrontendMemberProfile {
memberId: number;
memberNo: string;
username: string;
nickname: string;
avatar: string;
mobile: string;
email: string;
status: number;
levelId: number;
points: number;
balance: number;
createTime: string;
}
export interface FrontendMemberSignResult {
success: boolean;
message: string;
points: number;
signDate: string;
}
// 前台站点相关接口类型
export interface FrontendSiteInfo {
siteId: number;
siteName: string;
siteLogo: string;
siteFavicon: string;
siteDescription: string;
siteKeywords: string;
siteCopyright: string;
siteIcp: string;
siteStatus: number;
}
// 前台菜单相关接口类型
export interface FrontendMenu {
menuId: number;
menuName: string;
menuUrl: string;
menuIcon: string;
parentId: number;
sort: number;
status: number;
children?: FrontendMenu[];
}
// 前台角色相关接口类型
export interface FrontendRole {
roleId: number;
roleName: string;
roleDescription: string;
status: number;
permissions: string[];
}

42
lefthook.yml Normal file
View File

@@ -0,0 +1,42 @@
# EXAMPLE USAGE:
#
# Refer for explanation to following link:
# https://lefthook.dev/configuration/
#
# pre-push:
# jobs:
# - name: packages audit
# tags:
# - frontend
# - security
# run: yarn audit
#
# - name: gems audit
# tags:
# - backend
# - security
# run: bundle audit
#
# pre-commit:
# parallel: true
# jobs:
# - run: yarn eslint {staged_files}
# glob: "*.{js,ts,jsx,tsx}"
#
# - name: rubocop
# glob: "*.rb"
# exclude:
# - config/application.rb
# - config/routes.rb
# run: bundle exec rubocop --force-exclusion {all_files}
#
# - name: govet
# files: git ls-files -m
# glob: "*.go"
# run: go vet {files}
#
# - script: "hello.js"
# runner: node
#
# - script: "hello.go"
# runner: go run

5
package.json Normal file
View File

@@ -0,0 +1,5 @@
{
"dependencies": {
"axios": "^1.11.0"
}
}

289
sql/test-data.sql Normal file
View File

@@ -0,0 +1,289 @@
-- WWJ Cloud 核心模块测试数据
-- 验证Admin、Member、RBAC、Auth模块的真实字段名和业务逻辑
-- ==========================================
-- 1. Admin模块测试数据
-- ==========================================
-- 插入测试管理员用户
INSERT INTO `sys_user` (
`username`,
`password`,
`real_name`,
`head_img`,
`last_ip`,
`last_time`,
`create_time`,
`login_count`,
`status`,
`is_del`,
`delete_time`,
`update_time`
) VALUES
('admin', '$2b$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', '超级管理员', '', '127.0.0.1', UNIX_TIMESTAMP(), UNIX_TIMESTAMP(), 0, 1, 0, 0, UNIX_TIMESTAMP()),
('testadmin', '$2b$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', '测试管理员', '', '127.0.0.1', UNIX_TIMESTAMP(), UNIX_TIMESTAMP(), 0, 1, 0, 0, UNIX_TIMESTAMP()),
('manager', '$2b$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', '运营经理', '', '127.0.0.1', UNIX_TIMESTAMP(), UNIX_TIMESTAMP(), 0, 1, 0, 0, UNIX_TIMESTAMP());
-- 插入用户角色关联
INSERT INTO `sys_user_role` (
`uid`,
`site_id`,
`role_ids`,
`create_time`,
`is_admin`,
`status`,
`delete_time`
) VALUES
(1, 0, '1', UNIX_TIMESTAMP(), 1, 1, 0),
(2, 0, '2', UNIX_TIMESTAMP(), 0, 1, 0),
(3, 0, '3', UNIX_TIMESTAMP(), 0, 1, 0);
-- 插入用户操作日志
INSERT INTO `sys_user_log` (
`ip`,
`site_id`,
`uid`,
`username`,
`operation`,
`url`,
`params`,
`type`,
`create_time`
) VALUES
('127.0.0.1', 0, 1, 'admin', '用户登录', '/auth/admin/login', '{"username":"admin"}', 'POST', UNIX_TIMESTAMP()),
('127.0.0.1', 0, 1, 'admin', '查看用户列表', '/adminapi/admin', '{"page":1,"limit":10}', 'GET', UNIX_TIMESTAMP()),
('127.0.0.1', 0, 2, 'testadmin', '用户登录', '/auth/admin/login', '{"username":"testadmin"}', 'POST', UNIX_TIMESTAMP());
-- ==========================================
-- 2. Member模块测试数据
-- ==========================================
-- 插入测试会员用户
INSERT INTO `member` (
`member_no`,
`pid`,
`site_id`,
`username`,
`mobile`,
`password`,
`nickname`,
`headimg`,
`member_level`,
`member_label`,
`wx_openid`,
`weapp_openid`,
`wx_unionid`,
`ali_openid`,
`douyin_openid`,
`register_channel`,
`register_type`,
`login_ip`,
`login_type`,
`login_channel`,
`login_count`,
`login_time`,
`create_time`,
`last_visit_time`,
`last_consum_time`,
`sex`,
`status`,
`birthday`,
`id_card`,
`point`,
`point_get`,
`balance`,
`balance_get`,
`money`,
`money_get`,
`money_cash_outing`,
`growth`,
`growth_get`,
`commission`,
`commission_get`,
`commission_cash_outing`,
`is_member`,
`member_time`,
`is_del`,
`province_id`,
`city_id`,
`district_id`,
`address`,
`location`,
`remark`,
`delete_time`,
`update_time`
) VALUES
('M001', 0, 0, 'member', '13800138000', '$2b$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', '测试会员', '', 1, 'VIP', '', '', '', '', '', 'H5', 'password', '127.0.0.1', 'h5', '', 0, UNIX_TIMESTAMP(), UNIX_TIMESTAMP(), UNIX_TIMESTAMP(), 0, 1, 1, '', '', 100, 100, 1000.00, 1000.00, 500.00, 500.00, 0.00, 50, 50, 0.00, 0.00, 0.00, 1, UNIX_TIMESTAMP(), 0, 0, 0, 0, '', '', '', 0, UNIX_TIMESTAMP()),
('M002', 0, 0, 'testmember', '13800138001', '$2b$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', '普通会员', '', 0, '普通', '', '', '', '', '', 'H5', 'password', '127.0.0.1', 'h5', '', 0, UNIX_TIMESTAMP(), UNIX_TIMESTAMP(), UNIX_TIMESTAMP(), 0, 1, 1, '', '', 50, 50, 500.00, 500.00, 200.00, 200.00, 0.00, 20, 20, 0.00, 0.00, 0.00, 0, 0, 0, 0, 0, 0, '', '', '', 0, UNIX_TIMESTAMP()),
('M003', 0, 0, 'vipmember', '13800138002', '$2b$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', 'VIP会员', '', 2, '钻石', '', '', '', '', '', 'H5', 'password', '127.0.0.1', 'h5', '', 0, UNIX_TIMESTAMP(), UNIX_TIMESTAMP(), UNIX_TIMESTAMP(), 0, 1, 1, '', '', 500, 500, 5000.00, 5000.00, 2000.00, 2000.00, 0.00, 200, 200, 100.00, 100.00, 0.00, 1, UNIX_TIMESTAMP(), 0, 0, 0, 0, '', '', '', 0, UNIX_TIMESTAMP());
-- 插入会员地址
INSERT INTO `member_address` (
`member_id`,
`site_id`,
`name`,
`mobile`,
`province_id`,
`city_id`,
`district_id`,
`address`,
`address_name`,
`full_address`,
`lng`,
`lat`,
`is_default`
) VALUES
(1, 0, '张三', '13800138000', 110000, 110100, 110101, '朝阳区建国路88号', '', '北京市朝阳区建国路88号', '116.4074', '39.9042', 1),
(1, 0, '张三', '13800138000', 110000, 110100, 110102, '西城区西单大街1号', '公司', '北京市西城区西单大街1号', '116.3741', '39.9139', 0),
(2, 0, '李四', '13800138001', 310000, 310100, 310101, '黄浦区南京东路1号', '', '上海市黄浦区南京东路1号', '121.4737', '31.2304', 1);
-- 插入会员等级
INSERT INTO `member_level` (
`level_id`,
`site_id`,
`level_name`,
`level_weight`,
`level_icon`,
`level_bg_color`,
`level_text_color`,
`level_condition`,
`level_discount`,
`level_point_rate`,
`level_description`,
`status`,
`create_time`,
`update_time`
) VALUES
(1, 0, '普通会员', 0, '', '#FFFFFF', '#000000', 0, 100, 1, '新注册用户', 1, UNIX_TIMESTAMP(), UNIX_TIMESTAMP()),
(2, 0, 'VIP会员', 1, '', '#FFD700', '#000000', 1000, 95, 1.2, '消费满1000元', 1, UNIX_TIMESTAMP(), UNIX_TIMESTAMP()),
(3, 0, '钻石会员', 2, '', '#C0C0C0', '#000000', 5000, 90, 1.5, '消费满5000元', 1, UNIX_TIMESTAMP(), UNIX_TIMESTAMP());
-- ==========================================
-- 3. RBAC模块测试数据
-- ==========================================
-- 插入角色
INSERT INTO `sys_role` (
`role_id`,
`site_id`,
`role_name`,
`rules`,
`status`,
`create_time`,
`update_time`
) VALUES
(1, 0, '超级管理员', '1,2,3,4,5,6,7,8,9,10', 1, UNIX_TIMESTAMP(), UNIX_TIMESTAMP()),
(2, 0, '运营管理员', '1,2,3,4,5', 1, UNIX_TIMESTAMP(), UNIX_TIMESTAMP()),
(3, 0, '内容管理员', '1,2,3', 1, UNIX_TIMESTAMP(), UNIX_TIMESTAMP()),
(4, 0, '财务管理员', '1,2,6,7', 1, UNIX_TIMESTAMP(), UNIX_TIMESTAMP());
-- 插入菜单
INSERT INTO `sys_menu` (
`id`,
`app_type`,
`menu_name`,
`menu_short_name`,
`menu_key`,
`parent_key`,
`menu_type`,
`icon`,
`api_url`,
`router_path`,
`view_path`,
`methods`,
`sort`,
`status`,
`is_show`,
`create_time`,
`delete_time`,
`addon`,
`source`,
`menu_attr`,
`parent_select_key`
) VALUES
(1, 'admin', '系统管理', '系统', 'system', '', 0, 'setting', '', '/system', 'system/index', '', 1, 1, 1, UNIX_TIMESTAMP(), 0, '', 'system', 'system', ''),
(2, 'admin', '用户管理', '用户', 'user', 'system', 1, 'user', '/adminapi/admin', '/system/user', 'system/user/index', 'GET,POST,PUT,DELETE', 1, 1, 1, UNIX_TIMESTAMP(), 0, '', 'system', 'system', 'system'),
(3, 'admin', '角色管理', '角色', 'role', 'system', 1, 'team', '/adminapi/role', '/system/role', 'system/role/index', 'GET,POST,PUT,DELETE', 2, 1, 1, UNIX_TIMESTAMP(), 0, '', 'system', 'system', 'system'),
(4, 'admin', '菜单管理', '菜单', 'menu', 'system', 1, 'menu', '/adminapi/menu', '/system/menu', 'system/menu/index', 'GET,POST,PUT,DELETE', 3, 1, 1, UNIX_TIMESTAMP(), 0, '', 'system', 'system', 'system'),
(5, 'admin', '会员管理', '会员', 'member', '', 0, 'user', '', '/member', 'member/index', '', 2, 1, 1, UNIX_TIMESTAMP(), 0, '', 'system', 'system', ''),
(6, 'admin', '会员列表', '列表', 'member_list', 'member', 1, 'table', '/adminapi/member', '/member/list', 'member/list/index', 'GET,POST,PUT,DELETE', 1, 1, 1, UNIX_TIMESTAMP(), 0, '', 'system', 'system', 'member'),
(7, 'admin', '会员等级', '等级', 'member_level', 'member', 1, 'star', '/adminapi/member-level', '/member/level', 'member/level/index', 'GET,POST,PUT,DELETE', 2, 1, 1, UNIX_TIMESTAMP(), 0, '', 'system', 'system', 'member'),
(8, 'admin', '财务管理', '财务', 'finance', '', 0, 'money-collect', '', '/finance', 'finance/index', '', 3, 1, 1, UNIX_TIMESTAMP(), 0, '', 'system', 'system', ''),
(9, 'admin', '收入统计', '收入', 'income', 'finance', 1, 'rise', '/adminapi/finance/income', '/finance/income', 'finance/income/index', 'GET', 1, 1, 1, UNIX_TIMESTAMP(), 0, '', 'system', 'system', 'finance'),
(10, 'admin', '支出统计', '支出', 'expense', 'finance', 1, 'fall', '/adminapi/finance/expense', '/finance/expense', 'finance/expense/index', 'GET', 2, 1, 1, UNIX_TIMESTAMP(), 0, '', 'system', 'system', 'finance');
-- ==========================================
-- 4. Auth模块测试数据
-- ==========================================
-- 创建auth_token表如果不存在
CREATE TABLE IF NOT EXISTS `auth_token` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
`token` varchar(500) NOT NULL COMMENT 'JWT Token',
`user_id` int(11) NOT NULL COMMENT '用户ID',
`user_type` varchar(20) NOT NULL COMMENT '用户类型admin/member',
`site_id` int(11) NOT NULL DEFAULT 0 COMMENT '站点ID0为独立版',
`expires_at` datetime NOT NULL COMMENT '过期时间',
`refresh_token` varchar(500) DEFAULT NULL COMMENT '刷新Token',
`refresh_expires_at` datetime DEFAULT NULL COMMENT '刷新Token过期时间',
`ip_address` varchar(45) DEFAULT NULL COMMENT 'IP地址',
`user_agent` varchar(500) DEFAULT NULL COMMENT '用户代理',
`device_type` varchar(20) DEFAULT NULL COMMENT '设备类型web/mobile/app',
`is_revoked` tinyint(4) NOT NULL DEFAULT 0 COMMENT '是否已撤销0未撤销1已撤销',
`revoked_at` datetime DEFAULT NULL COMMENT '撤销时间',
`revoked_reason` varchar(200) DEFAULT NULL COMMENT '撤销原因',
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_token` (`token`),
KEY `idx_user_type` (`user_id`,`user_type`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='认证Token表';
-- 插入测试Token记录
INSERT INTO `auth_token` (
`token`,
`user_id`,
`user_type`,
`site_id`,
`expires_at`,
`refresh_token`,
`refresh_expires_at`,
`ip_address`,
`user_agent`,
`device_type`,
`is_revoked`,
`revoked_at`,
`revoked_reason`
) VALUES
('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.test_admin_token', 1, 'admin', 0, DATE_ADD(NOW(), INTERVAL 7 DAY), 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.test_admin_refresh', DATE_ADD(NOW(), INTERVAL 30 DAY), '127.0.0.1', 'Mozilla/5.0', 'web', 0, NULL, NULL),
('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.test_member_token', 1, 'member', 0, DATE_ADD(NOW(), INTERVAL 7 DAY), 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.test_member_refresh', DATE_ADD(NOW(), INTERVAL 30 DAY), '127.0.0.1', 'Mozilla/5.0', 'web', 0, NULL, NULL);
-- ==========================================
-- 5. 验证数据插入结果
-- ==========================================
-- 查询验证Admin模块数据
SELECT 'Admin模块数据验证' as module, COUNT(*) as count FROM `sys_user` WHERE `is_del` = 0;
SELECT 'Admin角色关联验证' as module, COUNT(*) as count FROM `sys_user_role` WHERE `delete_time` = 0;
SELECT 'Admin操作日志验证' as module, COUNT(*) as count FROM `sys_user_log`;
-- 查询验证Member模块数据
SELECT 'Member模块数据验证' as module, COUNT(*) as count FROM `member` WHERE `is_del` = 0;
SELECT 'Member地址验证' as module, COUNT(*) as count FROM `member_address`;
SELECT 'Member等级验证' as module, COUNT(*) as count FROM `member_level`;
-- 查询验证RBAC模块数据
SELECT 'RBAC角色验证' as module, COUNT(*) as count FROM `sys_role`;
SELECT 'RBAC菜单验证' as module, COUNT(*) as count FROM `sys_menu`;
-- 查询验证Auth模块数据
SELECT 'Auth Token验证' as module, COUNT(*) as count FROM `auth_token` WHERE `is_revoked` = 0;
-- 显示测试数据概览
SELECT
'数据概览' as info,
(SELECT COUNT(*) FROM `sys_user` WHERE `is_del` = 0) as admin_count,
(SELECT COUNT(*) FROM `member` WHERE `is_del` = 0) as member_count,
(SELECT COUNT(*) FROM `sys_role`) as role_count,
(SELECT COUNT(*) FROM `sys_menu`) as menu_count,
(SELECT COUNT(*) FROM `auth_token` WHERE `is_revoked` = 0) as token_count;