diff --git a/package.json b/package.json index a2d9663..9cabd49 100644 --- a/package.json +++ b/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", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d06e5b2..07dac89 100644 --- a/pnpm-lock.yaml +++ b/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'} diff --git a/projects/admin/proxy.conf.json b/projects/admin/proxy.conf.json new file mode 100644 index 0000000..58f8922 --- /dev/null +++ b/projects/admin/proxy.conf.json @@ -0,0 +1,6 @@ +{ + "/api": { + "target": "http://47.109.27.8:9527", + "secure": false + } +} diff --git a/projects/admin/src/app/app-routing.module.ts b/projects/admin/src/app/app-routing.module.ts index 8e4caad..47a3f6e 100644 --- a/projects/admin/src/app/app-routing.module.ts +++ b/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 }, diff --git a/projects/admin/src/app/components/app-layout/app-layout.component.ts b/projects/admin/src/app/components/app-layout/app-layout.component.ts index 4c4de7b..4b583fb 100644 --- a/projects/admin/src/app/components/app-layout/app-layout.component.ts +++ b/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"]); + }, }); } } diff --git a/projects/admin/src/app/components/role-permission/role-permission.component.html b/projects/admin/src/app/components/role-permission/role-permission.component.html index 26725c4..74b4cab 100644 --- a/projects/admin/src/app/components/role-permission/role-permission.component.html +++ b/projects/admin/src/app/components/role-permission/role-permission.component.html @@ -15,7 +15,7 @@
- diff --git a/projects/admin/src/app/components/role-permission/role-permission.component.ts b/projects/admin/src/app/components/role-permission/role-permission.component.ts index 364e846..4683a0a 100644 --- a/projects/admin/src/app/components/role-permission/role-permission.component.ts +++ b/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(); + 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>); + } + 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(); + + 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); + }); } } diff --git a/projects/admin/src/app/components/user-list/user-list.component.html b/projects/admin/src/app/components/user-list/user-list.component.html index b23f5c9..8332532 100644 --- a/projects/admin/src/app/components/user-list/user-list.component.html +++ b/projects/admin/src/app/components/user-list/user-list.component.html @@ -1,49 +1,86 @@ - - + + + + +
+
- + + + + + + - - +
+
+ + + +
+
- - - - - + + + + 账号 + 姓名 + 角色 + 添加时间 + 操作 + + + + + {{data.uid}} + {{data.name}} + {{data.roleName}} + {{data.roleName}} + + 编辑 + + 删除 + + + + -
+ 姓名 - - + + 账号 - - + + 密码 - - + +
+
+ + + \ No newline at end of file diff --git a/projects/admin/src/app/components/user-list/user-list.component.ts b/projects/admin/src/app/components/user-list/user-list.component.ts index 856bd18..4614a13 100644 --- a/projects/admin/src/app/components/user-list/user-list.component.ts +++ b/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; - 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; + }, }); } } diff --git a/projects/admin/src/app/dtos/index.ts b/projects/admin/src/app/dtos/index.ts new file mode 100644 index 0000000..c4be6d6 --- /dev/null +++ b/projects/admin/src/app/dtos/index.ts @@ -0,0 +1,2 @@ +export * from "./org.dto"; +export * from "./user.dto"; diff --git a/projects/admin/src/app/dtos/org.dto.ts b/projects/admin/src/app/dtos/org.dto.ts new file mode 100644 index 0000000..3edbd60 --- /dev/null +++ b/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; +}; diff --git a/projects/admin/src/app/dtos/user.dto.ts b/projects/admin/src/app/dtos/user.dto.ts new file mode 100644 index 0000000..f80c4d4 --- /dev/null +++ b/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; +}; diff --git a/projects/admin/src/app/pages/login/login.component.html b/projects/admin/src/app/pages/login/login.component.html index 8a5563d..1758f5c 100644 --- a/projects/admin/src/app/pages/login/login.component.html +++ b/projects/admin/src/app/pages/login/login.component.html @@ -28,7 +28,7 @@ - + @@ -58,6 +58,6 @@
- +
\ No newline at end of file diff --git a/projects/admin/src/app/pages/login/login.component.ts b/projects/admin/src/app/pages/login/login.component.ts index 7094d2e..a1ab908 100644 --- a/projects/admin/src/app/pages/login/login.component.ts +++ b/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(["/"]); } diff --git a/projects/admin/src/app/pages/organization/organization-form/organization-form.component.html b/projects/admin/src/app/pages/organization/organization-form/organization-form.component.html index 2b14bb9..7d4c861 100644 --- a/projects/admin/src/app/pages/organization/organization-form/organization-form.component.html +++ b/projects/admin/src/app/pages/organization/organization-form/organization-form.component.html @@ -7,7 +7,7 @@ 单位名称 - +
@@ -18,7 +18,7 @@ @@ -27,7 +27,7 @@ 地址 - + @@ -35,7 +35,7 @@ 联系人 - + @@ -43,7 +43,7 @@ 联系电话 - + @@ -51,19 +51,19 @@ 邮箱 - + - + 账号 - + @@ -71,7 +71,7 @@ 初始密码 - + @@ -79,7 +79,7 @@ 账号到期时间 - + diff --git a/projects/admin/src/app/pages/organization/organization-form/organization-form.component.ts b/projects/admin/src/app/pages/organization/organization-form/organization-form.component.ts index 64ce340..bb7faa3 100644 --- a/projects/admin/src/app/pages/organization/organization-form/organization-form.component.ts +++ b/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; diff --git a/projects/admin/src/app/pages/organization/organization-list/organization-list.component.html b/projects/admin/src/app/pages/organization/organization-list/organization-list.component.html index 469d132..ffb9d03 100644 --- a/projects/admin/src/app/pages/organization/organization-list/organization-list.component.html +++ b/projects/admin/src/app/pages/organization/organization-list/organization-list.component.html @@ -1,23 +1,14 @@ - - - - - +
+ - - - - - - - + + +
+
+ @@ -27,33 +18,57 @@ +
+ + + +
+ + + + + 账号 + 单位名称 + 单位类型 + 地址 + 联系人 + 联系电话 + 账号使用状态 + 账号到期时间 + 操作 + + + + + {{data.account}} + {{data.name}} + {{data.category}} + {{data.province}}{{data.area}}{{data.address}} + {{data.contacts}} + {{data.phone}} + + + + + {{data.expire | date:'yyyy-MM-dd'}} + + 编辑 + + 删除 + + + + -
- - - - - - {{data}} - - - -
-
- - - - - - - - \ No newline at end of file + \ No newline at end of file diff --git a/projects/admin/src/app/pages/organization/organization-list/organization-list.component.ts b/projects/admin/src/app/pages/organization/organization-list/organization-list.component.ts index ee6ec2c..3a768ce 100644 --- a/projects/admin/src/app/pages/organization/organization-list/organization-list.component.ts +++ b/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() {} diff --git a/projects/admin/src/app/pages/system/user-manage/user-manage.component.html b/projects/admin/src/app/pages/system/user-manage/user-manage.component.html index 39c2ce2..01fbe9e 100644 --- a/projects/admin/src/app/pages/system/user-manage/user-manage.component.html +++ b/projects/admin/src/app/pages/system/user-manage/user-manage.component.html @@ -10,37 +10,24 @@
@@ -64,8 +51,17 @@
- - + + + + +
@@ -75,14 +71,20 @@ -
+ 角色名称 - - + +
+
+ + +
+ +
\ No newline at end of file diff --git a/projects/admin/src/app/pages/system/user-manage/user-manage.component.less b/projects/admin/src/app/pages/system/user-manage/user-manage.component.less index 30c68b8..3be5697 100644 --- a/projects/admin/src/app/pages/system/user-manage/user-manage.component.less +++ b/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; + } + } } \ No newline at end of file diff --git a/projects/admin/src/app/pages/system/user-manage/user-manage.component.ts b/projects/admin/src/app/pages/system/user-manage/user-manage.component.ts index 4b61656..afd9add 100644 --- a/projects/admin/src/app/pages/system/user-manage/user-manage.component.ts +++ b/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(); + }, }); } } diff --git a/projects/admin/src/app/services/api.service.ts b/projects/admin/src/app/services/api.service.ts index cfebd54..b41b11e 100644 --- a/projects/admin/src/app/services/api.service.ts +++ b/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("/", v); - } - page(v: {}, q: {}) { return this.http.get("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("/api/login", { params }); + } + + logout() { + return this.http.get("/api/logout"); + } + + getRoleList() { + return this.http.get>("/api/role"); + } + + deleteRole(roleId: string) { + const params = new HttpParams().set("roleId", roleId); + return this.http.delete("/api/role", { + params, + }); + } + + updateRole(rule: AnyObject) { + const body = Utils.objectToFormData(rule); + const method = rule["roleId"] ? "post" : "put"; + return this.http[method]("/api/role", body); + } + + getRolePerms() { + return this.http.get>("/api/role/item"); + } + + getUserList() { + return this.http.get>("/api/user"); + } + + checkUid(uid: string) { + const params = new HttpParams().set("uid", uid); + return this.http.delete("/api/user/check", { + params, + }); + } + + saveUser(user: AnyObject) { + const body = Utils.objectToFormData(user); + const method = user["uid"] ? "post" : "put"; + return this.http[method]("/api/user", body); + } + + getOrgList() { + return this.http.get>("/api/vender"); + } + + checkOrgAccount(account: string) { + const params = new HttpParams().set("account", account); + return this.http.get>("/api/vender/check/account", { + params, + }); + } + checkOrgName(name: string) { + const params = new HttpParams().set("name", name); + return this.http.get>("/api/vender/check/name", { + params, + }); + } + + saveOrg(org: AnyObject) { + const body = Utils.objectToFormData(org); + const method = org["id"] ? "post" : "put"; + return this.http[method]("/api/vender", body); + } } diff --git a/projects/admin/src/app/services/auth.guard.ts b/projects/admin/src/app/services/auth.guard.ts new file mode 100644 index 0000000..fa0bc45 --- /dev/null +++ b/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; + } +}; diff --git a/projects/admin/src/app/services/http.interceptor.ts b/projects/admin/src/app/services/http.interceptor.ts index 82d9b50..9b9b69b 100644 --- a/projects/admin/src/app/services/http.interceptor.ts +++ b/projects/admin/src/app/services/http.interceptor.ts @@ -22,7 +22,7 @@ export class HTTPInterceptor implements HttpInterceptor { intercept(req: HttpRequest, next: HttpHandler): Observable> { const token = localStorage.getItem(this.localStroageKey); - + console.log("req.body", req); if (token) { req = req.clone({ // headers: req.headers.set('Authorization', `Bearer ${token}`), diff --git a/projects/cdk/src/utils/index.ts b/projects/cdk/src/utils/index.ts index 596c713..ba51ea8 100644 --- a/projects/cdk/src/utils/index.ts +++ b/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}`; // }