Browse Source

角色 & 用户

main
kkerwin 2 years ago
parent
commit
a9dc768637
  1. 5
      package.json
  2. 17
      pnpm-lock.yaml
  3. 6
      projects/admin/proxy.conf.json
  4. 2
      projects/admin/src/app/app-routing.module.ts
  5. 18
      projects/admin/src/app/components/app-layout/app-layout.component.ts
  6. 2
      projects/admin/src/app/components/role-permission/role-permission.component.html
  7. 98
      projects/admin/src/app/components/role-permission/role-permission.component.ts
  8. 77
      projects/admin/src/app/components/user-list/user-list.component.html
  9. 79
      projects/admin/src/app/components/user-list/user-list.component.ts
  10. 2
      projects/admin/src/app/dtos/index.ts
  11. 15
      projects/admin/src/app/dtos/org.dto.ts
  12. 22
      projects/admin/src/app/dtos/user.dto.ts
  13. 4
      projects/admin/src/app/pages/login/login.component.html
  14. 9
      projects/admin/src/app/pages/login/login.component.ts
  15. 20
      projects/admin/src/app/pages/organization/organization-form/organization-form.component.html
  16. 64
      projects/admin/src/app/pages/organization/organization-form/organization-form.component.ts
  17. 95
      projects/admin/src/app/pages/organization/organization-list/organization-list.component.html
  18. 72
      projects/admin/src/app/pages/organization/organization-list/organization-list.component.ts
  19. 68
      projects/admin/src/app/pages/system/user-manage/user-manage.component.html
  20. 12
      projects/admin/src/app/pages/system/user-manage/user-manage.component.less
  21. 97
      projects/admin/src/app/pages/system/user-manage/user-manage.component.ts
  22. 80
      projects/admin/src/app/services/api.service.ts
  23. 17
      projects/admin/src/app/services/auth.guard.ts
  24. 2
      projects/admin/src/app/services/http.interceptor.ts
  25. 33
      projects/cdk/src/utils/index.ts

5
package.json

@ -3,7 +3,7 @@
"version": "0.0.0",
"scripts": {
"ng": "ng",
"start:admin": "ng serve admin",
"start:admin": "ng serve admin --proxy-config ./projects/admin/proxy.conf.json",
"start:client": "ng serve client",
"build:admin": "ng build admin",
"build:client": "ng build client",
@ -22,6 +22,8 @@
"@angular/platform-browser-dynamic": "^16.1.0",
"@angular/router": "^16.1.0",
"@ant-design/icons-angular": "^16.0.0",
"crypto-js": "^4.1.1",
"date-fns": "^2.30.0",
"immer": "^10.0.2",
"ng-zorro-antd": "16.1.0",
"ngx-permissions": "^15.0.1",
@ -33,6 +35,7 @@
"@angular-devkit/build-angular": "^16.1.4",
"@angular/cli": "~16.1.4",
"@angular/compiler-cli": "^16.1.0",
"@types/crypto-js": "^4.1.2",
"@types/jasmine": "~4.3.0",
"autoprefixer": "^10.4.14",
"jasmine-core": "~4.6.0",

17
pnpm-lock.yaml

@ -35,6 +35,12 @@ dependencies:
'@ant-design/icons-angular':
specifier: ^16.0.0
version: 16.0.0(@angular/common@16.1.0)(@angular/core@16.1.0)(@angular/platform-browser@16.1.0)(rxjs@7.8.0)
crypto-js:
specifier: ^4.1.1
version: 4.1.1
date-fns:
specifier: ^2.30.0
version: 2.30.0
immer:
specifier: ^10.0.2
version: 10.0.2
@ -64,6 +70,9 @@ devDependencies:
'@angular/compiler-cli':
specifier: ^16.1.0
version: 16.1.0(@angular/compiler@16.1.0)(typescript@5.1.3)
'@types/crypto-js':
specifier: ^4.1.2
version: 4.1.2
'@types/jasmine':
specifier: ~4.3.0
version: 4.3.0
@ -2311,6 +2320,10 @@ packages:
'@types/node': 20.4.10
dev: true
/@types/crypto-js@4.1.2:
resolution: {integrity: sha512-t33RNmTu5ufG/sorROIafiCVJMx3jz95bXUMoPAZcUD14fxMXnuTzqzXZoxpR0tNx2xpw11Dlmem9vGCsrSOfA==}
dev: true
/@types/eslint-scope@3.7.4:
resolution: {integrity: sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==}
dependencies:
@ -3341,6 +3354,10 @@ packages:
which: 2.0.2
dev: true
/crypto-js@4.1.1:
resolution: {integrity: sha512-o2JlM7ydqd3Qk9CA0L4NL6mTzU2sdx96a+oOfPu8Mkl/PK51vSyoi8/rQ8NknZtk44vq15lmhAj9CIAGwgeWKw==}
dev: false
/css-loader@6.8.1(webpack@5.86.0):
resolution: {integrity: sha512-xDAXtEVGlD0gJ07iclwWVkLoZOpEvAWaSyf6W18S2pOC//K8+qUDIx8IIT3D+HjnmkJPQeesOPv5aiUaJsCM2g==}
engines: {node: '>= 12.13.0'}

6
projects/admin/proxy.conf.json

@ -0,0 +1,6 @@
{
"/api": {
"target": "http://47.109.27.8:9527",
"secure": false
}
}

2
projects/admin/src/app/app-routing.module.ts

@ -17,12 +17,14 @@ import {
StandardSettingComponent,
} from "./pages";
import { AppLayoutComponent } from "./components";
import { authGuard } from "./services/auth.guard";
const routes: Routes = [
{ path: "login", component: LoginComponent },
{
path: "",
component: AppLayoutComponent,
canActivate: [authGuard],
children: [
{ path: "", pathMatch: "full", redirectTo: "home" },
{ path: "home", component: HomeComponent },

18
projects/admin/src/app/components/app-layout/app-layout.component.ts

@ -1,8 +1,10 @@
import { ApiService } from "@admin/app/services";
import { Component } from "@angular/core";
import { NavigationEnd, Router, RouterModule } from "@angular/router";
import { NzMessageService } from "ng-zorro-antd/message";
import { NzModalService } from "ng-zorro-antd/modal";
import { Subject, filter, takeUntil } from "rxjs";
import { Subject, filter, lastValueFrom, takeUntil } from "rxjs";
@Component({
selector: "app-layout",
@ -10,7 +12,12 @@ import { Subject, filter, takeUntil } from "rxjs";
styleUrls: ["./app-layout.component.less"],
})
export class AppLayoutComponent {
constructor(private router: Router, private modal: NzModalService) {
constructor(
private router: Router,
private modal: NzModalService,
private api: ApiService,
private msg: NzMessageService
) {
this.router.events
.pipe(
takeUntil(this.unSubscribe$),
@ -29,7 +36,12 @@ export class AppLayoutComponent {
this.modal.confirm({
nzTitle: "警告",
nzContent: "是否要退出登录?",
nzOnOk: () => {},
nzOnOk: async () => {
const res = await lastValueFrom(this.api.logout());
this.msg.success(res.desc);
localStorage.removeItem("account");
this.router.navigate(["/login"]);
},
});
}
}

2
projects/admin/src/app/components/role-permission/role-permission.component.html

@ -15,7 +15,7 @@
<div class="fixed-footter bg-white py-2 absolute left-0 bottom-0 right-0">
<div class="flex pl-16">
<nz-space>
<button *nzSpaceItem nz-button nzType="primary" (click)="onSubmit()">
<button *nzSpaceItem nz-button nzType="primary" (click)="onSubmit()" [nzLoading]="loading">
保存
</button>
</nz-space>

98
projects/admin/src/app/components/role-permission/role-permission.component.ts

@ -1,64 +1,63 @@
import { PermItemDTO, UserRoleDTO } from "@admin/app/dtos/user.dto";
import { ApiService } from "@admin/app/services";
import { Component } from "@angular/core";
import { Component, Input, OnChanges, SimpleChanges } from "@angular/core";
import { ActivatedRoute } from "@angular/router";
import { AnyObject } from "@cdk/types";
import { NzMessageService } from "ng-zorro-antd/message";
import { finalize } from "rxjs";
@Component({
selector: "app-role-permission",
templateUrl: "./role-permission.component.html",
styleUrls: ["./role-permission.component.less"],
})
export class RolePermissionComponent {
constructor(private api: ApiService, private route: ActivatedRoute) {}
export class RolePermissionComponent implements OnChanges {
constructor(private api: ApiService, private route: ActivatedRoute, private msg: NzMessageService) {}
roleId: string | null = null;
@Input() perms: PermItemDTO[] = [];
permissions = {
: [
{ label: "食材列表-查看", value: "1-1" },
{ label: "食材-新增/编辑/删除", value: "1-2" },
],
: [
{ label: "菜品列表-查看", value: "2-1" },
{ label: "菜品-新增/编辑/删除", value: "2-2" },
],
: [
{ label: "食谱列表-查看", value: "3-1" },
{ label: "食谱-新增/编辑/删除", value: "3-2" },
{ label: "食谱审核列表-查看", value: "3-3" },
{ label: "食谱审核列表-通过/驳回", value: "3-4" },
{ label: "食谱发布计划-查看", value: "3-5" },
{ label: "食谱发布计划-发布/取消发布", value: "3-6" },
],
: [
{ label: "模型列表-查看", value: "4-1" },
{ label: "营养标准模型-新增/编辑/删除", value: "4-2" },
],
: [
{ label: "单位列表-查看", value: "5-1" },
{ label: "单位-新增/编辑/启用/禁用/删除", value: "5-2" },
],
: [
{ label: "用户列表-查看", value: "6-1" },
{ label: "角色权限-新增/编辑/删除", value: "6-2" },
{ label: "用户-新增/编辑/删除", value: "6-3" },
],
};
@Input() role!: UserRoleDTO;
hasPermissions = new Set<string>();
loading = false;
ngOnInit(): void {
this.route.queryParamMap.subscribe((r) => {
this.roleId = r.get("roleId");
if (this.roleId) {
}
});
ngOnChanges(changes: SimpleChanges): void {
if (changes["perms"]?.currentValue) {
const perms: PermItemDTO[] = changes["perms"].currentValue;
this.permissions = perms.reduce((a, c) => {
const key = c["category"];
const o = { ...c, label: c.itemName, value: c.id };
if (a[key]) {
a[key].push(o);
} else {
a[key] = [o];
}
return a;
}, {} as Record<string, Array<{ label: string; value: number } & AnyObject>>);
}
if (changes["role"]?.currentValue) {
const role: UserRoleDTO = changes["role"].currentValue;
let perms: number[] = [];
try {
perms = JSON.parse(role.roleItems);
} catch (error) {}
this.hasPermissions.clear();
perms.forEach((p) => {
this.hasPermissions.add(p);
});
}
}
permissions = {};
hasPermissions = new Set<number>();
ngOnInit(): void {}
returenZero() {
return 0;
}
onPermissionChange(checked: boolean, key: string) {
onPermissionChange(checked: boolean, key: number) {
if (!checked && this.hasPermissions.has(key)) {
this.hasPermissions.delete(key);
} else {
@ -67,6 +66,17 @@ export class RolePermissionComponent {
}
onSubmit() {
console.log("this.hasPermissions", this.hasPermissions);
const role = { ...this.role, roleId: this.role.id, items: Array.from(this.hasPermissions) };
this.loading = true;
this.api
.updateRole(role)
.pipe(
finalize(() => {
this.loading = false;
})
)
.subscribe((res) => {
this.msg.success(res.desc);
});
}
}

77
projects/admin/src/app/components/user-list/user-list.component.html

@ -1,49 +1,86 @@
<table-list [props]="tableList" [search]="searchTpl" [action]="pageExtraTpl" [formGroup]="queryForm">
<ng-template #searchTpl>
<ng-template #searchTpl>
</ng-template>
<div class="flex items-center justify-between">
<div>
<nz-form-item>
<nz-form-control>
<input nz-input placeholder="请输入用户" formControlName="name" />
<nz-input-group [nzSuffix]="suffixIconSearch">
<input nz-input placeholder="请输入用户" />
</nz-input-group>
<ng-template #suffixIconSearch>
<span nz-icon nzType="search"></span>
</ng-template>
</nz-form-control>
</nz-form-item>
</ng-template>
</table-list>
</div>
<div>
<nz-space>
<button *nzSpaceItem nz-button nzType="primary" (click)="openForm()">
<i nz-icon nzType="plus"></i>
新增用户
</button>
</nz-space>
</div>
</div>
<ng-template #pageExtraTpl>
<nz-space>
<button *nzSpaceItem nz-button nzType="primary" (click)="openForm()">
<i nz-icon nzType="plus"></i>
新增用户
</button>
</nz-space>
</ng-template>
<nz-table #table [nzData]="users">
<thead>
<tr>
<th>账号</th>
<th>姓名</th>
<th>角色</th>
<th>添加时间</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let data of table.data">
<td>{{data.uid}}</td>
<td>{{data.name}}</td>
<td>{{data.roleName}}</td>
<td>{{data.roleName}}</td>
<td>
<a>编辑</a>
<nz-divider nzType="vertical"></nz-divider>
<a>删除</a>
</td>
</tr>
</tbody>
</nz-table>
<ng-template #userFormTpl>
<form nz-form>
<form nz-form [formGroup]="userFrom">
<nz-form-item>
<nz-form-label nzSpan="6" nzRequired>
姓名
</nz-form-label>
<nz-form-control nzSpan="12">
<input nz-input placeholder="请输入用户姓名" />
<nz-form-control nzSpan="12" [nzErrorTip]="formErrorTipsTpl">
<input nz-input placeholder="请输入用户姓名" formControlName="name" />
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label nzSpan="6" nzRequired>
账号
</nz-form-label>
<nz-form-control nzSpan="12">
<input nz-input placeholder="请输入用户账号" />
<nz-form-control nzSpan="12" [nzErrorTip]="formErrorTipsTpl">
<input nz-input placeholder="请输入用户账号" formControlName="uid" />
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label nzSpan="6" nzRequired>
密码
</nz-form-label>
<nz-form-control nzSpan="12">
<input nz-input placeholder="请输入用户密码" type="password" />
<nz-form-control nzSpan="12" [nzErrorTip]="formErrorTipsTpl">
<input nz-input placeholder="请输入用户密码" type="password" formControlName="password" />
</nz-form-control>
</nz-form-item>
</form>
</ng-template>
<ng-template #formErrorTipsTpl let-control>
<form-error-tips [control]="control"></form-error-tips>
</ng-template>

79
projects/admin/src/app/components/user-list/user-list.component.ts

@ -1,9 +1,13 @@
import { UserDTO, UserRoleDTO } from "@admin/app/dtos/user.dto";
import { ApiService } from "@admin/app/services";
import { Component, OnInit, TemplateRef, ViewChild } from "@angular/core";
import { Component, Input, OnInit, TemplateRef, ViewChild } from "@angular/core";
import { FormControl, FormGroup } from "@angular/forms";
import { ActivatedRoute } from "@angular/router";
import { AnyObject, TableListOption } from "@cdk/public-api";
import { AnyObject, FormValidators, TableListOption, Utils } from "@cdk/public-api";
import { MD5 } from "crypto-js";
import { NzMessageService } from "ng-zorro-antd/message";
import { NzModalService } from "ng-zorro-antd/modal";
import { lastValueFrom } from "rxjs";
@Component({
selector: "app-user-list",
@ -11,56 +15,26 @@ import { NzModalService } from "ng-zorro-antd/modal";
styleUrls: ["./user-list.component.less"],
})
export class UserListComponent {
constructor(private api: ApiService, private route: ActivatedRoute, private modal: NzModalService) {}
constructor(
private api: ApiService,
private route: ActivatedRoute,
private modal: NzModalService,
private msg: NzMessageService
) {}
@ViewChild("userFormTpl") public userFormTpl!: TemplateRef<void>;
public tableList = new TableListOption(this.fetchData.bind(this), {
manual: true,
});
public queryForm = new FormGroup({
name: new FormControl(""),
});
roleId: string | null = null;
ngOnInit(): void {
this.route.queryParamMap.subscribe((r) => {
this.roleId = r.get("roleId");
if (this.roleId) {
this.tableList.reset();
}
});
this.initTableList();
}
@Input() users: UserDTO[] = [];
initTableList() {
this.tableList.scroll = { x: null };
this.tableList = this.tableList.setColumns([
{ key: "name", title: "账号" },
{ key: "name", title: "姓名" },
{ key: "name", title: "角色" },
{ key: "name", title: "添加时间" },
]);
@Input() role!: UserRoleDTO;
this.tableList = this.tableList.setOptions([
{
title: "编辑",
premissions: [],
onClick: this.openForm.bind(this),
},
{
title: "删除",
premissions: [],
onClick: this.deleteItem.bind(this),
},
]);
}
public userFrom = new FormGroup({
uid: new FormControl("", [FormValidators.required("请输入账号")]),
name: new FormControl("", [FormValidators.required("请输入姓名")]),
password: new FormControl("", [FormValidators.required("请输入密码")]),
});
fetchData(query: AnyObject, pager: AnyObject) {
return this.api.page(pager, query);
}
ngOnInit(): void {}
deleteItem() {}
@ -68,6 +42,19 @@ export class UserListComponent {
this.modal.create({
nzTitle: item ? "编辑用户" : "新增用户",
nzContent: this.userFormTpl,
nzOnOk: async () => {
if (Utils.validateFormGroup(this.userFrom)) {
const user = { ...this.userFrom.value, roleId: this.role.id };
user["password"] = MD5(user.password!).toString().substring(16).toUpperCase();
const check = await lastValueFrom(this.api.checkUid(user.uid!));
if (check.success) {
const res = await lastValueFrom(this.api.saveUser(user));
this.msg.success(res.desc);
return true;
}
}
return false;
},
});
}
}

2
projects/admin/src/app/dtos/index.ts

@ -0,0 +1,2 @@
export * from "./org.dto";
export * from "./user.dto";

15
projects/admin/src/app/dtos/org.dto.ts

@ -0,0 +1,15 @@
export type OrgDTO = {
account: string;
address: string;
area: string;
category: string;
city: string;
contacts: string;
expire: number;
id: number;
name: string;
phone: string;
province: string;
status: boolean;
icon: string;
};

22
projects/admin/src/app/dtos/user.dto.ts

@ -0,0 +1,22 @@
export type UserRoleDTO = {
id: string;
roleItems: string;
roleName: string;
roleType: string;
vender: number;
};
export type PermItemDTO = {
category: string;
id: number;
itemName: string;
itemType: string;
};
export type UserDTO = {
name: string;
phone: string;
roleId: number;
roleName: string;
uid: string;
};

4
projects/admin/src/app/pages/login/login.component.html

@ -28,7 +28,7 @@
<nz-form-item>
<nz-form-control [nzErrorTip]="formErrorTipsTpl">
<nz-input-group [nzPrefix]="prefixTemplatePassword" nzSize="large">
<input nz-input type="password" placeholder="密码" formControlName="password" />
<input nz-input type="password" placeholder="密码" formControlName="pwd" />
</nz-input-group>
<ng-template #prefixTemplatePassword>
<span nz-icon nzType="lock"></span>
@ -58,6 +58,6 @@
<ng-template #formErrorTipsTpl let-control>
<div class="text-left">
<!-- <dec-form-error-tips [control]="control"></dec-form-error-tips> -->
<form-error-tips [control]="control"></form-error-tips>
</div>
</ng-template>

9
projects/admin/src/app/pages/login/login.component.ts

@ -1,10 +1,12 @@
import { Component } from "@angular/core";
import { FormControl, FormGroup } from "@angular/forms";
import { Router } from "@angular/router";
import { finalize, lastValueFrom } from "rxjs";
import { NzMessageService } from "ng-zorro-antd/message";
import { MD5 } from "crypto-js";
import { FormValidators } from "projects/cdk/src/public-api";
import { Utils } from "projects/cdk/src/utils";
import { finalize, lastValueFrom } from "rxjs";
import { ApiService } from "../../services";
@Component({
@ -17,7 +19,7 @@ export class LoginComponent {
public loginForm = new FormGroup({
uid: new FormControl("", [FormValidators.required("请输入账户")]),
password: new FormControl("", [FormValidators.required("请输入密码")]),
pwd: new FormControl("", [FormValidators.required("请输入密码")]),
});
public loading: boolean = false;
@ -27,6 +29,8 @@ export class LoginComponent {
async onLogin() {
if (Utils.validateFormGroup(this.loginForm)) {
const { value } = this.loginForm;
const pwd = value.pwd as string;
value["pwd"] = MD5(pwd).toString().substring(16).toUpperCase();
this.loading = true;
const res = await lastValueFrom(
this.api.login(value).pipe(
@ -35,6 +39,7 @@ export class LoginComponent {
})
)
);
localStorage.setItem("account", JSON.stringify(res.body));
this.msg.success(res.desc);
this.router.navigate(["/"]);
}

20
projects/admin/src/app/pages/organization/organization-form/organization-form.component.html

@ -7,7 +7,7 @@
单位名称
</nz-form-label>
<nz-form-control [nzErrorTip]="formControlErrorTpl" nzSpan="12">
<input nz-input placeholder="请输入单位名称" />
<input nz-input placeholder="请输入单位名称" formControlName="name" />
</nz-form-control>
</nz-form-item>
<nz-form-item>
@ -18,7 +18,7 @@
<button class="upload-btn " nz-button [nzLoading]="uploadLoading">
<i nz-icon nzType="upload"></i>
上传图片
<input type="file" formControlName="logo" (change)="onFileChange($event)" />
<input type="file" formControlName="icon" (change)="onFileChange($event)" />
</button>
</nz-form-control>
</nz-form-item>
@ -27,7 +27,7 @@
地址
</nz-form-label>
<nz-form-control [nzErrorTip]="formControlErrorTpl" nzSpan="12">
<input nz-input placeholder="请输入单位地址" />
<input nz-input placeholder="请输入单位地址" formControlName="address" />
</nz-form-control>
</nz-form-item>
<nz-form-item>
@ -35,7 +35,7 @@
联系人
</nz-form-label>
<nz-form-control [nzErrorTip]="formControlErrorTpl" nzSpan="12">
<input nz-input placeholder="请输入联系人" />
<input nz-input placeholder="请输入联系人" formControlName="contacts" />
</nz-form-control>
</nz-form-item>
<nz-form-item>
@ -43,7 +43,7 @@
联系电话
</nz-form-label>
<nz-form-control [nzErrorTip]="formControlErrorTpl" nzSpan="12">
<input nz-input placeholder="请输入联系电话" />
<input nz-input placeholder="请输入联系电话" formControlName="phone" />
</nz-form-control>
</nz-form-item>
<nz-form-item>
@ -51,19 +51,19 @@
邮箱
</nz-form-label>
<nz-form-control [nzErrorTip]="formControlErrorTpl" nzSpan="12">
<input nz-input placeholder="请输入邮箱" />
<input nz-input placeholder="请输入邮箱" formControlName="email" />
</nz-form-control>
</nz-form-item>
</nz-card>
<nz-card nzTitle="账号信息" class="my-4">
<nz-card nzTitle="账号信息" class="mt-4 mb-10">
<nz-form-item>
<nz-form-label nzRequired>
账号
</nz-form-label>
<nz-form-control [nzErrorTip]="formControlErrorTpl" nzSpan="12">
<input nz-input placeholder="请输入账号" />
<input nz-input placeholder="请输入账号" formControlName="account" />
</nz-form-control>
</nz-form-item>
<nz-form-item>
@ -71,7 +71,7 @@
初始密码
</nz-form-label>
<nz-form-control [nzErrorTip]="formControlErrorTpl" nzSpan="12">
<input nz-input type="password" placeholder="请输入初始密码" />
<input nz-input type="password" placeholder="请输入初始密码" formControlName="password" />
</nz-form-control>
</nz-form-item>
<nz-form-item>
@ -79,7 +79,7 @@
账号到期时间
</nz-form-label>
<nz-form-control [nzErrorTip]="formControlErrorTpl" nzSpan="12">
<nz-date-picker nzPlaceHolder="请选择账号到期时间" class="w-full"></nz-date-picker>
<nz-date-picker nzPlaceHolder="请选择账号到期时间" class="w-full" formControlName="expire"></nz-date-picker>
</nz-form-control>
</nz-form-item>

64
projects/admin/src/app/pages/organization/organization-form/organization-form.component.ts

@ -1,6 +1,13 @@
import { ApiService } from "@admin/app/services";
import { Component } from "@angular/core";
import { FormBuilder, FormGroup } from "@angular/forms";
import { Utils } from "@cdk/utils";
import { FormValidators } from "@cdk/validators";
import { MD5 } from "crypto-js";
import { NzMessageService } from "ng-zorro-antd/message";
import { lastValueFrom } from "rxjs";
import { format } from "date-fns";
import { ActivatedRoute, Router } from "@angular/router";
@Component({
selector: "app-organization-form",
@ -8,7 +15,22 @@ import { FormValidators } from "@cdk/validators";
styleUrls: ["./organization-form.component.less"],
})
export class OrganizationFormComponent {
constructor(private fb: FormBuilder) {}
constructor(
private fb: FormBuilder,
private api: ApiService,
private msg: NzMessageService,
private router: Router,
private route: ActivatedRoute
) {
const data = this.router.getCurrentNavigation()?.extras;
if (data) {
this.state = data.state;
} else {
this.router.navigate(["/organization/list"]);
}
}
state: any;
formGroup!: FormGroup;
@ -16,15 +38,41 @@ export class OrganizationFormComponent {
ngOnInit(): void {
this.formGroup = this.fb.group({
id: this.fb.control("", [FormValidators.required()]),
name: this.fb.control("", [FormValidators.required()]),
unit: this.fb.control("", [FormValidators.required()]),
day: this.fb.control("1", [FormValidators.required()]),
logo: this.fb.control("", []),
month: this.fb.control([], []),
account: this.fb.control("", [FormValidators.required("账号不能为空")]),
password: this.fb.control("", [FormValidators.required("密码不能为空")]),
name: this.fb.control("", [FormValidators.required("单位名称不能为空")]),
expire: this.fb.control("", [FormValidators.required("账号到期事件不能为空")]),
icon: this.fb.control("", []),
address: this.fb.control("", []),
contacts: this.fb.control("", []),
phone: this.fb.control("", []),
email: this.fb.control("", []),
});
console.log("this.state", this.state);
this.formGroup.patchValue(this.state);
}
async onSubmit() {
if (Utils.validateFormGroup(this.formGroup)) {
const org = { ...this.formGroup.value };
org["password"] = MD5(org.password!).toString().substring(16).toUpperCase();
org["expire"] = format(org["expire"], "yyyy-MM-dd");
const account = await lastValueFrom(this.api.checkOrgAccount(org.account!));
const name = await lastValueFrom(this.api.checkOrgName(org.name!));
if (account.body) {
this.msg.error("账号重复");
return;
}
if (name.body) {
this.msg.error("单位名称重复");
return;
}
const res = await lastValueFrom(this.api.saveOrg(org));
this.msg.success(res.desc);
this.router.navigate(["/organization/list"]);
}
}
onSubmit() {}
onFileChange(e: Event) {
const target = e.target as HTMLInputElement;

95
projects/admin/src/app/pages/organization/organization-list/organization-list.component.html

@ -1,23 +1,14 @@
<app-page>
<ng-template #pageExtraTpl>
<nz-space>
<button *nzSpaceItem nz-button nzType="primary" [routerLink]="['/','organization','form','create']">
<i nz-icon nzType="plus"></i>
新增单位
</button>
</nz-space>
</ng-template>
<div class="h-full overflow-hidden bg-white rounded-lg">
<nz-card [nzBordered]="false" nzTitle="单位列表">
<table-list [props]="tableList" [search]="searchTpl" [action]="pageExtraTpl" [formGroup]="queryForm"
[renderColumns]="renderColumnsTpl">
<ng-template #actionTpl>
<button nz-button>批量删除</button>
</ng-template>
<ng-template #searchTpl>
<nz-form-item class="w-40">
<div class="flex items-center justify-between ">
<div nz-row [nzGutter]="12">
<nz-form-item class="w-52 mr-2">
<nz-form-control>
<nz-select nzPlaceHolder="单位类型" [nzOptions]="[]"></nz-select>
</nz-form-control>
@ -27,33 +18,57 @@
<input nz-input placeholder="请输入单位名称" />
</nz-form-control>
</nz-form-item>
</div>
<nz-space>
<button *nzSpaceItem nz-button nzType="primary" [routerLink]="['/','organization','form','create']">
<i nz-icon nzType="plus"></i>
新增单位
</button>
</nz-space>
</div>
<nz-table #table [nzData]="orgList">
<thead>
<tr>
<th>账号</th>
<th>单位名称</th>
<th>单位类型</th>
<th>地址</th>
<th>联系人</th>
<th>联系电话</th>
<th>账号使用状态</th>
<th>账号到期时间</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let data of table.data">
<td>{{data.account}}</td>
<td>{{data.name}}</td>
<td>{{data.category}}</td>
<td>{{data.province}}{{data.area}}{{data.address}}</td>
<td>{{data.contacts}}</td>
<td>{{data.phone}}</td>
<td>
<nz-switch
nzCheckedChildren="开"
nzUnCheckedChildren="关"
[(ngModel)]="data.status">
</nz-switch>
</td>
<td>{{data.expire | date:'yyyy-MM-dd'}}</td>
<td>
<a (click)="toEdit(data)">编辑</a>
<nz-divider nzType="vertical"></nz-divider>
<a>删除</a>
</td>
</tr>
</tbody>
</nz-table>
</ng-template>
<ng-template #renderColumnsTpl let-data let-key="key" let-row="row">
<ng-container [ngSwitch]="key">
<ng-container *ngSwitchCase="'img'">
</ng-container>
<ng-container *ngSwitchDefault>
{{data}}
</ng-container>
</ng-container>
</ng-template>
</table-list>
</nz-card>
</div>
</app-page>
<ng-template #formFooterTpl>
<nz-space>
<button *nzSpaceItem nz-button (click)="cancelFoodForm()">
取消
</button>
<button *nzSpaceItem nz-button nzType="primary">
保存
</button>
</nz-space>
</ng-template>
</app-page>

72
projects/admin/src/app/pages/organization/organization-list/organization-list.component.ts

@ -4,6 +4,8 @@ import { NzDrawerRef, NzDrawerService } from "ng-zorro-antd/drawer";
import { AnyObject, TableListOption } from "@cdk/public-api";
import { DishFormComponent } from "@admin/app/components";
import { ApiService } from "@admin/app/services";
import { OrgDTO } from "@admin/app/dtos";
import { Router } from "@angular/router";
@Component({
selector: "app-organization-list",
@ -11,71 +13,23 @@ import { ApiService } from "@admin/app/services";
styleUrls: ["./organization-list.component.less"],
})
export class OrganizationListComponent {
constructor(private drawer: NzDrawerService, private api: ApiService) {}
constructor(private router: Router, private api: ApiService) {}
@ViewChild("formFooterTpl") formFooterTpl!: TemplateRef<{}>;
private drawerRef?: NzDrawerRef;
public tableList = new TableListOption(this.fetchData.bind(this), {
selectable: true,
});
public queryForm = new FormGroup({
name: new FormControl(""),
});
originalOrgList: OrgDTO[] = [];
orgList: OrgDTO[] = [];
ngOnInit(): void {
this.initTableList();
}
initTableList() {
this.tableList.scroll = { x: null };
this.tableList = this.tableList.setColumns([
{ key: "name", title: "账号" },
{ key: "name", title: "单位名称" },
{ key: "name", title: "单位类型" },
{ key: "name", title: "地址", width: "30%" },
{ key: "name", title: "联系人" },
{ key: "name", title: "联系电话" },
{ key: "name", title: "使用状态" },
{ key: "name", title: "到期时间" },
]);
this.tableList = this.tableList.setOptions([
{
title: "续费",
premissions: [],
onClick: this.showFoodForm.bind(this),
},
{
title: "编辑",
premissions: [],
onClick: this.showFoodForm.bind(this),
},
{
title: "删除",
premissions: [],
onClick: this.deleteItem.bind(this),
},
]);
}
fetchData(query: AnyObject, pager: AnyObject) {
return this.api.page(pager, query);
}
showFoodForm(food?: any) {
this.drawerRef = this.drawer.create({
nzTitle: food ? "编辑菜品" : "新增菜品",
nzWidth: 700,
nzContent: DishFormComponent,
nzFooter: this.formFooterTpl,
this.api.getOrgList().subscribe((res) => {
console.log("res", res);
this.originalOrgList = res.body ?? [];
this.orgList = this.originalOrgList;
});
}
cancelFoodForm() {
this.drawerRef?.close();
toEdit(org: OrgDTO) {
this.router.navigate([`/organization/form/${org.id}`], {
state: org,
});
}
deleteItem() {}

68
projects/admin/src/app/pages/system/user-manage/user-manage.component.html

@ -10,37 +10,24 @@
<ul nz-menu nzMode="inline">
<li
*ngFor="let item of roleList"
nz-menu-item
(click)="onRoleChange('super')"
[nzSelected]="roleId === 'super'"
class="flex items-center justify-between">
(click)="onRoleChange(item.id)"
[nzSelected]="role?.id === item.id"
class="flex items-center justify-between role-item">
<span>
超级管理员12
{{item.roleName}}
</span>
<a nz-button nzType="text" nz-dropdown [nzDropdownMenu]="menu">
<span nz-icon nzType="more"></span>
</a>
<nz-dropdown-menu #menu="nzDropdownMenu">
<ul nz-menu nzSelectable>
<li nz-menu-item (click)="openForm(roleFormTpl,$event,'super')">编辑</li>
<li nz-menu-item nzDanger (click)="deleteItem($event,'super')">删除</li>
</ul>
</nz-dropdown-menu>
</li>
<li nz-menu-item (click)="onRoleChange('1')" [nzSelected]="roleId === '1'">
<a>
自定义管理员1
</a>
</li>
<li nz-menu-item (click)="onRoleChange('2')" [nzSelected]="roleId === '2'">
<a>
自定义管理员2
</a>
</li>
<li nz-menu-item (click)="onRoleChange('3')" [nzSelected]="roleId === '3'">
<a>
自定义管理员3
</a>
<nz-space nzSize="small" class="options">
<a *nzSpaceItem nz-button nzType="link" nzSize="small"
(click)="openForm(roleFormTpl,$event,item)">
<span nz-icon nzType="edit"></span>
</a>
<a *nzSpaceItem nz-button nzType="link" nzSize="small"
(click)="deleteItem($event,item.id)">
<span nz-icon nzType="delete"></span>
</a>
</nz-space>
</li>
</ul>
<div class="px-4 py-2">
@ -64,8 +51,17 @@
</nz-tabset>
</nz-card-tab>
<div class="p-4">
<app-user-list *ngIf="tab.toString() === '0'"></app-user-list>
<app-role-permission *ngIf="tab.toString() === '1'"></app-role-permission>
<app-user-list
*ngIf="role && tab.toString() === '0'"
[users]="userList"
[role]="role">
</app-user-list>
<app-role-permission
*ngIf="role && tab.toString() === '1'"
[perms]="allPerms"
[role]="role">
</app-role-permission>
</div>
</nz-card>
@ -75,14 +71,20 @@
<ng-template #roleFormTpl>
<form nz-form>
<form nz-form [formGroup]="roleForm">
<nz-form-item>
<nz-form-label nzSpan="6" nzRequired>
角色名称
</nz-form-label>
<nz-form-control nzSpan="12">
<input nz-input placeholder="请输入角色名称" />
<nz-form-control nzSpan="12" [nzErrorTip]="formErrorTipsTpl">
<input nz-input placeholder="请输入角色名称" formControlName="roleName" />
</nz-form-control>
</nz-form-item>
</form>
</ng-template>
<ng-template #formErrorTipsTpl let-control>
<div class="text-left">
<form-error-tips [control]="control"></form-error-tips>
</div>
</ng-template>

12
projects/admin/src/app/pages/system/user-manage/user-manage.component.less

@ -14,4 +14,16 @@
padding: 10px 0;
}
}
}
.role-item {
.options {
display: none;
}
&:hover {
.options {
display: flex;
}
}
}

97
projects/admin/src/app/pages/system/user-manage/user-manage.component.ts

@ -1,11 +1,14 @@
import { FoodFormComponent } from "@admin/app/components";
import { PermItemDTO, UserDTO, UserRoleDTO } from "@admin/app/dtos/user.dto";
import { ApiService } from "@admin/app/services";
import { Component, OnInit, TemplateRef, ViewChild } from "@angular/core";
import { FormControl, FormGroup } from "@angular/forms";
import { Component, OnChanges, OnInit, SimpleChanges, TemplateRef, ViewChild } from "@angular/core";
import { FormControl, FormGroup, FormGroupName } from "@angular/forms";
import { ActivatedRoute, Router } from "@angular/router";
import { AnyObject, TableListOption } from "@cdk/public-api";
import { AnyObject, FormValidators, TableListOption, Utils } from "@cdk/public-api";
import { NzDrawerRef, NzDrawerService } from "ng-zorro-antd/drawer";
import { NzMessageService } from "ng-zorro-antd/message";
import { NzModalService } from "ng-zorro-antd/modal";
import { lastValueFrom } from "rxjs";
@Component({
selector: "app-user-manage",
@ -17,28 +20,65 @@ export class UserManageComponent {
private route: ActivatedRoute,
private api: ApiService,
private router: Router,
private modal: NzModalService
private modal: NzModalService,
private msg: NzMessageService
) {}
public tab = 0;
public roleId: string | null = null;
public role: UserRoleDTO | null = null;
public roleForm = new FormGroup({
roleId: new FormControl(""),
roleName: new FormControl("", [FormValidators.required("请输入角色名称")]),
items: new FormControl("1"),
});
public allPerms: PermItemDTO[] = [];
public userList: UserDTO[] = [];
roleList: UserRoleDTO[] = [];
ngOnInit(): void {
this.roleId = this.route.snapshot.queryParamMap.get("roleId");
this.tab = Number(this.route.snapshot.queryParamMap.get("tab")) || 0;
this.api.getRolePerms().subscribe((res) => {
this.allPerms = res.body;
});
this.api.getUserList().subscribe((res) => {
this.userList = res.body;
});
this.getRoleList();
}
onRoleChange(roleId: string) {
this.roleId = roleId;
this.router.navigate(["/system/user"], {
queryParams: {
roleId,
},
queryParamsHandling: "merge",
getRoleList() {
this.api.getRoleList().subscribe((res) => {
this.roleList = res.body.map((i) => ({ ...i, id: i.id.toString() }));
const roleId = this.route.snapshot.queryParamMap.get("roleId");
const role = this.roleList.find((f) => f.id === roleId);
if (role) {
this.role = role;
return;
}
if (this.roleList.length > 0) {
this.onRoleChange(this.roleList[0].id);
}
});
}
onRoleChange(roleId: string) {
const role = this.roleList.find((f) => f.id === roleId);
if (role) {
this.role = role;
this.router.navigate(["/system/user"], {
queryParams: {
roleId,
},
queryParamsHandling: "merge",
});
}
}
onTabChange(index: number) {
this.tab = index;
this.router.navigate(["/system/user"], {
@ -49,20 +89,43 @@ export class UserManageComponent {
});
}
openForm(nzContent: TemplateRef<{}>, event: MouseEvent, roleId?: string) {
event.preventDefault();
openForm(nzContent: TemplateRef<{}>, event: MouseEvent, role?: UserRoleDTO) {
event.stopPropagation();
if (role) {
this.roleForm.patchValue({
...role,
roleId: role.id,
});
}
this.modal.create({
nzTitle: roleId ? "编辑角色" : "新增角色",
nzTitle: role ? "编辑角色" : "新增角色",
nzContent,
nzOnCancel: () => {
this.roleForm.reset();
},
nzOnOk: async () => {
if (Utils.validateFormGroup(this.roleForm)) {
const res = await lastValueFrom(this.api.updateRole(this.roleForm.value));
this.msg.success(res.desc);
this.getRoleList();
return true;
}
return false;
},
});
}
deleteItem(event: MouseEvent, id: string) {
event.preventDefault();
event.stopPropagation();
this.modal.confirm({
nzTitle: "警告",
nzContent: "是否要删除该角色?",
nzOkDanger: true,
nzOnOk: async () => {
const res = await lastValueFrom(this.api.deleteRole(id));
this.msg.success(res.desc);
this.getRoleList();
},
});
}
}

80
projects/admin/src/app/services/api.service.ts

@ -1,6 +1,10 @@
import { HttpClient } from "@angular/common/http";
import { HttpClient, HttpParams } from "@angular/common/http";
import { Injectable } from "@angular/core";
import { AnyObject, ResponseType } from "@cdk/types";
import { Utils } from "@cdk/utils";
import { map } from "rxjs";
import { PermItemDTO, UserDTO, UserRoleDTO } from "../dtos/user.dto";
import { OrgDTO } from "../dtos";
@Injectable({
providedIn: "root",
@ -8,10 +12,6 @@ import { map } from "rxjs";
export class ApiService {
constructor(private http: HttpClient) {}
login(v: {}) {
return this.http.post<any>("/", v);
}
page(v: {}, q: {}) {
return this.http.get<any>("https://jsonplaceholder.typicode.com/users", v).pipe(
map((r) => {
@ -22,4 +22,74 @@ export class ApiService {
})
);
}
login(v: {}) {
const params = Utils.objectToHttpParams(v);
return this.http.get<ResponseType>("/api/login", { params });
}
logout() {
return this.http.get<ResponseType>("/api/logout");
}
getRoleList() {
return this.http.get<ResponseType<UserRoleDTO[]>>("/api/role");
}
deleteRole(roleId: string) {
const params = new HttpParams().set("roleId", roleId);
return this.http.delete<ResponseType>("/api/role", {
params,
});
}
updateRole(rule: AnyObject) {
const body = Utils.objectToFormData(rule);
const method = rule["roleId"] ? "post" : "put";
return this.http[method]<ResponseType>("/api/role", body);
}
getRolePerms() {
return this.http.get<ResponseType<PermItemDTO[]>>("/api/role/item");
}
getUserList() {
return this.http.get<ResponseType<UserDTO[]>>("/api/user");
}
checkUid(uid: string) {
const params = new HttpParams().set("uid", uid);
return this.http.delete<ResponseType>("/api/user/check", {
params,
});
}
saveUser(user: AnyObject) {
const body = Utils.objectToFormData(user);
const method = user["uid"] ? "post" : "put";
return this.http[method]<ResponseType>("/api/user", body);
}
getOrgList() {
return this.http.get<ResponseType<OrgDTO[]>>("/api/vender");
}
checkOrgAccount(account: string) {
const params = new HttpParams().set("account", account);
return this.http.get<ResponseType<boolean>>("/api/vender/check/account", {
params,
});
}
checkOrgName(name: string) {
const params = new HttpParams().set("name", name);
return this.http.get<ResponseType<boolean>>("/api/vender/check/name", {
params,
});
}
saveOrg(org: AnyObject) {
const body = Utils.objectToFormData(org);
const method = org["id"] ? "post" : "put";
return this.http[method]<ResponseType>("/api/vender", body);
}
}

17
projects/admin/src/app/services/auth.guard.ts

@ -0,0 +1,17 @@
import { inject } from "@angular/core";
import { Router } from "@angular/router";
import { map } from "rxjs";
const accountTokenName = "account";
export const authGuard = () => {
const router = inject(Router);
const token = localStorage.getItem(accountTokenName);
if (!token) {
router.navigate(["/login"]);
return false;
} else {
return true;
}
};

2
projects/admin/src/app/services/http.interceptor.ts

@ -22,7 +22,7 @@ export class HTTPInterceptor implements HttpInterceptor {
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const token = localStorage.getItem(this.localStroageKey);
console.log("req.body", req);
if (token) {
req = req.clone({
// headers: req.headers.set('Authorization', `Bearer ${token}`),

33
projects/cdk/src/utils/index.ts

@ -1,4 +1,6 @@
import { HttpParams } from "@angular/common/http";
import { AbstractControl, FormControl, FormGroup } from "@angular/forms";
import { AnyObject } from "@cdk/types";
export class Utils {
static validateFormGroup(formGroup: FormGroup) {
@ -40,6 +42,37 @@ export class Utils {
return `${protocol}//${host}`;
}
static objectToHttpParams(obj: AnyObject, parentKey = ""): HttpParams {
let params = new HttpParams();
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
const value = obj[key];
const paramName = parentKey ? `${parentKey}.${key}` : key;
if (typeof value === "object" && !Array.isArray(value)) {
params = params.appendAll(Utils.objectToHttpParams(value, paramName) as any);
} else {
params = params.append(paramName, value);
}
}
}
return params;
}
static objectToFormData(obj: AnyObject): FormData {
let params = new FormData();
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
const value = obj[key];
params.append(key, value);
}
}
return params;
}
// static detectionImagePath(jobId: string, imgName: string) {
// return `/record/${jobId}/detect/${imgName}`;
// }

Loading…
Cancel
Save