@svton/cli 1.0.2 → 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +7 -4
- package/dist/index.mjs +7 -4
- package/package.json +2 -1
- package/templates/apps/admin/next-env.d.ts +2 -0
- package/templates/apps/admin/next.config.js +15 -0
- package/templates/apps/admin/package.json.tpl +54 -0
- package/templates/apps/admin/postcss.config.js +6 -0
- package/templates/apps/admin/src/app/globals.css +37 -0
- package/templates/apps/admin/src/app/layout.tsx +19 -0
- package/templates/apps/admin/src/app/login/page.tsx +96 -0
- package/templates/apps/admin/src/app/page.tsx +8 -0
- package/templates/apps/admin/src/app/users/page.tsx +165 -0
- package/templates/apps/admin/src/components/ui/switch.tsx +29 -0
- package/templates/apps/admin/src/hooks/useAPI.ts +130 -0
- package/templates/apps/admin/src/lib/api-client.ts +100 -0
- package/templates/apps/admin/tailwind.config.js +54 -0
- package/templates/apps/admin/tsconfig.json +22 -0
- package/templates/apps/backend/.env.example +14 -0
- package/templates/apps/backend/nest-cli.json +8 -0
- package/templates/apps/backend/package.json.tpl +57 -0
- package/templates/apps/backend/prisma/schema.prisma +72 -0
- package/templates/apps/backend/prisma/seed.ts +32 -0
- package/templates/apps/backend/src/app.controller.ts +15 -0
- package/templates/apps/backend/src/app.module.ts +19 -0
- package/templates/apps/backend/src/app.service.ts +12 -0
- package/templates/apps/backend/src/auth/auth.controller.ts +31 -0
- package/templates/apps/backend/src/auth/auth.module.ts +27 -0
- package/templates/apps/backend/src/auth/auth.service.ts +89 -0
- package/templates/apps/backend/src/auth/jwt-auth.guard.ts +5 -0
- package/templates/apps/backend/src/auth/jwt.strategy.ts +27 -0
- package/templates/apps/backend/src/main.ts +40 -0
- package/templates/apps/backend/src/prisma/prisma.module.ts +9 -0
- package/templates/apps/backend/src/prisma/prisma.service.ts +13 -0
- package/templates/apps/backend/src/user/user.controller.ts +50 -0
- package/templates/apps/backend/src/user/user.module.ts +12 -0
- package/templates/apps/backend/src/user/user.service.ts +117 -0
- package/templates/apps/backend/tsconfig.json +23 -0
- package/templates/apps/mobile/babel.config.js +8 -0
- package/templates/apps/mobile/config/index.ts +65 -0
- package/templates/apps/mobile/package.json.tpl +48 -0
- package/templates/apps/mobile/project.config.json.tpl +17 -0
- package/templates/apps/mobile/src/app.config.ts +9 -0
- package/templates/apps/mobile/src/app.scss +4 -0
- package/templates/apps/mobile/src/app.ts +8 -0
- package/templates/apps/mobile/src/pages/index/index.scss +7 -0
- package/templates/apps/mobile/src/pages/index/index.tsx +49 -0
- package/templates/apps/mobile/tsconfig.json +21 -0
- package/templates/packages/types/package.json.tpl +16 -0
- package/templates/packages/types/src/api.ts +88 -0
- package/templates/packages/types/src/common.ts +89 -0
- package/templates/packages/types/src/index.ts +3 -0
- package/templates/packages/types/tsconfig.json +16 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Controller,
|
|
3
|
+
Get,
|
|
4
|
+
Put,
|
|
5
|
+
Delete,
|
|
6
|
+
Body,
|
|
7
|
+
Param,
|
|
8
|
+
Query,
|
|
9
|
+
UseGuards,
|
|
10
|
+
ParseIntPipe,
|
|
11
|
+
} from '@nestjs/common';
|
|
12
|
+
import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger';
|
|
13
|
+
import { UserService } from './user.service';
|
|
14
|
+
import { JwtAuthGuard } from '../auth/jwt-auth.guard';
|
|
15
|
+
import type { UserListParams, UpdateUserDto } from '{{ORG_NAME}}/types';
|
|
16
|
+
|
|
17
|
+
@ApiTags('用户管理')
|
|
18
|
+
@Controller('users')
|
|
19
|
+
@UseGuards(JwtAuthGuard)
|
|
20
|
+
@ApiBearerAuth()
|
|
21
|
+
export class UserController {
|
|
22
|
+
constructor(private userService: UserService) {}
|
|
23
|
+
|
|
24
|
+
@Get()
|
|
25
|
+
@ApiOperation({ summary: '获取用户列表' })
|
|
26
|
+
async findAll(@Query() params: UserListParams) {
|
|
27
|
+
return this.userService.findAll(params);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
@Get(':id')
|
|
31
|
+
@ApiOperation({ summary: '获取用户详情' })
|
|
32
|
+
async findOne(@Param('id', ParseIntPipe) id: number) {
|
|
33
|
+
return this.userService.findOne(id);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
@Put(':id')
|
|
37
|
+
@ApiOperation({ summary: '更新用户' })
|
|
38
|
+
async update(
|
|
39
|
+
@Param('id', ParseIntPipe) id: number,
|
|
40
|
+
@Body() dto: UpdateUserDto,
|
|
41
|
+
) {
|
|
42
|
+
return this.userService.update(id, dto);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
@Delete(':id')
|
|
46
|
+
@ApiOperation({ summary: '删除用户' })
|
|
47
|
+
async remove(@Param('id', ParseIntPipe) id: number) {
|
|
48
|
+
return this.userService.remove(id);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Module } from '@nestjs/common';
|
|
2
|
+
import { UserController } from './user.controller';
|
|
3
|
+
import { UserService } from './user.service';
|
|
4
|
+
import { PrismaModule } from '../prisma/prisma.module';
|
|
5
|
+
|
|
6
|
+
@Module({
|
|
7
|
+
imports: [PrismaModule],
|
|
8
|
+
controllers: [UserController],
|
|
9
|
+
providers: [UserService],
|
|
10
|
+
exports: [UserService],
|
|
11
|
+
})
|
|
12
|
+
export class UserModule {}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { Injectable, NotFoundException } from '@nestjs/common';
|
|
2
|
+
import { PrismaService } from '../prisma/prisma.service';
|
|
3
|
+
import type { UserListParams, UpdateUserDto, PaginatedResponse, UserVo } from '{{ORG_NAME}}/types';
|
|
4
|
+
|
|
5
|
+
@Injectable()
|
|
6
|
+
export class UserService {
|
|
7
|
+
constructor(private prisma: PrismaService) {}
|
|
8
|
+
|
|
9
|
+
async findAll(params: UserListParams): Promise<PaginatedResponse<UserVo>> {
|
|
10
|
+
const { page = 1, pageSize = 10, keyword, role, status } = params;
|
|
11
|
+
const skip = (page - 1) * pageSize;
|
|
12
|
+
|
|
13
|
+
const where: any = {};
|
|
14
|
+
if (keyword) {
|
|
15
|
+
where.OR = [
|
|
16
|
+
{ phone: { contains: keyword } },
|
|
17
|
+
{ nickname: { contains: keyword } },
|
|
18
|
+
];
|
|
19
|
+
}
|
|
20
|
+
if (role) where.role = role;
|
|
21
|
+
if (status !== undefined) where.status = status;
|
|
22
|
+
|
|
23
|
+
const [list, total] = await Promise.all([
|
|
24
|
+
this.prisma.user.findMany({
|
|
25
|
+
where,
|
|
26
|
+
skip,
|
|
27
|
+
take: pageSize,
|
|
28
|
+
orderBy: { createdAt: 'desc' },
|
|
29
|
+
select: {
|
|
30
|
+
id: true,
|
|
31
|
+
phone: true,
|
|
32
|
+
nickname: true,
|
|
33
|
+
avatar: true,
|
|
34
|
+
role: true,
|
|
35
|
+
status: true,
|
|
36
|
+
createdAt: true,
|
|
37
|
+
updatedAt: true,
|
|
38
|
+
},
|
|
39
|
+
}),
|
|
40
|
+
this.prisma.user.count({ where }),
|
|
41
|
+
]);
|
|
42
|
+
|
|
43
|
+
return {
|
|
44
|
+
list: list.map((u) => ({
|
|
45
|
+
...u,
|
|
46
|
+
role: u.role as any,
|
|
47
|
+
status: u.status as any,
|
|
48
|
+
createdAt: u.createdAt.toISOString(),
|
|
49
|
+
updatedAt: u.updatedAt.toISOString(),
|
|
50
|
+
})),
|
|
51
|
+
total,
|
|
52
|
+
page,
|
|
53
|
+
pageSize,
|
|
54
|
+
totalPages: Math.ceil(total / pageSize),
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async findOne(id: number): Promise<UserVo> {
|
|
59
|
+
const user = await this.prisma.user.findUnique({
|
|
60
|
+
where: { id },
|
|
61
|
+
select: {
|
|
62
|
+
id: true,
|
|
63
|
+
phone: true,
|
|
64
|
+
nickname: true,
|
|
65
|
+
avatar: true,
|
|
66
|
+
role: true,
|
|
67
|
+
status: true,
|
|
68
|
+
createdAt: true,
|
|
69
|
+
updatedAt: true,
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
if (!user) {
|
|
74
|
+
throw new NotFoundException('用户不存在');
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return {
|
|
78
|
+
...user,
|
|
79
|
+
role: user.role as any,
|
|
80
|
+
status: user.status as any,
|
|
81
|
+
createdAt: user.createdAt.toISOString(),
|
|
82
|
+
updatedAt: user.updatedAt.toISOString(),
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
async update(id: number, dto: UpdateUserDto): Promise<UserVo> {
|
|
87
|
+
await this.findOne(id);
|
|
88
|
+
|
|
89
|
+
const user = await this.prisma.user.update({
|
|
90
|
+
where: { id },
|
|
91
|
+
data: dto,
|
|
92
|
+
select: {
|
|
93
|
+
id: true,
|
|
94
|
+
phone: true,
|
|
95
|
+
nickname: true,
|
|
96
|
+
avatar: true,
|
|
97
|
+
role: true,
|
|
98
|
+
status: true,
|
|
99
|
+
createdAt: true,
|
|
100
|
+
updatedAt: true,
|
|
101
|
+
},
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
return {
|
|
105
|
+
...user,
|
|
106
|
+
role: user.role as any,
|
|
107
|
+
status: user.status as any,
|
|
108
|
+
createdAt: user.createdAt.toISOString(),
|
|
109
|
+
updatedAt: user.updatedAt.toISOString(),
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
async remove(id: number): Promise<void> {
|
|
114
|
+
await this.findOne(id);
|
|
115
|
+
await this.prisma.user.delete({ where: { id } });
|
|
116
|
+
}
|
|
117
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"module": "commonjs",
|
|
4
|
+
"declaration": true,
|
|
5
|
+
"removeComments": true,
|
|
6
|
+
"emitDecoratorMetadata": true,
|
|
7
|
+
"experimentalDecorators": true,
|
|
8
|
+
"allowSyntheticDefaultImports": true,
|
|
9
|
+
"target": "ES2021",
|
|
10
|
+
"sourceMap": true,
|
|
11
|
+
"outDir": "./dist",
|
|
12
|
+
"baseUrl": "./",
|
|
13
|
+
"incremental": true,
|
|
14
|
+
"skipLibCheck": true,
|
|
15
|
+
"strictNullChecks": true,
|
|
16
|
+
"noImplicitAny": true,
|
|
17
|
+
"strictBindCallApply": true,
|
|
18
|
+
"forceConsistentCasingInFileNames": true,
|
|
19
|
+
"noFallthroughCasesInSwitch": true,
|
|
20
|
+
"esModuleInterop": true,
|
|
21
|
+
"resolveJsonModule": true
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import type { UserConfigExport } from '@tarojs/cli';
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
projectName: 'mobile',
|
|
5
|
+
date: '2024-1-1',
|
|
6
|
+
designWidth: 750,
|
|
7
|
+
deviceRatio: {
|
|
8
|
+
640: 2.34 / 2,
|
|
9
|
+
750: 1,
|
|
10
|
+
828: 1.81 / 2,
|
|
11
|
+
},
|
|
12
|
+
sourceRoot: 'src',
|
|
13
|
+
outputRoot: 'dist',
|
|
14
|
+
plugins: [],
|
|
15
|
+
defineConstants: {},
|
|
16
|
+
copy: {
|
|
17
|
+
patterns: [],
|
|
18
|
+
options: {},
|
|
19
|
+
},
|
|
20
|
+
framework: 'react',
|
|
21
|
+
compiler: {
|
|
22
|
+
type: 'webpack5',
|
|
23
|
+
prebundle: {
|
|
24
|
+
enable: false,
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
mini: {
|
|
28
|
+
postcss: {
|
|
29
|
+
pxtransform: {
|
|
30
|
+
enable: true,
|
|
31
|
+
config: {},
|
|
32
|
+
},
|
|
33
|
+
url: {
|
|
34
|
+
enable: true,
|
|
35
|
+
config: {
|
|
36
|
+
limit: 1024,
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
cssModules: {
|
|
40
|
+
enable: false,
|
|
41
|
+
config: {
|
|
42
|
+
namingPattern: 'module',
|
|
43
|
+
generateScopedName: '[name]__[local]___[hash:base64:5]',
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
h5: {
|
|
49
|
+
publicPath: '/',
|
|
50
|
+
staticDirectory: 'static',
|
|
51
|
+
postcss: {
|
|
52
|
+
autoprefixer: {
|
|
53
|
+
enable: true,
|
|
54
|
+
config: {},
|
|
55
|
+
},
|
|
56
|
+
cssModules: {
|
|
57
|
+
enable: false,
|
|
58
|
+
config: {
|
|
59
|
+
namingPattern: 'module',
|
|
60
|
+
generateScopedName: '[name]__[local]___[hash:base64:5]',
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
} satisfies UserConfigExport;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{ORG_NAME}}/mobile",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "{{PROJECT_NAME}} 移动端小程序",
|
|
5
|
+
"private": true,
|
|
6
|
+
"templateInfo": {
|
|
7
|
+
"name": "default",
|
|
8
|
+
"typescript": true,
|
|
9
|
+
"css": "sass"
|
|
10
|
+
},
|
|
11
|
+
"scripts": {
|
|
12
|
+
"build:weapp": "taro build --type weapp",
|
|
13
|
+
"dev": "npm run dev:weapp",
|
|
14
|
+
"dev:weapp": "npm run build:weapp -- --watch",
|
|
15
|
+
"dev:h5": "taro build --type h5 --watch",
|
|
16
|
+
"lint": "eslint \"src/**/*.{ts,tsx}\"",
|
|
17
|
+
"type-check": "tsc --noEmit"
|
|
18
|
+
},
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"@babel/runtime": "^7.23.6",
|
|
21
|
+
"@svton/api-client": "^1.0.0",
|
|
22
|
+
"@svton/hooks": "^1.0.0",
|
|
23
|
+
"@svton/taro-ui": "^1.0.0",
|
|
24
|
+
"@svton/types": "^1.0.0",
|
|
25
|
+
"@tarojs/components": "3.6.23",
|
|
26
|
+
"@tarojs/helper": "3.6.23",
|
|
27
|
+
"@tarojs/plugin-framework-react": "3.6.23",
|
|
28
|
+
"@tarojs/plugin-platform-weapp": "3.6.23",
|
|
29
|
+
"@tarojs/react": "3.6.23",
|
|
30
|
+
"@tarojs/runtime": "3.6.23",
|
|
31
|
+
"@tarojs/taro": "3.6.23",
|
|
32
|
+
"react": "^18.2.0",
|
|
33
|
+
"react-dom": "^18.2.0",
|
|
34
|
+
"zustand": "^4.4.7"
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@babel/core": "^7.23.6",
|
|
38
|
+
"@tarojs/cli": "3.6.23",
|
|
39
|
+
"@tarojs/webpack5-runner": "3.6.23",
|
|
40
|
+
"@types/react": "^18.2.45",
|
|
41
|
+
"@typescript-eslint/eslint-plugin": "^6.15.0",
|
|
42
|
+
"@typescript-eslint/parser": "^6.15.0",
|
|
43
|
+
"babel-preset-taro": "3.6.23",
|
|
44
|
+
"eslint": "^8.56.0",
|
|
45
|
+
"eslint-config-taro": "3.6.23",
|
|
46
|
+
"typescript": "^5.3.3"
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"miniprogramRoot": "dist/",
|
|
3
|
+
"projectname": "{{PROJECT_NAME}}",
|
|
4
|
+
"description": "{{PROJECT_NAME}} 小程序",
|
|
5
|
+
"appid": "",
|
|
6
|
+
"setting": {
|
|
7
|
+
"urlCheck": true,
|
|
8
|
+
"es6": false,
|
|
9
|
+
"enhance": false,
|
|
10
|
+
"compileHotReLoad": false,
|
|
11
|
+
"postcss": false,
|
|
12
|
+
"minified": false,
|
|
13
|
+
"bundle": false,
|
|
14
|
+
"nodeModules": false
|
|
15
|
+
},
|
|
16
|
+
"compileType": "miniprogram"
|
|
17
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { View } from '@tarojs/components';
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
import { usePersistFn, useMount } from '@svton/hooks';
|
|
4
|
+
import { NavBar, StatusBar, Loading, Empty } from '@svton/taro-ui';
|
|
5
|
+
import type { ContentVo } from '{{ORG_NAME}}/types';
|
|
6
|
+
import './index.scss';
|
|
7
|
+
|
|
8
|
+
export default function Index() {
|
|
9
|
+
const [loading, setLoading] = useState(true);
|
|
10
|
+
const [contents, setContents] = useState<ContentVo[]>([]);
|
|
11
|
+
|
|
12
|
+
const fetchContents = usePersistFn(async () => {
|
|
13
|
+
try {
|
|
14
|
+
setLoading(true);
|
|
15
|
+
// 这里应该使用 @svton/api-client 的 API
|
|
16
|
+
// const response = await apiClient.contents.list({ page: 1, pageSize: 10 });
|
|
17
|
+
// setContents(response.data.list);
|
|
18
|
+
|
|
19
|
+
// 模拟数据
|
|
20
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
21
|
+
setContents([]);
|
|
22
|
+
} catch (error) {
|
|
23
|
+
console.error('获取内容列表失败', error);
|
|
24
|
+
} finally {
|
|
25
|
+
setLoading(false);
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
useMount(() => {
|
|
30
|
+
fetchContents();
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
return (
|
|
34
|
+
<View className="index">
|
|
35
|
+
<StatusBar />
|
|
36
|
+
<NavBar title="首页" />
|
|
37
|
+
|
|
38
|
+
<View className="content">
|
|
39
|
+
{loading && <Loading text="加载中..." />}
|
|
40
|
+
{!loading && contents.length === 0 && <Empty text="暂无内容" />}
|
|
41
|
+
{!loading && contents.length > 0 && (
|
|
42
|
+
<View className="content-list">
|
|
43
|
+
{/* 内容列表 */}
|
|
44
|
+
</View>
|
|
45
|
+
)}
|
|
46
|
+
</View>
|
|
47
|
+
</View>
|
|
48
|
+
);
|
|
49
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2017",
|
|
4
|
+
"module": "CommonJS",
|
|
5
|
+
"moduleResolution": "node",
|
|
6
|
+
"esModuleInterop": true,
|
|
7
|
+
"strict": true,
|
|
8
|
+
"jsx": "react-jsx",
|
|
9
|
+
"allowSyntheticDefaultImports": true,
|
|
10
|
+
"resolveJsonModule": true,
|
|
11
|
+
"typeRoots": ["node_modules/@types"],
|
|
12
|
+
"noEmit": true,
|
|
13
|
+
"skipLibCheck": true,
|
|
14
|
+
"baseUrl": ".",
|
|
15
|
+
"paths": {
|
|
16
|
+
"@/*": ["./src/*"]
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"include": ["src/**/*", "types/**/*", "config/**/*"],
|
|
20
|
+
"exclude": ["node_modules", "dist"]
|
|
21
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@svton/types",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "{{PROJECT_NAME}} 共享类型定义",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"types": "./dist/index.d.ts",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"build": "tsc",
|
|
9
|
+
"dev": "tsc --watch",
|
|
10
|
+
"clean": "rm -rf dist",
|
|
11
|
+
"type-check": "tsc --noEmit"
|
|
12
|
+
},
|
|
13
|
+
"devDependencies": {
|
|
14
|
+
"typescript": "^5.3.0"
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
// ============================================================
|
|
2
|
+
// API 请求/响应类型定义
|
|
3
|
+
// ============================================================
|
|
4
|
+
|
|
5
|
+
import type { UserVo, UserRole, PaginationParams, ContentStatus } from './common';
|
|
6
|
+
|
|
7
|
+
// ============================================================
|
|
8
|
+
// 认证相关
|
|
9
|
+
// ============================================================
|
|
10
|
+
|
|
11
|
+
// 登录请求
|
|
12
|
+
export interface LoginDto {
|
|
13
|
+
phone: string;
|
|
14
|
+
password: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// 登录响应
|
|
18
|
+
export interface LoginVo {
|
|
19
|
+
accessToken: string;
|
|
20
|
+
refreshToken: string;
|
|
21
|
+
user: UserVo;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// 注册请求
|
|
25
|
+
export interface RegisterDto {
|
|
26
|
+
phone: string;
|
|
27
|
+
password: string;
|
|
28
|
+
nickname: string;
|
|
29
|
+
code?: string; // 验证码
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// 刷新 Token
|
|
33
|
+
export interface RefreshTokenDto {
|
|
34
|
+
refreshToken: string;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// ============================================================
|
|
38
|
+
// 用户管理
|
|
39
|
+
// ============================================================
|
|
40
|
+
|
|
41
|
+
// 用户列表查询
|
|
42
|
+
export interface UserListParams extends PaginationParams {
|
|
43
|
+
keyword?: string;
|
|
44
|
+
role?: UserRole;
|
|
45
|
+
status?: number;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// 创建用户
|
|
49
|
+
export interface CreateUserDto {
|
|
50
|
+
phone: string;
|
|
51
|
+
password: string;
|
|
52
|
+
nickname: string;
|
|
53
|
+
role?: UserRole;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// 更新用户
|
|
57
|
+
export interface UpdateUserDto {
|
|
58
|
+
nickname?: string;
|
|
59
|
+
avatar?: string;
|
|
60
|
+
role?: UserRole;
|
|
61
|
+
status?: number;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// ============================================================
|
|
65
|
+
// 内容管理
|
|
66
|
+
// ============================================================
|
|
67
|
+
|
|
68
|
+
// 内容列表查询
|
|
69
|
+
export interface ContentListParams extends PaginationParams {
|
|
70
|
+
keyword?: string;
|
|
71
|
+
status?: ContentStatus;
|
|
72
|
+
authorId?: number;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// 创建内容
|
|
76
|
+
export interface CreateContentDto {
|
|
77
|
+
title: string;
|
|
78
|
+
content: string;
|
|
79
|
+
images?: string[];
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// 更新内容
|
|
83
|
+
export interface UpdateContentDto {
|
|
84
|
+
title?: string;
|
|
85
|
+
content?: string;
|
|
86
|
+
images?: string[];
|
|
87
|
+
status?: ContentStatus;
|
|
88
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
// ============================================================
|
|
2
|
+
// 通用类型定义
|
|
3
|
+
// ============================================================
|
|
4
|
+
|
|
5
|
+
// 分页请求参数
|
|
6
|
+
export interface PaginationParams {
|
|
7
|
+
page?: number;
|
|
8
|
+
pageSize?: number;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
// 分页响应
|
|
12
|
+
export interface PaginatedResponse<T> {
|
|
13
|
+
list: T[];
|
|
14
|
+
total: number;
|
|
15
|
+
page: number;
|
|
16
|
+
pageSize: number;
|
|
17
|
+
totalPages: number;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// 通用 API 响应
|
|
21
|
+
export interface ApiResponse<T = unknown> {
|
|
22
|
+
code: number;
|
|
23
|
+
message: string;
|
|
24
|
+
data: T;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// ============================================================
|
|
28
|
+
// 用户相关类型
|
|
29
|
+
// ============================================================
|
|
30
|
+
|
|
31
|
+
// 用户角色
|
|
32
|
+
export type UserRole = 'user' | 'admin' | 'super_admin';
|
|
33
|
+
|
|
34
|
+
// 用户状态
|
|
35
|
+
export type UserStatus = 0 | 1; // 0: 禁用, 1: 启用
|
|
36
|
+
|
|
37
|
+
// 用户基础信息
|
|
38
|
+
export interface UserVo {
|
|
39
|
+
id: number;
|
|
40
|
+
phone: string;
|
|
41
|
+
nickname: string;
|
|
42
|
+
avatar?: string;
|
|
43
|
+
role: UserRole;
|
|
44
|
+
status: UserStatus;
|
|
45
|
+
createdAt: string;
|
|
46
|
+
updatedAt: string;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// 用户详情(包含更多字段)
|
|
50
|
+
export interface UserDetailVo extends UserVo {
|
|
51
|
+
email?: string;
|
|
52
|
+
bio?: string;
|
|
53
|
+
lastLoginAt?: string;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// ============================================================
|
|
57
|
+
// 内容相关类型
|
|
58
|
+
// ============================================================
|
|
59
|
+
|
|
60
|
+
// 内容状态
|
|
61
|
+
export type ContentStatus = 'draft' | 'pending' | 'published' | 'rejected';
|
|
62
|
+
|
|
63
|
+
// 内容基础信息
|
|
64
|
+
export interface ContentVo {
|
|
65
|
+
id: number;
|
|
66
|
+
title: string;
|
|
67
|
+
content: string;
|
|
68
|
+
images: string[];
|
|
69
|
+
status: ContentStatus;
|
|
70
|
+
viewCount: number;
|
|
71
|
+
likeCount: number;
|
|
72
|
+
commentCount: number;
|
|
73
|
+
author: UserVo;
|
|
74
|
+
createdAt: string;
|
|
75
|
+
updatedAt: string;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// ============================================================
|
|
79
|
+
// 通用工具类型
|
|
80
|
+
// ============================================================
|
|
81
|
+
|
|
82
|
+
// 可选的 ID
|
|
83
|
+
export type WithOptionalId<T> = Omit<T, 'id'> & { id?: number };
|
|
84
|
+
|
|
85
|
+
// 创建 DTO(移除系统字段)
|
|
86
|
+
export type CreateDto<T> = Omit<T, 'id' | 'createdAt' | 'updatedAt'>;
|
|
87
|
+
|
|
88
|
+
// 更新 DTO
|
|
89
|
+
export type UpdateDto<T> = Partial<CreateDto<T>> & { id: number };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2020",
|
|
4
|
+
"module": "commonjs",
|
|
5
|
+
"declaration": true,
|
|
6
|
+
"declarationMap": true,
|
|
7
|
+
"strict": true,
|
|
8
|
+
"esModuleInterop": true,
|
|
9
|
+
"skipLibCheck": true,
|
|
10
|
+
"forceConsistentCasingInFileNames": true,
|
|
11
|
+
"outDir": "./dist",
|
|
12
|
+
"rootDir": "./src"
|
|
13
|
+
},
|
|
14
|
+
"include": ["src/**/*"],
|
|
15
|
+
"exclude": ["node_modules", "dist"]
|
|
16
|
+
}
|