28 changed files with 2629 additions and 2619 deletions
@ -1,16 +0,0 @@ |
|||||
# Editor configuration, see https://editorconfig.org |
|
||||
root = true |
|
||||
|
|
||||
[*] |
|
||||
charset = utf-8 |
|
||||
indent_style = space |
|
||||
indent_size = 2 |
|
||||
insert_final_newline = true |
|
||||
trim_trailing_whitespace = true |
|
||||
|
|
||||
[*.ts] |
|
||||
quote_type = single |
|
||||
|
|
||||
[*.md] |
|
||||
max_line_length = off |
|
||||
trim_trailing_whitespace = false |
|
||||
@ -0,0 +1,8 @@ |
|||||
|
{ |
||||
|
"singleQuote": true, |
||||
|
"trailingComma": "all", |
||||
|
"useTabs": true, |
||||
|
"tabWidth": 4, |
||||
|
"semi": false, |
||||
|
"printWidth": 120 |
||||
|
} |
||||
@ -1,140 +1,128 @@ |
|||||
<app-page> |
<app-page> |
||||
<ng-template #pageExtraTpl> |
<ng-template #pageExtraTpl> |
||||
<nz-space> |
<nz-space> |
||||
<button *nzSpaceItem nz-button [disabled]="!selectedIds.length" (click)="deleteItem()">批量删除</button> |
<button *nzSpaceItem nz-button [disabled]="!selectedIds.length" (click)="deleteItem()">批量删除</button> |
||||
<button *nzSpaceItem nz-button [disabled]="!selectedIds.length" |
<button *nzSpaceItem nz-button [disabled]="!selectedIds.length" (click)="printTag()"> |
||||
(click)="printTag()">批量打印营养标签</button> |
批量打印营养标签 |
||||
<button *nzSpaceItem nz-button nzType="primary" (click)="showFoodForm()"> |
</button> |
||||
<i nz-icon nzType="plus"></i> |
<button *nzSpaceItem nz-button nzType="primary" (click)="showFoodForm()"> |
||||
新增菜品 |
<i nz-icon nzType="plus"></i> |
||||
</button> |
新增菜品 |
||||
</nz-space> |
</button> |
||||
</ng-template> |
</nz-space> |
||||
<div class="h-full overflow-hidden bg-white rounded-lg"> |
</ng-template> |
||||
|
<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" |
||||
|
> |
||||
|
<ng-template #searchTpl> |
||||
|
<nz-form-item class="w-60"> |
||||
|
<nz-form-control> |
||||
|
<nz-select nzPlaceHolder="请选择单位" formControlName="vendors"> |
||||
|
<nz-option |
||||
|
*ngFor="let o of listOfOption" |
||||
|
[nzLabel]="o.text" |
||||
|
[nzValue]="o.value" |
||||
|
></nz-option> |
||||
|
</nz-select> |
||||
|
</nz-form-control> |
||||
|
</nz-form-item> |
||||
|
<nz-form-item class="w-40"> |
||||
|
<nz-form-control> |
||||
|
<nz-select nzPlaceHolder="菜品标签" formControlName="mark" nzAllowClear> |
||||
|
<nz-option |
||||
|
*ngFor="let item of globalEnum.mark" |
||||
|
[nzLabel]="item.key" |
||||
|
[nzValue]="item.key" |
||||
|
> |
||||
|
</nz-option> |
||||
|
</nz-select> |
||||
|
</nz-form-control> |
||||
|
</nz-form-item> |
||||
|
|
||||
<nz-card [nzBordered]="false" nzTitle="菜品管理"> |
<nz-form-item> |
||||
<table-list [props]="tableList" [search]="searchTpl" [action]="pageExtraTpl" [formGroup]="queryForm" |
<nz-form-control> |
||||
[renderColumns]="renderColumnsTpl"> |
<input nz-input placeholder="请输入菜品名称" formControlName="keyword" /> |
||||
|
</nz-form-control> |
||||
|
</nz-form-item> |
||||
<ng-template #searchTpl> |
</ng-template> |
||||
<nz-form-item class="w-60"> |
<ng-template #renderColumnsTpl let-data let-key="key" let-row="row"> |
||||
<nz-form-control> |
<ng-container [ngSwitch]="key"> |
||||
<nz-select |
<ng-container *ngSwitchCase="'icon'"> |
||||
nzPlaceHolder="请选择单位" |
<div |
||||
formControlName="vendors"> |
class="dish-img overflow-auto" |
||||
<nz-option *ngFor="let o of listOfOption" [nzLabel]="o.text" |
*ngIf="data" |
||||
[nzValue]="o.value"></nz-option> |
[ngStyle]="{ 'background-image': 'url(/api/icon/' + data + ')' }" |
||||
</nz-select> |
></div> |
||||
</nz-form-control> |
</ng-container> |
||||
</nz-form-item> |
<ng-container *ngSwitchCase="'vender'"> |
||||
<nz-form-item class="w-40"> |
{{ tableOrg[data] ? tableOrg[data].name : '-' }} |
||||
<nz-form-control> |
</ng-container> |
||||
<nz-select nzPlaceHolder="菜品标签" formControlName="mark" nzAllowClear> |
<ng-container *ngSwitchCase="'label'"> |
||||
<nz-option *ngFor="let item of globalEnum.mark" [nzLabel]="item.key" |
<nz-tag *ngFor="let item of data ?? []"> |
||||
[nzValue]="item.key"> |
{{ item }} |
||||
</nz-option> |
</nz-tag> |
||||
</nz-select> |
</ng-container> |
||||
</nz-form-control> |
<ng-container *ngSwitchCase="'ingredient'"> |
||||
</nz-form-item> |
<div class="flex flex-wrap"> |
||||
|
<ng-container *ngFor="let item of data"> |
||||
<nz-form-item> |
<nz-tag *ngIf="tableFoods[item.key]" class="m-1"> |
||||
<nz-form-control> |
{{ tableFoods[item.key]['name'] }}:{{ item.value }} g |
||||
<input nz-input placeholder="请输入菜品名称" formControlName="keyword" /> |
</nz-tag> |
||||
</nz-form-control> |
</ng-container> |
||||
</nz-form-item> |
</div> |
||||
</ng-template> |
</ng-container> |
||||
<ng-template #renderColumnsTpl let-data let-key="key" let-row="row"> |
<ng-container *ngSwitchDefault> |
||||
<ng-container [ngSwitch]="key"> |
{{ data }} |
||||
<ng-container *ngSwitchCase="'icon'"> |
</ng-container> |
||||
<div class="dish-img overflow-auto" |
</ng-container> |
||||
*ngIf="data" |
</ng-template> |
||||
[ngStyle]="{'background-image':'url(/api/icon/' + data + ')'}"> |
</table-list> |
||||
</div> |
</nz-card> |
||||
</ng-container> |
</div> |
||||
<ng-container *ngSwitchCase="'vender'"> |
|
||||
{{ tableOrg[data] ? tableOrg[data].name : '-'}} |
|
||||
</ng-container> |
|
||||
<ng-container *ngSwitchCase="'ingredient'"> |
|
||||
<div class=" flex flex-wrap"> |
|
||||
<ng-container *ngFor="let item of data"> |
|
||||
<nz-tag *ngIf="tableFoods[item.key]" class="m-1"> |
|
||||
{{tableFoods[item.key]['name']}}:{{item.value}} g |
|
||||
</nz-tag> |
|
||||
</ng-container> |
|
||||
</div> |
|
||||
</ng-container> |
|
||||
<ng-container *ngSwitchDefault> |
|
||||
{{data}} |
|
||||
</ng-container> |
|
||||
</ng-container> |
|
||||
</ng-template> |
|
||||
</table-list> |
|
||||
</nz-card> |
|
||||
</div> |
|
||||
</app-page> |
</app-page> |
||||
|
|
||||
|
|
||||
<ng-template #formFooterTpl> |
<ng-template #formFooterTpl> |
||||
<nz-space> |
<nz-space> |
||||
<button *nzSpaceItem nz-button (click)="cancelForm()" type="button"> |
<button *nzSpaceItem nz-button (click)="cancelForm()" type="button">取消</button> |
||||
取消 |
<button *nzSpaceItem nz-button nzType="primary" [nzLoading]="submitLoading" (click)="onSubmit()">保存</button> |
||||
</button> |
</nz-space> |
||||
<button *nzSpaceItem nz-button nzType="primary" [nzLoading]="submitLoading" (click)="onSubmit()"> |
|
||||
保存 |
|
||||
</button> |
|
||||
</nz-space> |
|
||||
</ng-template> |
</ng-template> |
||||
|
|
||||
|
<app-print #print [content]="printContent"> </app-print> |
||||
<app-print #print |
|
||||
[content]="printContent"> |
|
||||
</app-print> |
|
||||
|
|
||||
|
|
||||
<ng-template #printContent> |
<ng-template #printContent> |
||||
|
<div class="printContent" *ngFor="let item of printData"> |
||||
<div class="printContent" |
<table class="print-table"> |
||||
*ngFor="let item of printData"> |
<tbody> |
||||
|
<tr> |
||||
<table class="print-table"> |
<th colspan="3"> |
||||
<tbody> |
{{ item.name }} |
||||
<tr> |
</th> |
||||
<th colspan="3"> |
</tr> |
||||
{{item.name}} |
<tr> |
||||
</th> |
<th colspan="3">营养成分表</th> |
||||
</tr> |
</tr> |
||||
<tr> |
<tr> |
||||
<th colspan="3"> |
<th class="text-left">名称</th> |
||||
营养成分表 |
<th class="text-center">每100克(g)</th> |
||||
</th> |
<th class="text-center">营养参考值%(NVR%)</th> |
||||
</tr> |
</tr> |
||||
<tr> |
</tbody> |
||||
<th class="text-left"> |
<tbody> |
||||
名称 |
<tr *ngFor="let th of item.component"> |
||||
</th> |
<td [width]="'38.2%'">{{ th.name }}</td> |
||||
<th class="text-center"> |
<td class="text-center">{{ th.nutrition }}</td> |
||||
每100克(g) |
<td class="text-center">{{ th.nvr }}</td> |
||||
</th> |
</tr> |
||||
<th class="text-center"> |
</tbody> |
||||
营养参考值%(NVR%) |
</table> |
||||
</th> |
<div>主要原料:{{ item.ingredients.join(',') }}</div> |
||||
</tr> |
<div>1毫克(mg)钠相当于2.5毫克食盐</div> |
||||
</tbody> |
</div> |
||||
<tbody> |
</ng-template> |
||||
<tr *ngFor="let th of item.component"> |
|
||||
<td [width]="'38.2%'">{{ th.name }}</td> |
|
||||
<td class="text-center">{{ th.nutrition }}</td> |
|
||||
<td class="text-center">{{ th.nvr }}</td> |
|
||||
</tr> |
|
||||
|
|
||||
</tbody> |
|
||||
</table> |
|
||||
<div> |
|
||||
主要原料:{{item.ingredients.join(',')}} |
|
||||
</div> |
|
||||
<div> |
|
||||
1毫克(mg)钠相当于2.5毫克食盐 |
|
||||
</div> |
|
||||
</div> |
|
||||
</ng-template> |
|
||||
|
|||||
@ -1,93 +1,97 @@ |
|||||
import { Component, OnInit, TemplateRef, ViewChild } from "@angular/core"; |
import { Component, OnInit, TemplateRef, ViewChild } from '@angular/core' |
||||
import { FormControl, FormGroup } from "@angular/forms"; |
import { FormControl, FormGroup } from '@angular/forms' |
||||
import { NzDrawerRef, NzDrawerService } from "ng-zorro-antd/drawer"; |
import { NzDrawerRef, NzDrawerService } from 'ng-zorro-antd/drawer' |
||||
import { AnyObject, TableListOption } from "@cdk/public-api"; |
import { AnyObject, 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 { NzModalService } from "ng-zorro-antd/modal"; |
import { NzModalService } from 'ng-zorro-antd/modal' |
||||
import { lastValueFrom } from "rxjs"; |
import { lastValueFrom } from 'rxjs' |
||||
import { NzMessageService } from "ng-zorro-antd/message"; |
import { NzMessageService } from 'ng-zorro-antd/message' |
||||
import { Router } from "@angular/router"; |
import { Router } from '@angular/router' |
||||
|
import { StandardService } from '../standard.service' |
||||
|
|
||||
@Component({ |
@Component({ |
||||
selector: "app-standard-list", |
selector: 'app-standard-list', |
||||
templateUrl: "./standard-list.component.html", |
templateUrl: './standard-list.component.html', |
||||
styleUrls: ["./standard-list.component.less"], |
styleUrls: ['./standard-list.component.less'], |
||||
}) |
}) |
||||
export class StandardListComponent { |
export class StandardListComponent { |
||||
constructor( |
constructor( |
||||
private api: ApiService, |
private api: ApiService, |
||||
private modal: NzModalService, |
private modal: NzModalService, |
||||
private msg: NzMessageService, |
private msg: NzMessageService, |
||||
private router: Router |
private router: Router, |
||||
|
private standard: StandardService, |
||||
) {} |
) {} |
||||
|
|
||||
public tableList = new TableListOption(this.fetchData.bind(this), { |
public tableList = new TableListOption(this.fetchData.bind(this), { |
||||
frontPagination: false, |
frontPagination: false, |
||||
}); |
}) |
||||
|
|
||||
public queryForm = new FormGroup({ |
public queryForm = new FormGroup({ |
||||
keyword: new FormControl(""), |
keyword: new FormControl(''), |
||||
}); |
}) |
||||
|
|
||||
ngOnInit(): void { |
ngOnInit(): void { |
||||
this.initTableList(); |
this.initTableList() |
||||
} |
} |
||||
|
|
||||
initTableList() { |
initTableList() { |
||||
this.tableList.scroll = { x: null }; |
this.tableList.scroll = { x: null } |
||||
this.tableList = this.tableList.setColumns([ |
this.tableList = this.tableList.setColumns([ |
||||
{ key: "name", title: "营养标准名称" }, |
{ key: 'name', title: '营养标准名称' }, |
||||
{ key: "people", title: "人群细分" }, |
{ key: 'people', title: '人群细分' }, |
||||
{ key: "vendors", title: "适用单位" }, |
{ key: 'vendors', title: '适用单位' }, |
||||
{ key: "modify", title: "更新时间" }, |
{ key: 'modify', title: '更新时间' }, |
||||
]); |
]) |
||||
|
|
||||
this.tableList = this.tableList.setOptions([ |
this.tableList = this.tableList.setOptions([ |
||||
{ |
{ |
||||
title: "标准设置", |
title: '标准设置', |
||||
premissions: [], |
premissions: [], |
||||
onClick: this.toSetting.bind(this), |
onClick: this.toSetting.bind(this), |
||||
}, |
}, |
||||
{ |
{ |
||||
title: "编辑", |
title: '编辑', |
||||
premissions: [], |
premissions: [], |
||||
onClick: this.toEdit.bind(this), |
onClick: this.toEdit.bind(this), |
||||
}, |
}, |
||||
{ |
{ |
||||
title: "删除", |
title: '删除', |
||||
premissions: [], |
premissions: [], |
||||
onClick: this.deleteItem.bind(this), |
onClick: this.deleteItem.bind(this), |
||||
}, |
}, |
||||
]); |
]) |
||||
} |
} |
||||
|
|
||||
fetchData(query: AnyObject, pager: AnyObject) { |
fetchData(query: AnyObject, pager: AnyObject) { |
||||
return this.api.getStandardPage(pager, query); |
return this.api.getStandardPage(pager, query) |
||||
} |
} |
||||
|
|
||||
toEdit(d: AnyObject) { |
toEdit(d: AnyObject) { |
||||
this.router.navigate([`/standard/form/${d["id"]}`], { |
// this.standard.settingData$.next(d)
|
||||
|
this.router.navigate([`/standard/form/${d['id']}`], { |
||||
state: d, |
state: d, |
||||
}); |
}) |
||||
} |
} |
||||
|
|
||||
toSetting(d: AnyObject) { |
toSetting(d: AnyObject) { |
||||
this.router.navigate([`/standard/setting/${d["id"]}`], { |
// this.standard.settingData$.next(d)
|
||||
|
this.router.navigate([`/standard/setting/${d['id']}`], { |
||||
state: d, |
state: d, |
||||
}); |
}) |
||||
} |
} |
||||
|
|
||||
deleteItem(v: any) { |
deleteItem(v: any) { |
||||
this.modal.confirm({ |
this.modal.confirm({ |
||||
nzTitle: "警告", |
nzTitle: '警告', |
||||
nzContent: `是否要删除该营养标准?`, |
nzContent: `是否要删除该营养标准?`, |
||||
nzOkDanger: true, |
nzOkDanger: true, |
||||
nzOnOk: async () => { |
nzOnOk: async () => { |
||||
const res = await lastValueFrom(this.api.deleteStandard(v.id)); |
const res = await lastValueFrom(this.api.deleteStandard(v.id)) |
||||
this.msg.success(res.desc); |
this.msg.success(res.desc) |
||||
this.tableList.run(); |
this.tableList.run() |
||||
}, |
}, |
||||
}); |
}) |
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -1,204 +1,283 @@ |
|||||
import { Component } from "@angular/core"; |
import { AfterViewInit, Component, ElementRef, OnDestroy, ViewChild } from '@angular/core' |
||||
import { FormBuilder, FormGroup } from "@angular/forms"; |
import { FormBuilder, FormGroup } from '@angular/forms' |
||||
import { ActivatedRoute, Router } from "@angular/router"; |
import { ActivatedRoute, Router } from '@angular/router' |
||||
import { ApiService } from "@cdk/services"; |
import { ApiService } from '@cdk/services' |
||||
import { AnyObject } from "@cdk/types"; |
import { AnyObject } from '@cdk/types' |
||||
import { FormValidators } from "@cdk/validators"; |
import { FormValidators } from '@cdk/validators' |
||||
import { NzMessageService } from "ng-zorro-antd/message"; |
import { NzMessageService } from 'ng-zorro-antd/message' |
||||
|
import { StandardService } from '../standard.service' |
||||
|
import { Observable, Subscription } from 'rxjs' |
||||
|
|
||||
|
// infer
|
||||
|
|
||||
export type StandardItemInterface = { |
export type StandardItemInterface = { |
||||
min: number; |
min: number |
||||
max: number | null; |
max: number | null |
||||
name: string; |
name: string |
||||
type: string; |
type: string |
||||
category: string[]; |
category: string[] |
||||
}; |
} |
||||
|
|
||||
export type StandardPeopleInterface = { |
export type StandardPeopleInterface = { |
||||
ul?: number; |
ul?: number |
||||
hasUl: boolean; |
hasUl: boolean |
||||
max: number; |
max: number |
||||
min: number; |
min: number |
||||
nutrition: string; |
nutrition: string |
||||
}; |
} |
||||
|
|
||||
@Component({ |
@Component({ |
||||
selector: "app-standard-setting", |
selector: 'app-standard-setting', |
||||
templateUrl: "./standard-setting.component.html", |
templateUrl: './standard-setting.component.html', |
||||
styleUrls: ["./standard-setting.component.less"], |
styleUrls: ['./standard-setting.component.less'], |
||||
}) |
}) |
||||
export class StandardSettingComponent { |
export class StandardSettingComponent implements AfterViewInit, OnDestroy { |
||||
constructor( |
constructor( |
||||
private fb: FormBuilder, |
private fb: FormBuilder, |
||||
private router: Router, |
private router: Router, |
||||
private route: ActivatedRoute, |
private route: ActivatedRoute, |
||||
private api: ApiService, |
private api: ApiService, |
||||
private msg: NzMessageService |
private msg: NzMessageService, |
||||
|
private standard: StandardService, |
||||
) { |
) { |
||||
const id = this.route.snapshot.paramMap.get("id"); |
const id = this.route.snapshot.paramMap.get('id') |
||||
if (id !== "create") { |
if (id !== 'create') { |
||||
const data = this.router.getCurrentNavigation()?.extras; |
const data = this.router.getCurrentNavigation()?.extras |
||||
if (data) { |
if (data) { |
||||
this.state = data.state; |
this.state = data.state |
||||
} else { |
} else { |
||||
this.router.navigate(["/standard/list"]); |
this.router.navigate(['/standard/list']) |
||||
} |
} |
||||
} |
} |
||||
} |
} |
||||
|
|
||||
public globalEnum = this.api.globalEnum; |
public globalEnum = this.api.globalEnum |
||||
|
|
||||
state: any; |
state: any |
||||
|
|
||||
calcType = this.globalEnum.measurementType?.[0]?.key; |
calcType = this.globalEnum.measurementType?.[0]?.key |
||||
|
|
||||
get calcTypeText() { |
get calcTypeText() { |
||||
return this.globalEnum.measurementType.find((f) => f.key === this.calcType)?.value; |
return this.globalEnum.measurementType.find((f) => f.key === this.calcType)?.value |
||||
} |
} |
||||
|
|
||||
uploadLoading = false; |
uploadLoading = false |
||||
|
|
||||
|
foodCategoryDay: StandardItemInterface[] = [] |
||||
|
|
||||
foodCategoryDay: StandardItemInterface[] = []; |
foodCategoryWeek: StandardItemInterface[] = [] |
||||
|
|
||||
foodCategoryWeek: StandardItemInterface[] = []; |
ingredient: { name: string; nutritions: StandardPeopleInterface[] }[] = [] |
||||
|
|
||||
ingredient: { name: string; nutritions: StandardPeopleInterface[] }[] = []; |
intersection$ = new Subscription() |
||||
|
|
||||
|
renderIngredient = false |
||||
|
|
||||
|
expanded = new Set<number>() |
||||
|
|
||||
|
@ViewChild('intersectionTpl') intersectionTpl!: ElementRef<HTMLDivElement> |
||||
|
|
||||
ngOnInit(): void { |
ngOnInit(): void { |
||||
this.foodCategoryDay = this.parseFoodCategory(this.state?.foodCategoryDay); |
this.foodCategoryDay = this.parseFoodCategory(this.state?.foodCategoryDay) |
||||
this.foodCategoryWeek = this.parseFoodCategory(this.state?.foodCategoryWeek); |
this.foodCategoryWeek = this.parseFoodCategory(this.state?.foodCategoryWeek) |
||||
this.ingredient = this.parseIngredient(this.state?.ingredient); |
|
||||
|
this.ingredient = this.parseIngredient(this.state) |
||||
|
} |
||||
|
|
||||
|
ngOnDestroy(): void { |
||||
|
// this.intersection$.unsubscribe()
|
||||
|
} |
||||
|
|
||||
|
ngAfterViewInit(): void { |
||||
|
// const el = this.intersectionTpl.nativeElement
|
||||
|
// if (el) {
|
||||
|
// this.intersection$.add(
|
||||
|
// this.observeElement(el).subscribe((isIn) => {
|
||||
|
// if (isIn) {
|
||||
|
// this.renderIngredient = true
|
||||
|
// this.intersection$.unsubscribe()
|
||||
|
// }
|
||||
|
// }),
|
||||
|
// )
|
||||
|
// }
|
||||
|
} |
||||
|
|
||||
|
observeElement = (element: HTMLElement) => { |
||||
|
return new Observable((observer) => { |
||||
|
const intersectionObserver = new IntersectionObserver((entries) => { |
||||
|
entries.forEach((entry) => { |
||||
|
observer.next(entry.isIntersecting) |
||||
|
}) |
||||
|
}) |
||||
|
|
||||
|
intersectionObserver.observe(element) |
||||
|
|
||||
|
return () => { |
||||
|
intersectionObserver.disconnect() |
||||
|
} |
||||
|
}) |
||||
} |
} |
||||
|
|
||||
parseIngredient(data: any): { name: string; nutritions: StandardPeopleInterface[] }[] { |
parseIngredient(data: any): { name: string; nutritions: StandardPeopleInterface[] }[] { |
||||
if (!data) { |
if (!data?.ingredient) { |
||||
return []; |
return [] |
||||
} |
} |
||||
return Object.entries(data).map(([k, v]) => { |
console.log('data', data) |
||||
|
const sorts = data.crows ?? Object.keys(data.ingredient) |
||||
|
return sorts.map((peopleName: string) => { |
||||
|
const v: any = data.ingredient[peopleName] |
||||
return { |
return { |
||||
name: k, |
name: peopleName, |
||||
nutritions: !v |
nutritions: !v |
||||
? [] |
? [] |
||||
: Object.entries(v).map(([kn, vn]) => { |
: Object.entries(v).map(([kn, vn]: [string, any]) => { |
||||
return { |
return { |
||||
ul: vn?.ul ?? void 0, |
ul: vn?.ul ?? void 0, |
||||
hasUl: !!vn?.ul, |
hasUl: !!vn?.ul, |
||||
max: vn?.max ?? 0, |
max: vn?.max ?? 0, |
||||
min: vn?.min ?? 0, |
min: vn?.min ?? 0, |
||||
nutrition: kn, |
nutrition: kn, |
||||
}; |
} |
||||
}), |
}), |
||||
}; |
} |
||||
}); |
}) |
||||
} |
} |
||||
|
|
||||
parseFoodCategory(data: any): StandardItemInterface[] { |
parseFoodCategory(data: any): StandardItemInterface[] { |
||||
if (!data) { |
if (!data) { |
||||
return []; |
return [] |
||||
} |
} |
||||
if (Array.isArray(data) && data.length > 0) { |
if (Array.isArray(data) && data.length > 0) { |
||||
this.calcType = data[0]?.type; |
this.calcType = data[0]?.type |
||||
} |
} |
||||
return data; |
return data |
||||
} |
} |
||||
|
|
||||
onSubmit() { |
onSubmit() { |
||||
if (this.foodCategoryDay.some((s) => !s.name || typeof s.min !== "number" || s.category.length === 0)) { |
if (this.foodCategoryDay.some((s) => !s.name || typeof s.min !== 'number' || s.category.length === 0)) { |
||||
this.msg.error("请设置正确的食物种类及数量标准(日)"); |
this.msg.error('请设置正确的食物种类及数量标准(日)') |
||||
return; |
return |
||||
} |
} |
||||
if (this.foodCategoryWeek.some((s) => !s.name || typeof s.min !== "number" || s.category.length === 0)) { |
if (this.foodCategoryWeek.some((s) => !s.name || typeof s.min !== 'number' || s.category.length === 0)) { |
||||
this.msg.error("请设置正确的食物种类及数量标准(周)"); |
this.msg.error('请设置正确的食物种类及数量标准(周)') |
||||
return; |
return |
||||
} |
} |
||||
if (this.ingredient.some((s) => !s.name || !s.nutritions.some((sn) => sn.nutrition))) { |
if (this.ingredient.some((s) => !s.name || !s.nutritions.some((sn) => sn.nutrition))) { |
||||
this.msg.error("请设置正确的营养标准人群"); |
this.msg.error('请设置正确的营养标准人群') |
||||
return; |
return |
||||
} |
} |
||||
const foodCategoryDay = this.foodCategoryDay; |
const foodCategoryDay = this.foodCategoryDay |
||||
|
|
||||
const foodCategoryWeek = this.foodCategoryWeek; |
|
||||
|
|
||||
const ingredient = this.ingredient.reduce((a, c) => { |
const foodCategoryWeek = this.foodCategoryWeek |
||||
|
let crows: string = '' |
||||
|
const ingredient = this.ingredient.reduce((a, c, idx) => { |
||||
|
const crowsName = (idx === 0 ? '' : ',') + c.name |
||||
|
crows += crowsName |
||||
return { |
return { |
||||
...a, |
...a, |
||||
[c.name]: c.nutritions.reduce((an, cn) => { |
[c.name]: c.nutritions.reduce((an, cn) => { |
||||
const ul = { ul: cn.hasUl ? cn.ul : void 0 }; |
const ul = { ul: cn.hasUl ? cn.ul : void 0 } |
||||
return { |
return { |
||||
...an, |
...an, |
||||
|
// idx,
|
||||
[cn.nutrition]: { |
[cn.nutrition]: { |
||||
min: cn.min, |
min: cn.min, |
||||
max: cn.max, |
max: cn.max, |
||||
...ul, |
...ul, |
||||
}, |
}, |
||||
}; |
} |
||||
}, {} as AnyObject), |
}, {} as AnyObject), |
||||
}; |
} |
||||
}, {} as AnyObject); |
}, {} as AnyObject) |
||||
|
|
||||
this.api.saveStandard({ ...this.state, foodCategoryDay, foodCategoryWeek, ingredient }, true).subscribe((res) => { |
this.api |
||||
this.msg.success(res.desc); |
.saveStandard({ ...this.state, foodCategoryDay, foodCategoryWeek, ingredient, crows }, true) |
||||
this.router.navigate(["/standard/list"]); |
.subscribe((res) => { |
||||
}); |
this.msg.success(res.desc) |
||||
|
this.router.navigate(['/standard/list']) |
||||
|
}) |
||||
} |
} |
||||
|
|
||||
addFoodType(type: string) { |
addFoodType(type: string) { |
||||
const item = type === "day" ? this.foodCategoryDay : this.foodCategoryWeek; |
const item = type === 'day' ? this.foodCategoryDay : this.foodCategoryWeek |
||||
// const withoutSelectType = this.globalEnum.category.find((f) => !item.some((s) => s.type === f.key));
|
// const withoutSelectType = this.globalEnum.category.find((f) => !item.some((s) => s.type === f.key));
|
||||
item.push({ |
item.push({ |
||||
category: [], |
category: [], |
||||
min: 0, |
min: 0, |
||||
max: null, |
max: null, |
||||
name: "", |
name: '', |
||||
type: this.calcType, |
type: this.calcType, |
||||
}); |
}) |
||||
} |
} |
||||
|
|
||||
removeFoodType(type: string, idx: number) { |
removeFoodType(type: string, idx: number) { |
||||
if (type === "day") { |
if (type === 'day') { |
||||
this.foodCategoryDay = this.foodCategoryDay.filter((f, i) => idx !== i); |
this.foodCategoryDay = this.foodCategoryDay.filter((f, i) => idx !== i) |
||||
} else { |
} else { |
||||
this.foodCategoryWeek = this.foodCategoryWeek.filter((f, i) => idx !== i); |
this.foodCategoryWeek = this.foodCategoryWeek.filter((f, i) => idx !== i) |
||||
} |
} |
||||
} |
} |
||||
|
|
||||
addPeopleGroup() { |
addPeopleGroup() { |
||||
this.ingredient.push({ |
this.ingredient.push({ |
||||
name: "", |
name: '', |
||||
nutritions: [], |
nutritions: [], |
||||
}); |
}) |
||||
} |
} |
||||
|
|
||||
removePeopleGroup(idx: number) { |
removePeopleGroup(idx: number) { |
||||
this.ingredient = this.ingredient.filter((_, i) => i !== idx); |
this.ingredient = this.ingredient.filter((_, i) => i !== idx) |
||||
} |
} |
||||
|
|
||||
calcTypeChange() { |
calcTypeChange() { |
||||
console.log("this.calcType", this.calcType); |
console.log('this.calcType', this.calcType) |
||||
this.foodCategoryDay = this.foodCategoryDay.map((i) => ({ ...i, type: this.calcType })); |
this.foodCategoryDay = this.foodCategoryDay.map((i) => ({ ...i, type: this.calcType })) |
||||
this.foodCategoryWeek = this.foodCategoryWeek.map((i) => ({ ...i, type: this.calcType })); |
this.foodCategoryWeek = this.foodCategoryWeek.map((i) => ({ ...i, type: this.calcType })) |
||||
|
} |
||||
|
|
||||
|
moveUp(idx: number) { |
||||
|
const arr = this.ingredient |
||||
|
if (idx > 0 && idx < arr.length) { |
||||
|
;[arr[idx], arr[idx - 1]] = [arr[idx - 1], arr[idx]] |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
moveDown(idx: number) { |
||||
|
const arr = this.ingredient |
||||
|
if (idx >= 0 && idx < arr.length - 1) { |
||||
|
;[arr[idx], arr[idx + 1]] = [arr[idx + 1], arr[idx]] |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
expand(idx: number) { |
||||
|
if (this.expanded.has(idx)) { |
||||
|
this.expanded.delete(idx) |
||||
|
} else { |
||||
|
this.expanded.add(idx) |
||||
|
} |
||||
} |
} |
||||
|
|
||||
addNutrition(idx: number) { |
addNutrition(idx: number) { |
||||
const current = this.ingredient[idx]; |
const current = this.ingredient[idx] |
||||
|
this.expanded.add(idx) |
||||
const withoutSelectNutritions = this.globalEnum.nutrient.find( |
const withoutSelectNutritions = this.globalEnum.nutrient.find( |
||||
(f) => !current.nutritions.some((s) => s.nutrition === f.key) |
(f) => !current.nutritions.some((s) => s.nutrition === f.key), |
||||
); |
) |
||||
current.nutritions.push({ |
current.nutritions.push({ |
||||
nutrition: withoutSelectNutritions?.key ?? "", |
nutrition: withoutSelectNutritions?.key ?? '', |
||||
min: 0, |
min: 0, |
||||
max: 0, |
max: 0, |
||||
hasUl: false, |
hasUl: false, |
||||
}); |
}) |
||||
} |
} |
||||
|
|
||||
removeNutrition(idx: number, nutrition: string) { |
removeNutrition(idx: number, nutrition: string) { |
||||
this.ingredient[idx].nutritions = this.ingredient[idx].nutritions.filter((f) => f.nutrition !== nutrition); |
this.ingredient[idx].nutritions = this.ingredient[idx].nutritions.filter((f) => f.nutrition !== nutrition) |
||||
} |
} |
||||
|
|
||||
ulChange(idx: number, nutrition: string, checked: boolean) { |
ulChange(idx: number, nutrition: string, checked: boolean) { |
||||
this.ingredient[idx].nutritions = this.ingredient[idx].nutritions.map((i) => { |
this.ingredient[idx].nutritions = this.ingredient[idx].nutritions.map((i) => { |
||||
return i.nutrition === nutrition ? { ...i, ul: checked ? 1 : void 0 } : i; |
return i.nutrition === nutrition ? { ...i, ul: checked ? 1 : void 0 } : i |
||||
}); |
}) |
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -0,0 +1,11 @@ |
|||||
|
import { Injectable } from '@angular/core' |
||||
|
import { BehaviorSubject } from 'rxjs' |
||||
|
|
||||
|
@Injectable({ |
||||
|
providedIn: 'root', |
||||
|
}) |
||||
|
export class StandardService { |
||||
|
constructor() {} |
||||
|
|
||||
|
settingData$ = new BehaviorSubject<any>(null) |
||||
|
} |
||||
@ -1,112 +1,96 @@ |
|||||
<div class="body flex flex-col"> |
<div class="body flex flex-col"> |
||||
<div class="head clearfix"> |
<div class="head clearfix"> |
||||
<div class="logo"> |
<div class="logo"> |
||||
<img *ngIf="logo" [attr.src]="'/api/icon/' + logo" /> |
<img *ngIf="logo" [attr.src]="'/api/icon/' + logo" /> |
||||
</div> |
</div> |
||||
<h1 class="title">{{orgName}}食谱营养报告</h1> |
<h1 class="title">{{ orgName }}食谱营养报告</h1> |
||||
<div class="time">{{showTime}}</div> |
<div class="time">{{ showTime }}</div> |
||||
</div> |
</div> |
||||
<div class="mainbox flex flex-1"> |
<div class="mainbox flex flex-1"> |
||||
|
<!-- <div class="boxnav mapc"> |
||||
<!-- <div class="boxnav mapc"> |
|
||||
|
|
||||
</div> --> |
</div> --> |
||||
<div class="flex-1 flex flex-col"> |
<div class="flex-1 flex flex-col"> |
||||
<div class="flex-1 overflow-hidden pb-2"> |
<div class="flex-1 overflow-hidden pb-2"> |
||||
<div class="box"> |
<div class="box"> |
||||
<div class="tit"> |
<div class="tit"> |
||||
今日带量食谱 |
今日带量食谱 |
||||
<ng-container *ngIf="currentMenu"> |
<ng-container *ngIf="currentMenu"> 【{{ currentMenu.name }}】 </ng-container> |
||||
【{{currentMenu.name}}】 |
</div> |
||||
</ng-container> |
<div class="boxnav overflow-hidden" #tableEl> |
||||
</div> |
<table class="w-full"> |
||||
<div class="boxnav overflow-hidden" #tableEl> |
<thead> |
||||
<table class="w-full"> |
<tr> |
||||
<thead> |
<th width="70px"></th> |
||||
<tr> |
<th>菜品名称</th> |
||||
<th width="70px"> |
<th>三低标识</th> |
||||
|
<th *ngFor="let p of peoples"> |
||||
</th> |
<div class="td"> |
||||
<th> |
{{ p }} |
||||
菜品名称 |
</div> |
||||
</th> |
</th> |
||||
<th *ngFor="let p of peoples"> |
</tr> |
||||
<div class="td"> |
</thead> |
||||
{{p}} |
<tbody> |
||||
</div> |
<ng-container *ngFor="let meal of globalEnum.mealType"> |
||||
</th> |
<ng-container *ngIf="dishs[meal.value] as mealDish"> |
||||
</tr> |
<tr *ngFor="let item of mealDish; let first = first"> |
||||
</thead> |
<td *ngIf="first" [attr.rowspan]="mealDish.length"> |
||||
<tbody> |
{{ meal.label }} |
||||
<ng-container *ngFor="let meal of globalEnum.mealType"> |
</td> |
||||
<ng-container *ngIf="dishs[meal.value] as mealDish"> |
<td> |
||||
<tr *ngFor="let item of mealDish;let first = first"> |
<div class="td"> |
||||
|
{{ item.name }} |
||||
<td *ngIf="first" [attr.rowspan]="mealDish.length"> |
</div> |
||||
{{meal.label}} |
</td> |
||||
</td> |
<td>123</td> |
||||
<th> |
<td *ngFor="let p of peoples"> |
||||
<div class="td"> |
<div class="td">{{ item.people[p] }}g</div> |
||||
{{ item.name}} |
</td> |
||||
</div> |
</tr> |
||||
</th> |
</ng-container> |
||||
<th *ngFor="let p of peoples"> |
</ng-container> |
||||
<div class="td"> |
</tbody> |
||||
{{item.people[p]}}g |
</table> |
||||
</div> |
</div> |
||||
</th> |
</div> |
||||
</tr> |
</div> |
||||
</ng-container> |
<div class="flex-1 overflow-hidden pt-2"> |
||||
</ng-container> |
<div class="box"> |
||||
|
<div class="tit">今日食材种类</div> |
||||
</tbody> |
<div class="boxnav"> |
||||
</table> |
<div class="p-4"> |
||||
</div> |
<div nz-row [nzGutter]="[12, 12]"> |
||||
</div> |
<div nz-col nzSpan="6" *ngFor="let type of analysis?.types | keyvalue"> |
||||
</div> |
{{ type.key }} : <b>{{ type.value }}</b> 种 |
||||
<div class="flex-1 overflow-hidden pt-2"> |
</div> |
||||
<div class="box"> |
</div> |
||||
<div class="tit">今日食材种类</div> |
</div> |
||||
<div class="boxnav"> |
</div> |
||||
<div class="p-4"> |
</div> |
||||
<div nz-row [nzGutter]="[12,12]"> |
</div> |
||||
<div nz-col nzSpan="6" *ngFor="let type of analysis?.types | keyvalue"> |
</div> |
||||
{{type.key}} : <b>{{type.value}}</b> 种 |
<div class="w-1/3 pl-4"> |
||||
</div> |
<div class="box"> |
||||
</div> |
<div class="tit flex justify-between items-center"> |
||||
</div> |
<span> 今日营养分析 </span> |
||||
</div> |
<span *ngIf="peoples.length"> |
||||
</div> |
<select [(ngModel)]="people" class="select" (ngModelChange)="getAnalysis()"> |
||||
</div> |
<option *ngFor="let p of peoples" [value]="p"> |
||||
</div> |
{{ p }} |
||||
<div class="w-1/3 pl-4"> |
</option> |
||||
<div class="box"> |
</select> |
||||
<div class="tit flex justify-between items-center"> |
</span> |
||||
<span> |
</div> |
||||
今日营养分析 |
<div class="boxnav overflow-hidden" #nutritionEl> |
||||
</span> |
<div class="p-4"> |
||||
<span *ngIf="peoples.length"> |
<nz-spin [nzSpinning]="analysisLoading"> |
||||
<select [(ngModel)]="people" class="select" (ngModelChange)="getAnalysis()"> |
<lib-nutrition-table *ngIf="analysis" [dark]="true" [nutritions]="analysis.ingredient"> |
||||
<option *ngFor="let p of peoples" [value]="p"> |
</lib-nutrition-table> |
||||
{{p}} |
</nz-spin> |
||||
</option> |
</div> |
||||
</select> |
</div> |
||||
</span> |
</div> |
||||
</div> |
</div> |
||||
<div class="boxnav overflow-hidden" #nutritionEl> |
</div> |
||||
<div class="p-4"> |
</div> |
||||
<nz-spin [nzSpinning]="analysisLoading"> |
|
||||
<lib-nutrition-table *ngIf="analysis" |
|
||||
[dark]="true" |
|
||||
[nutritions]="analysis.ingredient"> |
|
||||
</lib-nutrition-table> |
|
||||
</nz-spin> |
|
||||
</div> |
|
||||
</div> |
|
||||
</div> |
|
||||
</div> |
|
||||
|
|
||||
|
|
||||
|
|
||||
</div> |
|
||||
</div> |
|
||||
|
|||||
@ -1,184 +1,186 @@ |
|||||
import { AfterViewInit, Component, ElementRef, Renderer2, ViewChild } from "@angular/core"; |
import { AfterViewInit, Component, ElementRef, Renderer2, ViewChild } from '@angular/core' |
||||
import { ApiService } from "@cdk/services"; |
import { ApiService } from '@cdk/services' |
||||
import { format } from "date-fns"; |
import { format } from 'date-fns' |
||||
import { Subject, Subscription, finalize, interval, takeUntil } from "rxjs"; |
import { Subject, Subscription, finalize, interval, takeUntil } from 'rxjs' |
||||
|
|
||||
interface MenuDisplayItem { |
interface MenuDisplayItem { |
||||
name: string; |
name: string |
||||
id: number; |
id: number |
||||
} |
} |
||||
|
|
||||
const changeTime = 1000 * 60 * 3; |
const changeTime = 1000 * 60 * 3 |
||||
|
|
||||
@Component({ |
@Component({ |
||||
selector: "app-data-vis", |
selector: 'app-data-vis', |
||||
templateUrl: "./data-vis.component.html", |
templateUrl: './data-vis.component.html', |
||||
styleUrls: ["./data-vis.component.less"], |
styleUrls: ['./data-vis.component.less'], |
||||
}) |
}) |
||||
export class DataVisComponent implements AfterViewInit { |
export class DataVisComponent implements AfterViewInit { |
||||
constructor(private api: ApiService, private rd2: Renderer2) {} |
constructor(private api: ApiService, private rd2: Renderer2) {} |
||||
|
|
||||
@ViewChild("tableEl") tableEl!: ElementRef<HTMLElement>; |
@ViewChild('tableEl') tableEl!: ElementRef<HTMLElement> |
||||
|
|
||||
@ViewChild("nutritionEl") nutritionEl!: ElementRef<HTMLElement>; |
@ViewChild('nutritionEl') nutritionEl!: ElementRef<HTMLElement> |
||||
|
|
||||
destroy$ = new Subject(); |
destroy$ = new Subject() |
||||
|
|
||||
showTime: string = ""; |
showTime: string = '' |
||||
|
|
||||
orgName = ""; |
orgName = '' |
||||
|
|
||||
dishs: { |
dishs: { |
||||
[K: string]: any[]; |
[K: string]: any[] |
||||
} = {}; |
} = {} |
||||
|
|
||||
peoples: string[] = []; |
peoples: string[] = [] |
||||
|
|
||||
globalEnum = this.api.globalEnum; |
globalEnum = this.api.globalEnum |
||||
|
|
||||
analysisLoading = false; |
analysisLoading = false |
||||
|
|
||||
analysis: any; |
analysis: any |
||||
|
|
||||
scroll: Record<string, number> = {}; |
scroll: Record<string, number> = {} |
||||
|
|
||||
people = ""; |
people = '' |
||||
|
|
||||
menuId?: string; |
menuId?: string |
||||
|
|
||||
logo = ""; |
logo = '' |
||||
|
|
||||
menus: MenuDisplayItem[] = []; |
menus: MenuDisplayItem[] = [] |
||||
|
|
||||
currentMenu: MenuDisplayItem | null = null; |
currentMenu: MenuDisplayItem | null = null |
||||
|
|
||||
lastTime: number = 0; |
lastTime: number = 0 |
||||
|
|
||||
ngOnInit(): void { |
ngOnInit(): void { |
||||
this.api.getOrgInfo().subscribe((res) => { |
this.api.getOrgInfo().subscribe((res) => { |
||||
const account = this.api.account; |
const account = this.api.account |
||||
|
|
||||
this.orgName = account?.vender?.name ?? ""; |
this.orgName = account?.vender?.name ?? '' |
||||
this.logo = account?.vender?.icon ?? ""; |
this.logo = account?.vender?.icon ?? '' |
||||
}); |
}) |
||||
|
|
||||
interval(1000) |
interval(1000) |
||||
.pipe(takeUntil(this.destroy$)) |
.pipe(takeUntil(this.destroy$)) |
||||
.subscribe(() => { |
.subscribe(() => { |
||||
const now = new Date(); |
const now = new Date() |
||||
this.showTime = format(new Date(), "yyyy-MM-dd HH:mm:ss"); |
this.showTime = format(new Date(), 'yyyy-MM-dd HH:mm:ss') |
||||
if (now.getTime() - this.lastTime > changeTime) { |
if (now.getTime() - this.lastTime > changeTime) { |
||||
const currentIndex = this.menus.findIndex((f) => f.id === this.currentMenu?.id); |
const currentIndex = this.menus.findIndex((f) => f.id === this.currentMenu?.id) |
||||
let idx = currentIndex + 1; |
let idx = currentIndex + 1 |
||||
if (idx > this.menus.length - 1) { |
if (idx > this.menus.length - 1) { |
||||
idx = 0; |
idx = 0 |
||||
|
} |
||||
|
this.currentMenu = this.menus[idx] |
||||
|
if (this.currentMenu) { |
||||
|
this.getDataVisData(this.currentMenu.id) |
||||
|
this.lastTime = now.getTime() |
||||
} |
} |
||||
this.currentMenu = this.menus[idx]; |
|
||||
this.getDataVisData(this.currentMenu.id); |
|
||||
this.lastTime = now.getTime(); |
|
||||
} |
} |
||||
}); |
}) |
||||
|
|
||||
this.api.getCurrentDayDataVisList().subscribe((r) => { |
this.api.getCurrentDayDataVisList().subscribe((r) => { |
||||
if (Array.isArray(r.body)) { |
if (Array.isArray(r.body)) { |
||||
this.menus = r.body; |
this.menus = r.body |
||||
} |
} |
||||
}); |
}) |
||||
} |
} |
||||
|
|
||||
ngAfterViewInit(): void {} |
ngAfterViewInit(): void {} |
||||
|
|
||||
ngOnDestroy(): void { |
ngOnDestroy(): void { |
||||
this.destroy$.next(null); |
this.destroy$.next(null) |
||||
this.destroy$.complete(); |
this.destroy$.complete() |
||||
} |
} |
||||
|
|
||||
getDataVisData(id: number) { |
getDataVisData(id: number) { |
||||
this.analysis = null; |
this.analysis = null |
||||
this.peoples = []; |
this.peoples = [] |
||||
this.people = ""; |
this.people = '' |
||||
this.dishs = {}; |
this.dishs = {} |
||||
this.scroll = {}; |
this.scroll = {} |
||||
|
|
||||
this.api.getMenuDataVis(id).subscribe((res) => { |
this.api.getMenuDataVis(id).subscribe((res) => { |
||||
const dishs = res.body; |
const dishs = res.body |
||||
if (Array.isArray(dishs)) { |
if (Array.isArray(dishs)) { |
||||
this.peoples = Object.keys(dishs?.[0]?.ingredient?.[0]?.value); |
this.peoples = Object.keys(dishs?.[0]?.ingredient?.[0]?.value) |
||||
this.people = this.peoples[0]; |
this.people = this.peoples[0] |
||||
if (!this.peoples) { |
if (!this.peoples) { |
||||
console.error("dishs?.[0]?.ingredient?.[0]?.value 数据错误:", dishs); |
console.error('dishs?.[0]?.ingredient?.[0]?.value 数据错误:', dishs) |
||||
return; |
return |
||||
} |
} |
||||
this.menuId = dishs?.[0]?.menu; |
this.menuId = dishs?.[0]?.menu |
||||
this.getAnalysis(); |
this.getAnalysis() |
||||
|
|
||||
dishs.forEach((i: any) => { |
dishs.forEach((i: any) => { |
||||
// 把每个食材按照不同的人群将重量加起来
|
// 把每个食材按照不同的人群将重量加起来
|
||||
this.peoples.forEach((people) => { |
this.peoples.forEach((people) => { |
||||
const foods = i.ingredient as any[]; |
const foods = i.ingredient as any[] |
||||
const c = foods.reduce((a, c) => { |
const c = foods.reduce((a, c) => { |
||||
return a + c.value[people]; |
return a + c.value[people] |
||||
}, 0); |
}, 0) |
||||
if (!i.people) { |
if (!i.people) { |
||||
i.people = {}; |
i.people = {} |
||||
} |
} |
||||
i.people[people] = c; |
i.people[people] = c |
||||
}); |
}) |
||||
|
|
||||
if (Array.isArray(this.dishs[i.meal])) { |
if (Array.isArray(this.dishs[i.meal])) { |
||||
this.dishs[i.meal].push(i); |
this.dishs[i.meal].push(i) |
||||
} else { |
} else { |
||||
this.dishs[i.meal] = [i]; |
this.dishs[i.meal] = [i] |
||||
} |
} |
||||
}); |
}) |
||||
setTimeout(() => { |
setTimeout(() => { |
||||
this.autoScroll(this.tableEl.nativeElement, "1"); |
this.autoScroll(this.tableEl.nativeElement, '1') |
||||
}, 1000); |
}, 1000) |
||||
} |
} |
||||
}); |
}) |
||||
} |
} |
||||
|
|
||||
scrollSubs$?: Subscription; |
scrollSubs$?: Subscription |
||||
|
|
||||
autoScroll(el: HTMLElement, scroll: string) { |
autoScroll(el: HTMLElement, scroll: string) { |
||||
this.scrollSubs$?.unsubscribe(); |
this.scrollSubs$?.unsubscribe() |
||||
const child = el.children[0]; |
const child = el.children[0] |
||||
if (!child) { |
if (!child) { |
||||
return; |
return |
||||
} |
} |
||||
const elHeight = el.clientHeight; |
const elHeight = el.clientHeight |
||||
const childHeight = child.clientHeight; |
const childHeight = child.clientHeight |
||||
if (childHeight <= elHeight) { |
if (childHeight <= elHeight) { |
||||
return; |
return |
||||
} |
} |
||||
this.scrollSubs$ = interval(60) |
this.scrollSubs$ = interval(60) |
||||
.pipe(takeUntil(this.destroy$)) |
.pipe(takeUntil(this.destroy$)) |
||||
.subscribe(() => { |
.subscribe(() => { |
||||
this.scroll[scroll] = (this.scroll[scroll] ?? 0) + 1; |
this.scroll[scroll] = (this.scroll[scroll] ?? 0) + 1 |
||||
const paddingBottom = 100; |
const paddingBottom = 100 |
||||
if (this.scroll[scroll] - paddingBottom > childHeight - el.clientHeight) { |
if (this.scroll[scroll] - paddingBottom > childHeight - el.clientHeight) { |
||||
this.scroll[scroll] = 0; |
this.scroll[scroll] = 0 |
||||
} |
} |
||||
this.rd2.setStyle(child, "transform", `translateY(-${this.scroll[scroll]}px)`); |
this.rd2.setStyle(child, 'transform', `translateY(-${this.scroll[scroll]}px)`) |
||||
}); |
}) |
||||
} |
} |
||||
|
|
||||
getAnalysis() { |
getAnalysis() { |
||||
if (!this.menuId) { |
if (!this.menuId) { |
||||
return; |
return |
||||
} |
} |
||||
this.api |
this.api |
||||
.getAnalysis(this.menuId, void 0, this.people) |
.getAnalysis(this.menuId, void 0, this.people) |
||||
.pipe( |
.pipe( |
||||
finalize(() => { |
finalize(() => { |
||||
this.analysisLoading = false; |
this.analysisLoading = false |
||||
}) |
}), |
||||
) |
) |
||||
.subscribe((res) => { |
.subscribe((res) => { |
||||
this.analysis = res.body; |
this.analysis = res.body |
||||
// setTimeout(() => {
|
// setTimeout(() => {
|
||||
// this.autoScroll(this.nutritionEl.nativeElement, "2");
|
// this.autoScroll(this.nutritionEl.nativeElement, "2");
|
||||
// }, 1000);
|
// }, 1000);
|
||||
}); |
}) |
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -1,158 +1,116 @@ |
|||||
<app-page> |
<app-page> |
||||
<nz-card [nzTitle]="orgInfoTpl" *ngIf="account?.vender as org"> |
<nz-card [nzTitle]="orgInfoTpl" *ngIf="account?.vender as org"> |
||||
<ng-template #orgInfoTpl> |
<ng-template #orgInfoTpl> |
||||
<span> |
<span> 单位基础信息 </span> |
||||
单位基础信息 |
<small class="ml-2"> |
||||
</span> |
<a (click)="updateOrg()"> 编辑 </a> |
||||
<small class="ml-2"> |
</small> |
||||
<a (click)="updateOrg()"> |
</ng-template> |
||||
编辑 |
<div nz-form> |
||||
</a> |
<nz-form-item> |
||||
</small> |
<nz-form-label> 单位名称 </nz-form-label> |
||||
</ng-template> |
<nz-form-control> |
||||
<div nz-form> |
{{ org.name }} |
||||
<nz-form-item> |
</nz-form-control> |
||||
<nz-form-label> |
</nz-form-item> |
||||
单位名称 |
<nz-form-item> |
||||
</nz-form-label> |
<nz-form-label> 单位Logo </nz-form-label> |
||||
<nz-form-control> |
<nz-form-control> |
||||
{{org.name}} |
<div class="w-20 h-20" *ngIf="org.icon"> |
||||
</nz-form-control> |
<img [src]="'/api/icon/' + org.icon" class="w-full h-full" /> |
||||
</nz-form-item> |
</div> |
||||
<nz-form-item> |
</nz-form-control> |
||||
<nz-form-label> |
</nz-form-item> |
||||
单位Logo |
<nz-form-item> |
||||
</nz-form-label> |
<nz-form-label> 地址 </nz-form-label> |
||||
<nz-form-control> |
<nz-form-control> |
||||
<div class="w-20 h-20" *ngIf="org.icon"> |
{{ org.address ?? '-' }} |
||||
<img [src]="'/api/icon/' + org.icon" class=" w-full h-full" /> |
</nz-form-control> |
||||
</div> |
</nz-form-item> |
||||
</nz-form-control> |
<nz-form-item> |
||||
</nz-form-item> |
<nz-form-label> 联系人 </nz-form-label> |
||||
<nz-form-item> |
<nz-form-control> |
||||
<nz-form-label> |
{{ org.contacts ?? '-' }} |
||||
地址 |
</nz-form-control> |
||||
</nz-form-label> |
</nz-form-item> |
||||
<nz-form-control> |
<nz-form-item> |
||||
{{org.address ?? '-'}} |
<nz-form-label> 联系电话 </nz-form-label> |
||||
</nz-form-control> |
<nz-form-control> |
||||
</nz-form-item> |
{{ org.phone ?? '-' }} |
||||
<nz-form-item> |
</nz-form-control> |
||||
<nz-form-label> |
</nz-form-item> |
||||
联系人 |
<nz-form-item> |
||||
</nz-form-label> |
<nz-form-label> 邮箱 </nz-form-label> |
||||
<nz-form-control> |
<nz-form-control> |
||||
{{org.contacts ?? '-'}} |
{{ org.email ?? '-' }} |
||||
</nz-form-control> |
</nz-form-control> |
||||
</nz-form-item> |
</nz-form-item> |
||||
<nz-form-item> |
</div> |
||||
<nz-form-label> |
</nz-card> |
||||
联系电话 |
|
||||
</nz-form-label> |
|
||||
<nz-form-control> |
|
||||
{{org.phone ?? '-'}} |
|
||||
</nz-form-control> |
|
||||
</nz-form-item> |
|
||||
<nz-form-item> |
|
||||
<nz-form-label> |
|
||||
邮箱 |
|
||||
</nz-form-label> |
|
||||
<nz-form-control> |
|
||||
{{org.email ?? '-'}} |
|
||||
</nz-form-control> |
|
||||
</nz-form-item> |
|
||||
</div> |
|
||||
</nz-card> |
|
||||
|
|
||||
<nz-card [nzTitle]="orgInfoTpl" *ngIf="account?.vender as org" class="mt-4"> |
<nz-card [nzTitle]="orgInfoTpl" *ngIf="account?.vender as org" class="mt-4"> |
||||
<ng-template #orgInfoTpl> |
<ng-template #orgInfoTpl> |
||||
<span> |
<span> 账号信息 </span> |
||||
账号信息 |
<small class="ml-2 text-slate-500"> 仅支持主账号操作 </small> |
||||
</span> |
</ng-template> |
||||
<small class="ml-2 text-slate-500"> |
<div nz-form> |
||||
仅支持主账号操作 |
<nz-form-item> |
||||
</small> |
<nz-form-label> 账号 </nz-form-label> |
||||
</ng-template> |
<nz-form-control> |
||||
<div nz-form> |
{{ account?.uid }} |
||||
<nz-form-item> |
<a class="ml-4" (click)="updateAccount('uid', updateAccountInfoTpl)"> 修改账号 </a> |
||||
<nz-form-label> |
</nz-form-control> |
||||
账号 |
</nz-form-item> |
||||
</nz-form-label> |
|
||||
<nz-form-control> |
|
||||
{{account?.uid}} |
|
||||
<a class="ml-4" (click)="updateAccount('uid',updateAccountInfoTpl)"> |
|
||||
修改账号 |
|
||||
</a> |
|
||||
</nz-form-control> |
|
||||
</nz-form-item> |
|
||||
|
|
||||
<nz-form-item> |
<nz-form-item> |
||||
<nz-form-label> |
<nz-form-label> 密码 </nz-form-label> |
||||
密码 |
<nz-form-control> |
||||
</nz-form-label> |
<a (click)="changePassword(changePasswordTpl)"> 修改密码 </a> |
||||
<nz-form-control> |
</nz-form-control> |
||||
<a (click)="changePassword(changePasswordTpl)"> |
</nz-form-item> |
||||
修改密码 |
<nz-form-item> |
||||
</a> |
<nz-form-label> 账号到期时间 </nz-form-label> |
||||
</nz-form-control> |
<nz-form-control> |
||||
</nz-form-item> |
{{ org?.expire | date : 'yyyy-MM-dd' }} |
||||
<nz-form-item> |
<a class="ml-4" (click)="updateAccount(org?.expire, updateAccountInfoTpl)"> 续费 </a> |
||||
<nz-form-label> |
</nz-form-control> |
||||
账号到期时间 |
</nz-form-item> |
||||
</nz-form-label> |
</div> |
||||
<nz-form-control> |
</nz-card> |
||||
{{org?.expire | date:'yyyy-MM-dd'}} |
|
||||
<a class="ml-4" (click)="updateAccount(org?.expire,updateAccountInfoTpl)"> |
|
||||
续费 |
|
||||
</a> |
|
||||
</nz-form-control> |
|
||||
</nz-form-item> |
|
||||
|
|
||||
</div> |
|
||||
</nz-card> |
|
||||
</app-page> |
</app-page> |
||||
|
|
||||
<ng-template #updateAccountInfoTpl> |
<ng-template #updateAccountInfoTpl> |
||||
<div *ngIf="account?.vender as org" class=" text-base text-blue-500"> |
<div *ngIf="account?.vender as org" class="text-base text-blue-500"> |
||||
<span> |
<!-- <span> |
||||
{{org.contacts ?? '-'}} |
{{org.contacts ?? '-'}} |
||||
</span> |
</span> --> |
||||
<span> |
<span> 028-85463212 </span> |
||||
{{org.phone ?? '-'}} |
</div> |
||||
</span> |
|
||||
</div> |
|
||||
</ng-template> |
</ng-template> |
||||
|
|
||||
<ng-template #changePasswordTpl> |
<ng-template #changePasswordTpl> |
||||
<form nz-form [formGroup]="pwdForm"> |
<form nz-form [formGroup]="pwdForm"> |
||||
<nz-form-item> |
<nz-form-item> |
||||
<nz-form-label nzSpan="6" [nzRequired]="true"> |
<nz-form-label nzSpan="6" [nzRequired]="true"> 原密码 </nz-form-label> |
||||
原密码 |
<nz-form-control [nzErrorTip]="errTipTpl" nzSpan="12"> |
||||
</nz-form-label> |
<input nz-input type="password" placeholder="请输入原密码" formControlName="oldPwd" /> |
||||
<nz-form-control [nzErrorTip]="errTipTpl" nzSpan="12"> |
</nz-form-control> |
||||
<input nz-input type="password" placeholder="请输入原密码" formControlName="oldPwd" /> |
</nz-form-item> |
||||
</nz-form-control> |
<nz-form-item> |
||||
</nz-form-item> |
<nz-form-label nzSpan="6" [nzRequired]="true"> 新密码 </nz-form-label> |
||||
<nz-form-item> |
<nz-form-control [nzErrorTip]="errTipTpl" nzSpan="12"> |
||||
<nz-form-label nzSpan="6" [nzRequired]="true"> |
<input nz-input type="password" placeholder="请输入新密码" formControlName="newPwd" /> |
||||
新密码 |
</nz-form-control> |
||||
</nz-form-label> |
</nz-form-item> |
||||
<nz-form-control [nzErrorTip]="errTipTpl" nzSpan="12"> |
<nz-form-item> |
||||
<input nz-input type="password" placeholder="请输入新密码" formControlName="newPwd" /> |
<nz-form-label nzSpan="6" [nzRequired]="true"> 确认密码 </nz-form-label> |
||||
</nz-form-control> |
<nz-form-control [nzErrorTip]="errTipTpl" nzSpan="12"> |
||||
</nz-form-item> |
<input nz-input type="password" placeholder="请再次输入新密码" formControlName="rePwd" /> |
||||
<nz-form-item> |
</nz-form-control> |
||||
<nz-form-label nzSpan="6" [nzRequired]="true"> |
</nz-form-item> |
||||
确认密码 |
</form> |
||||
</nz-form-label> |
|
||||
<nz-form-control [nzErrorTip]="errTipTpl" nzSpan="12"> |
|
||||
<input nz-input type="password" placeholder="请再次输入新密码" formControlName="rePwd" /> |
|
||||
</nz-form-control> |
|
||||
</nz-form-item> |
|
||||
</form> |
|
||||
</ng-template> |
</ng-template> |
||||
|
|
||||
|
|
||||
<ng-template #errTipTpl let-control> |
<ng-template #errTipTpl let-control> |
||||
<form-error-tips [control]="control"></form-error-tips> |
<form-error-tips [control]="control"></form-error-tips> |
||||
</ng-template> |
</ng-template> |
||||
|
|||||
Loading…
Reference in new issue