Browse Source

食谱 添加 菜品

main
kely 2 years ago
parent
commit
4e80addeec
  1. 3
      angular.json
  2. 2
      projects/admin/src/app/app.module.ts
  3. 2
      projects/admin/src/app/components/dish-form/dish-form.component.html
  4. 34
      projects/admin/src/app/components/dish-form/dish-form.component.ts
  5. 2
      projects/admin/src/app/components/index.ts
  6. 2
      projects/admin/src/app/pages/dish/dish.component.html
  7. 33
      projects/admin/src/app/pages/dish/dish.component.ts
  8. 46
      projects/admin/src/app/pages/ingredients/ingredient-form/ingredient-form.component.html
  9. 92
      projects/admin/src/app/pages/ingredients/ingredient-form/ingredient-form.component.ts
  10. 2
      projects/admin/src/app/pages/ingredients/ingredient-list/ingredient-list.component.html
  11. 17
      projects/admin/src/app/pages/ingredients/ingredient-list/ingredient-list.component.ts
  12. 12
      projects/admin/src/app/pages/standard/standard-form/standard-form.component.ts
  13. 115
      projects/cdk/src/ingredient/add-dish-to-ingredient/add-dish-to-ingredient.component.html
  14. 61
      projects/cdk/src/ingredient/add-dish-to-ingredient/add-dish-to-ingredient.component.ts
  15. 36
      projects/cdk/src/ingredient/confirm-ingredient/confirm-ingredient.component.html
  16. 59
      projects/cdk/src/ingredient/confirm-ingredient/confirm-ingredient.component.ts
  17. 60
      projects/cdk/src/ingredient/ingredient-dish/ingredient-dish.component.html
  18. 25
      projects/cdk/src/ingredient/ingredient-dish/ingredient-dish.component.less
  19. 119
      projects/cdk/src/ingredient/ingredient-dish/ingredient-dish.component.ts
  20. 17
      projects/cdk/src/ingredient/ingredient-form-basic/ingredient-form-basic.component.html
  21. 0
      projects/cdk/src/ingredient/ingredient-form-basic/ingredient-form-basic.component.less
  22. 57
      projects/cdk/src/ingredient/ingredient-form-basic/ingredient-form-basic.component.ts
  23. 279
      projects/cdk/src/ingredient/ingredient-meals/ingredient-meals.component.html
  24. 6
      projects/cdk/src/ingredient/ingredient-meals/ingredient-meals.component.less
  25. 125
      projects/cdk/src/ingredient/ingredient-meals/ingredient-meals.component.ts
  26. 18
      projects/cdk/src/ingredient/ingredient.module.ts
  27. 10
      projects/cdk/src/services/api.service.ts
  28. 22
      projects/cdk/src/shared/components/dish-select/dish-select.component.html
  29. 0
      projects/cdk/src/shared/components/dish-select/dish-select.component.less
  30. 97
      projects/cdk/src/shared/components/dish-select/dish-select.component.ts
  31. 2
      projects/cdk/src/shared/components/index.ts
  32. 1
      projects/cdk/src/shared/components/month-select/month-select.component.ts
  33. 13
      projects/cdk/src/shared/components/org-select/org-select.component.html
  34. 0
      projects/cdk/src/shared/components/org-select/org-select.component.less
  35. 81
      projects/cdk/src/shared/components/org-select/org-select.component.ts
  36. 2
      projects/cdk/src/shared/ng-zorro.ts
  37. 13
      projects/cdk/src/shared/shared.module.ts

3
angular.json

@ -2,7 +2,8 @@
"$schema": "./node_modules/@angular/cli/lib/config/schema.json", "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1, "version": 1,
"cli": { "cli": {
"packageManager": "pnpm" "packageManager": "pnpm",
"analytics": false
}, },
"newProjectRoot": "projects", "newProjectRoot": "projects",
"projects": { "projects": {

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

@ -15,7 +15,6 @@ import {
AppLayoutComponent, AppLayoutComponent,
FoodFormComponent, FoodFormComponent,
DishFormComponent, DishFormComponent,
IngredientFormBasicComponent,
UserListComponent, UserListComponent,
RolePermissionComponent, RolePermissionComponent,
IngredientStatusListComponent, IngredientStatusListComponent,
@ -49,7 +48,6 @@ registerLocaleData(zh);
AppLayoutComponent, AppLayoutComponent,
FoodFormComponent, FoodFormComponent,
DishFormComponent, DishFormComponent,
IngredientFormBasicComponent,
UserListComponent, UserListComponent,
RolePermissionComponent, RolePermissionComponent,

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

@ -45,7 +45,7 @@
</nz-form-control> </nz-form-control>
</nz-form-item> </nz-form-item>
<nz-form-item> <nz-form-item>
<nz-form-label> <nz-form-label nzRequired>
适用月份 适用月份
</nz-form-label> </nz-form-label>
<nz-form-control [nzErrorTip]="formControlErrorTpl"> <nz-form-control [nzErrorTip]="formControlErrorTpl">

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

@ -42,25 +42,6 @@ export class DishFormComponent {
globalEnum = this.api.globalEnum; globalEnum = this.api.globalEnum;
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 },
];
allMonthChecked = false;
indeterminate = false;
uploadLoading = false; uploadLoading = false;
addFoodVisible = false; addFoodVisible = false;
@ -124,9 +105,9 @@ export class DishFormComponent {
this.orgListOfOption = this.orgs.map((i) => ({ text: i.name, value: i.id })); this.orgListOfOption = this.orgs.map((i) => ({ text: i.name, value: i.id }));
if (this.data) { if (this.data) {
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.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);
@ -164,14 +145,7 @@ export class DishFormComponent {
value: num, value: num,
}); });
} }
const month = this.allMonth const month = value.month.join(",");
.reduce((a: any, c: any) => {
if (c.checked) {
return a.concat(Number(c.value));
}
return a;
}, [] as number[])
.join(",");
const vendors = value.vendors?.join(",") ?? ""; const vendors = value.vendors?.join(",") ?? "";
values = { values = {
...value, ...value,

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

@ -3,8 +3,6 @@ export * from "./app-layout/app-layout.component";
export * from "./food-form/food-form.component"; export * from "./food-form/food-form.component";
export * from "./dish-form/dish-form.component"; export * from "./dish-form/dish-form.component";
export * from "./ingredient-form-basic/ingredient-form-basic.component";
export * from "./user-list/user-list.component"; export * from "./user-list/user-list.component";
export * from "./role-permission/role-permission.component"; export * from "./role-permission/role-permission.component";
export * from "./ingredient-status-list/ingredient-status-list.component"; export * from "./ingredient-status-list/ingredient-status-list.component";

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

@ -83,7 +83,7 @@
<button *nzSpaceItem nz-button (click)="cancelForm()" type="button"> <button *nzSpaceItem nz-button (click)="cancelForm()" type="button">
取消 取消
</button> </button>
<button *nzSpaceItem nz-button nzType="primary" (click)="onSubmit()"> <button *nzSpaceItem nz-button nzType="primary" [nzLoading]="submitLoading" (click)="onSubmit()">
保存 保存
</button> </button>
</nz-space> </nz-space>

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

@ -4,7 +4,17 @@ import { NzDrawerRef, NzDrawerService } from "ng-zorro-antd/drawer";
import { AnyObject, OrgDTO, TableListOption } from "@cdk/public-api"; import { AnyObject, OrgDTO, TableListOption } from "@cdk/public-api";
import { DishFormComponent } from "@admin/app/components"; import { DishFormComponent } from "@admin/app/components";
import { ApiService } from "@cdk/services"; import { ApiService } from "@cdk/services";
import { Subject, debounceTime, distinctUntilChanged, filter, lastValueFrom, switchMap, takeUntil, tap } from "rxjs"; import {
Subject,
debounceTime,
distinctUntilChanged,
filter,
finalize,
lastValueFrom,
switchMap,
takeUntil,
tap,
} from "rxjs";
import { NzModalService } from "ng-zorro-antd/modal"; import { NzModalService } from "ng-zorro-antd/modal";
import { NzMessageService } from "ng-zorro-antd/message"; import { NzMessageService } from "ng-zorro-antd/message";
import { ResponseType } from "@cdk/types"; import { ResponseType } from "@cdk/types";
@ -28,6 +38,8 @@ export class DishComponent {
private destroy$ = new Subject<void>(); private destroy$ = new Subject<void>();
private orgSearch$ = new Subject<string>();
public globalEnum = this.api.globalEnum; public globalEnum = this.api.globalEnum;
public tableList = new TableListOption(this.fetchData.bind(this), { public tableList = new TableListOption(this.fetchData.bind(this), {
@ -41,8 +53,6 @@ export class DishComponent {
vendors: new FormControl(""), vendors: new FormControl(""),
}); });
private orgSearch$ = new Subject<string>();
public selectedIds: string[] = []; public selectedIds: string[] = [];
tableOrg: { [k: number]: OrgDTO } = {}; tableOrg: { [k: number]: OrgDTO } = {};
@ -188,11 +198,18 @@ export class DishComponent {
const val = com.getValues(); const val = com.getValues();
if (val) { if (val) {
this.submitLoading = true; this.submitLoading = true;
this.api.saveDish(val).subscribe((res) => { this.api
this.msg.success(res.desc); .saveDish(val)
this.tableList.run(); .pipe(
this.cancelForm(); finalize(() => {
}); this.submitLoading = false;
})
)
.subscribe((res) => {
this.msg.success(res.desc);
this.tableList.run();
this.cancelForm();
});
} }
} }
} }

46
projects/admin/src/app/pages/ingredients/ingredient-form/ingredient-form.component.html

@ -2,11 +2,12 @@
<div class="p-4" *ngIf="step === 0"> <div class="p-4" *ngIf="step === 0">
<nz-card nzTitle="录入食谱基础信息"> <nz-card nzTitle="录入食谱基础信息">
<app-ingredient-form-basic (onSave)="onStepChange($event)"></app-ingredient-form-basic> <app-ingredient-form-basic [menu]="menuItem" (onSave)="onStepChange($event)"></app-ingredient-form-basic>
</nz-card> </nz-card>
</div> </div>
<ng-container *ngIf="step === 1"> <ng-container *ngIf="step === 1">
<nz-card nzSize="small"> <nz-card nzSize="small">
<div class="flex justify-between"> <div class="flex justify-between">
<div class="flex-1 "> <div class="flex-1 ">
@ -31,52 +32,15 @@
<button *nzSpaceItem nz-button nzType="primary" (click)="confirmSave()"> <button *nzSpaceItem nz-button nzType="primary" (click)="confirmSave()">
保存 保存
</button> </button>
<button *nzSpaceItem nz-button> <!-- <button *nzSpaceItem nz-button>
另存为 另存为
</button> </button> -->
</nz-space> </nz-space>
</div> </div>
</nz-card> </nz-card>
<div class="p-4"> <div class="p-4">
<nz-card <app-ingredient-dish #menuDish [menu]="menuItem"></app-ingredient-dish>
*ngFor="let i of ingredients"
[nzTitle]="dayTitleTpl"
class="day-item mb-4"
[nzExtra]="dayExtraTpl"
[nzBodyStyle]="{padding:0}">
<ng-template #dayTitleTpl>
<div class=" relative -left-4 z-10">
<button nz-button nzType="text" (click)="expandChange(i)">
<span nz-icon nzType="caret-right" nzTheme="outline"></span>
</button>
<span>
第{{i}}天
</span>
</div>
</ng-template>
<ng-template #dayExtraTpl>
<nz-space>
<button *nzSpaceItem nz-button nzType="link">
本天菜品应用到其他天
</button>
<button *nzSpaceItem nz-button nzType="link">
本日营养分析
</button>
</nz-space>
</ng-template>
<nz-card-tab>
<nz-tabset nzSize="large">
<nz-tab nzTitle="早餐"></nz-tab>
<nz-tab nzTitle="午餐"></nz-tab>
<nz-tab nzTitle="晚餐"></nz-tab>
</nz-tabset>
</nz-card-tab>
<div class="p-4" *ngIf="expanded.has(i)">
<lib-ingredient-meals></lib-ingredient-meals>
</div>
</nz-card>
</div> </div>
</ng-container> </ng-container>
</app-page> </app-page>

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

@ -1,8 +1,10 @@
import { IngredientFormBasicComponent } from "@admin/app/components"; import { Component, OnInit, ViewChild } from "@angular/core";
import { Component, OnInit } from "@angular/core";
import { ActivatedRoute, Router } from "@angular/router"; 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 { IngredientDishComponent } from "@cdk/ingredient/ingredient-dish/ingredient-dish.component";
import { MealDishInterface } from "@cdk/ingredient/ingredient-meals/ingredient-meals.component";
import { ApiService } from "@cdk/services"; import { ApiService } from "@cdk/services";
import { OptionItemInterface } from "@cdk/types";
import { NzMessageService } from "ng-zorro-antd/message"; import { NzMessageService } from "ng-zorro-antd/message";
import { NzModalService } from "ng-zorro-antd/modal"; import { NzModalService } from "ng-zorro-antd/modal";
@ -20,45 +22,99 @@ export class IngredientFormComponent implements OnInit {
private api: ApiService private api: ApiService
) { ) {
this.id = this.route.snapshot.paramMap.get("id"); this.id = this.route.snapshot.paramMap.get("id");
console.log("this.id", this.id);
} }
@ViewChild("menuDish") menuDish!: IngredientDishComponent;
step = 0; step = 0;
id: string | null = ""; id: string | null = "";
expanded = new Set<number>(); menuItem: any = null;
ingredients = Array.from({ length: 7 }, (_, i) => 1 + i);
ngOnInit(): void { ngOnInit(): void {
this.api.getMenuItem().subscribe((res) => { this.step = this.id && this.id !== "create" ? 1 : 0;
console.log("res", res); this.getDetail();
}); }
getDetail() {
if (this.id && this.id !== "create") {
this.api.getMenuItem(this.id).subscribe((res) => {
if (res.body) {
this.menuItem = res.body;
}
});
}
} }
onStepChange(basicInfo: any) { onStepChange(basicInfo: any) {
this.step = 1; this.step = 1;
console.log(basicInfo); this.menuItem = {
...basicInfo,
menuIds: basicInfo.menuId,
meals: basicInfo.meals.reduce(
(a: string[], c: OptionItemInterface) => (c["checked"] ? a.concat(c.value) : a),
[] as string[]
),
crows: basicInfo.peoples.reduce(
(a: string[], c: OptionItemInterface) => (c["checked"] ? a.concat(c.value) : a),
[] as string[]
),
};
} }
shopDishForm() {} shopDishForm() {}
cancelForm() {} cancelForm() {}
expandChange(i: number) {
if (this.expanded.has(i)) {
this.expanded.delete(i);
} else {
this.expanded.add(i);
}
}
confirmSave() { confirmSave() {
// console.log("this.menuItem", this.menuItem);
this.modal.create({ this.modal.create({
nzTitle: "确认食谱信息", nzTitle: "确认食谱信息",
nzContent: ConfirmIngredientComponent, nzContent: ConfirmIngredientComponent,
nzData: this.menuItem,
nzWidth: 650, nzWidth: 650,
nzOnOk: () => {
// const { menuObject } = this.menuDish;
// const serverNeed = this.formatData(menuObject);
// this.api.saveMenuDist(serverNeed).subscribe((res) => {
// this.msg.success(res.desc);
// this.router.navigate(["/ingredient/item/list"]);
// });
},
}); });
} }
formatData(menuObject: any) {
let dishes: any[] = [];
Object.entries(menuObject).forEach(([day, v]) => {
Object.entries(v as Record<string, MealDishInterface[]>).forEach(([mealIndex, dishList]) => {
dishList.forEach((dish) => {
dishes.push({
...dish,
day: Number(day),
meal: this.menuItem.meals[mealIndex],
items: dish.foods.map((food) => {
return {
...food,
value: food.groupValues.reduce((a, c) => {
return {
...a,
[c.peopleName]: c.value,
};
}, {} as Record<string, number>),
};
}),
});
});
});
});
const toServer = {
menuIds: this.menuItem.menuIds ?? [this.menuItem.id],
dishes,
};
return toServer;
}
} }

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

@ -19,7 +19,7 @@
<ng-template #searchTpl> <ng-template #searchTpl>
<nz-form-item class="w-60"> <nz-form-item class="w-60">
<nz-form-control> <nz-form-control>
<nz-select nzPlaceHolder="单位" [nzOptions]="[]"></nz-select> <app-org-select formControlName="vender"></app-org-select>
</nz-form-control> </nz-form-control>
</nz-form-item> </nz-form-item>
<nz-form-item class="w-40"> <nz-form-item class="w-40">

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

@ -8,6 +8,7 @@ import { NzModalService } from "ng-zorro-antd/modal";
import { lastValueFrom, tap } from "rxjs"; import { lastValueFrom, tap } from "rxjs";
import { NzMessageService } from "ng-zorro-antd/message"; import { NzMessageService } from "ng-zorro-antd/message";
import { MyResponse } from "@cdk/types"; import { MyResponse } from "@cdk/types";
import { Router } from "@angular/router";
@Component({ @Component({
selector: "app-ingredient-list", selector: "app-ingredient-list",
@ -19,7 +20,8 @@ export class IngredientListComponent {
private drawer: NzDrawerService, private drawer: NzDrawerService,
private api: ApiService, private api: ApiService,
private modal: NzModalService, private modal: NzModalService,
private msg: NzMessageService private msg: NzMessageService,
private router: Router
) {} ) {}
globalEnum = this.api.globalEnum; globalEnum = this.api.globalEnum;
@ -36,6 +38,8 @@ export class IngredientListComponent {
public queryForm = new FormGroup({ public queryForm = new FormGroup({
name: new FormControl(""), name: new FormControl(""),
vender: new FormControl(""),
status: new FormControl(""),
}); });
startTime: Date | null = null; startTime: Date | null = null;
@ -89,6 +93,7 @@ export class IngredientListComponent {
{ {
title: "导出", title: "导出",
premissions: [], premissions: [],
onClick: this.showFoodForm.bind(this), onClick: this.showFoodForm.bind(this),
}, },
{ {
@ -101,7 +106,7 @@ export class IngredientListComponent {
// 2 发布 编辑 删除 // 2 发布 编辑 删除
// 3 提交审核 编辑 删除 // 3 提交审核 编辑 删除
// 4 提交审核 编辑 删除 // 4 提交审核 编辑 删除
return ["0", "3", "4"].includes(v.status); return [0, 3, 4].includes(v.status);
}, },
}, },
{ {
@ -109,15 +114,17 @@ export class IngredientListComponent {
premissions: [], premissions: [],
onClick: this.release.bind(this), onClick: this.release.bind(this),
visible(v) { visible(v) {
return ["2"].includes(v.status); return [2].includes(v.status);
}, },
}, },
{ {
title: "编辑", title: "编辑",
premissions: [], premissions: [],
onClick: this.deleteItem.bind(this), onClick: (v) => {
this.router.navigate([`/ingredient/item/form/${v["id"]}`]);
},
visible(v) { visible(v) {
return v.status !== "1"; return v.status !== 1;
}, },
}, },
{ {

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

@ -115,9 +115,13 @@ export class StandardFormComponent {
onSubmit(gotoSetting?: boolean) { onSubmit(gotoSetting?: boolean) {
if (Utils.validateFormGroup(this.formGroup)) { if (Utils.validateFormGroup(this.formGroup)) {
this.submitLoading = true; this.submitLoading = true;
const { foodCategoryDay, foodCategoryWeek, ingredient } = this.state;
this.api this.api
.saveStandard({ foodCategoryDay, foodCategoryWeek, ingredient, ...this.formGroup.value }) .saveStandard({
foodCategoryDay: this.state?.foodCategoryDay,
foodCategoryWeek: this.state?.foodCategoryWeek,
ingredient: this.state?.ingredient,
...this.formGroup.value,
})
.pipe( .pipe(
finalize(() => { finalize(() => {
this.submitLoading = false; this.submitLoading = false;
@ -126,7 +130,9 @@ export class StandardFormComponent {
.subscribe((res) => { .subscribe((res) => {
this.msg.success(res.desc); this.msg.success(res.desc);
const redirectTo = gotoSetting ? ["/", "standard", "setting", res.body.id] : ["/standard/list"]; const redirectTo = gotoSetting ? ["/", "standard", "setting", res.body.id] : ["/standard/list"];
this.router.navigate(redirectTo); this.router.navigate(redirectTo, {
state: res.body,
});
}); });
} }
} }

115
projects/cdk/src/ingredient/add-dish-to-ingredient/add-dish-to-ingredient.component.html

@ -1,24 +1,28 @@
<form nz-form> <div nz-form>
<div nz-row [nzGutter]="12"> <div nz-row [nzGutter]="12">
<div nz-col nzSpan="12"> <div nz-col nzSpan="14">
<nz-form-item> <nz-form-item>
<nz-form-label nzRequired="">菜品名称</nz-form-label> <nz-form-label nzRequired="">菜品名称</nz-form-label>
<nz-form-control> <nz-form-control>
<nz-select nzShowSearch nzPlaceHolder="请输入菜品名称搜索"></nz-select> <!-- 请输入菜品名称搜索 -->
<app-dish-select [(ngModel)]="dish" (ngModelChange)="onDishChange($event)"></app-dish-select>
</nz-form-control> </nz-form-control>
</nz-form-item> </nz-form-item>
</div> </div>
<div nz-col nzSpan="12"> <div nz-col nzSpan="10">
<nz-form-item> <nz-form-item>
<nz-form-label nzRequired="">菜品标签</nz-form-label> <nz-form-label nzRequired="">菜品标签</nz-form-label>
<nz-form-control> <nz-form-control>
<nz-select nzPlaceHolder="请选择菜品标签"></nz-select> <nz-select nzPlaceHolder="请选择菜品标签" [(ngModel)]="mark">
<nz-option *ngFor="let item of globalEnum.mark" [nzValue]="item.value"
[nzLabel]="item.key"></nz-option>
</nz-select>
</nz-form-control> </nz-form-control>
</nz-form-item> </nz-form-item>
</div> </div>
</div> </div>
<nz-form-item> <!-- <nz-form-item>
<nz-form-label nzRequired="">食材搜索方式</nz-form-label> <nz-form-label nzRequired="">食材搜索方式</nz-form-label>
<nz-form-control> <nz-form-control>
<nz-radio-group nzButtonStyle="solid"> <nz-radio-group nzButtonStyle="solid">
@ -26,44 +30,47 @@
<label nz-radio nzValue="2" nz-radio-button>营养素</label> <label nz-radio nzValue="2" nz-radio-button>营养素</label>
</nz-radio-group> </nz-radio-group>
</nz-form-control> </nz-form-control>
</nz-form-item> </nz-form-item> -->
<div> <div>
<nz-table nzTemplateMode [nzBordered]="true" nzSize="small"> <nz-table nzTemplateMode [nzBordered]="true" nzSize="small" [nzScroll]="{ x: '1000px' }">
<thead> <thead>
<tr> <tr>
<th> <th nzWidth="200px">
食材 食材
</th> </th>
<th> <th nzWidth="80px">
是否主料 是否主料
</th> </th>
<th> <th *ngFor="let p of peopleGroups" nzWidth="120px">
轻体力1 {{p}}
</th> </th>
<th> <!-- <th nzRight nzWidth="150px">
轻体力2
</th>
<th>
操作 操作
</th> </th> -->
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr> <tr *ngFor="let item of foods">
<td> <td>
味精 {{item.foodName}}
</td> </td>
<td> <td>
<nz-switch nzCheckedChildren="是" nzUnCheckedChildren="否"></nz-switch> <nz-switch
[(ngModel)]="item.isMain"
[nzDisabled]="true"
nzCheckedChildren="是"
nzUnCheckedChildren="否">
</nz-switch>
</td> </td>
<td> <td *ngFor="let p of item.groupValues">
<input nz-input placeholder="重量" /> <nz-input-group nzAddOnAfter="g">
<input nz-input type="number" min="0" placeholder="重量" [(ngModel)]="p.value" />
</nz-input-group>
</td> </td>
<td> <!-- <td nzRight>
<input nz-input placeholder="重量" /> <nz-space nzSize="small">
</td>
<td>
<nz-space>
<button *nzSpaceItem nz-button nzType="link"> <button *nzSpaceItem nz-button nzType="link">
修改 修改
</button> </button>
@ -71,57 +78,11 @@
删除 删除
</button> </button>
</nz-space> </nz-space>
</td> </td> -->
</tr>
<tr>
<td>
味精
</td>
<td>
<nz-switch nzCheckedChildren="是" nzUnCheckedChildren="否"></nz-switch>
</td>
<td>
<input nz-input placeholder="重量" />
</td>
<td>
<input nz-input placeholder="重量" />
</td>
<td>
<nz-space>
<button *nzSpaceItem nz-button nzType="link">
修改
</button>
<button *nzSpaceItem nz-button nzType="link" nzDanger>
删除
</button>
</nz-space>
</td>
</tr>
<tr>
<td>
味精
</td>
<td>
<nz-switch nzCheckedChildren="是" nzUnCheckedChildren="否"></nz-switch>
</td>
<td>
<input nz-input placeholder="重量" />
</td>
<td>
<input nz-input placeholder="重量" />
</td>
<td>
<nz-space>
<button *nzSpaceItem nz-button nzType="link">
修改
</button>
<button *nzSpaceItem nz-button nzType="link" nzDanger>
删除
</button>
</nz-space>
</td>
</tr> </tr>
</tbody> </tbody>
</nz-table> </nz-table>
<nz-empty class="mt-4" *ngIf="foods.length === 0"></nz-empty>
</div> </div>
</form> </div>

61
projects/cdk/src/ingredient/add-dish-to-ingredient/add-dish-to-ingredient.component.ts

@ -1,8 +1,63 @@
import { Component } from "@angular/core"; import { Component, Input, OnInit } from "@angular/core";
import { ApiService } from "@cdk/services";
export interface FoodInDishInterface {
foodName: string;
key: string;
isMain: boolean;
groupValues: Array<{
peopleName: string;
value: number;
}>;
value: Record<string, number>;
}
@Component({ @Component({
selector: "lib-add-dish-to-ingredient", selector: "app-add-dish-to-ingredient",
templateUrl: "./add-dish-to-ingredient.component.html", templateUrl: "./add-dish-to-ingredient.component.html",
styleUrls: ["./add-dish-to-ingredient.component.less"], styleUrls: ["./add-dish-to-ingredient.component.less"],
}) })
export class AddDishToIngredientComponent {} export class AddDishToIngredientComponent implements OnInit {
constructor(private api: ApiService) {}
@Input() peopleGroups: string[] = [];
globalEnum = this.api.globalEnum;
dish: any = null;
mark: string = "";
foods: FoodInDishInterface[] = [];
ngOnInit(): void {
console.log("this.peopleGroups", this.peopleGroups);
}
onDishChange(dish: any) {
if (dish) {
this.mark = dish.marks;
this.getFoodNameByKeys(dish.ingredient);
}
}
getFoodNameByKeys(foods: any[]) {
const keys = foods.map((i) => i.key);
this.api.getFoodList({ keys }).subscribe((res) => {
this.foods = res.body.map((i) => {
return {
foodName: i.name,
key: i.key,
isMain: foods.find((f) => f.key === i.key)?.isMain ?? false,
groupValues: this.peopleGroups.map((p) => {
return {
peopleName: p,
value: 0,
};
}),
value: {},
};
});
});
}
}

36
projects/cdk/src/ingredient/confirm-ingredient/confirm-ingredient.component.html

@ -1,10 +1,10 @@
<form nz-form [formGroup]="formGroup"> <div nz-form>
<nz-form-item> <nz-form-item>
<nz-form-label nzSpan="4"> <nz-form-label nzSpan="4">
天数 天数
</nz-form-label> </nz-form-label>
<nz-form-control nzSpan="12"> <nz-form-control nzSpan="12">
<nz-tag nzColor="cyan">7</nz-tag> <nz-tag nzColor="cyan">{{data.day}}</nz-tag>
</nz-form-control> </nz-form-control>
</nz-form-item> </nz-form-item>
<nz-form-item> <nz-form-item>
@ -13,9 +13,7 @@
</nz-form-label> </nz-form-label>
<nz-form-control nzSpan="12"> <nz-form-control nzSpan="12">
<nz-space> <nz-space>
<nz-tag *nzSpaceItem nzColor="blue">早餐</nz-tag> <ng-container *ngFor="let m of data.meals">{{m}}</ng-container>
<nz-tag *nzSpaceItem nzColor="blue">午餐</nz-tag>
<nz-tag *nzSpaceItem nzColor="blue">晚餐</nz-tag>
</nz-space> </nz-space>
</nz-form-control> </nz-form-control>
</nz-form-item> </nz-form-item>
@ -24,30 +22,16 @@
食谱名称 食谱名称
</nz-form-label> </nz-form-label>
<nz-form-control nzSpan="16"> <nz-form-control nzSpan="16">
<input nz-input placeholder="请输入食谱名称" /> {{data.name}}
<!-- <input nz-input placeholder="请输入食谱名称" [ngModel]="data.name" /> -->
</nz-form-control> </nz-form-control>
</nz-form-item> </nz-form-item>
<nz-form-item> <!-- <nz-form-item>
<nz-form-label nzSpan="4" nzRequired> <nz-form-label nzSpan="4" nzRequired>
适用月份 适用月份
</nz-form-label> </nz-form-label>
<nz-form-control nzSpan="16"> <nz-form-control nzSpan="16">
<div> <app-month-select [ngModel]="[1,2,3]"></app-month-select>
<label
nz-checkbox
[(ngModel)]="allMonthChecked"
[ngModelOptions]="{standalone: true}"
(ngModelChange)="updateAllMonthChecked()"
[nzIndeterminate]="indeterminate">
全年
</label>
</div>
<nz-divider nzDashed class="my-2"></nz-divider>
<nz-checkbox-group [ngModel]="allMonth"
class="flex flex-wrap month-wrap"
formControlName="month"
(ngModelChange)="monthChecked()">
</nz-checkbox-group>
</nz-form-control> </nz-form-control>
</nz-form-item> </nz-form-item> -->
</form> </div>

59
projects/cdk/src/ingredient/confirm-ingredient/confirm-ingredient.component.ts

@ -1,7 +1,8 @@
import { Component } from "@angular/core"; import { Component, inject } from "@angular/core";
import { FormBuilder, FormGroup } from "@angular/forms"; import { FormBuilder, FormGroup } from "@angular/forms";
import { FormValidators } from "@cdk/public-api"; import { FormValidators } from "@cdk/public-api";
import { NzMessageService } from "ng-zorro-antd/message"; import { NzMessageService } from "ng-zorro-antd/message";
import { NZ_MODAL_DATA } from "ng-zorro-antd/modal";
@Component({ @Component({
selector: "lib-confirm-ingredient", selector: "lib-confirm-ingredient",
@ -11,61 +12,11 @@ import { NzMessageService } from "ng-zorro-antd/message";
export class ConfirmIngredientComponent { export class ConfirmIngredientComponent {
constructor(private fb: FormBuilder, private msg: NzMessageService) {} constructor(private fb: FormBuilder, private msg: NzMessageService) {}
formGroup!: FormGroup; data = inject(NZ_MODAL_DATA);
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 },
];
allMonthChecked = false;
indeterminate = false; formGroup!: FormGroup;
ngOnInit(): void { ngOnInit(): void {
this.formGroup = this.fb.group({ console.log("data", this.data);
id: this.fb.control("", [FormValidators.required()]),
name: this.fb.control("", [FormValidators.required()]),
month: this.fb.control([], [FormValidators.required()]),
});
}
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() {
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;
}
} }
} }

60
projects/cdk/src/ingredient/ingredient-dish/ingredient-dish.component.html

@ -0,0 +1,60 @@
<nz-spin [nzSpinning]="!menu">
<ng-container>
<!-- {{ menuObject | json }} -->
<nz-card
*ngFor="let day of days"
[nzTitle]="dayTitleTpl"
class="day-item mb-4"
[ngClass]="{'expanded':expanded.has(day)}"
[nzExtra]="dayExtraTpl"
[nzBodyStyle]="{padding:0}">
<ng-template #dayTitleTpl>
<div class=" relative -left-4 z-10">
<button nz-button nzType="text" (click)="expandChange(day)">
<span class="expanded-icon" nz-icon nzType="caret-right" nzTheme="outline"></span>
</button>
<span>
第 {{day + 1}} 天
</span>
</div>
</ng-template>
<ng-template #dayExtraTpl>
<nz-space>
<button *nzSpaceItem nz-button nzType="link" (click)="reuse(day + 1, selectDayTpl)">
本天菜品应用到其他天
</button>
<button *nzSpaceItem nz-button nzType="link">
本日营养分析
</button>
</nz-space>
</ng-template>
<ng-container *ngIf="expanded.has(day)">
<nz-card-tab>
<nz-tabset nzSize="large" [(nzSelectedIndex)]="mealCurrentIndex[day]">
<nz-tab [nzTitle]="meal" *ngFor="let meal of menu.meals; let idx = index">
</nz-tab>
</nz-tabset>
</nz-card-tab>
<div class="p-4">
<ng-container *ngFor="let meal of menu.meals; let mealIndex = index ">
<app-ingredient-meals *ngIf="mealCurrentIndex[day] === mealIndex"
[day]="day + 1"
[mealIndex]="mealIndex"
[peopleGroups]="menu.crows"
[mealDishs]="mealDishList"
(onSaveDish)="onSaveDish($event,day+1,mealIndex)">
<!-- (onSaveDish)="onSaveDish($event,day+1,mealIndex)" -->
</app-ingredient-meals>
</ng-container>
</div>
</ng-container>
</nz-card>
</ng-container>
</nz-spin>
<ng-template #selectDayTpl>
<nz-alert nzType="warning" nzMessage="请注意,如果其它天已经存在菜品,新应用的菜品将会追加在其中,不影响已经存在的菜品" nzShowIcon>
</nz-alert>
<nz-checkbox-group [(ngModel)]="selectDay" class="select-day mt-4"></nz-checkbox-group>
</ng-template>

25
projects/cdk/src/ingredient/ingredient-dish/ingredient-dish.component.less

@ -0,0 +1,25 @@
.day-item {
::ng-deep {
.ant-card-head-title {
overflow: visible;
}
}
&.expanded {
.expanded-icon {
transform: rotate(90deg);
}
}
}
.select-day {
display: flex;
flex-wrap: wrap;
::ng-deep {
>label {
margin: 0 0 12px 0;
flex-basis: 25%;
}
}
}

119
projects/cdk/src/ingredient/ingredient-dish/ingredient-dish.component.ts

@ -0,0 +1,119 @@
import { Component, Input, OnChanges, SimpleChanges, TemplateRef } from "@angular/core";
// import { MealDishInterface } from "../ingredient-meals/ingredient-meals.component";
import { NzModalService } from "ng-zorro-antd/modal";
import { Augmented, OptionItemInterface } from "@cdk/types";
import { NzMessageService } from "ng-zorro-antd/message";
// export interface MenuObjectInterface {
// [Day: number]: {
// [MealIndex: number]: MealDishInterface[];
// };
// }
export type DishInterface = Augmented<{
dishId: number;
day: number;
meal: string;
mark: string;
items: Array<
Augmented<{
key: string;
isMain: boolean;
value: Record<string, number>;
}>
>;
}>;
@Component({
selector: "app-ingredient-dish",
templateUrl: "./ingredient-dish.component.html",
styleUrls: ["./ingredient-dish.component.less"],
})
export class IngredientDishComponent implements OnChanges {
constructor(private modal: NzModalService, private msg: NzMessageService) {}
@Input() menu: any | null;
expanded = new Set<number>();
days: number[] = [];
selectDay: OptionItemInterface[] = [];
mealCurrentIndex: Record<number, number> = {};
// d = {
// 1:{
// zaocan:[
// {dishId:1...}
// ]
// }
// }
// menuObject!: MenuObjectInterface;
mealDishList: DishInterface[] = [];
ngOnChanges(changes: SimpleChanges): void {
if (changes["menu"]?.currentValue) {
this.initMenu();
}
}
initMenu() {
if (this.menu) {
const meals = this.menu.meals as string[];
const day = this.menu.day as number;
this.days = Array.from({ length: day }, (_, i) => {
this.selectDay.push({
label: `${i + 1}`,
value: String(i + 1),
});
this.mealCurrentIndex[i] = 0;
// if (!this.menuObject) {
// this.menuObject = {};
// }
// this.menuObject[i + 1] = meals.reduce((a, c, idx) => {
// return {
// ...a,
// [idx]: [],
// };
// }, {} as Record<number, MealDishInterface[]>);
return i;
});
}
}
expandChange(i: number) {
if (this.expanded.has(i)) {
this.expanded.delete(i);
} else {
this.expanded.add(i);
}
}
onSaveDish(v: DishInterface[], day: number, mealIndex: number) {
this.mealDishList = JSON.parse(JSON.stringify(v));
// this.menuObject[day][mealIndex] = JSON.parse(JSON.stringify(v));
}
reuse(day: number, nzContent: TemplateRef<{}>) {
const thisDayDishs = this.mealDishList.filter((f) => f.day === day);
console.log("dayDishs", day, this.mealDishList, thisDayDishs);
this.modal.create({
nzTitle: "请选择应用到的日期",
nzContent,
nzOnOk: () => {
this.selectDay.forEach((i) => {
if (i["checked"]) {
thisDayDishs.forEach((reused) => {
this.mealDishList.push(JSON.parse(JSON.stringify({ ...reused, day: Number(i.value) })));
});
}
i["checked"] = false;
});
this.mealDishList = JSON.parse(JSON.stringify(this.mealDishList));
this.msg.success("操作成功");
},
});
}
}

17
projects/admin/src/app/components/ingredient-form-basic/ingredient-form-basic.component.html → projects/cdk/src/ingredient/ingredient-form-basic/ingredient-form-basic.component.html

@ -13,6 +13,7 @@
</nz-form-label> </nz-form-label>
<nz-form-control [nzErrorTip]="formControlErrorTpl" nzSpan="12"> <nz-form-control [nzErrorTip]="formControlErrorTpl" nzSpan="12">
<nz-select <nz-select
[nzDisabled]="menu"
nzShowSearch nzShowSearch
nzServerSearch nzServerSearch
nzPlaceHolder="请选择标准" nzPlaceHolder="请选择标准"
@ -33,7 +34,7 @@
适用单位 适用单位
</nz-form-label> </nz-form-label>
<nz-form-control [nzErrorTip]="formControlErrorTpl" nzSpan="12"> <nz-form-control [nzErrorTip]="formControlErrorTpl" nzSpan="12">
<nz-select nzMode="multiple" formControlName="vendors" nzPlaceHolder="请选择单位" <nz-select nzMode="multiple" [nzDisabled]="menu" formControlName="vendors" nzPlaceHolder="请选择单位"
[nzOptions]="currentOrgs"> [nzOptions]="currentOrgs">
</nz-select> </nz-select>
</nz-form-control> </nz-form-control>
@ -52,13 +53,13 @@
</nz-form-label> </nz-form-label>
<nz-form-control [nzErrorTip]="formControlErrorTpl"> <nz-form-control [nzErrorTip]="formControlErrorTpl">
<nz-radio-group formControlName="day"> <nz-radio-group formControlName="day">
<label nz-radio nzValue="1">1天</label> <label nz-radio [nzValue]="1">1天</label>
<label nz-radio nzValue="2">2天</label> <label nz-radio [nzValue]="2">2天</label>
<label nz-radio nzValue="3">3天</label> <label nz-radio [nzValue]="3">3天</label>
<label nz-radio nzValue="4">4天</label> <label nz-radio [nzValue]="4">4天</label>
<label nz-radio nzValue="5">5天</label> <label nz-radio [nzValue]="5">5天</label>
<label nz-radio nzValue="6">6天</label> <label nz-radio [nzValue]="6">6天</label>
<label nz-radio nzValue="7">7天</label> <label nz-radio [nzValue]="7">7天</label>
</nz-radio-group> </nz-radio-group>
</nz-form-control> </nz-form-control>
</nz-form-item> </nz-form-item>

0
projects/admin/src/app/components/ingredient-form-basic/ingredient-form-basic.component.less → projects/cdk/src/ingredient/ingredient-form-basic/ingredient-form-basic.component.less

57
projects/admin/src/app/components/ingredient-form-basic/ingredient-form-basic.component.ts → projects/cdk/src/ingredient/ingredient-form-basic/ingredient-form-basic.component.ts

@ -1,6 +1,5 @@
import { Component, EventEmitter, OnInit, Output } from "@angular/core"; import { Component, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges } 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 { OrgDTO } from "@cdk/dtos";
import { ApiService } from "@cdk/services"; import { ApiService } from "@cdk/services";
import { OptionItemInterface } from "@cdk/types"; import { OptionItemInterface } from "@cdk/types";
@ -14,17 +13,14 @@ import { Subject, debounceTime, distinctUntilChanged, filter, finalize, switchMa
templateUrl: "./ingredient-form-basic.component.html", templateUrl: "./ingredient-form-basic.component.html",
styleUrls: ["./ingredient-form-basic.component.less"], styleUrls: ["./ingredient-form-basic.component.less"],
}) })
export class IngredientFormBasicComponent { export class IngredientFormBasicComponent implements OnChanges {
constructor( constructor(private fb: FormBuilder, private msg: NzMessageService, private api: ApiService) {}
private fb: FormBuilder,
private msg: NzMessageService, @Input() menu: any | null;
private api: ApiService,
private router: Router
) {}
@Output() onSave = new EventEmitter(); @Output() onSave = new EventEmitter();
private standardSearch$ = new Subject<string>(); private standardSearch$ = new Subject<{ id?: string; name?: string }>();
private destroy$ = new Subject<void>(); private destroy$ = new Subject<void>();
@ -49,22 +45,25 @@ export class IngredientFormBasicComponent {
id: this.fb.control("", []), id: this.fb.control("", []),
name: this.fb.control("", [FormValidators.required()]), name: this.fb.control("", [FormValidators.required()]),
nutrient: this.fb.control("", [FormValidators.required()]), nutrient: this.fb.control("", [FormValidators.required()]),
day: this.fb.control("1", [FormValidators.required()]), day: this.fb.control(1, [FormValidators.required()]),
vendors: this.fb.control([], [FormValidators.required()]), vendors: this.fb.control([], [FormValidators.required()]),
month: this.fb.control([], [FormValidators.required()]), month: this.fb.control([], [FormValidators.required()]),
}); });
this.standardSearch$ this.standardSearch$
.pipe( .pipe(
filter((f) => !!f), filter((f) => !!f),
debounceTime(500), debounceTime(500),
distinctUntilChanged(), distinctUntilChanged(),
takeUntil(this.destroy$), takeUntil(this.destroy$),
switchMap((term: string) => this.api.getStandard({ name: term })) switchMap((q) => this.api.getStandard(q))
) )
.subscribe((data) => { .subscribe((data) => {
let listOfOption: Array<OptionItemInterface> = []; let listOfOption: Array<OptionItemInterface> = [];
if (data.body) { if (data.body) {
const getById = data.body && !Array.isArray(data.body);
if (getById) {
data.body = [data.body];
}
data.body.forEach((item) => { data.body.forEach((item) => {
listOfOption.push({ listOfOption.push({
label: item.name, label: item.name,
@ -73,10 +72,29 @@ export class IngredientFormBasicComponent {
}); });
}); });
this.searchedStandard = this.searchedStandard.concat(listOfOption); this.searchedStandard = this.searchedStandard.concat(listOfOption);
if (getById && this.menu.nutrient) {
this.onStandardChange(this.menu.nutrient);
}
} }
this.standardOfOption = listOfOption; this.standardOfOption = listOfOption;
}); });
this.setValues();
}
ngOnChanges(changes: SimpleChanges): void {}
setValues() {
if (this.menu) {
console.log("this.formGroup", this.formGroup, this.menu);
this.standardSearch$.next({ id: this.menu.nutrient });
this.meals = this.meals.map((i) => (this.menu.meals.includes(i.value) ? { ...i, checked: true } : i));
this.formGroup.patchValue({
...this.menu,
vendors: [String(this.menu.vender)],
});
}
} }
ngOnDestroy(): void { ngOnDestroy(): void {
@ -87,7 +105,9 @@ export class IngredientFormBasicComponent {
ageChange() {} ageChange() {}
searchStandard(k: string) { searchStandard(k: string) {
this.standardSearch$.next(k); if (k) {
this.standardSearch$.next({ name: k });
}
} }
onStandardChange(v: any) { onStandardChange(v: any) {
@ -104,6 +124,7 @@ export class IngredientFormBasicComponent {
return { return {
label: k, label: k,
value: k, value: k,
checked: this.menu?.crows?.includes(k),
...(v as any), ...(v as any),
}; };
}); });
@ -144,8 +165,12 @@ export class IngredientFormBasicComponent {
) )
.subscribe((res) => { .subscribe((res) => {
this.msg.success(res.desc); this.msg.success(res.desc);
this.onSave.emit({ meals: this.meals, menuId: res.body, peoples: this.currentPeoples }); this.onSave.emit({
// this.router.navigate(["/ingredient/item/list"]); ...this.formGroup.value,
meals: this.meals,
menuId: res.body,
peoples: this.currentPeoples,
});
}); });
} }
} }

279
projects/cdk/src/ingredient/ingredient-meals/ingredient-meals.component.html

@ -4,7 +4,7 @@
<button *nzSpaceItem nz-button nzType="primary" (click)="shopDishForm()"> <button *nzSpaceItem nz-button nzType="primary" (click)="shopDishForm()">
添加菜品 添加菜品
</button> </button>
<button *nzSpaceItem nz-button> <button *nzSpaceItem nz-button (click)="clearThisMeal()">
清空本餐 清空本餐
</button> </button>
</nz-space> </nz-space>
@ -14,239 +14,82 @@
<tr> <tr>
<th colSpan="2"></th> <th colSpan="2"></th>
<th [colSpan]="5"> <th [colSpan]="peopleGroups.length">
重量/克 重量/克
</th> </th>
</tr> </tr>
<tr> <tr>
<th [rowSpan]="2"> <th nzWidth="200px">
菜品 菜品
</th> </th>
<th [rowSpan]="2"> <th nzWidth="200px">
食材 食材
</th> </th>
<th> <th *ngFor="let p of peopleGroups">
轻体力(体重过低) {{p}}
</th>
<th>
轻体力(正常体重)
</th>
<th>
休息(超重/肥胖)
</th>
<th>
轻体力(体重过低)
</th>
<th>
轻体力(正常体重)
</th> </th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr> <ng-container *ngFor="let dish of currentDishs">
<td [rowSpan]="2"> <ng-container *ngFor="let food of dish['items'];let first = first;">
<div class="flex justify-between"> <tr>
<span> <td *ngIf="first" [rowSpan]="dish['items'].length ">
番茄煎蛋面 <div class="flex justify-between">
</span> <span>
<button nz-button nzType="text" nz-dropdown [nzDropdownMenu]="dishOptions"> {{dish['dishName']}}
<i nz-icon nzType="more"></i> </span>
</button> <button nz-button nzType="text" (click)="onRemoveDish(dish)">
<nz-dropdown-menu #dishOptions="nzDropdownMenu"> <i nz-icon nzType="delete"></i>
<ul nz-menu nzSelectable class=" w-20"> </button>
<li nz-menu-item>编辑</li> <!-- nz-dropdown [nzDropdownMenu]="dishOptions" -->
<li nz-menu-item nzDanger>删除</li> <!-- <nz-dropdown-menu #dishOptions="nzDropdownMenu">
</ul> <ul nz-menu nzSelectable class=" w-20">
</nz-dropdown-menu> <li nz-menu-item>编辑</li>
</div> <li nz-menu-item nzDanger>删除</li>
</td> </ul>
<td> </nz-dropdown-menu> -->
</div>
<div class="flex justify-between"> </td>
<span> <td>
番茄
</span>
<button nz-button nzType="text" nz-dropdown [nzDropdownMenu]="foodOptions">
<i nz-icon nzType="more"></i>
</button>
<nz-dropdown-menu #foodOptions="nzDropdownMenu">
<ul nz-menu nzSelectable class="w-100">
<li nz-menu-item>设置价格</li>
<li nz-menu-item nzDanger>删除</li>
</ul>
</nz-dropdown-menu>
</div>
</td>
<td>
1
</td>
<td>
1
</td>
<td>
1
</td>
<td>
1
</td>
<td>
1
</td>
</tr>
<tr>
<td>
<div class="flex justify-between">
<span>
面条
</span>
<button nz-button nzType="text">
<i nz-icon nzType="more"></i>
</button>
</div>
</td>
<td>
1
</td>
<td>
1
</td>
<td>
1
</td>
<td>
1
</td>
<td>
1
</td>
</tr>
<tr>
<td [rowSpan]="4">
<div class="flex justify-between">
<span>
鸡蛋青菜面
</span>
<button nz-button nzType="text">
<i nz-icon nzType="more"></i>
</button>
</div>
</td>
<td>
<div class="flex justify-between">
<span>
食用油
</span>
<button nz-button nzType="text">
<i nz-icon nzType="more"></i>
</button>
</div>
</td>
<td>
1
</td>
<td>
1
</td>
<td>
1
</td>
<td>
1
</td>
<td>
1
</td>
</tr>
<tr>
<td>
<div class="flex justify-between"> <div class="flex justify-between">
<span> <span>
小白菜[青菜] {{food['foodName']}}
</span> </span>
<button nz-button nzType="text"> <!-- <button nz-button nzType="text" nz-dropdown [nzDropdownMenu]="foodOptions">
<i nz-icon nzType="more"></i> <i nz-icon nzType="more"></i>
</button> </button>
</div> <nz-dropdown-menu #foodOptions="nzDropdownMenu">
</td> <ul nz-menu nzSelectable class="w-100">
<td> <li nz-menu-item>设置价格</li>
1 <li nz-menu-item nzDanger>删除</li>
</td> </ul>
<td> </nz-dropdown-menu> -->
1 </div>
</td> </td>
<td> <td *ngFor="let g of food.value | keyvalue">
1 {{g.value}}
</td> </td>
<td> </tr>
1 </ng-container>
</td> </ng-container>
<td>
1
</td>
</tr>
<tr>
<td>
<div class="flex justify-between">
<span>
鸡蛋(均值)
</span>
<button nz-button nzType="text">
<i nz-icon nzType="more"></i>
</button>
</div>
</td>
<td>
1
</td>
<td>
1
</td>
<td>
1
</td>
<td>
1
</td>
<td>
1
</td>
</tr>
<tr>
<td>
<div class="flex justify-between">
<span>
面条(均值)
</span>
<button nz-button nzType="text">
<i nz-icon nzType="more"></i>
</button>
</div>
</td>
<td>
1
</td>
<td>
1
</td>
<td>
1
</td>
<td>
1
</td>
<td>
1
</td>
</tr>
</tbody> </tbody>
</nz-table> </nz-table>
</div> <nz-empty *ngIf="currentDishs.length === 0" class="empty"></nz-empty>
</div>
<ng-template #addDishFooter>
<nz-space>
<button *nzSpaceItem nz-button (click)="cancelForm()" type="button">
取消
</button>
<button *nzSpaceItem nz-button nzType="primary" [nzLoading]="submitLoading" (click)="onSubmit()">
保存
</button>
</nz-space>
</ng-template>

6
projects/cdk/src/ingredient/ingredient-meals/ingredient-meals.component.less

@ -0,0 +1,6 @@
.empty {
margin: 0;
padding: 24px;
border: 1px solid #f0f0f0;
border-top: none;
}

125
projects/cdk/src/ingredient/ingredient-meals/ingredient-meals.component.ts

@ -1,21 +1,130 @@
import { Component } from "@angular/core"; import {
Component,
EventEmitter,
Input,
OnChanges,
OnInit,
Output,
SimpleChanges,
TemplateRef,
ViewChild,
} from "@angular/core";
import { NzModalService } from "ng-zorro-antd/modal"; import { NzModalService } from "ng-zorro-antd/modal";
import { AddDishToIngredientComponent } from "../add-dish-to-ingredient/add-dish-to-ingredient.component"; import {
import { NzDrawerService } from "ng-zorro-antd/drawer"; AddDishToIngredientComponent,
FoodInDishInterface,
} from "../add-dish-to-ingredient/add-dish-to-ingredient.component";
import { NzDrawerRef, NzDrawerService } from "ng-zorro-antd/drawer";
import { NzMessageService } from "ng-zorro-antd/message";
import { Augmented } from "@cdk/types";
import { DishInterface } from "../ingredient-dish/ingredient-dish.component";
export type MealDishInterface = Augmented<{
dishId: number;
dishName: string;
mark: string;
foods: FoodInDishInterface[];
}>;
@Component({ @Component({
selector: "lib-ingredient-meals", selector: "app-ingredient-meals",
templateUrl: "./ingredient-meals.component.html", templateUrl: "./ingredient-meals.component.html",
styleUrls: ["./ingredient-meals.component.less"], styleUrls: ["./ingredient-meals.component.less"],
}) })
export class IngredientMealsComponent { export class IngredientMealsComponent implements OnChanges, OnInit {
constructor(private modal: NzModalService, private drawer: NzDrawerService) {} constructor(private modal: NzModalService, private msg: NzMessageService, private drawer: NzDrawerService) {}
@Input() day!: number;
@Input() mealIndex!: number;
@Input() peopleGroups: string[] = [];
@Input() mealDishs: DishInterface[] = [];
@Output() onSaveDish = new EventEmitter<DishInterface[]>();
@ViewChild("addDishFooter") addDishFooter!: TemplateRef<{}>;
drawerRef?: NzDrawerRef;
submitLoading = false;
currentDishs: DishInterface[] = [];
ngOnInit(): void {
this.init();
}
ngOnChanges(changes: SimpleChanges): void {
if (changes["mealDishs"]?.currentValue) {
this.init();
}
}
init() {
console.log(" ", this.mealDishs, this.day, this.mealIndex);
this.currentDishs = this.mealDishs.filter((f) => f.day === this.day && this.mealIndex === f["mealIndex"]);
}
shopDishForm() { shopDishForm() {
this.drawer.create({ this.drawerRef = this.drawer.create({
nzTitle: "添加菜品", nzTitle: "添加菜品",
nzWidth: 1000, nzWidth: 1200,
nzContent: AddDishToIngredientComponent, nzContent: AddDishToIngredientComponent,
nzFooter: this.addDishFooter,
nzContentParams: {
peopleGroups: this.peopleGroups,
},
}); });
} }
clearThisMeal() {
this.modal.confirm({
nzTitle: "警告",
nzContent: "是否要清空本餐?",
nzOkDanger: true,
nzOnOk: () => {
this.mealDishs = this.mealDishs.filter((f) => !(f.day === this.day && f["mealIndex"] === this.mealIndex));
this.onSaveDish.emit(this.mealDishs);
},
});
}
cancelForm() {
this.drawerRef?.close();
}
onSubmit() {
if (this.drawerRef) {
const { dish, foods } = this.drawerRef.getContentComponent() as AddDishToIngredientComponent;
this.mealDishs.push({
day: this.day,
mealIndex: this.mealIndex,
meal: "",
dishId: dish.id,
dishName: dish.name,
mark: dish.marks,
items: foods.map((f) => ({
...f,
value: f.groupValues.reduce((a, c) => {
return {
...a,
[c.peopleName]: c.value,
};
}, {} as Record<string, number>),
})),
});
this.onSaveDish.emit(this.mealDishs);
}
this.cancelForm();
}
onRemoveDish(d: DishInterface) {
this.mealDishs = this.mealDishs.filter(
(f) => !(f.dishId === d.dishId && f.day === this.day && f["mealIndex"] === this.mealIndex)
);
this.onSaveDish.emit(this.mealDishs);
}
} }

18
projects/cdk/src/ingredient/ingredient.module.ts

@ -3,10 +3,24 @@ import { SharedModule } from "@cdk/shared/shared.module";
import { AddDishToIngredientComponent } from "./add-dish-to-ingredient/add-dish-to-ingredient.component"; import { AddDishToIngredientComponent } from "./add-dish-to-ingredient/add-dish-to-ingredient.component";
import { IngredientMealsComponent } from "./ingredient-meals/ingredient-meals.component"; import { IngredientMealsComponent } from "./ingredient-meals/ingredient-meals.component";
import { ConfirmIngredientComponent } from "./confirm-ingredient/confirm-ingredient.component"; import { ConfirmIngredientComponent } from "./confirm-ingredient/confirm-ingredient.component";
import { IngredientDishComponent } from "./ingredient-dish/ingredient-dish.component";
import { IngredientFormBasicComponent } from "./ingredient-form-basic/ingredient-form-basic.component";
@NgModule({ @NgModule({
declarations: [AddDishToIngredientComponent, IngredientMealsComponent, ConfirmIngredientComponent], declarations: [
AddDishToIngredientComponent,
IngredientMealsComponent,
ConfirmIngredientComponent,
IngredientFormBasicComponent,
IngredientDishComponent,
],
imports: [SharedModule], imports: [SharedModule],
exports: [AddDishToIngredientComponent, IngredientMealsComponent, ConfirmIngredientComponent], exports: [
AddDishToIngredientComponent,
IngredientMealsComponent,
ConfirmIngredientComponent,
IngredientFormBasicComponent,
IngredientDishComponent,
],
}) })
export class IngredientModule {} export class IngredientModule {}

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

@ -372,9 +372,9 @@ export class ApiService {
return this.http.get<ResponseType<PageResult>>(`/api/menu?${params}`); return this.http.get<ResponseType<PageResult>>(`/api/menu?${params}`);
} }
getMenuItem() { getMenuItem(id: string | number) {
const params = Utils.objectStringify({ menuId: 1 }); const params = Utils.objectStringify({ id });
return this.http.get(`/api/menu/dish?${params}`); return this.http.get<ResponseType>(`/api/menu?${params}`);
} }
saveMenu(v: AnyObject) { saveMenu(v: AnyObject) {
@ -408,4 +408,8 @@ export class ApiService {
const params = Utils.objectToFormData({ id }); const params = Utils.objectToFormData({ id });
return this.http.delete<ResponseType>(`/api/menu`, { body: params }); return this.http.delete<ResponseType>(`/api/menu`, { body: params });
} }
saveMenuDist(d: {}) {
return this.http.put<ResponseType>(`/api/menu/dish/batch`, d);
}
} }

22
projects/cdk/src/shared/components/dish-select/dish-select.component.html

@ -0,0 +1,22 @@
<nz-select
nzShowSearch
nzServerSearch
nzPlaceHolder="请输入菜品名称搜索"
[nzShowArrow]="false"
[nzFilterOption]="nzFilterOption"
[(ngModel)]="value"
(ngModelChange)="onSelectChange($event)"
(nzOnSearch)="search($event)">
<ng-container *ngIf="!loading">
<nz-option *ngFor="let o of listOfOption" [nzLabel]="o.label"
[nzValue]="o.value">
</nz-option>
</ng-container>
<nz-option *ngIf="loading" nzDisabled nzCustomContent>
<span nz-icon nzType="loading" class="loading-icon"></span>
数据加载中...
</nz-option>
</nz-select>

0
projects/cdk/src/shared/components/dish-select/dish-select.component.less

97
projects/cdk/src/shared/components/dish-select/dish-select.component.ts

@ -0,0 +1,97 @@
import { Component, OnInit } from "@angular/core";
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from "@angular/forms";
import { ApiService } from "@cdk/services";
import { OptionItemInterface } from "@cdk/types";
import { Subject, debounceTime, distinctUntilChanged, filter, finalize, switchMap, takeUntil, tap } from "rxjs";
@Component({
selector: "app-dish-select",
templateUrl: "./dish-select.component.html",
styleUrls: ["./dish-select.component.less"],
providers: [
{
provide: NG_VALUE_ACCESSOR,
multi: true,
useExisting: DishSelectComponent,
},
],
})
export class DishSelectComponent implements OnInit, ControlValueAccessor {
constructor(private api: ApiService) {}
private destroy$ = new Subject<void>();
private dishSearch$ = new Subject<string>();
nzFilterOption = (): boolean => true;
value?: string | string[];
listOfOption: OptionItemInterface[] = [];
loading = false;
ngOnInit(): void {
this.dishSearch$
.pipe(
filter((f) => !!f),
debounceTime(500),
distinctUntilChanged(),
takeUntil(this.destroy$),
tap(() => {
this.loading = true;
}),
switchMap((term: string) =>
this.api.getDishPage({ pageNo: 0, pageSize: 5 }, { keyword: term }).pipe(
finalize(() => {
this.loading = false;
})
)
)
)
.subscribe((data) => {
const listOfOption: Array<OptionItemInterface> = [];
data.body.content.forEach((item) => {
listOfOption.push({
...item,
value: String(item.id),
label: item.name,
});
});
this.listOfOption = listOfOption;
});
}
ngOnDestroy(): void {
this.destroy$.next();
this.destroy$.complete();
}
onSelectChange(v: any) {
const item = this.listOfOption.find((f) => f.value === v);
// console.log("v", item);
if (item) {
this.onChange(item);
}
}
search = (k: string) => {
this.dishSearch$.next(k);
};
onChange(v: OptionItemInterface) {}
ontouch(v: any) {}
writeValue(v?: string[] | string): void {
this.value = v;
}
registerOnChange(fn: any): void {
this.onChange = fn;
}
registerOnTouched(fn: any): void {
this.ontouch = fn;
}
}

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

@ -1,2 +1,4 @@
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"; export * from "./month-select/month-select.component";
export * from "./org-select/org-select.component";
export * from "./dish-select/dish-select.component";

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

@ -79,6 +79,7 @@ export class MonthSelectComponent implements ControlValueAccessor {
ontouch(v: any) {} ontouch(v: any) {}
writeValue(v: number[]): void { writeValue(v: number[]): void {
console.log("v", v);
this.allMonth = this.allMonth.map((i) => (v.includes(i.value) ? { ...i, checked: true } : i)); this.allMonth = this.allMonth.map((i) => (v.includes(i.value) ? { ...i, checked: true } : i));
this.monthCheckEffect(); this.monthCheckEffect();
} }

13
projects/cdk/src/shared/components/org-select/org-select.component.html

@ -0,0 +1,13 @@
<nz-select
nzShowSearch
nzServerSearch
nzPlaceHolder="请选择单位"
[nzShowArrow]="false"
[nzFilterOption]="nzFilterOption"
[(ngModel)]="value"
(ngModelChange)="onSelectChange($event)"
(nzOnSearch)="searchOrg($event)">
<nz-option *ngFor="let o of listOfOption" [nzLabel]="o.label"
[nzValue]="o.value">
</nz-option>
</nz-select>

0
projects/cdk/src/shared/components/org-select/org-select.component.less

81
projects/cdk/src/shared/components/org-select/org-select.component.ts

@ -0,0 +1,81 @@
import { Component, OnInit } from "@angular/core";
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from "@angular/forms";
import { ApiService } from "@cdk/services";
import { OptionItemInterface } from "@cdk/types";
import { Subject, debounceTime, distinctUntilChanged, filter, switchMap, takeUntil } from "rxjs";
@Component({
selector: "app-org-select",
templateUrl: "./org-select.component.html",
styleUrls: ["./org-select.component.less"],
providers: [
{
provide: NG_VALUE_ACCESSOR,
multi: true,
useExisting: OrgSelectComponent,
},
],
})
export class OrgSelectComponent implements OnInit, ControlValueAccessor {
constructor(private api: ApiService) {}
private destroy$ = new Subject<void>();
private orgSearch$ = new Subject<string>();
nzFilterOption = (): boolean => true;
value?: string | string[];
listOfOption: OptionItemInterface[] = [];
ngOnInit(): void {
this.orgSearch$
.pipe(
filter((f) => !!f),
debounceTime(500),
distinctUntilChanged(),
takeUntil(this.destroy$),
switchMap((term: string) => this.api.getOrgList({ keyword: term }))
)
.subscribe((data) => {
const listOfOption: Array<OptionItemInterface> = [];
data.body.forEach((item) => {
listOfOption.push({
value: String(item.id),
label: item.name,
});
});
this.listOfOption = listOfOption;
});
}
ngOnDestroy(): void {
this.destroy$.next();
this.destroy$.complete();
}
onSelectChange(v: any) {
this.onChange(v);
}
searchOrg = (k: string) => {
this.orgSearch$.next(k);
};
onChange(v: number[]) {}
ontouch(v: any) {}
writeValue(v?: string[] | string): void {
this.value = v;
}
registerOnChange(fn: any): void {
this.onChange = fn;
}
registerOnTouched(fn: any): void {
this.ontouch = fn;
}
}

2
projects/cdk/src/shared/ng-zorro.ts

@ -47,8 +47,10 @@ import { NzInputNumberModule } from "ng-zorro-antd/input-number";
import { NzLayoutModule } from "ng-zorro-antd/layout"; import { NzLayoutModule } from "ng-zorro-antd/layout";
import { NzBreadCrumbModule } from "ng-zorro-antd/breadcrumb"; import { NzBreadCrumbModule } from "ng-zorro-antd/breadcrumb";
import { NzOutletModule } from "ng-zorro-antd/core/outlet"; import { NzOutletModule } from "ng-zorro-antd/core/outlet";
import { NzAlertModule } from "ng-zorro-antd/alert";
export const ngZorroModules = [ export const ngZorroModules = [
NzAlertModule,
NzOutletModule, NzOutletModule,
NzBreadCrumbModule, NzBreadCrumbModule,
NzLayoutModule, NzLayoutModule,

13
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, MonthSelectComponent } from "./components"; import { SearchAndSelectComponent, MonthSelectComponent, OrgSelectComponent, DishSelectComponent } 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,14 @@ const cdks = [
] as any; ] as any;
@NgModule({ @NgModule({
declarations: [...components, ...directives, SearchAndSelectComponent, MonthSelectComponent], declarations: [
...components,
...directives,
SearchAndSelectComponent,
MonthSelectComponent,
DishSelectComponent,
OrgSelectComponent,
],
imports: [...ngZorroModules, ...ngModules, ...cdks, AppPageComponent], imports: [...ngZorroModules, ...ngModules, ...cdks, AppPageComponent],
exports: [ exports: [
...ngZorroModules, ...ngZorroModules,
@ -47,6 +54,8 @@ const cdks = [
AppPageComponent, AppPageComponent,
SearchAndSelectComponent, SearchAndSelectComponent,
MonthSelectComponent, MonthSelectComponent,
OrgSelectComponent,
DishSelectComponent,
], ],
}) })
export class SharedModule {} export class SharedModule {}

Loading…
Cancel
Save