Browse Source

食谱

main
kely 2 years ago
parent
commit
7ada4fe31e
  1. 6
      README.md
  2. 6
      projects/admin/src/app/app-routing.module.ts
  3. 2
      projects/admin/src/app/app.module.ts
  4. 132
      projects/admin/src/app/components/app-layout/app-layout.component.html
  5. 1
      projects/admin/src/app/components/app-layout/app-layout.component.less
  6. 3
      projects/admin/src/app/components/app-layout/app-layout.component.ts
  7. 13
      projects/admin/src/app/components/ingredient-status-list/ingredient-status-list.component.html
  8. 38
      projects/admin/src/app/components/ingredient-status-list/ingredient-status-list.component.ts
  9. 1
      projects/admin/src/app/pages/index.ts
  10. 6
      projects/admin/src/app/pages/ingredients/ingredient-form/ingredient-form.component.html
  11. 44
      projects/admin/src/app/pages/ingredients/ingredient-form/ingredient-form.component.ts
  12. 8
      projects/admin/src/app/pages/ingredients/ingredient-list/ingredient-list.component.html
  13. 29
      projects/admin/src/app/pages/ingredients/ingredient-list/ingredient-list.component.ts
  14. 1
      projects/admin/src/app/pages/ingredients/ingredient-preview-page/ingredient-preview-page.component.html
  15. 0
      projects/admin/src/app/pages/ingredients/ingredient-preview-page/ingredient-preview-page.component.less
  16. 27
      projects/admin/src/app/pages/ingredients/ingredient-preview-page/ingredient-preview-page.component.ts
  17. 38
      projects/admin/src/app/pages/ingredients/ingredient-release/ingredient-release.component.html
  18. 102
      projects/admin/src/app/pages/ingredients/ingredient-release/ingredient-release.component.ts
  19. 20
      projects/admin/src/app/pages/ingredients/ingredient-review/ingredient-review.component.html
  20. 66
      projects/admin/src/app/pages/ingredients/ingredient-review/ingredient-review.component.ts
  21. 2
      projects/cdk/src/ingredient/ingredient-dish/ingredient-dish.component.ts
  22. 101
      projects/cdk/src/ingredient/ingredient-meals/ingredient-meals.component.html
  23. 10
      projects/cdk/src/ingredient/ingredient-meals/ingredient-meals.component.less
  24. 64
      projects/cdk/src/ingredient/ingredient-meals/ingredient-meals.component.ts
  25. 133
      projects/cdk/src/ingredient/ingredient-preview/ingredient-preview.component.html
  26. 84
      projects/cdk/src/ingredient/ingredient-preview/ingredient-preview.component.less
  27. 8
      projects/cdk/src/ingredient/ingredient-preview/ingredient-preview.component.ts
  28. 3
      projects/cdk/src/ingredient/ingredient.module.ts
  29. 36
      projects/cdk/src/services/api.service.ts
  30. 2
      projects/cdk/src/table-list/table-list/table-list.component.html
  31. 8
      projects/cdk/src/table-list/table-list/table-list.component.ts

6
README.md

@ -61,6 +61,8 @@ To get more help on the Angular CLI use `ng help` or go check out the [Angular C
----------------
# 09/26
# 09/28
1. 食谱审核 列表需要 提交审核时间、提交人 字段
1. 食谱审核 列表需要 提交审核时间、提交人 字段
2. 食谱列表 需要 返回一个字段 标识当前食谱 是否是 管理系统添加的还是业务系统添加的
3. 食谱保存 菜品 报500,同样的数据 昨天都可以

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

@ -15,6 +15,7 @@ import {
StandardListComponent,
StandardFormComponent,
StandardSettingComponent,
IngredientPreviewPageComponent,
} from "./pages";
import { AppLayoutComponent } from "./components";
import { authGuard } from "./services/auth.guard";
@ -86,6 +87,11 @@ const routes: Routes = [
title: "食谱审核",
component: IngredientReviewComponent,
},
{
path: "preview",
title: "食谱预览",
component: IngredientPreviewPageComponent,
},
{
path: "release",
title: "食谱发布计划",

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

@ -28,6 +28,7 @@ import {
IngredientReleaseComponent,
IngredientReviewComponent,
IngredientFormComponent,
IngredientPreviewPageComponent,
OrganizationListComponent,
OrganizationFormComponent,
UserManageComponent,
@ -59,6 +60,7 @@ registerLocaleData(zh);
IngredientReleaseComponent,
IngredientReviewComponent,
IngredientFormComponent,
IngredientPreviewPageComponent,
OrganizationListComponent,
OrganizationFormComponent,

132
projects/admin/src/app/components/app-layout/app-layout.component.html

@ -1,68 +1,74 @@
<nz-layout class="app-layout">
<nz-header class="app-header">
<div class="flex items-center justify-between h-full">
<div></div>
<div class="profile">
<button
nz-button
nzType="text"
nz-dropdown
[nzDropdownMenu]="menu">
{{account.name}}
</button>
<nz-dropdown-menu #menu="nzDropdownMenu">
<ul nz-menu nzSelectable>
<li nz-menu-item (click)="logout()">
退出登录
</li>
</ul>
</nz-dropdown-menu>
</div>
</div>
</nz-header>
<nz-layout class="app-layout-main">
<nz-sider nzWidth="220px" nzTheme="dark" class="sider-menu">
<div class="logo flex items-center py-4">
<img class="block h-[40px] mr-2" src="../assets/images/jl-logo.png" />
<span class="text-base text-white font-bold">
智慧配餐管理后台
</span>
<ng-container *ngIf="fullPage else layoutTpl">
<router-outlet></router-outlet>
</ng-container>
<ng-template #layoutTpl>
<nz-layout class="app-layout">
<nz-header class="app-header">
<div class="flex items-center justify-between h-full">
<div></div>
<div class="profile">
<button
nz-button
nzType="text"
nz-dropdown
[nzDropdownMenu]="menu">
{{account.name}}
</button>
<nz-dropdown-menu #menu="nzDropdownMenu">
<ul nz-menu nzSelectable>
<li nz-menu-item (click)="logout()">
退出登录
</li>
</ul>
</nz-dropdown-menu>
</div>
</div>
<ul nz-menu nzMode="inline" nzTheme="dark">
<li nz-menu-item class="k-icon" [routerLink]="['/','food']" nzMatchRouter>
<span nz-icon nzType="k-icon:carrot" nzTheme="outline"></span>
<span>食材管理</span>
</li>
<li nz-menu-item class="k-icon" [routerLink]="['/','dish']" nzMatchRouter>
<span nz-icon nzType="k-icon:food" nzTheme="outline"></span>
<span>菜品管理</span>
</li>
</nz-header>
<nz-layout class="app-layout-main">
<nz-sider nzWidth="220px" nzTheme="dark" class="sider-menu">
<div class="logo flex items-center py-4">
<img class="block h-[40px] mr-2" src="../assets/images/jl-logo.png" />
<span class="text-base text-white font-bold">
智慧配餐管理后台
</span>
</div>
<ul nz-menu nzMode="inline" nzTheme="dark">
<li nz-menu-item class="k-icon" [routerLink]="['/','food']" nzMatchRouter>
<span nz-icon nzType="k-icon:carrot" nzTheme="outline"></span>
<span>食材管理</span>
</li>
<li nz-menu-item class="k-icon" [routerLink]="['/','dish']" nzMatchRouter>
<span nz-icon nzType="k-icon:food" nzTheme="outline"></span>
<span>菜品管理</span>
</li>
<li nz-submenu nzTitle="食谱管理" nzIcon="book" [nzOpen]="currentUrl.includes('/ingredient/')">
<ul>
<li nz-menu-item nzMatchRouter [routerLink]="['/','ingredient','item']">食谱库</li>
<li nz-menu-item nzMatchRouter [routerLink]="['/','ingredient','review']">食谱审核</li>
<li nz-menu-item nzMatchRouter [routerLink]="['/','ingredient','release']">食谱发布计划</li>
</ul>
</li>
<li nz-menu-item nz-icon="profile" nzMatchRouter [routerLink]="['/','standard']">
<span nz-icon nzType="profile" nzTheme="outline"></span>
<span>人群营养标准管理</span>
</li>
<li nz-menu-item nzMatchRouter [routerLink]="['/','organization']">
<span nz-icon nzType="usergroup-add" nzTheme="outline"></span>
<span>单位管理</span>
</li>
<li nz-submenu nzTitle="系统设置" nzIcon="setting" [nzOpen]="currentUrl.includes('/system/')">
<ul>
<li nz-menu-item nzMatchRouter [routerLink]="['/','system','user']">用户管理</li>
</ul>
</li>
</ul>
</nz-sider>
<nz-layout class="inner-layout overflow-hidden">
<router-outlet></router-outlet>
<li nz-submenu nzTitle="食谱管理" nzIcon="book" [nzOpen]="currentUrl.includes('/ingredient/')">
<ul>
<li nz-menu-item nzMatchRouter [routerLink]="['/','ingredient','item']">食谱库</li>
<li nz-menu-item nzMatchRouter [routerLink]="['/','ingredient','review']">食谱审核</li>
<li nz-menu-item nzMatchRouter [routerLink]="['/','ingredient','release']">食谱发布计划</li>
</ul>
</li>
<li nz-menu-item nz-icon="profile" nzMatchRouter [routerLink]="['/','standard']">
<span nz-icon nzType="profile" nzTheme="outline"></span>
<span>人群营养标准管理</span>
</li>
<li nz-menu-item nzMatchRouter [routerLink]="['/','organization']">
<span nz-icon nzType="usergroup-add" nzTheme="outline"></span>
<span>单位管理</span>
</li>
<li nz-submenu nzTitle="系统设置" nzIcon="setting" [nzOpen]="currentUrl.includes('/system/')">
<ul>
<li nz-menu-item nzMatchRouter [routerLink]="['/','system','user']">用户管理</li>
</ul>
</li>
</ul>
</nz-sider>
<nz-layout class="inner-layout overflow-hidden">
<router-outlet></router-outlet>
</nz-layout>
</nz-layout>
</nz-layout>
</nz-layout>
</ng-template>

1
projects/admin/src/app/components/app-layout/app-layout.component.less

@ -24,6 +24,7 @@
line-height: @header-height;
padding: 0 24px;
background-color: #fff;
border-bottom: 1px solid #e8e8e8;
}

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

@ -25,9 +25,12 @@ export class AppLayoutComponent implements OnInit {
)
.subscribe((e) => {
this.currentUrl = e.url;
this.fullPage = ["/ingredient/preview"].some((s) => e.url.startsWith(s));
});
}
fullPage = false;
account = this.api.adminAccount;
ngOnInit(): void {}

13
projects/admin/src/app/components/ingredient-status-list/ingredient-status-list.component.html

@ -5,16 +5,12 @@
<button nz-button>批量删除</button>
</ng-template>
<ng-template #searchTpl>
<nz-form-item class="w-40">
<nz-form-item class="w-60">
<nz-form-control>
<nz-select nzPlaceHolder="单位" [nzOptions]="[]"></nz-select>
</nz-form-control>
</nz-form-item>
<nz-form-item class="w-40">
<nz-form-control>
<nz-select nzPlaceHolder="状态" [nzOptions]="[]"></nz-select>
<app-org-select formControlName="vender"></app-org-select>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-control>
<input nz-input placeholder="请输入食谱名称" formControlName="name" />
@ -32,6 +28,9 @@
<ng-container *ngSwitchCase="'day'">
{{data}} 天
</ng-container>
<ng-container *ngSwitchCase="'vender'">
{{ tableOrg[data] ? tableOrg[data].name : '-'}}
</ng-container>
<ng-container *ngSwitchCase="'month'">
<div class="flex flex-wrap">
<ng-container *ngIf="data.length === 12">

38
projects/admin/src/app/components/ingredient-status-list/ingredient-status-list.component.ts

@ -1,11 +1,11 @@
import { Component, Input, OnInit, TemplateRef, ViewChild } from "@angular/core";
import { Component, EventEmitter, Input, OnInit, Output, TemplateRef, ViewChild } from "@angular/core";
import { FormControl, FormGroup } from "@angular/forms";
import { NzDrawerRef, NzDrawerService } from "ng-zorro-antd/drawer";
import { AnyObject, TableListOption } from "@cdk/public-api";
import { AnyObject, MyResponse, OrgDTO, TableListOption } from "@cdk/public-api";
import { DishFormComponent } from "@admin/app/components";
import { ApiService } from "@cdk/services";
import { NzModalService } from "ng-zorro-antd/modal";
import { lastValueFrom } from "rxjs";
import { lastValueFrom, tap } from "rxjs";
import { NzMessageService } from "ng-zorro-antd/message";
@Component({
@ -23,6 +23,8 @@ export class IngredientStatusListComponent {
@Input() status!: number;
@Output() onReload = new EventEmitter();
reason = "";
@ViewChild("reviewFailMenuTpl") reviewFailMenuTpl!: TemplateRef<{}>;
@ -35,8 +37,11 @@ export class IngredientStatusListComponent {
public queryForm = new FormGroup({
name: new FormControl(""),
vender: new FormControl(""),
});
tableOrg: { [k: number]: OrgDTO } = {};
monthText = {
1: "一月",
2: "二月",
@ -97,7 +102,30 @@ export class IngredientStatusListComponent {
}
fetchData(query: AnyObject, pager: AnyObject) {
return this.api.getMenuStatusPage(pager, { ...query, status: this.status });
return this.api.getMenuStatusPage(pager, { ...query, status: this.status }).pipe(
tap((res) => {
this.getTableColumData(res);
})
);
}
getTableColumData(res: MyResponse) {
if (Array.isArray(res.body.content)) {
const vendors = res.body.content.map((i: any) => i.vender);
if (vendors.length > 0) {
this.api.getOrgList({ vendors }).subscribe((org) => {
if (Array.isArray(org.body)) {
this.tableOrg = org.body.reduce((a, c) => {
return {
...a,
[c.id]: c,
};
}, {} as AnyObject);
}
});
}
}
}
showFoodForm(food?: any) {
@ -121,6 +149,7 @@ export class IngredientStatusListComponent {
const res = await lastValueFrom(this.api.reviewMenu(id, true));
this.msg.success(res.desc);
this.tableList.run();
this.onReload.emit();
},
});
}
@ -133,6 +162,7 @@ export class IngredientStatusListComponent {
const res = await lastValueFrom(this.api.reviewMenu(id, false, this.reason));
this.msg.success(res.desc);
this.tableList.run();
this.onReload.emit();
},
});
}

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

@ -9,6 +9,7 @@ export * from "./ingredients/ingredient-list/ingredient-list.component";
export * from "./ingredients/ingredient-review/ingredient-review.component";
export * from "./ingredients/ingredient-release/ingredient-release.component";
export * from "./ingredients/ingredient-form/ingredient-form.component";
export * from "./ingredients/ingredient-preview-page/ingredient-preview-page.component";
export * from "./organization/organization-list/organization-list.component";
export * from "./organization/organization-form/organization-form.component";

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

@ -8,7 +8,7 @@
<ng-container *ngIf="step === 1">
<nz-card nzSize="small">
<nz-card nzSize="small" [nzBordered]="false">
<div class="flex justify-between">
<div class="flex-1 ">
<button nz-button (click)="step = 0">
@ -17,10 +17,10 @@
</div>
<nz-space>
<button *nzSpaceItem nz-button nzType="primary">
<button *nzSpaceItem nz-button>
食谱营养分析
</button>
<button *nzSpaceItem nz-button nzType="primary">
<button *nzSpaceItem nz-button (click)="createNewMenu()">
新建食谱
</button>
<button *nzSpaceItem nz-button>

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

@ -47,8 +47,19 @@ export class IngredientFormComponent implements OnInit {
}
});
this.api.getMenuDist(this.id).subscribe((res) => {
// console.log("res", res);
this.menuDishFormServer = res.body;
if (Array.isArray(res.body)) {
res.body.forEach((d) => {
d.ingredient.forEach((f: any) => {
f["groupValues"] = Object.entries(f.value).map(([peopleName, value]) => {
return {
peopleName,
value,
};
});
});
});
this.menuDishFormServer = res.body;
}
});
}
}
@ -69,12 +80,17 @@ export class IngredientFormComponent implements OnInit {
};
}
shopDishForm() {}
cancelForm() {}
createNewMenu() {
this.modal.confirm({
nzTitle: "警告",
nzContent: "新建食谱将清空本次所有的配餐数据,确认要清空吗?",
nzOnOk: () => {
this.menuDish.mealDishList = [];
},
});
}
confirmSave() {
// console.log("this.menuItem", this.menuItem);
this.modal.create({
nzTitle: "确认食谱信息",
nzContent: ConfirmIngredientComponent,
@ -82,7 +98,21 @@ export class IngredientFormComponent implements OnInit {
nzWidth: 650,
nzOnOk: () => {
const { mealDishList } = this.menuDish;
// const serverNeed = this.formatData(menuObject);
mealDishList.forEach((dish) => {
dish["dishId"] = dish.dish;
dish.items = dish.items.map((i) => {
return {
...i,
value: (i["groupValues"] as any[]).reduce((a, c) => {
return {
...a,
[c.peopleName]: c.value,
};
}, {} as Record<string, number>),
};
});
});
console.log("mealDishList", mealDishList);
this.api
.saveMenuDist({

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

@ -10,8 +10,12 @@
<div class="h-full overflow-hidden bg-white rounded-lg">
<nz-card [nzBordered]="false" nzTitle="食谱库">
<table-list [props]="tableList" [search]="searchTpl" [action]="pageExtraTpl" [formGroup]="queryForm"
[renderColumns]="renderColumnsTpl">
<table-list [props]="tableList"
[search]="searchTpl"
[action]="pageExtraTpl"
[formGroup]="queryForm"
[renderColumns]="renderColumnsTpl"
optionWidth="300px">
<ng-template #actionTpl>
<button nz-button>批量删除</button>

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

@ -88,7 +88,7 @@ export class IngredientListComponent {
{
title: "详情",
premissions: [],
onClick: this.showFoodForm.bind(this),
onClick: this.preview.bind(this),
},
{
title: "导出",
@ -117,6 +117,14 @@ export class IngredientListComponent {
return [2].includes(v.status);
},
},
{
title: "禁用",
premissions: [],
onClick: this.disableMenu.bind(this),
visible(v) {
return [2].includes(v.status);
},
},
{
title: "编辑",
premissions: [],
@ -124,7 +132,7 @@ export class IngredientListComponent {
this.router.navigate([`/ingredient/item/form/${v["id"]}`]);
},
visible(v) {
return v.status !== 1;
return [0, 3, 4].includes(v.status);
},
},
{
@ -162,6 +170,10 @@ export class IngredientListComponent {
}
}
preview({ id }: any) {
window.open(`/ingredient/preview?id=${id}`);
}
showFoodForm(food?: any) {
this.drawerRef = this.drawer.create({
nzTitle: food ? "编辑菜品" : "新增菜品",
@ -216,4 +228,17 @@ export class IngredientListComponent {
},
});
}
disableMenu({ id }: any) {
this.modal.confirm({
nzTitle: "警告",
nzContent: `是否要禁用该食谱?`,
nzOkDanger: true,
nzOnOk: async () => {
const res = await lastValueFrom(this.api.disableMenu(id));
this.msg.success(res.desc);
this.tableList.run();
},
});
}
}

1
projects/admin/src/app/pages/ingredients/ingredient-preview-page/ingredient-preview-page.component.html

@ -0,0 +1 @@
<app-ingredient-preview></app-ingredient-preview>

0
projects/admin/src/app/pages/ingredients/ingredient-preview-page/ingredient-preview-page.component.less

27
projects/admin/src/app/pages/ingredients/ingredient-preview-page/ingredient-preview-page.component.ts

@ -0,0 +1,27 @@
import { Component, OnInit } from "@angular/core";
import { ActivatedRoute, Router } from "@angular/router";
@Component({
selector: "app-ingredient-preview-page",
templateUrl: "./ingredient-preview-page.component.html",
styleUrls: ["./ingredient-preview-page.component.less"],
})
export class IngredientPreviewPageComponent implements OnInit {
constructor(private route: ActivatedRoute, private router: Router) {}
ngOnInit(): void {
const id = this.route.snapshot.queryParamMap.get("id");
const storage = sessionStorage.getItem("current_menu");
if (id) {
console.log(id);
return;
}
if (storage) {
return;
}
this.router.navigate(["/ingredient/item/list"]);
}
}

38
projects/admin/src/app/pages/ingredients/ingredient-release/ingredient-release.component.html

@ -13,24 +13,26 @@
<input nz-input placeholder="请输入食谱名称" formControlName="name" />
</nz-form-control>
</nz-form-item>
<nz-form-item class="w-40">
<nz-form-item class="w-60">
<nz-form-control>
<nz-select nzPlaceHolder="单位" [nzOptions]="[]"></nz-select>
<app-org-select formControlName="vender"></app-org-select>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-control>
<nz-space>
<nz-radio-group *nzSpaceItem nzButtonStyle="solid">
<label nz-radio-button nzValue="A">全部</label>
<label nz-radio-button nzValue="B">本周</label>
<label nz-radio-button nzValue="C">上周</label>
<nz-radio-group *nzSpaceItem nzButtonStyle="solid"
[(ngModel)]="week"
(ngModelChange)="onWeekChange($event)"
[ngModelOptions]="{standalone: true}">
<label nz-radio-button [nzValue]="0">全部</label>
<label nz-radio-button [nzValue]="1">本周</label>
<label nz-radio-button [nzValue]="-1">上周</label>
</nz-radio-group>
<ng-container *nzSpaceItem>
<nz-range-picker
[nzShowTime]="{ nzFormat: 'HH:mm' }"
nzFormat="yyyy-MM-dd HH:mm"
ngModel>
[(ngModel)]="dateRange"
[ngModelOptions]="{standalone: true}">
</nz-range-picker>
</ng-container>
</nz-space>
@ -40,11 +42,19 @@
</ng-template>
<ng-template #renderColumnsTpl let-data let-key="key" let-row="row">
<ng-container [ngSwitch]="key">
<!-- <ng-container *ngSwitchCase="'img'">
<div class="dish-img overflow-auto"
[ngStyle]="{'background-image':'url(' + tempImg + ')'}">
</div>
</ng-container> -->
<ng-container *ngSwitchCase="'created'">
{{data | date:'yyyy-MM-dd HH:mm:ss'}}
</ng-container>
<ng-container *ngSwitchCase="'vender'">
{{ tableOrg[data] ? tableOrg[data].name : '-'}}
</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 *ngSwitchDefault>
{{data}}

102
projects/admin/src/app/pages/ingredients/ingredient-release/ingredient-release.component.ts

@ -1,9 +1,13 @@
import { Component, OnInit, TemplateRef, ViewChild } from "@angular/core";
import { FormControl, FormGroup } from "@angular/forms";
import { NzDrawerRef, NzDrawerService } from "ng-zorro-antd/drawer";
import { AnyObject, TableListOption } from "@cdk/public-api";
import { AnyObject, MyResponse, OrgDTO, TableListOption } from "@cdk/public-api";
import { DishFormComponent } from "@admin/app/components";
import { ApiService } from "@cdk/services";
import { lastValueFrom, tap } from "rxjs";
import { endOfWeek, format, startOfWeek, subWeeks } from "date-fns";
import { NzModalService } from "ng-zorro-antd/modal";
import { NzMessageService } from "ng-zorro-antd/message";
@Component({
selector: "app-ingredient-release",
@ -11,20 +15,30 @@ import { ApiService } from "@cdk/services";
styleUrls: ["./ingredient-release.component.less"],
})
export class IngredientReleaseComponent {
constructor(private drawer: NzDrawerService, private api: ApiService) {}
constructor(
private drawer: NzDrawerService,
private api: ApiService,
private modal: NzModalService,
private msg: NzMessageService
) {}
@ViewChild("foofFormFooterTpl") foofFormFooterTpl!: TemplateRef<{}>;
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));
public queryForm = new FormGroup({
name: new FormControl(""),
vender: new FormControl(""),
});
tableOrg: { [k: number]: OrgDTO } = {};
week: number = 0;
dateRange: Date[] | null = null;
ngOnInit(): void {
this.initTableList();
}
@ -33,11 +47,11 @@ export class IngredientReleaseComponent {
this.tableList.scroll = { x: null };
this.tableList = this.tableList.setColumns([
{ key: "name", title: "食谱名称" },
{ key: "name", title: "单位" },
{ key: "name", title: "包含餐次" },
{ key: "name", title: "周期" },
{ key: "name", title: "创建时间" },
{ key: "name", title: "应用时间" },
{ key: "vender", title: "单位" },
{ key: "meals", title: "包含餐次" },
{ key: "day", title: "周期" },
{ key: "created", title: "创建时间" },
{ key: "dateRange", title: "应用时间" },
]);
this.tableList = this.tableList.setOptions([
@ -55,13 +69,64 @@ export class IngredientReleaseComponent {
{
title: "取消发布",
premissions: [],
onClick: this.showFoodForm.bind(this),
onClick: this.cancelRelease.bind(this),
},
]);
}
fetchData(query: AnyObject, pager: AnyObject) {
return this.api.page(pager, query);
fetchData(pager: AnyObject, query: AnyObject) {
if (this.dateRange) {
if (this.dateRange[0]) {
query["startTime"] = format(this.dateRange[0], "yyyy-MM-dd");
}
if (this.dateRange[1]) {
query["endTime"] = format(this.dateRange[1], "yyyy-MM-dd");
}
}
return this.api.getMenuReleasePage(pager, query).pipe(
tap((res) => {
this.getTableColumData(res);
})
);
}
getTableColumData(res: MyResponse) {
if (Array.isArray(res.body.content)) {
const vendors = res.body.content.map((i: any) => i.vender);
if (vendors.length > 0) {
this.api.getOrgList({ vendors }).subscribe((org) => {
if (Array.isArray(org.body)) {
this.tableOrg = org.body.reduce((a, c) => {
return {
...a,
[c.id]: c,
};
}, {} as AnyObject);
}
});
}
}
}
onWeekChange(e: -1 | 0 | 1) {
if (e !== 0) {
const range = this.getWeekDates(e);
this.dateRange = range;
} else {
this.dateRange = null;
}
}
getWeekDates(offset: -1 | 1) {
const now = new Date();
const startDate =
offset === -1 ? startOfWeek(subWeeks(now, 1), { weekStartsOn: 1 }) : startOfWeek(now, { weekStartsOn: 1 });
const endDate =
offset === -1 ? endOfWeek(subWeeks(now, 1), { weekStartsOn: 1 }) : endOfWeek(now, { weekStartsOn: 1 });
return [startDate, endDate];
}
showFoodForm(food?: any) {
@ -77,5 +142,16 @@ export class IngredientReleaseComponent {
this.drawerRef?.close();
}
deleteItem() {}
cancelRelease({ id }: any) {
this.modal.confirm({
nzTitle: "警告",
nzContent: "是否要取消发布该食谱?",
nzOkDanger: true,
nzOnOk: async () => {
const res = await lastValueFrom(this.api.cancelRelease(id));
this.msg.success(res.desc);
this.tableList.run();
},
});
}
}

20
projects/admin/src/app/pages/ingredients/ingredient-review/ingredient-review.component.html

@ -3,15 +3,23 @@
class="h-full scroll-card-body ">
<nz-card-tab>
<nz-tabset nzSize="large" [nzSelectedIndex]="statusIndex" (nzSelectedIndexChange)="onStatusChange($event)">
<nz-tab [nzTitle]="'待审核' + (statusCount[1] || '')"></nz-tab>
<nz-tab [nzTitle]="'已审核'+ (statusCount[2] || '')"></nz-tab>
<nz-tab [nzTitle]="'审核失败'+ (statusCount[3] || '')"></nz-tab>
<nz-tab [nzTitle]="'待审核' + (statusCount[1] || '0')"></nz-tab>
<nz-tab [nzTitle]="'已审核'+ (statusCount[2] || '0')"></nz-tab>
<nz-tab [nzTitle]="'审核失败'+ (statusCount[3] || '0')"></nz-tab>
</nz-tabset>
</nz-card-tab>
<div class="p-4">
<app-ingredient-status-list *ngIf="statusIndex === 0" [status]="1"></app-ingredient-status-list>
<app-ingredient-status-list *ngIf="statusIndex === 1" [status]="3"></app-ingredient-status-list>
<app-ingredient-status-list *ngIf="statusIndex === 2" [status]="2"></app-ingredient-status-list>
<app-ingredient-status-list
*ngIf="statusIndex === 0"
[status]="1"
(onReload)="loadCount()">
</app-ingredient-status-list>
<app-ingredient-status-list *ngIf="statusIndex === 1" [status]="2">
</app-ingredient-status-list>
<app-ingredient-status-list *ngIf="statusIndex === 2" [status]="3">
</app-ingredient-status-list>
</div>
</nz-card>

66
projects/admin/src/app/pages/ingredients/ingredient-review/ingredient-review.component.ts

@ -19,25 +19,17 @@ export class IngredientReviewComponent {
private api: ApiService
) {}
@ViewChild("foofFormFooterTpl") foofFormFooterTpl!: TemplateRef<{}>;
private drawerRef?: NzDrawerRef;
statusIndex = 0;
public tableList = new TableListOption(this.fetchData.bind(this), {
selectable: true,
});
public queryForm = new FormGroup({
name: new FormControl(""),
});
statusCount: Record<number, string> = {};
ngOnInit(): void {
this.statusIndex = Number(this.route.snapshot.queryParamMap.get("statusIndex")) ?? 0;
this.initTableList();
this.loadCount();
}
loadCount() {
this.api.getCountByStatus().subscribe((res) => {
if (Array.isArray(res.body)) {
this.statusCount = res.body.reduce((a, c) => {
@ -50,54 +42,6 @@ export class IngredientReviewComponent {
});
}
initTableList() {
this.tableList.scroll = { x: null };
this.tableList = this.tableList.setColumns([
{ key: "name", title: "食谱名称" },
{ key: "name", title: "单位" },
{ key: "name", title: "提交审核时间" },
{ key: "name", title: "提交人" },
]);
this.tableList = this.tableList.setOptions([
{
title: "详情",
premissions: [],
onClick: this.showFoodForm.bind(this),
},
{
title: "导出食谱",
premissions: [],
onClick: this.showFoodForm.bind(this),
},
{
title: "取消发布",
premissions: [],
onClick: this.showFoodForm.bind(this),
},
]);
}
fetchData(query: AnyObject, pager: AnyObject) {
return this.api.page(pager, query);
}
showFoodForm(food?: any) {
this.drawerRef = this.drawer.create({
nzTitle: food ? "编辑菜品" : "新增菜品",
nzWidth: 700,
nzContent: DishFormComponent,
nzFooter: this.foofFormFooterTpl,
});
}
cancelFoodForm() {
this.drawerRef?.close();
}
deleteItem() {}
onStatusChange(index: number) {
this.statusIndex = index;
this.router.navigate(["/ingredient/review"], {

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

@ -13,7 +13,7 @@ import { ApiService } from "@cdk/services";
// }
export type DishInterface = Augmented<{
dishId: number;
dish: number;
day: number;
meal: string;
mark: string;

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

@ -9,19 +9,33 @@
</button>
</nz-space>
</div>
<nz-table nzTemplateMode [nzBordered]="true" nzSize="small">
<nz-table nzTemplateMode [nzBordered]="true" nzSize="small" [nzScroll]="{ x: '1200px' }" class=" relative">
<thead>
<!-- <tr>
<th nzWidth="300px"></th>
<th nzWidth="200px"></th>
<th [colSpan]="8">
</th>
</tr> -->
<tr>
<th colSpan="2"></th>
<th nzWidth="300px" class="placeholder-th">
&nbsp;
</th>
<th nzWidth="200px">
<span class=" absolute top-2 left-[500px] z-10 w-[150px] h-[40px]">重量/克</span>
</th>
<th *ngFor="let p of peopleGroups; let last = last" [ngClass]="{'placeholder-th':!last}"
nzWidth="150px">
<th [colSpan]="peopleGroups.length">
重量/克
</th>
</tr>
<tr>
<th nzWidth="200px">
<th nzWidth="300px">
菜品
</th>
<th nzWidth="200px">
@ -30,37 +44,40 @@
<th *ngFor="let p of peopleGroups">
{{p}}
</th>
</tr>
</thead>
<tbody>
<ng-container *ngFor="let dish of currentDishs">
<ng-container *ngFor="let food of dish['items'];let first = first;">
<tr>
<td *ngIf="first" [rowSpan]="dish['items'].length ">
<div class="flex justify-between">
<span>
{{dish['dishName']}}
</span>
<button nz-button nzType="text" (click)="onRemoveDish(dish)">
<i nz-icon nzType="delete"></i>
</button>
<!-- nz-dropdown [nzDropdownMenu]="dishOptions" -->
<!-- <nz-dropdown-menu #dishOptions="nzDropdownMenu">
<ng-container *ngFor="let dish of mealDishs;let dishIndex = index">
<ng-container *ngIf="dish['mealIndex'] === mealIndex && dish['day'] === day">
<ng-container *ngFor="let food of dish['items'];let first = first;">
<tr>
<td *ngIf="first" [rowSpan]="dish['items'].length ">
<div class="flex justify-between">
<span>
{{dish['dishName']}}
</span>
<button nz-button nzType="text" (click)="onRemoveDish(dish,dishIndex)">
<i nz-icon nzType="delete"></i>
</button>
<!-- nz-dropdown [nzDropdownMenu]="dishOptions" -->
<!-- <nz-dropdown-menu #dishOptions="nzDropdownMenu">
<ul nz-menu nzSelectable class=" w-20">
<li nz-menu-item>编辑</li>
<li nz-menu-item nzDanger>删除</li>
</ul>
</nz-dropdown-menu> -->
</div>
</td>
<td>
<div class="flex justify-between">
<span>
{{food['foodName']}}
</span>
<!-- <button nz-button nzType="text" nz-dropdown [nzDropdownMenu]="foodOptions">
</div>
</td>
<td>
<div class="flex justify-between">
<span>
{{food['foodName']}}
</span>
<!-- <button nz-button nzType="text" nz-dropdown [nzDropdownMenu]="foodOptions">
<i nz-icon nzType="more"></i>
</button>
<nz-dropdown-menu #foodOptions="nzDropdownMenu">
@ -69,18 +86,32 @@
<li nz-menu-item nzDanger>删除</li>
</ul>
</nz-dropdown-menu> -->
</div>
</td>
<td *ngFor="let g of food.value | keyvalue">
{{g.value}}
</td>
</tr>
</div>
</td>
<td *ngFor="let g of food['groupValues'] ">
<input nz-input type="number" [(ngModel)]="g.value" (ngModelChange)="onValueChange()" />
</td>
</tr>
</ng-container>
</ng-container>
</ng-container>
<tr class="total">
<td colSpan="2" class="text-center">
本餐生重总量
</td>
<td *ngFor="let p of peopleGroups">
{{totalObj[p]}}
</td>
</tr>
</tbody>
</nz-table>
<nz-empty *ngIf="currentDishs.length === 0" class="empty"></nz-empty>
<!-- <nz-empty *ngIf="currentDishs.length === 0" class="empty"></nz-empty> -->
</div>
<ng-template #addDishFooter>

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

@ -3,4 +3,14 @@
padding: 24px;
border: 1px solid #f0f0f0;
border-top: none;
}
.total {
td {
background-color: #fafafa;
}
}
.placeholder-th {
border-right: none !important;
}

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

@ -52,7 +52,9 @@ export class IngredientMealsComponent implements OnChanges, OnInit {
submitLoading = false;
currentDishs: DishInterface[] = [];
// currentDishs: DishInterface[] = [];
totalObj: Record<string, string> = {};
ngOnInit(): void {
this.init();
@ -65,9 +67,28 @@ export class IngredientMealsComponent implements OnChanges, OnInit {
}
init() {
console.log(" ", this.mealDishs, this.day, this.mealIndex);
this.currentDishs = this.mealDishs.filter((f) => f.day === this.day && this.mealIndex === f["mealIndex"]);
this.calcTotal();
// console.log(" init", this.mealDishs, this.day, this.mealIndex);
// this.currentDishs = this.mealDishs.filter((f) => f.day === this.day && this.mealIndex === f["mealIndex"]);
}
calcTotal() {
this.totalObj = {};
this.mealDishs.forEach((dish) => {
if (dish.day === this.day && this.mealIndex === dish["mealIndex"]) {
dish.items.forEach((food) => {
food["groupValues"].forEach((p: any) => {
if (!this.totalObj[p.peopleName]) {
this.totalObj[p.peopleName] = p.value;
} else {
this.totalObj[p.peopleName] = this.totalObj[p.peopleName] + p.value;
}
});
});
}
});
}
shopDishForm() {
this.drawerRef = this.drawer.create({
nzTitle: "添加菜品",
@ -80,6 +101,16 @@ export class IngredientMealsComponent implements OnChanges, OnInit {
});
}
getTotal(dishId: number, people: string) {
const r = this.mealDishs.filter(
(f) => f.day === this.day && f["mealIndex"] === this.mealIndex && f.dish === dishId
);
r.forEach((dish) => {
dish.items;
});
return "ad";
}
clearThisMeal() {
this.modal.confirm({
nzTitle: "警告",
@ -104,18 +135,10 @@ export class IngredientMealsComponent implements OnChanges, OnInit {
day: this.day,
mealIndex: this.mealIndex,
meal: this.meals[this.mealIndex],
dishId: dish.id,
dish: 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>),
})),
items: foods,
});
this.onSaveDish.emit(this.mealDishs);
@ -123,10 +146,17 @@ export class IngredientMealsComponent implements OnChanges, OnInit {
this.cancelForm();
}
onRemoveDish(d: DishInterface) {
this.mealDishs = this.mealDishs.filter(
(f) => !(f.dishId === d.dishId && f.day === this.day && f["mealIndex"] === this.mealIndex)
);
onRemoveDish(d: DishInterface, idx: number) {
// this.mealDishs = this.mealDishs.filter(
// (f) => !(f.dish === d.dish && f.day === this.day && f["mealIndex"] === this.mealIndex)
// );
this.mealDishs = this.mealDishs.filter((f, i) => i !== idx);
this.onSaveDish.emit(this.mealDishs);
}
onValueChange() {
// this.onSaveDish.emit(this.mealDishs);
// console.log("this.currentDishs", this.currentDishs);
this.calcTotal();
}
}

133
projects/cdk/src/ingredient/ingredient-preview/ingredient-preview.component.html

@ -0,0 +1,133 @@
<header class="header text-center text-base">
食谱名称
</header>
<div class="p-4">
<nz-descriptions [nzColumn]="4">
<nz-descriptions-item nzTitle="采用标准">Zhou Maomao</nz-descriptions-item>
<nz-descriptions-item nzTitle="食谱周期">18100000000</nz-descriptions-item>
<nz-descriptions-item nzTitle="适用月份">Hangzhou, Zhejiang</nz-descriptions-item>
<nz-descriptions-item nzTitle="人群显示">Empty</nz-descriptions-item>
</nz-descriptions>
</div>
<div class="p-4">
<table class="menu-table">
<thead>
<tr>
<th width="100px">
</th>
<th>
<div>
<div class="table-day-row">
<div class="td"> 第1天 </div>
<div class="td"> 重量/克 </div>
</div>
<div class="table-menu-row flex ">
<div class="td dish-name text-left">
菜品
</div>
<div class="td food-name text-left">
食材
</div>
<div class="table-herder-ages">
<div class="td age-range"> 18-49岁男 </div>
<div class="td age-range"> 18-49岁男 </div>
<div class="td age-range"> 18-49岁男 </div>
</div>
</div>
</div>
</th>
<th>
<div>
<div class="table-day-row">
<div class="td"> 第2天 </div>
<div class="td"> 重量/克 </div>
</div>
<div class="table-menu-row flex ">
<div class="td dish-name text-left">
菜品
</div>
<div class="td food-name text-left">
食材
</div>
<div class="table-herder-ages">
<div class="td age-range"> 18-49岁男 </div>
<div class="td age-range"> 18-49岁男 </div>
<div class="td age-range"> 18-49岁男 </div>
</div>
</div>
</div>
</th>
</tr>
</thead>
<tbody>
<tr>
<td class="text-center">
<b>
早餐
</b>
</td>
<td>
<div class="flex">
<div class="menu-dish dish-name">
<div class="text-left td">烂肉泡菜L</div>
</div>
<div class="menu-food">
<ul>
<li class="flex">
<div class="td food-name text-left">
酸白菜[酸菜]
</div>
<div class="td age-range text-right">
1
</div>
<div class="td age-range text-right">
2
</div>
<div class="td age-range text-right">
3
</div>
</li>
<li class="flex">
<div class="td food-name text-left">
酸白菜[酸菜]
</div>
<div class="td age-range text-right">
1
</div>
<div class="td age-range text-right">
2
</div>
<div class="td age-range text-right">
3
</div>
</li>
<li class="flex">
<div class="td food-name text-left">
酸白菜[酸菜]
</div>
<div class="td age-range text-right">
1
</div>
<div class="td age-range text-right">
2
</div>
<div class="td age-range text-right">
3
</div>
</li>
</ul>
</div>
</div>
</td>
<td>
</td>
</tr>
</tbody>
</table>
</div>

84
projects/cdk/src/ingredient/ingredient-preview/ingredient-preview.component.less

@ -0,0 +1,84 @@
.header {
padding: 10px;
background-color: #fff;
border-bottom: 1px solid #e8e8e8;
}
.menu-table {
// width: 100%;
margin: 0 auto;
border-collapse: collapse;
border-spacing: 0;
border: 1px solid #e8e8e8;
thead {
.table-day-row {
display: flex;
border-bottom: 1px solid #fafafa;
.td {
flex: 1;
padding: 10px;
border-right: 1px solid #fafafa;
&:first-child {
flex: 0 0 420px;
}
&:last-child {
border-right: none;
}
}
}
th {
.td {
background-color: transparent;
border-right: 1px solid #fafafa;
background-color: #13c2c2;
}
border-right: 1px solid #fafafa;
background-color: #13c2c2;
color: #fff;
}
}
.table-herder-ages {
display: flex;
.td {
&:last-child {
border-right: none;
}
}
}
.dish-name {
width: 240px;
}
.food-name {
width: 180px;
}
.td {
height: 100%;
padding: 10px;
background-color: #fafafa;
}
.age-range {
// display: inline-block;
width: 150px;
// background-color: #fafafa;
font-weight: bold;
}
}

8
projects/cdk/src/ingredient/ingredient-preview/ingredient-preview.component.ts

@ -0,0 +1,8 @@
import { Component } from "@angular/core";
@Component({
selector: "app-ingredient-preview",
templateUrl: "./ingredient-preview.component.html",
styleUrls: ["./ingredient-preview.component.less"],
})
export class IngredientPreviewComponent {}

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

@ -5,6 +5,7 @@ import { IngredientMealsComponent } from "./ingredient-meals/ingredient-meals.co
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";
import { IngredientPreviewComponent } from "./ingredient-preview/ingredient-preview.component";
@NgModule({
declarations: [
@ -13,6 +14,7 @@ import { IngredientFormBasicComponent } from "./ingredient-form-basic/ingredient
ConfirmIngredientComponent,
IngredientFormBasicComponent,
IngredientDishComponent,
IngredientPreviewComponent,
],
imports: [SharedModule],
exports: [
@ -21,6 +23,7 @@ import { IngredientFormBasicComponent } from "./ingredient-form-basic/ingredient
ConfirmIngredientComponent,
IngredientFormBasicComponent,
IngredientDishComponent,
IngredientPreviewComponent,
],
})
export class IngredientModule {}

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

@ -34,17 +34,6 @@ export class ApiService {
globalEnum!: GlobalEnum;
page(v: {}, q: {}) {
return this.http.get<any>("https://jsonplaceholder.typicode.com/users", v).pipe(
map((r) => {
return {
total: 10,
content: r,
};
})
);
}
initAccount() {
try {
const stragedAccount = localStorage.getItem(this.accountKey);
@ -397,6 +386,11 @@ export class ApiService {
return this.http.put<ResponseType>(`/api/menu/review`, params);
}
disableMenu(id: string | number) {
const params = Utils.objectToFormData({ id });
return this.http.delete<ResponseType>(`/api/menu/review`, { body: params });
}
reviewMenu(id: number, pass: boolean, reason?: string) {
const params = Utils.objectToFormData({ id, pass, reason });
return this.http.post<ResponseType>(`/api/menu/review`, params);
@ -412,6 +406,11 @@ export class ApiService {
return this.http.put<ResponseType>(`/api/menu/release`, params);
}
cancelRelease(id: string | number) {
const params = Utils.objectToFormData({ id });
return this.http.delete<ResponseType>(`/api/menu/release`, { body: params });
}
deleteMenu(id: string | number) {
const params = Utils.objectToFormData({ id });
return this.http.delete<ResponseType>(`/api/menu`, { body: params });
@ -424,4 +423,19 @@ export class ApiService {
saveMenuDist(d: {}) {
return this.http.put<ResponseType>(`/api/menu/dish/batch`, d);
}
getMenuReleasePage(p: {}, q: {}) {
const params = Utils.objectStringify({ ...p, ...q });
return this.http.get<ResponseType<PageResult>>(`/api/menu/release?${params}`).pipe(
map((res) => {
if (Array.isArray(res.body.content)) {
res.body.content = res.body.content.map((i) => ({
...i,
dateRange: `${format(new Date(i.startTime), "yyyy-MM-dd")}${format(new Date(i.endTime), "yyyy-MM-dd")}`,
}));
}
return res;
})
);
}
}

2
projects/cdk/src/table-list/table-list/table-list.component.html

@ -73,7 +73,7 @@
{{col.title}}
</th>
</ng-container>
<th *ngIf="operation.length" [nzWidth]="optionWidth" [nzRight]="!!props.scroll.x">
<th *ngIf="operation.length" [nzWidth]="optionWidth!" [nzRight]="!!props.scroll.x">
操作
</th>
<th nzRight nzWidth="40px" *ngIf="props.theadSettable">

8
projects/cdk/src/table-list/table-list/table-list.component.ts

@ -95,6 +95,8 @@ export class TableListComponent implements OnInit, OnChanges, AfterViewInit, OnD
@Input() rowClass?: string;
@Input() public optionWidth?: string;
// @Input() resizeable?: boolean;
@Output() onRowClick = new EventEmitter();
@ -107,8 +109,6 @@ export class TableListComponent implements OnInit, OnChanges, AfterViewInit, OnD
public advanceSearchVisible: boolean = false;
public optionWidth: string = "200px";
private cache?: CacheItem;
get columns(): TableListColumns[] {
@ -171,7 +171,9 @@ export class TableListComponent implements OnInit, OnChanges, AfterViewInit, OnD
if (opEl) {
setTimeout(() => {
const paddingX = 2 * 24;
this.optionWidth = Math.ceil(opEl.offsetWidth + paddingX) + "px";
if (!this.optionWidth) {
this.optionWidth = Math.ceil(opEl.offsetWidth + paddingX) + "px";
}
this.cdr.detectChanges();
});
}

Loading…
Cancel
Save