Browse Source

单位 & 枚举

main
kkerwin 2 years ago
parent
commit
046104ba39
  1. 5
      projects/admin/src/app/components/app-layout/app-layout.component.ts
  2. 8
      projects/admin/src/app/components/food-form/food-form.component.html
  3. 14
      projects/admin/src/app/components/food-form/food-form.component.ts
  4. 8
      projects/admin/src/app/components/user-list/user-list.component.html
  5. 80
      projects/admin/src/app/components/user-list/user-list.component.ts
  6. 20
      projects/admin/src/app/dtos/enum.dto.ts
  7. 1
      projects/admin/src/app/dtos/index.ts
  8. 19
      projects/admin/src/app/pages/food/food.component.html
  9. 4
      projects/admin/src/app/pages/food/food.component.ts
  10. 57
      projects/admin/src/app/pages/organization/organization-form/organization-form.component.ts
  11. 2
      projects/admin/src/app/pages/organization/organization-list/organization-list.component.html
  12. 34
      projects/admin/src/app/pages/organization/organization-list/organization-list.component.ts
  13. 3
      projects/admin/src/app/pages/system/user-manage/user-manage.component.html
  14. 11
      projects/admin/src/app/pages/system/user-manage/user-manage.component.ts
  15. 42
      projects/admin/src/app/services/api.service.ts
  16. 6
      projects/admin/src/app/services/auth.guard.ts
  17. 1
      projects/admin/src/app/services/http.interceptor.ts

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

@ -1,5 +1,5 @@
import { ApiService } from "@admin/app/services";
import { Component } from "@angular/core";
import { Component, OnInit } from "@angular/core";
import { NavigationEnd, Router, RouterModule } from "@angular/router";
import { NzMessageService } from "ng-zorro-antd/message";
@ -11,7 +11,7 @@ import { Subject, filter, lastValueFrom, takeUntil } from "rxjs";
templateUrl: "./app-layout.component.html",
styleUrls: ["./app-layout.component.less"],
})
export class AppLayoutComponent {
export class AppLayoutComponent implements OnInit {
constructor(
private router: Router,
private modal: NzModalService,
@ -27,6 +27,7 @@ export class AppLayoutComponent {
this.currentUrl = e.url;
});
}
ngOnInit(): void {}
unSubscribe$ = new Subject<void>();

8
projects/admin/src/app/components/food-form/food-form.component.html

@ -43,11 +43,17 @@
<div class="flex">
<div>
<nz-select class="!w-[160px]" nzPlaceHolder="营养素"
(ngModelChange)="nutritionChange($event,i)"
formControlName="nutritionName">
<nz-option
*ngFor="let item of globalEnum.nutrient"
[nzValue]="item.key"
[nzLabel]="item.value">
</nz-option>
</nz-select>
</div>
<div class="flex-1 px-2">
<nz-input-group [nzAddOnAfter]="'μgRAE'" class="w-full">
<nz-input-group [nzAddOnAfter]="nutrition.value[i].measurement" class="w-full">
<input nz-input formControlName="nutritionNum" />
</nz-input-group>
</div>

14
projects/admin/src/app/components/food-form/food-form.component.ts

@ -1,3 +1,4 @@
import { ApiService } from "@admin/app/services";
import { Component, OnInit } from "@angular/core";
import { FormArray, FormBuilder, FormGroup } from "@angular/forms";
import { FormValidators } from "@cdk/validators";
@ -8,10 +9,12 @@ import { FormValidators } from "@cdk/validators";
styleUrls: ["./food-form.component.less"],
})
export class FoodFormComponent implements OnInit {
constructor(private fb: FormBuilder) {}
constructor(private fb: FormBuilder, private api: ApiService) {}
formGroup!: FormGroup;
public globalEnum = this.api.globalEnum;
get nutrition(): FormArray {
return this.formGroup.get("nutrition") as FormArray;
}
@ -23,6 +26,14 @@ export class FoodFormComponent implements OnInit {
type: this.fb.control("", [FormValidators.required()]),
nutrition: this.fb.array([], [FormValidators.required()]),
});
this.api.getAllEnum().subscribe((r) => {});
}
nutritionChange(v: string, idx: number) {
const nutrient = this.globalEnum.nutrient.find((f) => f.key === v);
this.nutrition.at(idx).patchValue({
measurement: nutrient?.measurement,
});
}
createNutrition() {
@ -30,6 +41,7 @@ export class FoodFormComponent implements OnInit {
this.fb.group({
nutritionName: this.fb.control("", [FormValidators.required()]),
nutritionNum: this.fb.control(0, [FormValidators.required()]),
measurement: this.fb.control("", [FormValidators.required()]),
})
);
}

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

@ -7,7 +7,7 @@
<nz-form-item>
<nz-form-control>
<nz-input-group [nzSuffix]="suffixIconSearch">
<input nz-input placeholder="请输入用户" />
<input nz-input placeholder="请输入用户" [(ngModel)]="searchValue" (ngModelChange)="onSearch($event)" />
</nz-input-group>
<ng-template #suffixIconSearch>
<span nz-icon nzType="search"></span>
@ -25,7 +25,7 @@
</div>
</div>
<nz-table #table [nzData]="users">
<nz-table #table [nzData]="visibledUsers">
<thead>
<tr>
<th>账号</th>
@ -42,9 +42,9 @@
<td>{{data.roleName}}</td>
<td>{{data.time | date:'yyyy-MM-dd HH:mm:ss'}}</td>
<td>
<a>编辑</a>
<a (click)="openForm(data)">编辑</a>
<nz-divider nzType="vertical"></nz-divider>
<a>删除</a>
<a (click)="deleteItem(data.uid)">删除</a>
</td>
</tr>
</tbody>

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

@ -1,6 +1,16 @@
import { UserDTO, UserRoleDTO } from "@admin/app/dtos/user.dto";
import { ApiService } from "@admin/app/services";
import { Component, Input, OnInit, TemplateRef, ViewChild } from "@angular/core";
import {
Component,
EventEmitter,
Input,
OnChanges,
OnInit,
Output,
SimpleChanges,
TemplateRef,
ViewChild,
} from "@angular/core";
import { FormControl, FormGroup } from "@angular/forms";
import { ActivatedRoute } from "@angular/router";
import { AnyObject, FormValidators, TableListOption, Utils } from "@cdk/public-api";
@ -14,7 +24,7 @@ import { lastValueFrom } from "rxjs";
templateUrl: "./user-list.component.html",
styleUrls: ["./user-list.component.less"],
})
export class UserListComponent {
export class UserListComponent implements OnChanges {
constructor(
private api: ApiService,
private route: ActivatedRoute,
@ -28,6 +38,12 @@ export class UserListComponent {
@Input() role!: UserRoleDTO;
@Output() onReload = new EventEmitter();
searchValue = "";
visibledUsers: UserDTO[] = [];
public userFrom = new FormGroup({
uid: new FormControl("", [FormValidators.required("请输入账号")]),
name: new FormControl("", [FormValidators.required("请输入姓名")]),
@ -36,22 +52,68 @@ export class UserListComponent {
ngOnInit(): void {}
deleteItem() {}
ngOnChanges(changes: SimpleChanges): void {
const u = changes["users"]?.currentValue;
if (Array.isArray(u)) {
this.onSearch(this.searchValue);
}
}
onSearch(kw: string) {
this.visibledUsers = this.users.filter((f) => f.name.includes(kw) || f.uid.includes(kw));
}
deleteItem(uid: string) {
this.modal.confirm({
nzTitle: "警告",
nzContent: "是否要删除该用户?",
nzOkDanger: true,
nzOnOk: async () => {
const res = await lastValueFrom(this.api.deleteUser(uid));
if (res.success) {
this.msg.success(res.desc);
this.onReload.emit();
return true;
}
return false;
},
});
}
resetUserForm() {
this.userFrom.reset();
}
openForm(item?: any) {
if (item) {
this.userFrom.patchValue(item);
}
this.modal.create({
nzTitle: item ? "编辑用户" : "新增用户",
nzContent: this.userFormTpl,
nzOnCancel: () => {
this.resetUserForm();
},
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.body) {
const res = await lastValueFrom(this.api.saveUser(user));
this.msg.success(res.desc);
return true;
// }
let notExist = true;
if ((item && item.uid !== user.uid) || !item) {
const check = await lastValueFrom(this.api.checkUid(user.uid!));
notExist = check.body;
}
if (notExist) {
const res = await lastValueFrom(this.api.saveUser(user, Boolean(item)));
this.msg.success(res.desc);
this.onReload.emit();
this.resetUserForm();
return true;
} else {
this.msg.error("账号重复");
return false;
}
}
return false;
},

20
projects/admin/src/app/dtos/enum.dto.ts

@ -0,0 +1,20 @@
export type GlobalEnum = {
category: CategoryDTO[];
mark: MarkDTO[];
nutrient: NutrientDTO[];
};
export type CategoryDTO = {
key: string;
value: string;
};
export type MarkDTO = {
key: string;
value: string;
};
export type NutrientDTO = {
key: string;
value: string;
measurement: string;
nrv: number;
};

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

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

19
projects/admin/src/app/pages/food/food.component.html

@ -10,27 +10,18 @@
</nz-space>
</ng-template>
<div nz-row class="h-full overflow-hidden bg-white rounded-lg">
<div nz-col nzFlex="220px" class="food-type">
<nz-card class="h-full" [nzBordered]="false" nzTitle="食材类型" [nzBodyStyle]="{padding:'1px 0 0 0'}">
<div nz-col nzFlex="220px" class="food-type h-full">
<nz-card class="h-full" [nzBordered]="false" nzTitle="食材类型"
[nzBodyStyle]="{padding:'1px 0 0 0', height:'100%',overflow:'auto'}">
<ul nz-menu nzMode="inline">
<li nz-menu-item>
<a>
全部
</a>
</li>
<li nz-menu-item>
<a>
谷薯类
</a>
</li>
<li nz-menu-item>
<a>
大豆类及其制品
</a>
</li>
<li nz-menu-item>
<li nz-menu-item *ngFor="let cate of globalEnum.category">
<a>
蔬菜类
{{cate.key}}
</a>
</li>
</ul>

4
projects/admin/src/app/pages/food/food.component.ts

@ -1,4 +1,5 @@
import { FoodFormComponent } from "@admin/app/components";
import { GlobalEnum } from "@admin/app/dtos";
import { ApiService } from "@admin/app/services";
import { Component, OnDestroy, OnInit, TemplateRef, ViewChild } from "@angular/core";
import { FormControl, FormGroup } from "@angular/forms";
@ -23,6 +24,8 @@ export class FoodComponent implements OnInit, OnDestroy {
selectable: true,
});
public globalEnum = this.api.globalEnum;
public queryForm = new FormGroup({
name: new FormControl(""),
});
@ -38,6 +41,7 @@ export class FoodComponent implements OnInit, OnDestroy {
this.tableList.getState$.pipe(takeUntil(this.destroy$)).subscribe((res) => {
this.selectedIds = res.selectedKeys as Array<string>;
});
console.log("this.globalEnum", this.globalEnum);
}
ngOnDestroy(): void {

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

@ -22,11 +22,14 @@ export class OrganizationFormComponent {
private router: Router,
private route: ActivatedRoute
) {
const data = this.router.getCurrentNavigation()?.extras;
if (data) {
this.state = data.state;
} else {
this.router.navigate(["/organization/list"]);
const id = this.route.snapshot.paramMap.get("id");
if (id !== "create") {
const data = this.router.getCurrentNavigation()?.extras;
if (data) {
this.state = data.state;
} else {
this.router.navigate(["/organization/list"]);
}
}
}
@ -53,26 +56,26 @@ export class OrganizationFormComponent {
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 };
const org = { ...(this.state ?? {}), ...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!));
org["venderId"] = org.id;
// 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;
}
// 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);
@ -84,25 +87,13 @@ export class OrganizationFormComponent {
const target = e.target as HTMLInputElement;
const file = target.files![0];
target.value = "";
const formData = new FormData();
const fileReader = new FileReader();
fileReader.onload = () => {
const base64 = fileReader.result as string;
const v = base64.split("base64,")[1];
this.formGroup.patchValue({
icon: base64,
});
};
formData.append("file", file);
this.uploadLoading = true;
// this.api
// .uploadLogo(formData)
// .pipe(
// finalize(() => {
// this.uploadLoading = false;
// })
// )
// .subscribe((r) => {
// this.msg.success(r.desc);
// fileReader.readAsDataURL(file);
// });
fileReader.readAsDataURL(file);
}
}

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

@ -60,7 +60,7 @@
<td>
<a (click)="toEdit(data)">编辑</a>
<nz-divider nzType="vertical"></nz-divider>
<a>删除</a>
<a (click)="deleteItem(data.id)">删除</a>
</td>
</tr>
</tbody>

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

@ -6,6 +6,9 @@ import { DishFormComponent } from "@admin/app/components";
import { ApiService } from "@admin/app/services";
import { OrgDTO } from "@admin/app/dtos";
import { Router } from "@angular/router";
import { NzModalService } from "ng-zorro-antd/modal";
import { lastValueFrom } from "rxjs";
import { NzMessageService } from "ng-zorro-antd/message";
@Component({
selector: "app-organization-list",
@ -13,14 +16,23 @@ import { Router } from "@angular/router";
styleUrls: ["./organization-list.component.less"],
})
export class OrganizationListComponent {
constructor(private router: Router, private api: ApiService) {}
constructor(
private router: Router,
private api: ApiService,
private modal: NzModalService,
private msg: NzMessageService
) {}
originalOrgList: OrgDTO[] = [];
orgList: OrgDTO[] = [];
ngOnInit(): void {
this.getList();
}
getList() {
this.api.getOrgList().subscribe((res) => {
console.log("res", res);
this.originalOrgList = res.body ?? [];
this.orgList = this.originalOrgList;
});
@ -32,5 +44,21 @@ export class OrganizationListComponent {
});
}
deleteItem() {}
deleteItem(id: number) {
this.modal.confirm({
nzTitle: "警告",
nzContent: "是否要删除该单位?",
nzOkDanger: true,
nzOnOk: async () => {
const res = await lastValueFrom(this.api.deleteOrg(id));
if (res.success) {
this.msg.success(res.desc);
this.originalOrgList = this.originalOrgList.filter((f) => f.id !== id);
this.orgList = this.orgList.filter((f) => f.id !== id);
return true;
}
return false;
},
});
}
}

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

@ -54,7 +54,8 @@
<app-user-list
*ngIf="role && tab.toString() === '0'"
[users]="currentUserList"
[role]="role">
[role]="role"
(onReload)="reloadUserList()">
</app-user-list>
<app-role-permission

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

@ -47,10 +47,19 @@ export class UserManageComponent {
this.api.getRolePerms().subscribe((res) => {
this.allPerms = res.body;
});
this.getRoleList();
this.getUserList();
}
getUserList(reload?: boolean) {
this.api.getUserList().subscribe((res) => {
this.userList = res.body;
this.currentUserList = this.userList.filter((f) => Number(f.roleId) === Number(this.role!.id));
});
this.getRoleList();
}
reloadUserList() {
this.getUserList(true);
}
getRoleList() {

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

@ -2,9 +2,9 @@ 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 { Observable, map, of, tap } from "rxjs";
import { PermItemDTO, UserDTO, UserRoleDTO } from "../dtos/user.dto";
import { OrgDTO } from "../dtos";
import { GlobalEnum, OrgDTO } from "../dtos";
@Injectable({
providedIn: "root",
@ -12,6 +12,8 @@ import { OrgDTO } from "../dtos";
export class ApiService {
constructor(private http: HttpClient) {}
globalEnum!: GlobalEnum;
page(v: {}, q: {}) {
return this.http.get<any>("https://jsonplaceholder.typicode.com/users", v).pipe(
map((r) => {
@ -23,6 +25,20 @@ export class ApiService {
);
}
getAllEnum(force?: boolean): Observable<GlobalEnum> {
if (this.globalEnum && !force) {
return of(this.globalEnum);
}
return this.http.get<ResponseType<GlobalEnum>>("/api/basic/enum").pipe(
map((res) => {
return res.body;
}),
tap((r) => {
this.globalEnum = r;
})
);
}
login(v: {}) {
const params = Utils.objectToHttpParams(v);
return this.http.get<ResponseType>("/api/login", { params });
@ -64,12 +80,19 @@ export class ApiService {
});
}
saveUser(user: AnyObject) {
saveUser(user: AnyObject, edit: boolean) {
const body = Utils.objectToFormData(user);
const method = user["id"] ? "post" : "put";
const method = edit ? "post" : "put";
return this.http[method]<ResponseType>("/api/user", body);
}
deleteUser(uid: string) {
const params = new HttpParams().set("uid", uid);
return this.http.delete<ResponseType>("/api/user", {
params,
});
}
getOrgList() {
return this.http.get<ResponseType<OrgDTO[]>>("/api/vender");
}
@ -88,9 +111,20 @@ export class ApiService {
});
}
deleteOrg(id: number) {
const params = new HttpParams().set("vender", id);
return this.http.delete<ResponseType>("/api/vender", {
params,
});
}
saveOrg(org: AnyObject) {
const body = Utils.objectToFormData(org);
const method = org["id"] ? "post" : "put";
return this.http[method]<ResponseType>("/api/vender", body);
}
// getOrgConfig() {
// return this.http.get<ResponseType>("/api/vender/config");
// }
}

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

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

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

@ -22,7 +22,6 @@ 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}`),

Loading…
Cancel
Save