Browse Source

食谱

main
kkerwin 2 years ago
parent
commit
70f49af415
  1. 16
      angular.json
  2. 2
      projects/admin/src/app/app-routing.module.ts
  3. 33
      projects/admin/src/app/components/dish-form/dish-form.component.html
  4. 63
      projects/admin/src/app/components/dish-form/dish-form.component.ts
  5. 74
      projects/admin/src/app/components/ingredient-form-basic/ingredient-form-basic.component.html
  6. 141
      projects/admin/src/app/components/ingredient-form-basic/ingredient-form-basic.component.ts
  7. 2
      projects/admin/src/app/pages/dish/dish.component.html
  8. 4
      projects/admin/src/app/pages/dish/dish.component.ts
  9. 2
      projects/admin/src/app/pages/food/food.component.html
  10. 4
      projects/admin/src/app/pages/food/food.component.ts
  11. 74
      projects/admin/src/app/pages/ingredients/ingredient-form/ingredient-form.component.ts
  12. 28
      projects/admin/src/app/pages/ingredients/ingredient-list/ingredient-list.component.html
  13. 38
      projects/admin/src/app/pages/ingredients/ingredient-list/ingredient-list.component.ts
  14. 2
      projects/admin/src/app/pages/standard/standard-form/standard-form.component.ts
  15. 10
      projects/admin/src/app/pages/standard/standard-setting/standard-setting.component.ts
  16. 5
      projects/cdk/src/dtos/enum.dto.ts
  17. 63
      projects/cdk/src/services/api.service.ts
  18. 1
      projects/cdk/src/shared/components/index.ts
  19. 15
      projects/cdk/src/shared/components/month-select/month-select.component.html
  20. 17
      projects/cdk/src/shared/components/month-select/month-select.component.less
  21. 93
      projects/cdk/src/shared/components/month-select/month-select.component.ts
  22. 5
      projects/cdk/src/shared/shared.module.ts
  23. 13
      projects/client/src/app/pages/system/org-info/org-info.component.ts

16
angular.json

@ -43,13 +43,13 @@
"budgets": [ "budgets": [
{ {
"type": "initial", "type": "initial",
"maximumWarning": "500kb", "maximumWarning": "21mb",
"maximumError": "1mb" "maximumError": "21mb"
}, },
{ {
"type": "anyComponentStyle", "type": "anyComponentStyle",
"maximumWarning": "2kb", "maximumWarning": "21mb",
"maximumError": "4kb" "maximumError": "21mb"
} }
], ],
"outputHashing": "all" "outputHashing": "all"
@ -164,13 +164,13 @@
"budgets": [ "budgets": [
{ {
"type": "initial", "type": "initial",
"maximumWarning": "500kb", "maximumWarning": "21mb",
"maximumError": "1mb" "maximumError": "21mb"
}, },
{ {
"type": "anyComponentStyle", "type": "anyComponentStyle",
"maximumWarning": "2kb", "maximumWarning": "21mb",
"maximumError": "4kb" "maximumError": "21mb"
} }
], ],
"outputHashing": "all" "outputHashing": "all"

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

@ -26,7 +26,7 @@ const routes: Routes = [
component: AppLayoutComponent, component: AppLayoutComponent,
canActivate: [authGuard], canActivate: [authGuard],
children: [ children: [
{ path: "", pathMatch: "full", redirectTo: "home" }, { path: "", pathMatch: "full", redirectTo: "food" },
{ path: "home", component: HomeComponent }, { path: "home", component: HomeComponent },
{ path: "food", component: FoodComponent, title: "食材管理" }, { path: "food", component: FoodComponent, title: "食材管理" },
{ path: "dish", component: DishComponent, title: "菜品管理" }, { path: "dish", component: DishComponent, title: "菜品管理" },

33
projects/admin/src/app/components/dish-form/dish-form.component.html

@ -49,26 +49,7 @@
适用月份 适用月份
</nz-form-label> </nz-form-label>
<nz-form-control [nzErrorTip]="formControlErrorTpl"> <nz-form-control [nzErrorTip]="formControlErrorTpl">
<div> <app-month-select formControlName="month"></app-month-select>
<label
nz-checkbox
[(ngModel)]="allMonthChecked"
[ngModelOptions]="{standalone: true}"
(ngModelChange)="updateAllMonthChecked()"
[nzIndeterminate]="indeterminate">
全年
</label>
</div>
<nz-divider nzDashed class="my-1"></nz-divider>
<div class="flex flex-wrap month-wrap">
<label *ngFor="let m of allMonth" nz-checkbox [(nzChecked)]="m.checked"
(nzCheckedChange)="monthChecked($event,m.value)">{{m.label}}</label>
</div>
<!-- <nz-checkbox-group [(ngModel)]="allMonth"
class="flex flex-wrap month-wrap"
[ngModelOptions]="{standalone: true}"
(ngModelChange)="monthChecked()">
</nz-checkbox-group> -->
</nz-form-control> </nz-form-control>
</nz-form-item> </nz-form-item>
@ -146,11 +127,7 @@
{{f.value}}-{{f.text}}: {{f.value}}-{{f.text}}:
</button> </button>
</div> --> </div> -->
<!-- <div class="pr-2">
<nz-select class="!w-[200px]" nzPlaceHolder="食材标签"
formControlName="tag">
</nz-select>
</div> -->
<div class="flex-1 pr-2"> <div class="flex-1 pr-2">
<nz-input-group nzAddOnBefore="{{f.value}}-{{f.text}}:" [nzAddOnAfter]="'g'" class="w-full"> <nz-input-group nzAddOnBefore="{{f.value}}-{{f.text}}:" [nzAddOnAfter]="'g'" class="w-full">
<input <input
@ -161,6 +138,12 @@
placeholder="请输入{{f.value}}-{{f.text}}重量" /> placeholder="请输入{{f.value}}-{{f.text}}重量" />
</nz-input-group> </nz-input-group>
</div> </div>
<div class="pl-2">
<nz-switch [ngModel]="f.isMain" (ngModelChange)="onMainChange($event,f.value)"
[ngModelOptions]="{standalone: true}">
</nz-switch>
是否主料
</div>
<!-- <div> <!-- <div>
<button nz-button (click)="removeFood(i)"> <button nz-button (click)="removeFood(i)">
<span nz-icon nzType="delete"></span> <span nz-icon nzType="delete"></span>

63
projects/admin/src/app/components/dish-form/dish-form.component.ts

@ -127,15 +127,13 @@ export class DishFormComponent {
this.allMonth = this.allMonth.map((i) => this.allMonth = this.allMonth.map((i) =>
(this.data.month ?? []).includes(i.value) ? { ...i, checked: true } : i (this.data.month ?? []).includes(i.value) ? { ...i, checked: true } : i
); );
this.monthCheckEffect();
this.foods.forEach((f) => { this.foods.forEach((f) => {
const item = { text: f.name, value: f.key }; const item = { text: f.name, value: f.key };
this.foodListOfOption.push(item); this.foodListOfOption.push(item);
this.searchedFood.push(item); this.searchedFood.push(item);
const num = this.data.ingredient[f.key]; const num = this.data.ingredient.find((i: any) => i.key === f.key);
if (num) { if (num) {
this.foodItemSelected.push({ num, ...item }); this.foodItemSelected.push({ num: num.value, ...item, isMain: num.isMain });
this.foodSelected.push(f.key); this.foodSelected.push(f.key);
} }
}); });
@ -149,18 +147,22 @@ export class DishFormComponent {
public getValues() { public getValues() {
let values = null; let values = null;
console.log("this.formGroup.getRawValue()", this.formGroup.getRawValue()); console.log("this.formGroup.getRawValue()", this.formGroup.getRawValue(), this.foodItemSelected);
if (Utils.validateFormGroup(this.formGroup)) { if (Utils.validateFormGroup(this.formGroup)) {
const value = this.formGroup.getRawValue(); const value = this.formGroup.getRawValue();
// const { _nutrition, key, name, type } = this.formGroup.getRawValue(); // const { _nutrition, key, name, type } = this.formGroup.getRawValue();
let ingredient = Object.create(null); let ingredient: any[] = [];
for (const f of this.foodItemSelected) { for (const f of this.foodItemSelected) {
let num = Number(f.num); let num = Number(f.num);
if (!num) { if (!num) {
this.msg.error(`请输入${f.value}-${f.text}的重量`); this.msg.error(`请输入${f.value}-${f.text}的重量`);
return; return;
} }
ingredient[f.value] = num; ingredient.push({
isMain: f.isMain,
key: f.value,
value: num,
});
} }
const month = this.allMonth const month = this.allMonth
.reduce((a: any, c: any) => { .reduce((a: any, c: any) => {
@ -181,6 +183,21 @@ export class DishFormComponent {
return values; return values;
} }
onMainChange(e: boolean, key: string) {
this.foodItemSelected.forEach((i) => {
if (e) {
i.isMain = false;
if (i.value === key) {
i.isMain = true;
}
} else {
if (i.value === key) {
i.isMain = false;
}
}
});
}
searchOrg(value: string): void { searchOrg(value: string): void {
if (value) { if (value) {
this.orgSearch$.next({ keyword: value }); this.orgSearch$.next({ keyword: value });
@ -223,38 +240,6 @@ export class DishFormComponent {
this.food.removeAt(idx); this.food.removeAt(idx);
} }
updateAllMonthChecked() {
this.indeterminate = false;
if (this.allMonthChecked) {
this.allMonth = this.allMonth.map((item) => ({
...item,
checked: true,
}));
} else {
this.allMonth = this.allMonth.map((item) => ({
...item,
checked: false,
}));
}
}
monthChecked(checked: boolean, value: number) {
this.allMonth = this.allMonth.map((i) => (i.value === value ? { ...i, checked } : i));
this.monthCheckEffect();
}
monthCheckEffect() {
if (this.allMonth.every((item) => !item.checked)) {
this.allMonthChecked = false;
this.indeterminate = false;
} else if (this.allMonth.every((item) => item.checked)) {
this.allMonthChecked = true;
this.indeterminate = false;
} else {
this.indeterminate = true;
}
}
onFileChange(e: Event) { onFileChange(e: Event) {
const target = e.target as HTMLInputElement; const target = e.target as HTMLInputElement;
const file = target.files![0]; const file = target.files![0];

74
projects/admin/src/app/components/ingredient-form-basic/ingredient-form-basic.component.html

@ -1,10 +1,49 @@
<form nz-form [formGroup]="formGroup" nzLayout="vertical"> <form nz-form [formGroup]="formGroup" nzLayout="vertical">
<nz-form-item>
<nz-form-label nzRequired nzSpan="6">
食谱名称
</nz-form-label>
<nz-form-control [nzErrorTip]="formControlErrorTpl" nzSpan="12">
<input nz-input placeholder="请输入食谱名称" formControlName="name" />
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label nzRequired nzSpan="6">
标准
</nz-form-label>
<nz-form-control [nzErrorTip]="formControlErrorTpl" nzSpan="12">
<nz-select
nzShowSearch
nzServerSearch
nzPlaceHolder="请选择标准"
[nzShowArrow]="false"
formControlName="nutrient"
[nzFilterOption]="nzFilterOption"
(nzOnSearch)="searchStandard($event)"
(ngModelChange)="onStandardChange($event)">
<nz-option *ngFor="let o of standardOfOption"
[nzLabel]="o.label"
[nzValue]="o.value">
</nz-option>
</nz-select>
</nz-form-control>
</nz-form-item>
<nz-form-item> <nz-form-item>
<nz-form-label nzRequired nzSpan="6"> <nz-form-label nzRequired nzSpan="6">
适用单位 适用单位
</nz-form-label> </nz-form-label>
<nz-form-control [nzErrorTip]="formControlErrorTpl" nzSpan="12"> <nz-form-control [nzErrorTip]="formControlErrorTpl" nzSpan="12">
<nz-select [nzOptions]="[]" nzPlaceHolder="请选择单位"></nz-select> <nz-select nzMode="multiple" formControlName="vendors" nzPlaceHolder="请选择单位"
[nzOptions]="currentOrgs">
</nz-select>
</nz-form-control>
</nz-form-item>
<nz-form-item class="block">
<nz-form-label nzRequired nzSpan="6">
适用月份
</nz-form-label>
<nz-form-control [nzErrorTip]="formControlErrorTpl" nzSpan="12">
<app-month-select formControlName="month"></app-month-select>
</nz-form-control> </nz-form-control>
</nz-form-item> </nz-form-item>
<nz-form-item> <nz-form-item>
@ -23,40 +62,33 @@
</nz-radio-group> </nz-radio-group>
</nz-form-control> </nz-form-control>
</nz-form-item> </nz-form-item>
<nz-form-item> <nz-form-item class="block">
<nz-form-label nzRequired nzSpan="6"> <nz-form-label nzRequired nzSpan="6">
标题 餐次
</nz-form-label> </nz-form-label>
<nz-form-control [nzErrorTip]="formControlErrorTpl" nzSpan="12"> <nz-form-control [nzErrorTip]="formControlErrorTpl" nzSpan="12">
<nz-checkbox-wrapper class="flex flex-wrap checkbox-wrap"> <nz-checkbox-group
<label nz-checkbox nzValue="1">早餐</label> class="flex flex-wrap checkbox-wrap"
<label nz-checkbox nzValue="2">午餐</label> [(ngModel)]="meals"
<label nz-checkbox nzValue="3">晚餐</label> [ngModelOptions]="{standalone: true}">
</nz-checkbox-wrapper> </nz-checkbox-group>
</nz-form-control> </nz-form-control>
</nz-form-item> </nz-form-item>
<nz-form-item> <nz-form-item class="block" *ngIf="currentPeoples.length">
<nz-form-label nzRequired nzSpan="6">
标准
</nz-form-label>
<nz-form-control [nzErrorTip]="formControlErrorTpl" nzSpan="12">
<nz-select [nzOptions]="[]" nzPlaceHolder="请选择标准"></nz-select>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label nzRequired nzSpan="6"> <nz-form-label nzRequired nzSpan="6">
人群显示 人群显示
</nz-form-label> </nz-form-label>
<nz-form-control [nzErrorTip]="formControlErrorTpl"> <nz-form-control [nzErrorTip]="formControlErrorTpl">
<nz-checkbox-group [ngModel]="ages" <nz-checkbox-group [(ngModel)]="currentPeoples"
class="flex flex-wrap checkbox-wrap" [ngModelOptions]="{standalone: true}"
formControlName="month" class="flex flex-wrap checkbox-wrap">
(ngModelChange)="ageChange()">
</nz-checkbox-group> </nz-checkbox-group>
</nz-form-control> </nz-form-control>
</nz-form-item> </nz-form-item>
<nz-divider></nz-divider> <nz-divider></nz-divider>
<nz-form-item> <nz-form-item>
<nz-form-label nzRequired nzSpan="6"> <nz-form-label nzRequired nzSpan="6">
批量修改重量 批量修改重量

141
projects/admin/src/app/components/ingredient-form-basic/ingredient-form-basic.component.ts

@ -1,6 +1,13 @@
import { Component, EventEmitter, OnInit, Output } from "@angular/core"; import { Component, EventEmitter, OnInit, Output } from "@angular/core";
import { FormArray, FormBuilder, FormGroup } from "@angular/forms"; import { FormArray, FormBuilder, FormGroup } from "@angular/forms";
import { Router } from "@angular/router";
import { OrgDTO } from "@cdk/dtos";
import { ApiService } from "@cdk/services";
import { OptionItemInterface } from "@cdk/types";
import { Utils } from "@cdk/utils";
import { FormValidators } from "@cdk/validators"; import { FormValidators } from "@cdk/validators";
import { NzMessageService } from "ng-zorro-antd/message";
import { Subject, debounceTime, distinctUntilChanged, filter, finalize, switchMap, takeUntil } from "rxjs";
@Component({ @Component({
selector: "app-ingredient-form-basic", selector: "app-ingredient-form-basic",
@ -8,36 +15,138 @@ import { FormValidators } from "@cdk/validators";
styleUrls: ["./ingredient-form-basic.component.less"], styleUrls: ["./ingredient-form-basic.component.less"],
}) })
export class IngredientFormBasicComponent { export class IngredientFormBasicComponent {
constructor(private fb: FormBuilder) {} constructor(
private fb: FormBuilder,
private msg: NzMessageService,
private api: ApiService,
private router: Router
) {}
@Output() onSave = new EventEmitter(); @Output() onSave = new EventEmitter();
private standardSearch$ = new Subject<string>();
private destroy$ = new Subject<void>();
formGroup!: FormGroup; formGroup!: FormGroup;
ages = [ meals = this.api.globalEnum.mealType;
{ value: "1", label: "6-8岁(男)", checked: false },
{ value: "2", label: "6-8岁(女)", checked: false }, standardOfOption: Array<OptionItemInterface> = [];
{ value: "3", label: "9-11岁(男)", checked: false },
{ value: "4", label: "9-11岁(女)", checked: false }, searchedStandard: Array<OptionItemInterface> = [];
{ value: "5", label: "12-14岁(男)", checked: false },
{ value: "6", label: "12-14岁(女)", checked: false }, currentOrgs: OptionItemInterface[] = [];
];
currentPeoples: OptionItemInterface[] = [];
submitLoading = false;
nzFilterOption = (): boolean => true;
ngOnInit(): void { ngOnInit(): void {
this.formGroup = this.fb.group({ this.formGroup = this.fb.group({
id: this.fb.control("", [FormValidators.required()]), id: this.fb.control("", []),
unit: this.fb.control("", [FormValidators.required()]),
day: this.fb.control("1", [FormValidators.required()]),
name: this.fb.control("", [FormValidators.required()]), name: this.fb.control("", [FormValidators.required()]),
food: this.fb.array([], [FormValidators.required()]), nutrient: this.fb.control("", [FormValidators.required()]),
tag: this.fb.control([], []), day: this.fb.control("1", [FormValidators.required()]),
month: this.fb.control([], []), vendors: this.fb.control([], [FormValidators.required()]),
month: this.fb.control([], [FormValidators.required()]),
}); });
this.standardSearch$
.pipe(
filter((f) => !!f),
debounceTime(500),
distinctUntilChanged(),
takeUntil(this.destroy$),
switchMap((term: string) => this.api.getStandard({ name: term }))
)
.subscribe((data) => {
let listOfOption: Array<OptionItemInterface> = [];
if (data.body) {
data.body.forEach((item) => {
listOfOption.push({
label: item.name,
value: item.id,
...item,
});
});
this.searchedStandard = this.searchedStandard.concat(listOfOption);
}
this.standardOfOption = listOfOption;
});
}
ngOnDestroy(): void {
this.destroy$.next();
this.destroy$.complete();
} }
ageChange() {} ageChange() {}
searchStandard(k: string) {
this.standardSearch$.next(k);
}
onStandardChange(v: any) {
const currentStandard = this.searchedStandard.find((f) => f.value === v);
if (currentStandard) {
this.api.getOrgList({ vendors: currentStandard["vendors"] }).subscribe((res) => {
this.currentOrgs = res.body.map((i) => ({
...i,
value: String(i.id),
label: i.name,
}));
});
this.currentPeoples = Object.entries(currentStandard["ingredient"] ?? {}).map(([k, v]) => {
return {
label: k,
value: k,
...(v as any),
};
});
}
}
onSubmit() { onSubmit() {
this.onSave.emit(); if (Utils.validateFormGroup(this.formGroup)) {
if (!this.meals.some((s) => s["checked"])) {
this.msg.error("请选择餐次");
return;
}
if (!this.currentPeoples.some((s) => s["checked"])) {
this.msg.error("请选择人群显示");
return;
}
this.submitLoading = true;
this.api
.saveMenu({
...this.formGroup.value,
crows: this.currentPeoples
.reduce((a, c) => {
return c["checked"] ? a.concat(c.value) : a;
}, [] as string[])
.join(","),
month: this.formGroup.value.month.join(","),
vendors: this.formGroup.value.vendors.join(","),
meals: this.meals
.reduce((a, c) => {
return c["checked"] ? a.concat(c.value) : a;
}, [] as string[])
.join(","),
})
.pipe(
finalize(() => {
this.submitLoading = false;
})
)
.subscribe((res) => {
this.msg.success(res.desc);
this.onSave.emit();
this.router.navigate(["/ingredient/item/list"]);
});
}
} }
} }

2
projects/admin/src/app/pages/dish/dish.component.html

@ -58,7 +58,7 @@
<ng-container *ngSwitchCase="'vender'"> <ng-container *ngSwitchCase="'vender'">
{{ tableOrg[data] ? tableOrg[data].name : '-'}} {{ tableOrg[data] ? tableOrg[data].name : '-'}}
</ng-container> </ng-container>
<ng-container *ngSwitchCase="'foodArr'"> <ng-container *ngSwitchCase="'ingredient'">
<div class=" flex flex-wrap"> <div class=" flex flex-wrap">
<ng-container *ngFor="let item of data"> <ng-container *ngFor="let item of data">
<nz-tag *ngIf="tableFoods[item.key]" class="m-1"> <nz-tag *ngIf="tableFoods[item.key]" class="m-1">

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

@ -96,7 +96,7 @@ export class DishComponent {
{ key: "icon", title: "菜品图片", width: "66px" }, { key: "icon", title: "菜品图片", width: "66px" },
{ key: "name", title: "菜品名称" }, { key: "name", title: "菜品名称" },
{ key: "marks", title: "菜品标签" }, { key: "marks", title: "菜品标签" },
{ key: "foodArr", title: "食材及含量", width: "30%" }, { key: "ingredient", title: "食材及含量", width: "30%" },
{ key: "vender", title: "单位" }, { key: "vender", title: "单位" },
]); ]);
@ -132,7 +132,7 @@ export class DishComponent {
const vendors = res.body.content.map((i: any) => i.vender); const vendors = res.body.content.map((i: any) => i.vender);
const foodKeys = new Set( const foodKeys = new Set(
res.body.content.reduce((a: string[], c: any) => { res.body.content.reduce((a: string[], c: any) => {
return a.concat(Object.keys(c.ingredient ?? {})); return a.concat(c.ingredient.map((i: any) => i.key));
}, [] as string[]) }, [] as string[])
); );

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

@ -102,7 +102,7 @@
</ng-template> </ng-template>
<ng-template #foofFormFooterTpl> <ng-template #foodFormFooterTpl>
<nz-space> <nz-space>
<button *nzSpaceItem nz-button (click)="cancelFoodForm()" type="button"> <button *nzSpaceItem nz-button (click)="cancelFoodForm()" type="button">
取消 取消

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

@ -21,7 +21,7 @@ export class FoodComponent implements OnInit, OnDestroy {
private msg: NzMessageService private msg: NzMessageService
) {} ) {}
@ViewChild("foofFormFooterTpl") foofFormFooterTpl!: TemplateRef<{}>; @ViewChild("foodFormFooterTpl") foodFormFooterTpl!: TemplateRef<{}>;
private drawerRef?: NzDrawerRef; private drawerRef?: NzDrawerRef;
@ -104,7 +104,7 @@ export class FoodComponent implements OnInit, OnDestroy {
food, food,
}, },
nzContent: FoodFormComponent, nzContent: FoodFormComponent,
nzFooter: this.foofFormFooterTpl, nzFooter: this.foodFormFooterTpl,
}); });
} }

74
projects/admin/src/app/pages/ingredients/ingredient-form/ingredient-form.component.ts

@ -1,6 +1,9 @@
import { IngredientFormBasicComponent } from "@admin/app/components"; import { IngredientFormBasicComponent } from "@admin/app/components";
import { Component, OnInit } from "@angular/core"; import { Component, OnInit } from "@angular/core";
import { ActivatedRoute, Router } from "@angular/router";
import { ConfirmIngredientComponent } from "@cdk/ingredient/confirm-ingredient/confirm-ingredient.component"; import { ConfirmIngredientComponent } from "@cdk/ingredient/confirm-ingredient/confirm-ingredient.component";
import { ApiService } from "@cdk/services";
import { NzMessageService } from "ng-zorro-antd/message";
import { NzModalService } from "ng-zorro-antd/modal"; import { NzModalService } from "ng-zorro-antd/modal";
@Component({ @Component({
@ -9,15 +12,30 @@ import { NzModalService } from "ng-zorro-antd/modal";
styleUrls: ["./ingredient-form.component.less"], styleUrls: ["./ingredient-form.component.less"],
}) })
export class IngredientFormComponent implements OnInit { export class IngredientFormComponent implements OnInit {
constructor(private modal: NzModalService) {} constructor(
private modal: NzModalService,
private msg: NzMessageService,
private router: Router,
private route: ActivatedRoute,
private api: ApiService
) {
this.id = this.route.snapshot.paramMap.get("id");
console.log("this.id", this.id);
}
step = 0;
step = 1; id: string | null = "";
expanded = new Set<number>(); expanded = new Set<number>();
ingredients = Array.from({ length: 7 }, (_, i) => 1 + i); ingredients = Array.from({ length: 7 }, (_, i) => 1 + i);
ngOnInit(): void {} ngOnInit(): void {
this.api.getMenuItem().subscribe((res) => {
console.log("res", res);
});
}
onStepChange() { onStepChange() {
this.step = 1; this.step = 1;
@ -44,3 +62,53 @@ export class IngredientFormComponent implements OnInit {
}); });
} }
} }
const data = {
menuId: [1, 2, 3],
dishs: [
{
name: "番茄炒鸡蛋",
dishId: 1,
foods: [
{
key: "001001",
isMain: false,
ingredient: [
{ name: "轻体力", value: 500 },
{ name: "重体力", value: 200 },
],
},
{
key: "001002",
isMain: false,
ingredient: [
{ name: "轻体力", value: 100 },
{ name: "重体力", value: 200 },
],
},
],
},
{
name: "另一个菜品",
dishId: 1,
foods: [
{
key: "001001",
isMain: false,
ingredient: [
{ name: "轻体力", value: 500 },
{ name: "重体力", value: 200 },
],
},
{
key: "001002",
isMain: false,
ingredient: [
{ name: "轻体力", value: 100 },
{ name: "重体力", value: 200 },
],
},
],
},
],
};

28
projects/admin/src/app/pages/ingredients/ingredient-list/ingredient-list.component.html

@ -35,15 +35,31 @@
</ng-template> </ng-template>
<ng-template #renderColumnsTpl let-data let-key="key" let-row="row"> <ng-template #renderColumnsTpl let-data let-key="key" let-row="row">
<ng-container [ngSwitch]="key"> <ng-container [ngSwitch]="key">
<!-- <ng-container *ngSwitchCase="'img'"> <ng-container *ngSwitchCase="'modify'">
<div class="dish-img overflow-auto" {{data | date:'yyyy-MM-dd HH:mm:ss'}}
[ngStyle]="{'background-image':'url(' + tempImg + ')'}"> </ng-container>
<ng-container *ngSwitchCase="'meals'">
<nz-tag *ngFor="let item of data">{{item}}</nz-tag>
</ng-container>
<ng-container *ngSwitchCase="'day'">
{{data}} 天
</ng-container>
<ng-container *ngSwitchCase="'month'">
<div class="flex flex-wrap">
<ng-container *ngIf="data.length === 12">
<nz-tag>
全年
</nz-tag>
</ng-container>
<ng-container *ngIf="data.length !== 12">
<nz-tag *ngFor="let item of data" class="mb-1">
{{monthText[item]}}
</nz-tag>
</ng-container>
</div> </div>
</ng-container> --> </ng-container>
<ng-container *ngSwitchDefault> <ng-container *ngSwitchDefault>
{{data}} {{data}}
</ng-container> </ng-container>
</ng-container> </ng-container>
</ng-template> </ng-template>

38
projects/admin/src/app/pages/ingredients/ingredient-list/ingredient-list.component.ts

@ -17,14 +17,29 @@ export class IngredientListComponent {
private drawerRef?: NzDrawerRef; private drawerRef?: NzDrawerRef;
tempImg = "https://cdn.pixabay.com/photo/2023/08/08/18/01/butterfly-8177925_1280.jpg"; public tableList = new TableListOption(this.fetchData.bind(this), {
frontPagination: false,
public tableList = new TableListOption(this.fetchData.bind(this)); });
public queryForm = new FormGroup({ public queryForm = new FormGroup({
name: new FormControl(""), name: new FormControl(""),
}); });
monthText = {
1: "一月",
2: "二月",
3: "三月",
4: "四月",
5: "五月",
6: "六月",
7: "七月",
8: "八月",
9: "九月",
10: "十月",
11: "十一月",
12: "十二月",
} as any;
ngOnInit(): void { ngOnInit(): void {
this.initTableList(); this.initTableList();
} }
@ -33,14 +48,13 @@ export class IngredientListComponent {
this.tableList.scroll = { x: null }; this.tableList.scroll = { x: null };
this.tableList = this.tableList.setColumns([ this.tableList = this.tableList.setColumns([
{ key: "name", title: "食谱名称" }, { key: "name", title: "食谱名称" },
{ key: "name", title: "单位" }, { key: "vender", title: "单位" },
{ key: "name", title: "包含餐次" }, { key: "meals", title: "包含餐次" },
{ key: "name", title: "单位" }, { key: "month", title: "适用月份", width: "300px" },
{ key: "name", title: "适用月份" }, { key: "day", title: "周期" },
{ key: "name", title: "周期" }, { key: "status", title: "状态" },
{ key: "name", title: "状态" }, { key: "modify", title: "更新时间" },
{ key: "name", title: "更新时间" }, { key: "operate", title: "创建人" },
{ key: "name", title: "创建人" },
]); ]);
this.tableList = this.tableList.setOptions([ this.tableList = this.tableList.setOptions([
@ -78,7 +92,7 @@ export class IngredientListComponent {
} }
fetchData(query: AnyObject, pager: AnyObject) { fetchData(query: AnyObject, pager: AnyObject) {
return this.api.page(pager, query); return this.api.getMenuPage(pager, query);
} }
showFoodForm(food?: any) { showFoodForm(food?: any) {

2
projects/admin/src/app/pages/standard/standard-form/standard-form.component.ts

@ -125,7 +125,7 @@ export class StandardFormComponent {
) )
.subscribe((res) => { .subscribe((res) => {
this.msg.success(res.desc); this.msg.success(res.desc);
const redirectTo = gotoSetting ? ["/", "standard", "setting", res.body] : ["/standard/list"]; const redirectTo = gotoSetting ? ["/", "standard", "setting", res.body.id] : ["/standard/list"];
this.router.navigate(redirectTo); this.router.navigate(redirectTo);
}); });
} }

10
projects/admin/src/app/pages/standard/standard-setting/standard-setting.component.ts

@ -139,12 +139,10 @@ export class StandardSettingComponent {
}; };
}, {} as AnyObject); }, {} as AnyObject);
this.api this.api.saveStandard({ ...this.state, foodCategoryDay, foodCategoryWeek, ingredient }, true).subscribe((res) => {
.saveStandard({ id: this.state.id, foodCategoryDay, foodCategoryWeek, ingredient }, true) this.msg.success(res.desc);
.subscribe((res) => { this.router.navigate(["/standard/list"]);
this.msg.success(res.desc); });
this.router.navigate(["/standard/list"]);
});
} }
addFoodType(type: string) { addFoodType(type: string) {

5
projects/cdk/src/dtos/enum.dto.ts

@ -1,14 +1,19 @@
import { OptionItemInterface } from "@cdk/types";
export type GlobalEnum = { export type GlobalEnum = {
category: CategoryDTO[]; category: CategoryDTO[];
mark: MarkDTO[]; mark: MarkDTO[];
nutrient: NutrientDTO[]; nutrient: NutrientDTO[];
venderType: CategoryDTO[]; venderType: CategoryDTO[];
mealType: OptionItemInterface[];
menuStatus: OptionItemInterface[];
}; };
export type CategoryDTO = { export type CategoryDTO = {
key: string; key: string;
value: string; value: string;
}; };
export type MarkDTO = { export type MarkDTO = {
key: string; key: string;
value: string; value: string;

63
projects/cdk/src/services/api.service.ts

@ -1,6 +1,6 @@
import { HttpClient, HttpParams, HttpResponse } from "@angular/common/http"; import { HttpClient, HttpParams, HttpResponse } from "@angular/common/http";
import { Inject, Injectable, InjectionToken } from "@angular/core"; import { Inject, Injectable, InjectionToken } from "@angular/core";
import { AnyObject, PageResult, ResponseType } from "@cdk/types"; import { AnyObject, OptionItemInterface, PageResult, ResponseType } from "@cdk/types";
import { Utils } from "@cdk/utils"; import { Utils } from "@cdk/utils";
import { Observable, map, of, tap } from "rxjs"; import { Observable, map, of, tap } from "rxjs";
import { import {
@ -12,6 +12,7 @@ import {
ClientAccountDTO, ClientAccountDTO,
AdminAccountDTO, AdminAccountDTO,
OrgConfigDTO, OrgConfigDTO,
CategoryDTO,
} from "@cdk/public-api"; } from "@cdk/public-api";
export const PROJECT_NAME = new InjectionToken<string>("projectName"); export const PROJECT_NAME = new InjectionToken<string>("projectName");
@ -58,13 +59,20 @@ export class ApiService {
} }
} }
private _formatEnum(v: CategoryDTO[]): OptionItemInterface[] {
return v.map((i) => ({ label: i.key, value: i.value }));
}
getAllEnum(force?: boolean): Observable<GlobalEnum> { getAllEnum(force?: boolean): Observable<GlobalEnum> {
if (this.globalEnum && !force) { if (this.globalEnum && !force) {
return of(this.globalEnum); return of(this.globalEnum);
} }
return this.http.get<ResponseType<GlobalEnum>>("/api/basic/enum").pipe( return this.http.get<ResponseType<any>>("/api/enum").pipe(
map((res) => { map((res) => {
return res.body; return {
...res.body,
mealType: this._formatEnum(res.body.mealType),
};
}), }),
tap((r) => { tap((r) => {
this.globalEnum = r; this.globalEnum = r;
@ -103,7 +111,7 @@ export class ApiService {
updatePassword(v: {}) { updatePassword(v: {}) {
const body = Utils.objectToFormData(v); const body = Utils.objectToFormData(v);
return this.http.post<ResponseType>("/api/basic/user", body); return this.http.post<ResponseType>("/api/password", body);
} }
getRoleList() { getRoleList() {
@ -151,7 +159,7 @@ export class ApiService {
}); });
} }
getOrgList(query: {}) { getOrgList(query: { vendors?: number[]; keyword?: string }) {
const q = Utils.objectStringify(query); const q = Utils.objectStringify(query);
return this.http.get<ResponseType<OrgDTO[]>>(`/api/vender/select?${q}`); return this.http.get<ResponseType<OrgDTO[]>>(`/api/vender/select?${q}`);
} }
@ -302,6 +310,11 @@ export class ApiService {
); );
} }
getStandard(q: { id?: string; name?: string }) {
const query = Utils.objectStringify(q);
return this.http.get<ResponseType<any[]>>(`/api/nutrition/select?${query}`);
}
saveStandard(v: AnyObject, isEdit?: boolean) { saveStandard(v: AnyObject, isEdit?: boolean) {
const body = Utils.objectToFormData({ ...v, vendors: v["vendors"]?.join(",") }); const body = Utils.objectToFormData({ ...v, vendors: v["vendors"]?.join(",") });
const method = v["id"] ? "post" : "put"; const method = v["id"] ? "post" : "put";
@ -318,18 +331,18 @@ export class ApiService {
return this.http.get<ResponseType<PageResult>>(`/api/dish?${params}`).pipe( return this.http.get<ResponseType<PageResult>>(`/api/dish?${params}`).pipe(
map((r) => { map((r) => {
if (Array.isArray(r.body.content)) { if (Array.isArray(r.body.content)) {
r.body.content = r.body.content.map((o) => { // r.body.content = r.body.content.map((o) => {
return { // return {
...o, // ...o,
foodArr: Object.entries(o.ingredient).map(([k, v]) => { // foodArr: Object.entries(o.ingredient).map(([k, v]) => {
return { // return {
key: k, // key: k,
value: v, // value: v,
label: k, // label: k,
}; // };
}), // }),
}; // };
}); // });
} }
return r; return r;
}) })
@ -346,4 +359,20 @@ export class ApiService {
const params = Utils.objectToFormData({ ids: ids.join(",") }); const params = Utils.objectToFormData({ ids: ids.join(",") });
return this.http.delete<ResponseType>(`/api/dish`, { body: params }); return this.http.delete<ResponseType>(`/api/dish`, { body: params });
} }
getMenuPage(p: {}, q: {}) {
const params = Utils.objectStringify({ ...p, ...q });
return this.http.get<ResponseType<PageResult>>(`/api/menu?${params}`);
}
getMenuItem() {
const params = Utils.objectStringify({ menuId: 1 });
return this.http.get(`/api/menu/dish?${params}`);
}
saveMenu(v: AnyObject) {
const body = Utils.objectToFormData(v);
const method = v["id"] ? "post" : "put";
return this.http[method]<ResponseType>("/api/menu", body);
}
} }

1
projects/cdk/src/shared/components/index.ts

@ -1 +1,2 @@
export * from "./search-and-select/search-and-select.component"; export * from "./search-and-select/search-and-select.component";
export * from "./month-select/month-select.component";

15
projects/cdk/src/shared/components/month-select/month-select.component.html

@ -0,0 +1,15 @@
<div>
<label
nz-checkbox
[(ngModel)]="allMonthChecked"
[ngModelOptions]="{standalone: true}"
(ngModelChange)="updateAllMonthChecked()"
[nzIndeterminate]="indeterminate">
全年
</label>
</div>
<nz-divider nzDashed class="my-1"></nz-divider>
<div class="flex flex-wrap month-wrap">
<label *ngFor="let m of allMonth" nz-checkbox [(nzChecked)]="m.checked"
(nzCheckedChange)="monthChecked($event,m.value)">{{m.label}}</label>
</div>

17
projects/cdk/src/shared/components/month-select/month-select.component.less

@ -0,0 +1,17 @@
.month-wrap {
::ng-deep {
.ant-checkbox-wrapper {
margin: 6px 0;
flex-basis: calc(100% / 6);
}
}
}
.block-label {
::ng-deep {
label {
display: inline-flex;
width: 100%;
}
}
}

93
projects/cdk/src/shared/components/month-select/month-select.component.ts

@ -0,0 +1,93 @@
import { Component } from "@angular/core";
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from "@angular/forms";
@Component({
selector: "app-month-select",
templateUrl: "./month-select.component.html",
styleUrls: ["./month-select.component.less"],
providers: [
{
provide: NG_VALUE_ACCESSOR,
multi: true,
useExisting: MonthSelectComponent,
},
],
})
export class MonthSelectComponent implements ControlValueAccessor {
allMonthChecked = false;
indeterminate = false;
allMonth = [
{ value: 1, label: "一月", checked: false },
{ value: 2, label: "二月", checked: false },
{ value: 3, label: "三月", checked: false },
{ value: 4, label: "四月", checked: false },
{ value: 5, label: "五月", checked: false },
{ value: 6, label: "六月", checked: false },
{ value: 7, label: "七月", checked: false },
{ value: 8, label: "八月", checked: false },
{ value: 9, label: "九月", checked: false },
{ value: 10, label: "十月", checked: false },
{ value: 11, label: "十一月", checked: false },
{ value: 12, label: "十二月", checked: false },
];
updateAllMonthChecked() {
this.indeterminate = false;
if (this.allMonthChecked) {
this.allMonth = this.allMonth.map((item) => ({
...item,
checked: true,
}));
} else {
this.allMonth = this.allMonth.map((item) => ({
...item,
checked: false,
}));
}
this.formatVal();
}
monthChecked(checked: boolean, value: number) {
this.allMonth = this.allMonth.map((i) => (i.value === value ? { ...i, checked } : i));
this.monthCheckEffect();
this.formatVal();
}
monthCheckEffect() {
if (this.allMonth.every((item) => !item.checked)) {
this.allMonthChecked = false;
this.indeterminate = false;
} else if (this.allMonth.every((item) => item.checked)) {
this.allMonthChecked = true;
this.indeterminate = false;
} else {
this.indeterminate = true;
}
}
formatVal() {
const vals = this.allMonth.reduce((a, c) => {
return c.checked ? a.concat(c.value) : a;
}, [] as number[]);
this.onChange(vals);
}
onChange(v: number[]) {}
ontouch(v: any) {}
writeValue(v: number[]): void {
this.allMonth = this.allMonth.map((i) => (v.includes(i.value) ? { ...i, checked: true } : i));
this.monthCheckEffect();
}
registerOnChange(fn: any): void {
this.onChange = fn;
}
registerOnTouched(fn: any): void {
this.ontouch = fn;
}
}

5
projects/cdk/src/shared/shared.module.ts

@ -20,7 +20,7 @@ import {
// import { environment } from "@manage/environments/environment"; // import { environment } from "@manage/environments/environment";
import { NgxPermissionsModule } from "ngx-permissions"; import { NgxPermissionsModule } from "ngx-permissions";
import { AppPageComponent } from "@cdk/app-page/app-page.component"; import { AppPageComponent } from "@cdk/app-page/app-page.component";
import { SearchAndSelectComponent } from "./components"; import { SearchAndSelectComponent, MonthSelectComponent } from "./components";
const ngModules = [CommonModule, HttpClientModule, FormsModule, RouterModule, ReactiveFormsModule]; const ngModules = [CommonModule, HttpClientModule, FormsModule, RouterModule, ReactiveFormsModule];
const components: any = []; const components: any = [];
@ -36,7 +36,7 @@ const cdks = [
] as any; ] as any;
@NgModule({ @NgModule({
declarations: [...components, ...directives, SearchAndSelectComponent], declarations: [...components, ...directives, SearchAndSelectComponent, MonthSelectComponent],
imports: [...ngZorroModules, ...ngModules, ...cdks, AppPageComponent], imports: [...ngZorroModules, ...ngModules, ...cdks, AppPageComponent],
exports: [ exports: [
...ngZorroModules, ...ngZorroModules,
@ -46,6 +46,7 @@ const cdks = [
...cdks, ...cdks,
AppPageComponent, AppPageComponent,
SearchAndSelectComponent, SearchAndSelectComponent,
MonthSelectComponent,
], ],
}) })
export class SharedModule {} export class SharedModule {}

13
projects/client/src/app/pages/system/org-info/org-info.component.ts

@ -9,6 +9,7 @@ import { NzMessageService } from "ng-zorro-antd/message";
import { OrgFormComponent } from "../../../components"; import { OrgFormComponent } from "../../../components";
import { lastValueFrom } from "rxjs"; import { lastValueFrom } from "rxjs";
import { MD5 } from "crypto-js"; import { MD5 } from "crypto-js";
import { Router } from "@angular/router";
@Component({ @Component({
selector: "app-org-info", selector: "app-org-info",
@ -16,7 +17,12 @@ import { MD5 } from "crypto-js";
styleUrls: ["./org-info.component.less"], styleUrls: ["./org-info.component.less"],
}) })
export class OrgInfoComponent implements OnInit { export class OrgInfoComponent implements OnInit {
constructor(private api: ApiService, private modal: NzModalService, private msg: NzMessageService) {} constructor(
private api: ApiService,
private modal: NzModalService,
private msg: NzMessageService,
private router: Router
) {}
account: any = this.api.account; account: any = this.api.account;
@ -73,11 +79,16 @@ export class OrgInfoComponent implements OnInit {
} }
const res = await lastValueFrom( const res = await lastValueFrom(
this.api.updatePassword({ this.api.updatePassword({
oldPassword: MD5(value.oldPwd!).toString().slice(-16),
password: MD5(value.newPwd!).toString().slice(-16), password: MD5(value.newPwd!).toString().slice(-16),
// name: // name:
}) })
); );
this.msg.success(res.desc); this.msg.success(res.desc);
this.api.logout().subscribe(() => {
this.msg.success("请重新登录");
this.router.navigate(["/login"]);
});
return true; return true;
} }
return false; return false;

Loading…
Cancel
Save