Browse Source

大屏轮播

main
kkerwin 1 year ago
parent
commit
24fb762a2e
  1. 92
      projects/admin/src/app/components/food-form/food-form.component.ts
  2. 14
      projects/admin/src/app/pages/ingredients/ingredient-form/ingredient-form.component.ts
  3. 2
      projects/client/src/app/pages/data-vis/data-vis.component.html
  4. 126
      projects/client/src/app/pages/data-vis/data-vis.component.ts
  5. 155
      projects/client/src/app/pages/ingredients/ingredient-form/ingredient-form.component.ts

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

@ -1,95 +1,95 @@
import { ApiService } from "@cdk/services";
import { Component, Input, OnInit } from "@angular/core";
import { FormArray, FormBuilder, FormGroup } from "@angular/forms";
import { Utils } from "@cdk/utils";
import { FormValidators } from "@cdk/validators";
import { NzMessageService } from "ng-zorro-antd/message";
import { ApiService } from '@cdk/services'
import { Component, Input, OnInit } from '@angular/core'
import { FormArray, FormBuilder, FormGroup } from '@angular/forms'
import { Utils } from '@cdk/utils'
import { FormValidators } from '@cdk/validators'
import { NzMessageService } from 'ng-zorro-antd/message'
@Component({
selector: "app-food-form",
templateUrl: "./food-form.component.html",
styleUrls: ["./food-form.component.less"],
selector: 'app-food-form',
templateUrl: './food-form.component.html',
styleUrls: ['./food-form.component.less'],
})
export class FoodFormComponent implements OnInit {
constructor(private fb: FormBuilder, private api: ApiService, private msg: NzMessageService) {}
formGroup!: FormGroup;
formGroup!: FormGroup
@Input() food: any;
@Input() food: any
public globalEnum = this.api.globalEnum;
public globalEnum = this.api.globalEnum
get nutrition(): FormArray {
return this.formGroup.get("_nutrition") as FormArray;
return this.formGroup.get('_nutrition') as FormArray
}
ngOnInit(): void {
this.formGroup = this.fb.group({
key: this.fb.control("", [FormValidators.required("请输入食材编号")]),
name: this.fb.control("", [FormValidators.required("请输入食材名称")]),
type: this.fb.control("", [FormValidators.required("请选择食材类型")]),
nutrient: this.fb.control(null, [FormValidators.required("请输入营养素")]),
key: this.fb.control('', [FormValidators.required('请输入食材编号')]),
name: this.fb.control('', [FormValidators.required('请输入食材名称')]),
type: this.fb.control('', [FormValidators.required('请选择食材类型')]),
nutrient: this.fb.control(null, [FormValidators.required('请输入营养素')]),
_nutrition: this.fb.array([], []),
});
})
if (this.food) {
this.formGroup.patchValue(this.food);
this.formGroup.get("key")?.disable();
this.formGroup.patchValue(this.food)
this.formGroup.get('key')?.disable()
this.food.nutrientArr?.forEach((n: any) => {
this.createNutrition(n);
});
this.createNutrition(n)
})
}
}
nutritionChange(v: string, idx: number) {
const nutrient = this.globalEnum.nutrient.find((f) => f.key === v);
const nutrient = this.globalEnum.nutrient.find((f) => f.key === v)
if (this.nutrition.value?.filter((s: any) => s.nutritionName === nutrient?.key).length < 2) {
this.nutrition.at(idx).patchValue({
measurement: nutrient?.measurement,
});
})
} else {
this.msg.error("重复的营养素");
this.msg.error('重复的营养素')
this.nutrition.at(idx).patchValue(
{
nutritionName: "",
measurement: "",
nutritionName: '',
measurement: '',
},
{ emitEvent: false }
);
{ emitEvent: false },
)
}
}
createNutrition(v?: any) {
this.nutrition.push(
this.fb.group({
nutritionName: this.fb.control(v?.key ?? ""),
nutritionName: this.fb.control(v?.key ?? ''),
nutritionNum: this.fb.control(v?.value ?? 0),
measurement: this.fb.control(v?.measurement ?? ""),
})
);
const nutrient = this.formGroup.get("nutrient");
measurement: this.fb.control(v?.measurement ?? ''),
}),
)
const nutrient = this.formGroup.get('nutrient')
if (!nutrient?.value) {
nutrient?.patchValue({});
nutrient?.patchValue({})
}
}
removeNutrition(idx: number) {
this.nutrition.removeAt(idx);
this.nutrition.removeAt(idx)
}
public getValues() {
let values = null;
let values = null
if (Utils.validateFormGroup(this.formGroup)) {
const { _nutrition, key, name, type } = this.formGroup.getRawValue();
let nutrient = Object.create(null);
const { _nutrition, key, name, type } = this.formGroup.getRawValue()
let nutrient = Object.create(null)
if (Array.isArray(_nutrition)) {
for (const n of _nutrition) {
let num = Number(n.nutritionNum);
if (!n.nutritionName || !num) {
this.msg.error("请输入正确的营养素");
return;
let num = Number(n.nutritionNum)
if (!n.nutritionName) {
this.msg.error('请选择正确的营养素')
return
}
nutrient[n.nutritionName] = num;
nutrient[n.nutritionName] = num
}
}
values = {
@ -97,8 +97,8 @@ export class FoodFormComponent implements OnInit {
name,
type,
nutrient,
};
}
return values;
}
return values
}
}

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

@ -9,7 +9,7 @@ import { OptionItemInterface } from '@cdk/types'
import { NzDrawerService } from 'ng-zorro-antd/drawer'
import { NzMessageService } from 'ng-zorro-antd/message'
import { NzModalService } from 'ng-zorro-antd/modal'
import { forkJoin } from 'rxjs'
import { forkJoin, lastValueFrom } from 'rxjs'
@Component({
selector: 'app-ingredient-form',
@ -142,17 +142,17 @@ export class IngredientFormComponent implements OnInit {
nzContent: ConfirmIngredientComponent,
nzData: this.menuItem,
nzWidth: 650,
nzOnOk: () => {
nzOnOk: async () => {
const { mealDishList } = this.menuDish
this.api
.saveMenuDist({
const res = await lastValueFrom(
this.api.saveMenuDist({
menuIds: String(this.id)?.split(','),
dishes: this.formatData(mealDishList),
})
.subscribe((res) => {
}),
)
this.msg.success(res.desc)
this.router.navigate(['/ingredient/item/list'])
})
},
})
}

2
projects/client/src/app/pages/data-vis/data-vis.component.html

@ -90,7 +90,7 @@
<div class="tit flex justify-between items-center">
<span> 今日营养分析 </span>
<span *ngIf="peoples.length">
<select [(ngModel)]="people" class="select" (ngModelChange)="getAnalysis()">
<select [(ngModel)]="people" class="select" (ngModelChange)="peopleChange()">
<option *ngFor="let p of peoples" [value]="p">
{{ p }}
</option>

126
projects/client/src/app/pages/data-vis/data-vis.component.ts

@ -10,7 +10,8 @@ interface MenuDisplayItem {
id: number
}
const changeTime = 1000 * 60 * 3
const menuChangeTime = 1000 * 60 * 3
const peopleChangeTime = 1000 * 10
@Component({
selector: 'app-data-vis',
@ -58,12 +59,18 @@ export class DataVisComponent implements AfterViewInit {
currentMenu: MenuDisplayItem | null = null
lastTime: number = 0
menuChangeLastTime: number = 0
peopleChangeLastTime: number = 0
weekdayMap = weekdayMap
scrollFlag = true
dishCache = new Map<string, any>()
analysisCache = new Map<string, any>()
ngOnInit(): void {
this.api.getOrgInfo().subscribe((res) => {
const account = this.api.account
@ -76,7 +83,8 @@ export class DataVisComponent implements AfterViewInit {
.subscribe(() => {
const now = new Date()
this.showTime = format(new Date(), 'yyyy-MM-dd HH:mm:ss')
if (now.getTime() - this.lastTime > changeTime) {
if (now.getTime() - this.menuChangeLastTime > menuChangeTime) {
const currentIndex = this.menus.findIndex((f) => f.id === this.currentMenu?.id)
let idx = currentIndex + 1
if (idx > this.menus.length - 1) {
@ -84,8 +92,25 @@ export class DataVisComponent implements AfterViewInit {
}
this.currentMenu = this.menus[idx]
if (this.currentMenu) {
this.lastTime = now.getTime()
this.getDataVisData(this.currentMenu.id)
this.menuChangeLastTime = now.getTime()
this.getDishData(this.currentMenu.id)
}
}
if (now.getTime() - this.peopleChangeLastTime > peopleChangeTime) {
const currentPeopleIndex = this.peoples.findIndex((f) => f === this.people)
if (this.peoples.length > 1) {
let idx = currentPeopleIndex + 1
if (idx > this.peoples.length - 1) {
idx = 0
}
this.people = this.peoples[idx]
} else if (this.peoples.length === 1) {
this.people = this.peoples[0]
}
if (this.people) {
this.peopleChangeLastTime = now.getTime()
this.getAnalysis()
}
}
})
@ -107,13 +132,6 @@ export class DataVisComponent implements AfterViewInit {
})
}
ngAfterViewInit(): void {}
ngOnDestroy(): void {
this.destroy$.next(null)
this.destroy$.complete()
}
getMenuListByDay() {
if (!this.day) {
this.msg.error('请选择星期')
@ -122,15 +140,11 @@ export class DataVisComponent implements AfterViewInit {
this.api.getMenusByDay(this.day).subscribe((res) => {
this.menus = res.body
//重置轮播时间
this.lastTime = new Date('2023-01-01').getTime()
this.resetAutoPlay()
})
}
dayChange() {
this.getMenuListByDay()
}
getDataVisData(id: number) {
getDishData(id: number) {
this.analysis = null
this.peoples = []
this.people = ''
@ -145,13 +159,15 @@ export class DataVisComponent implements AfterViewInit {
const dishs = res.body
if (Array.isArray(dishs)) {
this.peoples = Object.keys(dishs?.[0]?.ingredient?.[0]?.value)
this.people = this.peoples[0]
// this.people = this.peoples[0]
if (!this.peoples) {
this.msg.error('没有找到当前食谱适用的人群')
console.error('dishs?.[0]?.ingredient?.[0]?.value 数据错误:', dishs)
return
}
this.peopleChangeLastTime = 0
this.menuId = dishs?.[0]?.menu
this.getAnalysis()
// this.getAnalysis()
dishs.forEach((i: any) => {
// 把每个食材按照不同的人群将重量加起来
@ -180,6 +196,57 @@ export class DataVisComponent implements AfterViewInit {
})
}
ngAfterViewInit(): void {}
ngOnDestroy(): void {
this.destroy$.next(null)
this.destroy$.complete()
}
resetAutoPlay() {
this.menuChangeLastTime = 0
this.peopleChangeLastTime = 0
}
resetData() {
this.analysis = null
this.menus = []
this.people = ''
this.peoples = []
this.dishs = {}
}
dayChange() {
this.resetData()
this.getMenuListByDay()
}
peopleChange() {
this.peopleChangeLastTime = this.peopleChangeLastTime + peopleChangeTime
this.analysis = null
this.getAnalysis()
}
getAnalysis() {
if (!this.menuId) {
return
}
this.api
.getAnalysis(this.menuId, this.day, this.people)
.pipe(
finalize(() => {
this.analysisLoading = false
}),
)
.subscribe((res) => {
this.analysis = res.body
// setTimeout(() => {
// this.autoScroll(this.nutritionEl.nativeElement, "2");
// }, 1000);
})
}
scrollSubs$?: Subscription
@HostListener('window:resize')
@ -220,23 +287,4 @@ export class DataVisComponent implements AfterViewInit {
},
})
}
getAnalysis() {
if (!this.menuId) {
return
}
this.api
.getAnalysis(this.menuId, this.day, this.people)
.pipe(
finalize(() => {
this.analysisLoading = false
}),
)
.subscribe((res) => {
this.analysis = res.body
// setTimeout(() => {
// this.autoScroll(this.nutritionEl.nativeElement, "2");
// }, 1000);
})
}
}

155
projects/client/src/app/pages/ingredients/ingredient-form/ingredient-form.component.ts

@ -1,19 +1,19 @@
import { Component, OnInit, ViewChild } from "@angular/core";
import { ActivatedRoute, Router } from "@angular/router";
import { ConfirmIngredientComponent } from "@cdk/ingredient/confirm-ingredient/confirm-ingredient.component";
import { IngredientAnalysisComponent } from "@cdk/ingredient/ingredient-analysis/ingredient-analysis.component";
import { DishInterface, IngredientDishComponent } from "@cdk/ingredient/ingredient-dish/ingredient-dish.component";
import { ApiService } from "@cdk/services";
import { OptionItemInterface } from "@cdk/types";
import { NzDrawerService } from "ng-zorro-antd/drawer";
import { NzMessageService } from "ng-zorro-antd/message";
import { NzModalService } from "ng-zorro-antd/modal";
import { forkJoin } from "rxjs";
import { Component, OnInit, ViewChild } from '@angular/core'
import { ActivatedRoute, Router } from '@angular/router'
import { ConfirmIngredientComponent } from '@cdk/ingredient/confirm-ingredient/confirm-ingredient.component'
import { IngredientAnalysisComponent } from '@cdk/ingredient/ingredient-analysis/ingredient-analysis.component'
import { DishInterface, IngredientDishComponent } from '@cdk/ingredient/ingredient-dish/ingredient-dish.component'
import { ApiService } from '@cdk/services'
import { OptionItemInterface } from '@cdk/types'
import { NzDrawerService } from 'ng-zorro-antd/drawer'
import { NzMessageService } from 'ng-zorro-antd/message'
import { NzModalService } from 'ng-zorro-antd/modal'
import { forkJoin, lastValueFrom } from 'rxjs'
@Component({
selector: "app-ingredient-form",
templateUrl: "./ingredient-form.component.html",
styleUrls: ["./ingredient-form.component.less"],
selector: 'app-ingredient-form',
templateUrl: './ingredient-form.component.html',
styleUrls: ['./ingredient-form.component.less'],
})
export class IngredientFormComponent implements OnInit {
constructor(
@ -22,58 +22,58 @@ export class IngredientFormComponent implements OnInit {
private router: Router,
private route: ActivatedRoute,
private api: ApiService,
private drawer: NzDrawerService
private drawer: NzDrawerService,
) {
this.id = this.route.snapshot.paramMap.get("id");
this.id = this.route.snapshot.paramMap.get('id')
}
@ViewChild("menuDish") menuDish!: IngredientDishComponent;
@ViewChild('menuDish') menuDish!: IngredientDishComponent
step = 0;
step = 0
id: string | null = "";
id: string | null = ''
menuItem: any = null;
menuItem: any = null
menuDishFormServer: any = null;
menuDishFormServer: any = null
ngOnInit(): void {
this.step = this.id && this.id !== "create" ? 1 : 0;
this.getDetail();
this.step = this.id && this.id !== 'create' ? 1 : 0
this.getDetail()
}
getDetail() {
if (this.id && this.id !== "create") {
if (this.id && this.id !== 'create') {
this.api.getMenuItem(this.id).subscribe((res) => {
if (res.body) {
this.menuItem = res.body;
this.menuItem = res.body
}
});
})
this.api.getMenuDist(this.id).subscribe((res) => {
if (Array.isArray(res.body)) {
res.body.forEach((d) => {
d.ingredient.forEach((f: any) => {
f["groupValues"] = Object.entries(f.value).map(([peopleName, value]) => {
f['groupValues'] = Object.entries(f.value).map(([peopleName, value]) => {
return {
peopleName,
value,
};
});
});
});
this.initMenuDish(res.body);
}
});
})
})
})
this.initMenuDish(res.body)
}
})
}
}
initMenuDish(menuDishFormServer: any[]) {
const foodIds = new Set<number>();
const foodIds = new Set<number>()
menuDishFormServer.forEach((i: any) => {
i.ingredient.map((food: any) => {
foodIds.add(food.key);
});
});
foodIds.add(food.key)
})
})
forkJoin([this.api.getFoodList({ keys: Array.from(foodIds) })]).subscribe(([res]) => {
this.menuDishFormServer = menuDishFormServer.map((i: any) => {
return {
@ -81,35 +81,35 @@ export class IngredientFormComponent implements OnInit {
dishName: i.name,
mealIndex: this.menuItem.meals.findIndex((m: string) => m === i.meal),
items: i.ingredient.map((food: any) => {
const fd = res.body.find((f) => f.key === food.key);
food.foodName = fd.name;
return food;
const fd = res.body.find((f) => f.key === food.key)
food.foodName = fd.name
return food
}),
};
});
});
}
})
})
}
onStepChange(idStr: string) {
this.step = 1;
this.id = idStr;
this.getDetail();
this.step = 1
this.id = idStr
this.getDetail()
}
createNewMenu() {
this.modal.confirm({
nzTitle: "警告",
nzContent: "新建食谱将清空本次所有的配餐数据,确认要清空吗?",
nzTitle: '警告',
nzContent: '新建食谱将清空本次所有的配餐数据,确认要清空吗?',
nzOnOk: () => {
this.menuDish.mealDishList = [];
this.menuDish.mealDishList = []
},
});
})
}
analysis() {
this.drawer.create({
nzWidth: 720,
nzWrapClassName: "analysis-drawer",
nzWrapClassName: 'analysis-drawer',
nzContent: IngredientAnalysisComponent,
nzContentParams: {
menu: {
@ -118,60 +118,59 @@ export class IngredientFormComponent implements OnInit {
},
current: {},
},
});
})
}
previewMenu() {
const { mealDishList } = this.menuDish;
const snapshot = Date.now().toString();
const { mealDishList } = this.menuDish
const snapshot = Date.now().toString()
sessionStorage.setItem(
snapshot,
JSON.stringify({
basic: this.menuItem,
dishs: this.formatData(mealDishList),
})
);
window.open(`/ingredient/preview?snapshot=${snapshot}`);
}),
)
window.open(`/ingredient/preview?snapshot=${snapshot}`)
}
confirmSave() {
this.modal.create({
nzTitle: "确认食谱信息",
nzTitle: '确认食谱信息',
nzContent: ConfirmIngredientComponent,
nzData: this.menuItem,
nzWidth: 650,
nzOnOk: () => {
const { mealDishList } = this.menuDish;
this.api
.saveMenuDist({
menuIds: this.id?.split(","),
nzOnOk: async () => {
const { mealDishList } = this.menuDish
const res = await lastValueFrom(
this.api.saveMenuDist({
menuIds: this.id?.split(','),
dishes: this.formatData(mealDishList),
})
.subscribe((res) => {
this.msg.success(res.desc);
this.router.navigate(["/ingredient/item/list"]);
});
}),
)
this.msg.success(res.desc)
this.router.navigate(['/ingredient/item/list'])
},
});
})
}
formatData(d: DishInterface[]) {
const data: DishInterface[] = JSON.parse(JSON.stringify(d));
const data: DishInterface[] = JSON.parse(JSON.stringify(d))
data.forEach((dish) => {
dish["dishId"] = dish.dish;
dish['dishId'] = dish.dish
dish.items = dish.items.map((i) => {
return {
...i,
value: (i["groupValues"] as any[]).reduce((a, c) => {
value: (i['groupValues'] as any[]).reduce((a, c) => {
return {
...a,
[c.peopleName]: c.value,
};
}
}, {} as Record<string, number>),
};
});
});
return data;
}
})
})
return data
}
}

Loading…
Cancel
Save