上一章介绍了使用Minio创建文件管理模块的aspnetcore后端代码的实现,这一章主要介绍angular前端代码的实现,具体步骤如下:
1、安装文件上传依赖包
上一章我们已经使用模板生成了框架代码,使用vscode打开filemanagement.angular文件夹,启用终端,输入如下命令安装ngx-uploader文件上传组件
npm install ngx-uploader
2、添加文件管理模块
在vscode终端输入如下命令添加文件管理库:
ng generate library file-management
文件管理lib中可以删除掉自动生成的component和service,只保留module文件,注意同时要删除错误的引用
输入如下命令添加一个文件浏览组件file-browser
ng generate component file-browser --skip-tests --project file-management
输入命令添加个人文件浏览组件
ng generate component my-file-browser --skip-tests --project file-management
输入命令添加公共文件浏览组件
ng generate component public-file-browser --skip-tests --project file-management
接着在lib目录添加file-management-routing.module.ts文件,内容如下:
import { NgModule } from '@angular/core';
import { AuthGuard, DynamicLayoutComponent, PermissionGuard } from '@abp/ng.core';
import { Routes, RouterModule } from '@angular/router';
import { MyFileBrowserComponent } from './my-file-browser/my-file-browser.component';
import { PublicFileBrowserComponent } from './public-file-browser/public-file-browser.component';
const routes: Routes = [
{
path: '',
// 注意升级5.0.0正式版本后,需要将DynamicLayoutComponent修改为RouterOutletComponent,否则组件页面无法显示
component: DynamicLayoutComponent,
canActivate: [AuthGuard, PermissionGuard],
children: [
{
path: 'public-files',
component: PublicFileBrowserComponent,
data: { requiredPolicy: 'FileManagement.PublicFiles'},
},
{
path: 'my-files',
component: MyFileBrowserComponent,
data: { requiredPolicy: 'FileManagement.MyFiles'},
},
],
},
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
})
export class FileManagementRoutingModule {}
最后修改模块file-management.module.ts文件,添加必须的模块引入以及配置模块懒加载:
import { CoreModule, LazyModuleFactory } from '@abp/ng.core';
import { ThemeSharedModule } from '@abp/ng.theme.shared';
import { ModuleWithProviders, NgModule, NgModuleFactory } from '@angular/core';
import { NgxUploaderModule } from 'ngx-uploader';
import { FileBrowserComponent } from './file-browser/file-browser.component';
import { FileManagementRoutingModule } from './file-management-routing.module';
import { MyFileBrowserComponent } from './my-file-browser/my-file-browser.component';
import { PublicFileBrowserComponent } from './public-file-browser/public-file-browser.component';
import { UploadFilesComponent } from './upload-files/upload-files.component';
import { NgbDropdownModule, NgbProgressbarModule } from '@ng-bootstrap/ng-bootstrap';
@NgModule({
declarations: [ FileBrowserComponent, MyFileBrowserComponent, PublicFileBrowserComponent, UploadFilesComponent
],
imports: [ CoreModule, ThemeSharedModule, FileManagementRoutingModule, NgxUploaderModule, NgbDropdownModule, NgbProgressbarModule ],
exports: [ ]
})
export class FileManagementModule {
static forChild(): ModuleWithProviders<FileManagementModule> {
return {
ngModule: FileManagementModule
};
}
static forLazy(): NgModuleFactory<FileManagementModule> {
return new LazyModuleFactory(FileManagementModule.forChild());
}
}
routing中配置的是模块的组件路由表,控制页面跳转,我们还需要根据路由生成一个菜单导航,因此还需要配置菜单路由表
3、配置Abp菜单路由表
菜单路由的配置是不直接依赖于页面组件的,可以将其定义在config子模块中,这样根模块中就可以从文件管理的config子模块中加载菜单,而文件管理主模块使用LazyLoad懒加载模式,这样程序打包后主文件会小一些;这很重要,如果直接在文件管理主模块中配置路由菜单,那么根模块就不能懒加载文件模块,因为菜单必须在应用程序初始化时生成,打包后会将整个文件管理模块打包到主文件;另外如果模块有公共的组件或服务需要在根模块引用,那么最好也放到一个子模块中,否则懒加载就没意义了
添加文件管理config子模块步骤如下:
- 在projects\file-management目录下添加config目录,在其中添加ng-package.json文件,内容如下:
{ "$schema": "../../../node_modules/ng-packagr/ng-package.schema.json", "dest": "../../dist/file-management/config", "lib": { "entryFile": "src/public-api.ts" } }
- 在config目录下添加src\enums目录,在其中添加route-names.ts,配置菜单枚举常量
export const enum eFileManagementRouteNames { FileManagement = 'FileManagement::Menu:FileManagement', PublicFiles = 'FileManagement::Menu:PublicFiles', MyFiles = 'FileManagement::Menu:MyFiles', AppMenu = '::Menu:AppMenu' }
- 在src目录下添加providers目录,在其中添加route.provider.ts,配置路由菜单项
import { eLayoutType, RoutesService } from '@abp/ng.core'; import { APP_INITIALIZER } from '@angular/core'; import { eFileManagementRouteNames } from '../enums/route-names'; export const FILE_MANAGEMENT_ROUTE_PROVIDERS = [ { provide: APP_INITIALIZER, useFactory: configureRoutes, deps: [RoutesService], multi: true, }, ]; export function configureRoutes(routesService: RoutesService) { return () => { routesService.add([ { path: '/file-management', name: eFileManagementRouteNames.FileManagement, iconClass: 'cil-file', layout: eLayoutType.application, requiredPolicy: 'FileManagement.MyFiles || FileManagement.ProjectResources', order: 50, }, { path: '/file-management/public-files', name: eFileManagementRouteNames.PublicFiles, parentName: eFileManagementRouteNames.FileManagement, requiredPolicy: 'FileManagement.PublicFiles', layout: eLayoutType.application, order: 1, }, { path: '/file-management/my-files', name: eFileManagementRouteNames.MyFiles, parentName: eFileManagementRouteNames.FileManagement, requiredPolicy: 'FileManagement.MyFiles', layout: eLayoutType.application, order: 2, }, ]); }; }
- 在src目录下添加file-management-config.module.ts文件,内容如下:
import { CoreModule } from '@abp/ng.core'; import { ModuleWithProviders, NgModule } from '@angular/core'; import { FILE_MANAGEMENT_ROUTE_PROVIDERS } from './providers/route.provider'; @NgModule({ imports: [CoreModule], declarations: [], exports: [], }) export class FileManagementConfigModule { // 在跟模块中import时调用此方法,将模块的配置提供给根模块进行初始化路由菜单 static forRoot(): ModuleWithProviders<FileManagementConfigModule> { return { ngModule: FileManagementConfigModule, providers: [FILE_MANAGEMENT_ROUTE_PROVIDERS], }; } }
- 在src目录下添加public-api.ts文件,内容如下:
export * from './enums/route-names'; export * from './file-management-config.module'; export * from './providers/route.provider';
- 在终端执行如下命令打包模块
ng build file-management --configuration production
最好在package.json文件中添加命令脚本,如下:
"scripts": { ... "build:files": "ng build file-management --configuration production", ... },
这样以后打包只要执行 yarn build:files就可以了,打包完成后你可以把它发布到npm服务器上
4、在根模块中引入文件管理模块
在引入文件管理模块之前,需要先打包,
在app.module.ts中添加如下内容:
import { FileManagementConfigModule } from 'file-management/config';
...
@NgModule({
imports: [
...
...
FileManagementConfigModule.forRoot(), // 文件管理模块配置子模块
],
...
接着在app-routing.module.ts添加模块懒加载路由如下:
const routes: Routes = [
...
...
{
path: 'file-management',
loadChildren: () =>
import('file-management').then(m => m.FileManagementModule.forLazy()),
},
];
此处import模块参数的配置来源于tsconfig.json中的paths配置
它指向打包后的文件目录,因此必须打包后才能引入
在终端执行命令npm start 启动项目,可以看到模块菜单已经启用:
现在页面还是空的,我们需要为其添加内容,在这之前我们还需要生成webapi访问的客户端代理服务
5、使用abp cli生成客户端代理的代码
生成客户端代理,直接在vscode终端执行 abp generate-proxy即可,但是这样生成的代码都是根模块中的,即src/app目录下;既然我们将文件管理封装为独立模块,就需要将客户端代理的代码生成在文件管理模块中,需要的操作步骤如下:
首先,找到aspnetcore后端文件管理模块的MyCompany.FileManagement.HttpApi项目,依次打开MyFilesController和PublicFilesController文件,为类添加如下属性装饰:
[RemoteService(Name = FileManagementRemoteServiceConsts.RemoteServiceName)]
[Area(FileManagementRemoteServiceConsts.ModuleName)]
...
public class ...
然后,打开angular前端根模块中environments\environments.ts文件,添加模块api配置
apis: {
...
FileManagement: {
// api的地址,不配置时使用default中配置
url: 'https://localhost:44358',
// 与后端根命名空间对应,生成客户端代理时不生成此命名空间目录
rootNamespace: 'MyCompany.FileManagement',
}
},
接着打开package.json,在脚本中添加生成客户端代理的指令(注意abp5.0.0正式版后,指令有所变化,参考CLI | Documentation Center | ABP.IO):
"scripts": {
...
...
"gen:files": "abp generate-proxy -m fileManagement -a FileManagement -t file-management",
...
},
--module
或-m
: 指定要为其生成代理的后端模块的名称. 默认值:app,在本示例中,此值为controller属性装饰[Area(FileManagementRemoteServiceConsts.ModuleName)]中ModuleName对应的值,即
fileManagement--api-name
或-a
: 在/src/environments/environment.ts
中定义的API端点名称。. 默认值:default。
在本示例中,此值为environments.ts中配置的api名称FileManagement--target
或-t
: 指定放置生成的代码的Angular项目名称. 默认值:defaultProject。本实例中此值为模块的项目名称,即file-management
最后执行如下指令生成客户端代理:
yarn gen:files
生成的代码文件如下:
6、编写文件管理模块组件代码
这部分代码比较多,篇幅有限,就不贴在这,可在文章结尾找到源码下载查看
7、多语言资源
主要涉及到文件模块组件页面、菜单显示,以及后台权限部分的多语言资源,整理好后添加到后台文件模块的MyCompany.FileManagement.Domain.Shared\Localization\FileManagement中的资源文件中,中文资源文件zh-Hans.json如下:
{
"culture": "zh-Hans",
"texts": {
"Menu:FileManagement": "文件管理",
"Menu:PublicFiles": "公共文件",
"Menu:MyFiles": "我的文件",
"Files:CurrentFolder": "当前目录",
"Files:CreateDir": "新建目录",
"Files:UploadFiles": "上传文件",
"Files:GoUpFolder": "上级目录",
"Files:Filter": "筛选",
"Files:Actions": "操作",
"Files:ReName": "重命名",
"Files:Delete": "删除",
"Files:Download": "下载",
"Files:Size": "文件大小",
"Files:LastWriteTime": "最后修改时间",
"Files:Save": "保存",
"Files:Name": "文件名",
"Files:UploadDesc": "拖拽文件到这里,或者",
"Files:UploadDescEnd": "上传。",
"Files:Browse": "浏览文件",
"Files:DeleteDirComfirm": "目录<strong>[{0}]</strong>以及目录中的内容都将被删除. 你要继续吗?",
"Files:DeleteFileComfirm": "文件<strong>[{0}]</strong>将被删除. 你要继续吗?"
}
}
7、编译运行
编译文件管理模块
yarn build:files
执行npm start 启动项目,效果如下:
上传文件: