NG-ZORRO-TEMPLATE是基于阿里angular组件NG-ZORRO开发的一套企业后台管理系统模板。目的是简单、方便、快速的搭建一个企业后台管理系统。
模板项目提供了登录页面、动态菜单、session存储、权限路由守卫等功能,您只需要开发对应的后台服务,即可实现一个简单的后台管理系统;
为了方便大家在没有后台服务时也能使用,项目提供了一些fake和demo,可以直接使用。
登录界面 顶部菜单 左边菜单-展开 左边菜单-折叠 修改密码
- 安装git
- 安装npm
- 安装最新版angular-cli
直接clone代码
git clone https://github.com/alexspring123/NG-ZORRO-TEMPLATE.git
npm install
如果npm速度较慢,大家可以安装使用cnpm
然后在console中执行下面命令
ng s --open
此时浏览器就自动打开了模板网站,是否特别简单。
模板网站允许通过配置来更改网站的外观。所有配置项都存放在/src/config/global-config.ts文件中
配置项 | 说明 |
---|---|
app_title | 系统名称,显示在浏览器的title中(浏览器的标签) 如果路由中配置了data:{title:'xxxx'}参数,系统激活路由时会自动替换为title参数的取值,例如模板中角色样例模块RoleRoutes |
登录页面配置对应配置文件loginConfig类中
配置项 | 说明 |
---|---|
background_image | 登录页面背景图片,图片一般放在/src/assets目录中 |
form_title | 登录表单的标题,最好控制在8个汉字以内 |
所有菜单相关配置存放在配置文件menuConfig类中
配置项 | 说明 |
---|---|
placement | 取值'left'或'top'。 设置为'left',菜单显示在左侧 设置为'top',菜单显示在顶部 |
配置项 | 说明 |
---|---|
copyright | 版权信息。目前仅支持字符串 配置后会在主窗口最下方显示版权信息 如果值为空或空字符串,则不显示版权信息。 |
模板项目为大家提供了本地session的存储功能,存放在配置文件的sessionConfig类中
配置项 | 说明 |
---|---|
store_key | 本地session存储的key 系统会自动将session存放在本地的localstorage中 |
目前系统严格定义了后台服务需要返回的接口格式如下:
/**预定义服务 */
export interface LoginService {
/**
* 登录
*/
login(loginData: { login: string, password: string }): Observable<HttpResult<Session>>;
/**
* 注销
* userCode:当前登录用户代码
* token:当前登录的token
* userCode和token必须有一个不为Null。
* 登录后服务端会生成一个token并返回给界面,此时只需要传入token一个参数服务端即可完成注销
*/
logout(token: string): Observable<HttpResult<any>>;
/**
* 修改密码
* 处于安全,session不会保存用户的密码,因此修改密码时需要传入原始密码,服务端需要对原始密码和token进行验证
* 服务端成功后不用返回data
*/
changePassword(data: { token: string, oldPassword: string, newPassword: string }): Observable<HttpResult<any>>;
}
http远程调用返回angular的Observable异步对象(建议大家也采用此方式) Ï 其中的HttpResult和Session是系统定义的数据格式:
export class HttpResult<T> {
constructor(public code: number, public message: string, public data: T) {
this.code = code;
this.message = message;
this.data = data;
}
}
//菜单
export interface Menu {
title: string;//菜单标题
path: string;//路由路径
icon?: string; //图片
subMenus?: Array<Menu>; //子菜单
}
//权限
export interface Permission {
code: string; //权限代码
name: string; //权限名称
}
/**登录后返回的Session */
export interface Session {
userCode: string;
userName: string;
token?: string;
menus: Array<Menu>;
permissions: Array<Permission>;
}
上面只是解释了登录用到的接口和数据结果,实际开发中大家只需要替换/src/app/providers/login.service-impl.ts文件的实现即可
特别注意: 此文件名称和位置不能更改
模板提供了为每个路由页面单独设置浏览器标题的功能。
设置方法:在路由定义中增加data参数,并在其中定义title属性,例如
export const RoleRoutes: Route[] = [
{
path: 'role', component: RoleComponent, data: { title: '角色' },
children: [
{ path: 'list', component: RoleListComponent, data: { title: '角色列表', permission: ['/role1/view'] } },
]
},
];
当路由导航到 role/list 页面时,浏览器标题显示为:智能照明管理系统-角色列表
其中“智能照明管理系统”全局选项app_title的值
如果某个路由未设置data['title']属性,那么浏览器标题默认为app_title的值
管理系统一般会根据用户权限来控制能够进入某个模块,通常做法是编写一个路由守卫,然后添加到路由定义中; 为了方便大家使用,模板提供了默认的路由权限守卫PermissionGurid,大家只需要在路由定义中增加data参数,并配置permission字段即可,例如
export const RoleRoutes: Route[] = [
{ path: 'role', redirectTo: '/frame/role/list', pathMatch: 'full' },
{
path: 'role', component: RoleComponent, data: { title: '角色' },
children: [
{ path: 'list', component: RoleListComponent, data: { title: '角色列表', permission: ['/role/view'] } },
]
},
];
permission字段是一个字符串数组,可以配置多个权限,目前实现的功能为,只要用户包含其中一个权限,守卫即放行,而不是同时具有所有权限。
如果用户没有permission中定义的任一个权限,那么系统将不跳转,并且谈框提示缺少权限。
在SessionService类中提供了
hasPermission(permissionCode: string): boolean {
if (!permissionCode) return false;
let session = this.getSession();
return session ? session.permissions.some(p => p.code == permissionCode) : false;
}
因此在模块中仅需要调用此方法来判断是否具有权限,然后控制界面按钮是否可见
_canCreate = false;
_canEdit = false;
_canDelete = false;
constructor(private sessionService: SessionService,
......) {
}
ngOnInit(): void {
this.refreshPermission();
this.search(true);
}
private refreshPermission(): void {
this._canCreate = this.sessionService.hasPermission('/role/create');
this._canEdit = this.sessionService.hasPermission('/role/edit');
this._canDelete = this.sessionService.hasPermission('/role/delete');
}
<button nz-button *ngIf="_canCreate" [nzType]="'primary'" [nzGhost]="true" [nzSize]="'small'" routerLink="./create">
<i class="anticon anticon-plus"></i>
<span>添加角色</span>
</button>
模板项目的目录结构定义为
目录或文件 | 用户是否可更改 | 说明 |
---|---|---|
/doc/*.* | 可以删除 | 记录项目相关的文档 |
/src/*.* | 不可更改 | src下面的文件(不包含子目录)属于模板项目 |
/src/assets/ | 可以更改 | 此目录下面是用户的静态资源,比如图片、文件等,用户可以自由修改 |
/src/config/ | 可以更改 | 此目录下存放的是系统配置文件,用户可以更改,但是不能删除任何文件 |
/src/environments/ | 可以更改 | 此目录是anguler-cli标准的环境变量文件,可以按需修改 |
/src/app/base/ | 不可更改 | 存放项目的登录页面、主页面、修改密码页面、注销页面等,用户不可修改 |
/src/app/providers/ | 可以修改,但是不能删除 | 存放模板定义好的接口实现,用户可以修改实现,但是不能修改文件名、类名和实现的接口 |
/src/app/contents/ | 可以任何修改 | 存放用户自己的模块代码,可以任意修改 |
/src/app/config/ | 可以修改,但是不能删除 | 存放用户模块和路由的注册文件 |
自定义的模块通过在/src/app/config/contents-modules.ts中注册。
//客户自定的模块注册
export const ContentsRoutes: Route[] = [
{ path: '', loadChildren: getRoleModule },
];
export function getRoleModule(): any { return RoleModule; }
由于整个模板使用了异步路由,因此新增的模块不再需要在其他模块中import,仅需要在此配置中增加一行异步路由即可;
-
下载最新的项目文件
-
替换如下文件
/src/*.html *.ts *.css *.json
/src/app/base/,整个目录覆盖
- 比对并合并如下文件
/src/config/global-config.ts
开发调试好后需要部署到服务器上运行,我这里仅介绍apache的部署方式(其他如Nginx,IIS等类似)
编译制品
ng build -prod -aot
将编译结果/dist目录中的文件直接复制到apache的根目录(linux上的默认目录为/var/www/html)
启动apache,打开浏览器访问http://IP:端口,就可以看到你的项目界面了
比如想将项目部署到apache的subDir子目录中
编译制品
ng build -prod -aot -bh /subDir/ -d /subDir/
其中subDir是apache中的目录名称,你可以替换成你自己的目录名称
将编译结果/dist目录中的文件直接复制到apache的subDir目录(linux上的默认目录为/var/www/html/subDir)
配置项目目录 打开apache的配置文件,ubuntu上是/etc/apache2/apache2.conf,添加如下代码
<Directory /subDir>
Options FollowSymLinks
AllowOverride all
allow from all
</Directory>
启动apache,打开浏览器访问:http://IP:端口/subDir 可以正常访问
上面部署可以正常访问,但是刷新浏览器时会报错
The requested URL /***** was not found on this server 原因是,正常访问时url被angular接管,浏览器并没有向服务器发送请求。当刷新浏览器时,由浏览器接管url,会向服务端发送请求。而服务器上并没有人处理,从而报Not found错误。
要解决这个问题,我们只需要让服务器处理这个请求即可,下面以ubuntu上的apache为例。
激活mod_rewrite模块
sudo a2enmod rewrite
重新apache生效
sudo systemctl restart apache2
修改/etc/apache2/apache2.conf文件
如果部署在根目录,找到下面的配置
<Directory /var/www/>
Options Indexes FollowSymLinks
AllowOverride None
Require all granted
</Directory>
将其中 AllowOverride None 改为 AllowOverride all,如果没有就增加一条。
如果部署在子目录subDir中,找到下面的配置
<Directory /subDir>
Options FollowSymLinks
AllowOverride all
allow from all
</Directory>
将其中 AllowOverride None 改为 AllowOverride all,如果没有就增加一条。
如果部署在根目录,在/var/www/html/下新建.htaccess文件,内容为
RewriteEngine On
# If an existing asset or directory is requested go to it as it is
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR]
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d
RewriteRule ^ - [L]
# If the requested resource doesn't exist, use index.html
RewriteRule ^ /index.html
如果部署在子目录/var/www/html/subDir中,则在subDir目录中新增.htaccess文件,内容为
RewriteEngine On
# If an existing asset or directory is requested go to it as it is
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR]
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d
RewriteRule ^ - [L]
# If the requested resource doesn't exist, use index.html
RewriteRule ^ /subDir/index.html
修改.htaccess文件不需要重启apache