Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
af75cf7
fix(menu): remove menu
GaoNeng-wWw Jul 20, 2026
fe9daf8
fix(menu): update menu
GaoNeng-wWw Jul 20, 2026
cfcaac8
fix(role): permission update
GaoNeng-wWw Jul 20, 2026
e1f81ac
style(role): remove console.log
GaoNeng-wWw Jul 20, 2026
6ef889d
feat(role): remove role will check user
GaoNeng-wWw Jul 20, 2026
b723010
fix(permission): allow empty description
GaoNeng-wWw Jul 20, 2026
9404770
fix: collection<UserRole> not not initialized
GaoNeng-wWw Jul 20, 2026
c52e0f8
feat(user): add `PasswordNotMatch` error
GaoNeng-wWw Jul 20, 2026
999bcd1
fix(user): transform array-string to array
GaoNeng-wWw Jul 20, 2026
d542f54
fix(i18): remove batch-remove-i18.dto
GaoNeng-wWw Jul 20, 2026
accd787
feat(role): better role cache
GaoNeng-wWw Jul 20, 2026
3ff798e
fix: prevent user create if user exists
GaoNeng-wWw Jul 21, 2026
62702e1
fix: token flush fail
GaoNeng-wWw Jul 21, 2026
c603040
feat: winston nest logger
GaoNeng-wWw Jul 21, 2026
d53b436
feat(mock): endpoint
GaoNeng-wWw Jul 21, 2026
713f0ed
feat(v1/application): application endpoint
GaoNeng-wWw Jul 22, 2026
fb0e9c4
feat: remove debugger
GaoNeng-wWw Jul 22, 2026
ef77b4d
revert: vite.config.dev.ts
GaoNeng-wWw Jul 22, 2026
5399626
fix: typo
GaoNeng-wWw Jul 22, 2026
9ccef7c
fix(tinyvue): review suggestion
GaoNeng-wWw Jul 22, 2026
b06dc02
fix: compare confirmPassword and oldPassword
GaoNeng-wWw Jul 22, 2026
c13729b
fix: transactional
GaoNeng-wWw Jul 22, 2026
9d49254
feat: add cn i18n record
GaoNeng-wWw Jul 22, 2026
18cd3bb
fix: can not get accept-language
GaoNeng-wWw Jul 22, 2026
2fed476
fix: remove cache
GaoNeng-wWw Jul 22, 2026
5b594ae
feat: singleton refresh
GaoNeng-wWw Jul 22, 2026
53eb4e2
feat(tinyvue): name will be fallback in add-role select component
GaoNeng-wWw Jul 22, 2026
a83a476
fix: remove ParseIntPipe
GaoNeng-wWw Jul 22, 2026
6fc35c6
chore: merge upstream refactor branch, keep dev version for deps
GaoNeng-wWw Jul 22, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
Comment thread
GaoNeng-wWw marked this conversation as resolved.
"Lua.runtime.version": "Lua 5.1",
"Lua.diagnostics.globals": [
"redis",
"KEYS",
"ARGV"
]
}
1 change: 1 addition & 0 deletions template/nest-next/eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export default tseslint.config(
'@typescript-eslint/no-unsafe-argument': 'warn',
"prettier/prettier": ["error", { endOfLine: "auto" }],
'@typescript-eslint/no-unsafe-call': 'off',
'@typescript-eslint/no-unsafe-assignment': 'off',
},
},
);
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/* DO NOT EDIT, file generated by nestjs-i18n */

/* eslint-disable */
/* prettier-ignore */
import type { Path } from "nestjs-i18n";
/* prettier-ignore */
Expand All @@ -19,11 +20,13 @@ export type I18nTranslations = {
"role": {
"NOT_FOUND": string;
"EXISTS": string;
"NOT_EMPTY": string;
};
"user": {
"NOT_FOUND": string;
"EXISTS": string;
"PASSWORD_INCORRECT": string;
"PASSWORD_NOT_MATCH": string;
};
"auth": {
"INVALID_TOKEN": string;
Expand All @@ -43,6 +46,10 @@ export type I18nTranslations = {
"EXISTS": string;
"NOT_FOUND": string;
};
"i18n": {
"EXISTS": string;
"NOT_FOUND": string;
};
};
"validation": {
"NOT_EMPTY": string;
Expand Down
3 changes: 2 additions & 1 deletion template/nest-next/libs/shared/src/constant.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export const roleTotal = () => `tinypro:v1:role:total`;
export const roleTotal = (condition?: string) =>
condition ? `tinypro:v1:role:total:${condition}` : `tinypro:v1:role:total`;
export const userTotal = (condition?: string) =>
condition ? `tinypro:v1:user:total:${condition}` : `tinypro:v1:user:total`;
12 changes: 11 additions & 1 deletion template/nest-next/libs/shared/src/global-exception.filter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {
ArgumentsHost,
Catch,
ExceptionFilter,
HttpException,
Injectable,
Logger,
} from '@nestjs/common';
Expand All @@ -20,7 +21,9 @@ export class GlobalExceptionFilter implements ExceptionFilter<Error> {
const ctx = host.switchToHttp();
const response: Response = ctx.getResponse();
const request: Request = ctx.getRequest();
const lang = request.headers['accept-language']?.split(',')[0] || 'enUS';
const lang =
request.headers['accept-language']?.replace('-', '').split(',')[0] ||
'enUS';
if (exception instanceof DomainError) {
const { code, message, details, args } = exception;
const translatedMessage = this.i18n.translate(message, { args, lang });
Expand All @@ -30,6 +33,13 @@ export class GlobalExceptionFilter implements ExceptionFilter<Error> {
details,
});
}
if (exception instanceof HttpException && exception.getStatus() !== 500) {
const msg = exception.message;
return response.status(exception.getStatus()).json({
statusCode: exception.getStatus(),
message: msg,
});
}
return response.status(500).json({
statusCode: 500,
message: this.i18n.translate('exception.common.INTERNAL_ERROR', { lang }),
Expand Down
17 changes: 11 additions & 6 deletions template/nest-next/libs/shared/src/guard/reject.guard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { Reflector } from '@nestjs/core';
import { I18nTranslations } from '../.generate/i18n.generated';
import { I18nContext } from 'nestjs-i18n';
import { ConfigureService } from '@app/configure';
import { DomainError } from '../error.base';

@Injectable()
export class RejectRequestGuard implements CanActivate {
Expand All @@ -31,11 +32,15 @@ export class RejectRequestGuard implements CanActivate {
if (!i18n) {
return Promise.resolve(false);
}
throw new HttpException(
i18n.t('exception.preview.REJECT_THIS_REQUEST', {
lang: I18nContext?.current()?.lang || 'enUS',
}),
HttpStatus.BAD_REQUEST,
);
throw new RejectRequest();
}
}

export class RejectRequest extends DomainError {
constructor() {
super({
message: 'exception.preview.REJECT_THIS_REQUEST',
code: HttpStatus.BAD_REQUEST,
})
}
}
2 changes: 2 additions & 0 deletions template/nest-next/mikro-orm.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import config from './configs/config.json';
import { Role, RoleMenu, RolePermission } from './src/role';
import { User, UserRole } from './src/user';
import { I18n, Lang } from './src/i18';
import { Application } from './src/application';

export default defineConfig({
entities: [
Expand All @@ -19,6 +20,7 @@ export default defineConfig({
UserRole,
Lang,
I18n,
Application,
],
host: config.database.host,
port: config.database.port,
Expand Down
2 changes: 2 additions & 0 deletions template/nest-next/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@
"class-validator": "^0.14.1",
"ioredis": "^5.11.1",
"lodash.get": "^4.4.2",
"mockjs": "^1.1.0",
"nest-winston": "^1.10.2",
"nestjs-i18n": "^10.5.1",
"reflect-metadata": "^0.2.2",
"rimraf": "5.0.1",
Expand Down
116 changes: 116 additions & 0 deletions template/nest-next/seeder/application-seeder.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import type { EntityManager } from '@mikro-orm/core';
import { Seeder } from '@mikro-orm/seeder';
import { Application } from '../src/application';
import { log } from './utils/log';

const applicationData = [
{
name: 'Tiny Design 设计体系',
description:
'华为云产品和服务的规范体系,包括交互视觉设计、业务流程、国际化、术语词条。',
tag: '[{ "type": "", "value": "机会点定义" }, { "type": "danger", "value": "交互设计" }]',
classify: 'design',
icon: 'card-list-application-default.png',
},
{
name: 'Tiny DesignLink 设计流水线工具',
description:
'设计+协同+资源管理,一个工具就够了,在线原型设计、设计过程融入DevOps流程。',
tag: '[{ "type": "error", "value": "交互设计" }, { "type": "warning", "value": "视觉设计" }]',
classify: 'design',
icon: 'card-list-application-default.png',
},
{
name: 'TinyUI3.0 开发工具 ',
description: 'Cloud Design System 提供了丰富的规范文档及开发组件。',
tag: '[{ "type": "success", "value": "开发" }]',
classify: 'dev',
icon: 'card-list-application-default.png',
},
{
name: 'TinyPlus3.0 开发工具',
description:
'TinyPlus3.0 是基于Angular + Typescript的Web前端云业务组件库。',
tag: '[{ "type": "success", "value": "开发" }]',
classify: 'dev',
icon: 'card-list-tiny-plus.png',
},
{
name: 'Tiny Stage 工程工具 ',
description:
'一个跨平台的前端工程化cli工具,为开发提供一系列开发套件和工程插件',
tag: '[{ "type": "success", "value": "开发" }]',
classify: 'dev',
icon: 'card-list-console-framework.png',
},
{
name: 'Tiny Flow 接口编排工具 ',
description:
'端到端的API编排解决方案,通过可视化编程的方式快速生成、发布、调试的API编排。',
tag: '[{ "type": "success", "value": "开发" }]',
classify: 'dev',
icon: 'card-list-console-framework.png',
},
{
name: 'Tiny Gate 门禁系统',
description:
'门禁系统,通过卡点方式集成到伏羲流水线,在服务发布时生成预览页面。',
tag: '[{ "type": "info", "value": "测试验证" }]',
classify: 'dev',
icon: 'card-list-console-framework.png',
},
{
name: 'Console Framework 控制台框架',
description: '华为云各服务快速构建管理控制台的平台。',
tag: '[{ "type": "success", "value": "开发" },{ "type": "info", "value": "测试验证" },{ "type": "warning", "value": "上线" }]',
classify: 'dev',
icon: 'card-list-console-framework.png',
},
{
name: 'Nodejs Framework Nodejs应用',
description:
'基于egg的定制化web服务框架,让你快速上手Nodejs做BFF意见微服务。',
tag: '[{ "type": "success", "value": "开发" },{ "type": "info", "value": "测试验证" }]',
classify: 'dev',
icon: 'card-list-console-framework.png',
},
{
name: 'Furion 前端体验监控',
description:
'提供端到端前端用户体验度量,让产品用户体验可度量、可监控、可优化。',
tag: '[{ "type": "", "value": "机会点定义" }]',
classify: 'dev',
icon: 'card-list-furion.png',
},
{
name: 'Tiny Mock API 管理',
description:
'功能强大的API管理平台,旨在为开发、产品、测试人员提供更优雅的接口管理服务。',
tag: '[{ "type": "success", "value": "开发" },{ "type": "warning", "value": "视觉设计" }]',
classify: 'dev',
icon: 'card-list-application-default.png',
},
];

export class ApplicationSeeder extends Seeder {
async run(em: EntityManager): Promise<void> {
for (const app of applicationData) {
const existsData = await em.findOne(Application, {
name: app.name,
});
if (existsData) {
log.info(`Application ${app.name} already exists`);
continue;
}
const application = em.create(Application, {
name: app.name,
description: app.description,
icon: app.icon,
tag: app.tag,
classify: app.classify,
});
em.persist(application);
}
await em.flush();
}
}
2 changes: 2 additions & 0 deletions template/nest-next/seeder/database-seeder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { PermissionSeeder } from './permission-seeder';
import { RoleSeeder } from './role-seeder';
import { UserSeeder } from './user-seeder';
import { I18nRecordSeeder } from './i18n-seeder';
import { ApplicationSeeder } from './application-seeder';

export class DatabaseSeeder extends Seeder {
async run(em: EntityManager): Promise<void> {
Expand All @@ -15,6 +16,7 @@ export class DatabaseSeeder extends Seeder {
RoleSeeder,
UserSeeder,
I18nRecordSeeder,
ApplicationSeeder,
]);
});
}
Expand Down
6 changes: 6 additions & 0 deletions template/nest-next/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ import { randomBytes } from 'crypto';
import { I18Module } from './i18/i18.module';
import { I18n, Lang } from './i18';
import { RejectRequestGuard } from '@app/shared';
import { MockModule } from './mock/mock.module';
import { ApplicationModule } from './application/application.module';
import { Application } from './application';

@Module({
imports: [
Expand Down Expand Up @@ -84,6 +87,7 @@ import { RejectRequestGuard } from '@app/shared';
UserRole,
Lang,
I18n,
Application,
],
host: configService.get('database.host'),
port: configService.get('database.port'),
Expand Down Expand Up @@ -113,6 +117,8 @@ import { RejectRequestGuard } from '@app/shared';
UserModule,
AuthModule,
I18Module,
MockModule,
ApplicationModule,
],
providers: [
{
Expand Down
21 changes: 21 additions & 0 deletions template/nest-next/src/application/application.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { Controller, Get, Query } from '@nestjs/common';
import { ApplicationService } from './application.service';
import {
FindApplicationEntity,
FindApplicationsRequest,
} from './dto/find-applications';
import { ApiOkResponse, ApiOperation } from '@nestjs/swagger';

@Controller('application')
export class ApplicationController {
constructor(private readonly applicationService: ApplicationService) {}

@ApiOperation({ summary: '获取应用' })
@ApiOkResponse({
type: FindApplicationEntity,
})
@Get()
async getAllApplication(@Query() searchInfo: FindApplicationsRequest) {
return this.applicationService.findAllAplication(searchInfo);
}
}
31 changes: 31 additions & 0 deletions template/nest-next/src/application/application.entity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { type Opt } from '@mikro-orm/core';
import { Entity, PrimaryKey, Property } from '@mikro-orm/decorators/legacy';
import { v7 } from 'uuid';

export enum TagEnum {
DEFAULT = '',
SUCCESS = 'success',
INFO = 'info',
DANGER = 'danger',
WARNING = 'warning',
}

export type ApplicationId = string & { readonly __brand: unique symbol };
export const createApplicationId = () => v7() as ApplicationId;
export const toApplicationId = (val: string) => val as ApplicationId;

@Entity({ tableName: 'application' })
export class Application {
@PrimaryKey({ type: 'uuid' })
id: Opt<ApplicationId> = createApplicationId();
@Property({ type: 'text' })
name: string;
@Property({ type: 'text' })
description: string;
@Property({ type: 'text' })
icon: string;
@Property({ type: 'text' })
tag: string;
@Property({ type: 'text' })
classify: string;
}
12 changes: 12 additions & 0 deletions template/nest-next/src/application/application.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { Module } from '@nestjs/common';
import { ApplicationService } from './application.service';
import { ApplicationController } from './application.controller';
import { MikroOrmModule } from '@mikro-orm/nestjs';
import { Application } from './application.entity';

@Module({
imports: [MikroOrmModule.forFeature([Application])],
controllers: [ApplicationController],
providers: [ApplicationService],
})
export class ApplicationModule {}
Loading
Loading