import { AfterViewInit, Component, ElementRef, OnDestroy, ViewChild } from '@angular/core' import { FormBuilder, FormGroup } from '@angular/forms' import { ActivatedRoute, Router } from '@angular/router' import { ApiService } from '@cdk/services' import { AnyObject } from '@cdk/types' import { FormValidators } from '@cdk/validators' import { NzMessageService } from 'ng-zorro-antd/message' import { StandardService } from '../standard.service' import { Observable, Subscription } from 'rxjs' // infer export type StandardItemInterface = { min: number max: number | null name: string type: string category: string[] } export type StandardPeopleInterface = { ul?: number hasUl: boolean max: number min: number nutrition: string } @Component({ selector: 'app-standard-setting', templateUrl: './standard-setting.component.html', styleUrls: ['./standard-setting.component.less'], }) export class StandardSettingComponent implements AfterViewInit, OnDestroy { constructor( private fb: FormBuilder, private router: Router, private route: ActivatedRoute, private api: ApiService, private msg: NzMessageService, private standard: StandardService, ) { const id = this.route.snapshot.paramMap.get('id') if (id !== 'create') { const data = this.router.getCurrentNavigation()?.extras if (data) { this.state = data.state } else { this.router.navigate(['/standard/list']) } } } public globalEnum = this.api.globalEnum state: any calcType = this.globalEnum.measurementType?.[0]?.key get calcTypeText() { return this.globalEnum.measurementType.find((f) => f.key === this.calcType)?.value } uploadLoading = false foodCategoryDay: StandardItemInterface[] = [] foodCategoryWeek: StandardItemInterface[] = [] ingredient: { name: string; nutritions: StandardPeopleInterface[] }[] = [] intersection$ = new Subscription() renderIngredient = false expanded = new Set() @ViewChild('intersectionTpl') intersectionTpl!: ElementRef ngOnInit(): void { this.foodCategoryDay = this.parseFoodCategory(this.state?.foodCategoryDay) this.foodCategoryWeek = this.parseFoodCategory(this.state?.foodCategoryWeek) 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[] }[] { if (!data?.ingredient) { return [] } this.expand(0) const sorts = data.crows ?? Object.keys(data.ingredient) return sorts.map((peopleName: string) => { const v: any = data.ingredient[peopleName] return { name: peopleName, nutritions: !v ? [] : Object.entries(v).map(([kn, vn]: [string, any]) => { return { ul: vn?.ul ?? void 0, hasUl: !!vn?.ul, max: vn?.max ?? 0, min: vn?.min ?? 0, nutrition: kn, } }), } }) } parseFoodCategory(data: any): StandardItemInterface[] { if (!data) { return [] } if (Array.isArray(data) && data.length > 0) { this.calcType = data[0]?.type } return data } onSubmit() { if (this.foodCategoryDay.some((s) => !s.name || typeof s.min !== 'number' || s.category.length === 0)) { this.msg.error('请设置正确的食物种类及数量标准(日)') return } if (this.foodCategoryWeek.some((s) => !s.name || typeof s.min !== 'number' || s.category.length === 0)) { this.msg.error('请设置正确的食物种类及数量标准(周)') return } if (this.ingredient.some((s) => !s.name || !s.nutritions.some((sn) => sn.nutrition))) { this.msg.error('请设置正确的营养标准人群') return } const foodCategoryDay = this.foodCategoryDay const foodCategoryWeek = this.foodCategoryWeek let crows: string = '' const ingredient = this.ingredient.reduce((a, c, idx) => { const crowsName = (idx === 0 ? '' : ',') + c.name crows += crowsName return { ...a, [c.name]: c.nutritions.reduce((an, cn) => { const ul = { ul: cn.hasUl ? cn.ul : void 0 } return { ...an, // idx, [cn.nutrition]: { min: cn.min, max: cn.max, ...ul, }, } }, {} as AnyObject), } }, {} as AnyObject) this.api .saveStandard({ ...this.state, foodCategoryDay, foodCategoryWeek, ingredient, crows }, true) .subscribe((res) => { this.msg.success(res.desc) this.router.navigate(['/standard/list']) }) } addFoodType(type: string) { const item = type === 'day' ? this.foodCategoryDay : this.foodCategoryWeek // const withoutSelectType = this.globalEnum.category.find((f) => !item.some((s) => s.type === f.key)); item.push({ category: [], min: 0, max: null, name: '', type: this.calcType, }) } removeFoodType(type: string, idx: number) { if (type === 'day') { this.foodCategoryDay = this.foodCategoryDay.filter((f, i) => idx !== i) } else { this.foodCategoryWeek = this.foodCategoryWeek.filter((f, i) => idx !== i) } } addPeopleGroup() { this.ingredient.push({ name: '', nutritions: [], }) this.expand(this.ingredient.length - 1) } removePeopleGroup(idx: number) { this.ingredient = this.ingredient.filter((_, i) => i !== idx) } calcTypeChange() { console.log('this.calcType', this.calcType) this.foodCategoryDay = this.foodCategoryDay.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) { const current = this.ingredient[idx] this.expanded.add(idx) const withoutSelectNutritions = this.globalEnum.nutrient.find( (f) => !current.nutritions.some((s) => s.nutrition === f.key), ) current.nutritions.push({ nutrition: withoutSelectNutritions?.key ?? '', min: 0, max: 0, hasUl: false, }) } removeNutrition(idx: number, nutrition: string) { this.ingredient[idx].nutritions = this.ingredient[idx].nutritions.filter((f) => f.nutrition !== nutrition) } ulChange(idx: number, nutrition: string, checked: boolean) { this.ingredient[idx].nutritions = this.ingredient[idx].nutritions.map((i) => { return i.nutrition === nutrition ? { ...i, ul: checked ? 1 : void 0 } : i }) } }