diff --git a/.editorconfig b/.editorconfig deleted file mode 100644 index 59d9a3a..0000000 --- a/.editorconfig +++ /dev/null @@ -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 diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..9f0dd71 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,8 @@ +{ + "singleQuote": true, + "trailingComma": "all", + "useTabs": true, + "tabWidth": 4, + "semi": false, + "printWidth": 120 +} \ No newline at end of file diff --git a/README.md b/README.md index a31d4b3..0ef067e 100644 --- a/README.md +++ b/README.md @@ -50,4 +50,9 @@ 2. 权限 3. 详情&编辑食谱 -> 显示类型优化 & 分析 4. 菜品分类 -5. 食材批量删除 \ No newline at end of file +5. 食材批量删除 + +# 12/09 + +1. 新增菜品报错,编辑没有问题 +2. \ No newline at end of file diff --git a/projects/admin/src/app/components/dish-form/dish-form.component.html b/projects/admin/src/app/components/dish-form/dish-form.component.html index 2bf8580..e041490 100644 --- a/projects/admin/src/app/components/dish-form/dish-form.component.html +++ b/projects/admin/src/app/components/dish-form/dish-form.component.html @@ -1,10 +1,29 @@
- - - 单位 - - - - - - - - - - - 菜品名称 - - - - - - - - 菜品标签 - - - - - - - - - - 烹饪方式 - - - - - - - - - + + + + + + + 菜品名称 + + + + + + 菜品标签 + + + + + + + + 烹饪方式 + + + + + + + + 适用月份 + + + + - - - 适用月份 - - - - - + + 菜品图片 + + +
+ +
+ +
+
- - - 菜品图片 - - - -
- -
- -
-
- - - - -
- - 食材名称 - - -
-
- - - - - - -
    -
  • -
    - -
    - - - -
    -
    - - - 是否主料 -
    - -
    -
  • -
-
-
+ + + + +
- - \ No newline at end of file + + diff --git a/projects/admin/src/app/components/dish-form/dish-form.component.ts b/projects/admin/src/app/components/dish-form/dish-form.component.ts index a770f86..d1db4cd 100644 --- a/projects/admin/src/app/components/dish-form/dish-form.component.ts +++ b/projects/admin/src/app/components/dish-form/dish-form.component.ts @@ -1,75 +1,75 @@ -import { Component, Input, OnInit } from "@angular/core"; -import { FormArray, FormBuilder, FormGroup } from "@angular/forms"; -import { ApiService } from "@cdk/services"; -import { Utils } from "@cdk/utils"; -import { FormValidators } from "@cdk/validators"; -import { NzMessageService } from "ng-zorro-antd/message"; -import { Subject, debounceTime, distinctUntilChanged, filter, finalize, switchMap, throttleTime } from "rxjs"; +import { Component, Input, OnInit } from '@angular/core' +import { FormArray, FormBuilder, FormGroup } from '@angular/forms' +import { ApiService } from '@cdk/services' +import { Utils } from '@cdk/utils' +import { FormValidators } from '@cdk/validators' +import { NzMessageService } from 'ng-zorro-antd/message' +import { Subject, debounceTime, distinctUntilChanged, filter, finalize, switchMap, throttleTime } from 'rxjs' @Component({ - selector: "app-dish-form", - templateUrl: "./dish-form.component.html", - styleUrls: ["./dish-form.component.less"], + selector: 'app-dish-form', + templateUrl: './dish-form.component.html', + styleUrls: ['./dish-form.component.less'], }) export class DishFormComponent { constructor(private fb: FormBuilder, private msg: NzMessageService, private api: ApiService) {} - @Input() data: any; + @Input() data: any - @Input() orgs: any[] = []; + @Input() orgs: any[] = [] - @Input() foods: any[] = []; + @Input() foods: any[] = [] - private orgSearch$ = new Subject>(); + private orgSearch$ = new Subject>() - private foodSearch$ = new Subject>(); + private foodSearch$ = new Subject>() - formGroup!: FormGroup; + formGroup!: FormGroup - selectedValue = null; + selectedValue = null - orgListOfOption: Array<{ value: string; text: string }> = []; + orgListOfOption: Array<{ value: string; text: string }> = [] - foodListOfOption: Array<{ value: string; text: string }> = []; + foodListOfOption: Array<{ value: string; text: string }> = [] - searchedFood: Array<{ value: string; text: string }> = []; + searchedFood: Array<{ value: string; text: string }> = [] - foodSelected: string[] = []; + foodSelected: string[] = [] - foodItemSelected: any[] = []; + foodItemSelected: any[] = [] - nzFilterOption = (): boolean => true; + nzFilterOption = (): boolean => true - globalEnum = this.api.globalEnum; + globalEnum = this.api.globalEnum - uploadLoading = false; + uploadLoading = false - addFoodVisible = false; + addFoodVisible = false - iconPreview = ""; + iconPreview = '' get food(): FormArray { - return this.formGroup.get("ingredient") as FormArray; + return this.formGroup.get('ingredient') as FormArray } get icon() { - return this.formGroup.get("icon")?.value; + return this.formGroup.get('icon')?.value } ngOnInit(): void { this.formGroup = this.fb.group({ - id: this.fb.control("", []), + id: this.fb.control('', []), vendors: this.fb.control([], [FormValidators.required()]), - name: this.fb.control("", [FormValidators.required()]), - icon: this.fb.control("", []), - mark: this.fb.control("", [FormValidators.required()]), - poly: this.fb.control("", [FormValidators.required()]), + name: this.fb.control('', [FormValidators.required()]), + icon: this.fb.control('', []), + mark: this.fb.control('', [FormValidators.required()]), + poly: this.fb.control('', [FormValidators.required()]), month: this.fb.control([], []), - }); + }) this.api.getOrgList().subscribe((res) => { - this.orgListOfOption = res; - }); + this.orgListOfOption = res + }) // this.orgSearch$ // .pipe( @@ -92,118 +92,119 @@ export class DishFormComponent { filter((f) => !!f), debounceTime(500), distinctUntilChanged(), - switchMap((q) => this.api.getFoodList(q)) + switchMap((q) => this.api.getFoodList(q)), ) .subscribe((data) => { - const listOfOption: Array<{ value: string; text: string }> = []; + const listOfOption: Array<{ value: string; text: string }> = [] data.body.forEach((item) => { listOfOption.push({ value: item.key, text: item.name, - }); - }); - this.searchedFood = this.searchedFood.concat(listOfOption); - this.foodListOfOption = listOfOption; - }); - this.setValues(); + }) + }) + this.searchedFood = this.searchedFood.concat(listOfOption) + this.foodListOfOption = listOfOption + }) + this.setValues() } setValues() { - this.orgListOfOption = this.orgs.map((i) => ({ text: i.name, value: i.id })); + this.orgListOfOption = this.orgs.map((i) => ({ text: i.name, value: i.id })) if (this.data) { // this.allMonth = this.allMonth.map((i) => // (this.data.month ?? []).includes(i.value) ? { ...i, checked: true } : i // ); + this.formGroup.get('vendors')?.disable() this.foods.forEach((f) => { - const item = { text: f.name, value: f.key }; - this.foodListOfOption.push(item); - this.searchedFood.push(item); - const num = this.data.ingredient.find((i: any) => i.key === f.key); + const item = { text: f.name, value: f.key } + this.foodListOfOption.push(item) + this.searchedFood.push(item) + const num = this.data.ingredient.find((i: any) => i.key === f.key) if (num) { - this.foodItemSelected.push({ num: num.value, ...item, isMain: num.isMain }); - this.foodSelected.push(f.key); + this.foodItemSelected.push({ num: num.value, ...item, isMain: num.isMain }) + this.foodSelected.push(f.key) } - }); - if (this.data["icon"]) { - this.iconPreview = "/api/icon/" + this.data["icon"]; + }) + if (this.data['icon']) { + this.iconPreview = '/api/icon/' + this.data['icon'] } this.formGroup.patchValue({ ...this.data, vendors: [this.data.vender], mark: this.data.marks, - }); + }) } } public getValues() { - let values = null; - console.log("this.formGroup.getRawValue()", this.formGroup.getRawValue(), this.foodItemSelected); + let values = null + console.log('this.formGroup.getRawValue()', this.formGroup.getRawValue(), this.foodItemSelected) if (Utils.validateFormGroup(this.formGroup)) { - const value = this.formGroup.getRawValue(); + const value = this.formGroup.getRawValue() // const { _nutrition, key, name, type } = this.formGroup.getRawValue(); - let ingredient: any[] = []; + let ingredient: any[] = [] for (const f of this.foodItemSelected) { - let num = Number(f.num); + let num = Number(f.num) if (!num) { - this.msg.error(`请输入${f.value}-${f.text}的重量`); - return; + this.msg.error(`请输入${f.value}-${f.text}的重量`) + return } ingredient.push({ isMain: f.isMain, key: f.value, value: num, - }); + }) } - const month = value.month.join(","); - const vendors = value.vendors?.join(",") ?? ""; + const month = value.month.join(',') + const vendors = value.vendors?.join(',') ?? '' values = { ...value, vendors, month, ingredient, - }; + } } - return values; + return values } onMainChange(e: boolean, key: string) { this.foodItemSelected.forEach((i) => { if (e) { - i.isMain = false; + i.isMain = false if (i.value === key) { - i.isMain = true; + i.isMain = true } } else { if (i.value === key) { - i.isMain = false; + i.isMain = false } } - }); + }) } searchOrg(value: string): void { if (value) { - this.orgSearch$.next({ keyword: value }); + this.orgSearch$.next({ keyword: value }) } } searchFood(value: string): void { if (value) { - this.foodSearch$.next({ keyword: value }); + this.foodSearch$.next({ keyword: value }) } } onFoodSelected(v: string[]) { - this.foodItemSelected = []; + this.foodItemSelected = [] this.searchedFood.forEach((item) => { if (this.foodItemSelected.some((s) => s.value === item.value)) { - return; + return } if (v.includes(item.value)) { - this.foodItemSelected.push(item); + this.foodItemSelected.push(item) } - }); + }) // this.foodItemSelected = this.searchedFood.filter((f) => { // return v.includes(f.value) @@ -213,36 +214,36 @@ export class DishFormComponent { addFood() { this.food.push( this.fb.group({ - name: this.fb.control("", [FormValidators.required()]), + name: this.fb.control('', [FormValidators.required()]), tag: this.fb.control(0, [FormValidators.required()]), weight: this.fb.control(0, [FormValidators.required()]), - }) - ); + }), + ) } removeFood(idx: number) { - this.food.removeAt(idx); + this.food.removeAt(idx) } onFileChange(e: Event) { - const target = e.target as HTMLInputElement; - const file = target.files![0]; - target.value = ""; + const target = e.target as HTMLInputElement + const file = target.files![0] + target.value = '' if (file.size / 1024 / 1024 >= 2) { - this.msg.error("图片大小不能超过2M"); - return; + this.msg.error('图片大小不能超过2M') + return } - const fileReader = new FileReader(); + const fileReader = new FileReader() fileReader.onload = () => { - const base64 = fileReader.result as string; - this.iconPreview = base64; + const base64 = fileReader.result as string + this.iconPreview = base64 // this.formGroup.get("icon")?.setValue(base64); - }; - fileReader.readAsDataURL(file); - const formdata = new FormData(); - formdata.append("file", file); + } + fileReader.readAsDataURL(file) + const formdata = new FormData() + formdata.append('file', file) this.api.upload(formdata).subscribe((res) => { - this.formGroup.get("icon")?.setValue(res.body); - }); + this.formGroup.get('icon')?.setValue(res.body) + }) } } diff --git a/projects/admin/src/app/pages/dish/dish.component.html b/projects/admin/src/app/pages/dish/dish.component.html index 245dca3..7b13a28 100644 --- a/projects/admin/src/app/pages/dish/dish.component.html +++ b/projects/admin/src/app/pages/dish/dish.component.html @@ -1,140 +1,128 @@ - - - - - - - -
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-
- - {{ tableOrg[data] ? tableOrg[data].name : '-'}} - - -
- - - {{tableFoods[item.key]['name']}}:{{item.value}} g - - -
-
- - {{data}} - -
-
-
-
-
+ + + + + + + + + +
+
+ + {{ tableOrg[data] ? tableOrg[data].name : '-' }} + + + + {{ item }} + + + +
+ + + {{ tableFoods[item.key]['name'] }}:{{ item.value }} g + + +
+
+ + {{ data }} + +
+
+ + +
- - - - - + + + + - - - - + - -
- - - - - - - - - - - - - - - - - - - - - - - - -
- 主要原料:{{item.ingredients.join(',')}} -
-
- 1毫克(mg)钠相当于2.5毫克食盐 -
-
-
\ No newline at end of file +
+ + + + + + + + + + + + + + + + + + + + + + +
主要原料:{{ item.ingredients.join(',') }}
+
1毫克(mg)钠相当于2.5毫克食盐
+
+ diff --git a/projects/admin/src/app/pages/dish/dish.component.ts b/projects/admin/src/app/pages/dish/dish.component.ts index 60edb17..07995aa 100644 --- a/projects/admin/src/app/pages/dish/dish.component.ts +++ b/projects/admin/src/app/pages/dish/dish.component.ts @@ -1,9 +1,9 @@ -import { Component, OnInit, TemplateRef, ViewChild } from "@angular/core"; -import { FormControl, FormGroup } from "@angular/forms"; -import { NzDrawerRef, NzDrawerService } from "ng-zorro-antd/drawer"; -import { AnyObject, OrgDTO, TableListOption } from "@cdk/public-api"; -import { DishFormComponent } from "@admin/app/components"; -import { ApiService } from "@cdk/services"; +import { Component, OnInit, TemplateRef, ViewChild } from '@angular/core' +import { FormControl, FormGroup } from '@angular/forms' +import { NzDrawerRef, NzDrawerService } from 'ng-zorro-antd/drawer' +import { AnyObject, OrgDTO, TableListOption } from '@cdk/public-api' +import { DishFormComponent } from '@admin/app/components' +import { ApiService } from '@cdk/services' import { Subject, debounceTime, @@ -14,68 +14,68 @@ import { switchMap, takeUntil, tap, -} from "rxjs"; -import { NzModalService } from "ng-zorro-antd/modal"; -import { NzMessageService } from "ng-zorro-antd/message"; -import { ResponseType } from "@cdk/types"; -import { PrintComponent } from "@cdk/shared/components"; +} from 'rxjs' +import { NzModalService } from 'ng-zorro-antd/modal' +import { NzMessageService } from 'ng-zorro-antd/message' +import { ResponseType } from '@cdk/types' +import { PrintComponent } from '@cdk/shared/components' @Component({ - selector: "app-dish", - templateUrl: "./dish.component.html", - styleUrls: ["./dish.component.less"], + selector: 'app-dish', + templateUrl: './dish.component.html', + styleUrls: ['./dish.component.less'], }) export class DishComponent { constructor( private drawer: NzDrawerService, private api: ApiService, private modal: NzModalService, - private msg: NzMessageService + private msg: NzMessageService, ) {} - @ViewChild("formFooterTpl") formFooterTpl!: TemplateRef<{}>; + @ViewChild('formFooterTpl') formFooterTpl!: TemplateRef<{}> - @ViewChild("print") printRef!: PrintComponent; + @ViewChild('print') printRef!: PrintComponent - private drawerRef?: NzDrawerRef; + private drawerRef?: NzDrawerRef - private destroy$ = new Subject(); + private destroy$ = new Subject() - private orgSearch$ = new Subject(); + private orgSearch$ = new Subject() - public globalEnum = this.api.globalEnum; + public globalEnum = this.api.globalEnum - public printData: any | null; + public printData: any | null public tableList = new TableListOption(this.fetchData.bind(this), { selectable: true, frontPagination: false, - }); + }) public queryForm = new FormGroup({ - keyword: new FormControl(""), - mark: new FormControl(""), - vendors: new FormControl(""), - }); + keyword: new FormControl(''), + mark: new FormControl(''), + vendors: new FormControl(''), + }) - public selectedIds: string[] = []; + public selectedIds: string[] = [] - tableOrg: { [k: number]: OrgDTO } = {}; + tableOrg: { [k: number]: OrgDTO } = {} - tableFoods: { [k: string]: any } = {}; + tableFoods: { [k: string]: any } = {} - listOfOption: Array<{ value: number | string; text: string }> = []; + listOfOption: Array<{ value: number | string; text: string }> = [] - nzFilterOption = (): boolean => true; + nzFilterOption = (): boolean => true - submitLoading = false; + submitLoading = false ngOnInit(): void { - this.initTableList(); + this.initTableList() this.api.getOrgList().subscribe((res) => { - this.listOfOption = res; - }); + this.listOfOption = res + }) // this.orgSearch$ // .pipe( // filter((f) => !!f), @@ -96,85 +96,86 @@ export class DishComponent { // }); this.tableList.getState$.pipe(takeUntil(this.destroy$)).subscribe((res) => { - this.selectedIds = res.selectedKeys as Array; - }); + this.selectedIds = res.selectedKeys as Array + }) } searchOrg = (k: string) => { - this.orgSearch$.next(k); - }; + this.orgSearch$.next(k) + } ngOnDestroy(): void { - this.destroy$.next(); - this.destroy$.complete(); + this.destroy$.next() + this.destroy$.complete() } initTableList() { - this.tableList.scroll = { x: null }; + this.tableList.scroll = { x: null } this.tableList = this.tableList.setColumns([ - { key: "icon", title: "菜品图片", width: "66px" }, - { key: "name", title: "菜品名称" }, - { key: "marks", title: "菜品标签" }, - { key: "poly", title: "烹饪方式" }, - { key: "ingredient", title: "食材及含量", width: "30%" }, - { key: "vender", title: "单位" }, - ]); + { key: 'icon', title: '菜品图片', width: '66px' }, + { key: 'name', title: '菜品名称' }, + { key: 'marks', title: '菜品标签' }, + { key: 'label', title: '三低菜品标识' }, + { key: 'poly', title: '烹饪方式' }, + { key: 'ingredient', title: '食材及含量', width: '30%' }, + { key: 'vender', title: '单位' }, + ]) this.tableList = this.tableList.setOptions([ { - title: "打印营养标签", + title: '打印营养标签', premissions: [], onClick: this.printTag.bind(this), }, { - title: "编辑", + title: '编辑', premissions: [], onClick: this.showFoodForm.bind(this), }, { - title: "删除", + title: '删除', premissions: [], onClick: this.deleteItem.bind(this), }, - ]); + ]) } printTag(v?: any) { - this.msg.loading("数据请求中,请不要刷新页面", { + this.msg.loading('数据请求中,请不要刷新页面', { nzDuration: 0, - }); - const ids = v ? [v.id] : this.selectedIds; + }) + const ids = v ? [v.id] : this.selectedIds this.api .getDishLabel(ids) .pipe( finalize(() => { setTimeout(() => { - this.msg.remove(); - }, 1000); - }) + this.msg.remove() + }, 1000) + }), ) .subscribe((res) => { - this.printData = res.body; - this.printRef.print(); - }); + this.printData = res.body + this.printRef.print() + }) } fetchData(query: AnyObject, pager: AnyObject) { return this.api.getDishPage(pager, query).pipe( tap((res) => { - this.getTableColumData(res); - }) - ); + this.getTableColumData(res) + }), + ) } getTableColumData(res: ResponseType) { if (Array.isArray(res.body.content)) { - const vendors = res.body.content.map((i: any) => i.vender); + const vendors = res.body.content.map((i: any) => i.vender) const foodKeys = new Set( res.body.content.reduce((a: string[], c: any) => { - return a.concat(c.ingredient.map((i: any) => i.key)); - }, [] as string[]) - ); + return a.concat(c.ingredient.map((i: any) => i.key)) + }, [] as string[]), + ) if (vendors.length > 0) { this.api.getOrgList({ vendors }).subscribe((org) => { @@ -183,10 +184,10 @@ export class DishComponent { return { ...a, [c.id]: c, - }; - }, {} as AnyObject); + } + }, {} as AnyObject) } - }); + }) } if (foodKeys.size > 0) { this.api.getFoodList({ keys: Array.from(foodKeys) }).subscribe((foods) => { @@ -195,18 +196,18 @@ export class DishComponent { return { ...a, [c.key]: c, - }; - }, {} as AnyObject); - console.log("this.tableFoods", this.tableFoods); + } + }, {} as AnyObject) + console.log('this.tableFoods', this.tableFoods) } - }); + }) } } } showFoodForm(data?: any) { this.drawerRef = this.drawer.create({ - nzTitle: data ? "编辑菜品" : "新增菜品", + nzTitle: data ? '编辑菜品' : '新增菜品', nzWidth: 700, nzContent: DishFormComponent, nzContentParams: { @@ -215,46 +216,46 @@ export class DishComponent { foods: Object.values(this.tableFoods), }, nzFooter: this.formFooterTpl, - }); + }) } cancelForm() { - this.drawerRef?.close(); + this.drawerRef?.close() } onSubmit() { if (this.drawerRef) { - const com = this.drawerRef.getContentComponent() as DishFormComponent; - const val = com.getValues(); + const com = this.drawerRef.getContentComponent() as DishFormComponent + const val = com.getValues() if (val) { - this.submitLoading = true; + this.submitLoading = true this.api .saveDish(val) .pipe( finalize(() => { - this.submitLoading = false; - }) + this.submitLoading = false + }), ) .subscribe((res) => { - this.msg.success(res.desc); - this.tableList.run(); - this.cancelForm(); - }); + this.msg.success(res.desc) + this.tableList.run() + this.cancelForm() + }) } } } deleteItem(v?: any) { - const ids = v ? [v.id] : this.selectedIds; + const ids = v ? [v.id] : this.selectedIds this.modal.confirm({ - nzTitle: "警告", + nzTitle: '警告', nzContent: `是否要删除${ids.length}个菜品?`, nzOkDanger: true, nzOnOk: async () => { - const res = await lastValueFrom(this.api.deleteDish(ids)); - this.msg.success(res.desc); - this.tableList.run(); + const res = await lastValueFrom(this.api.deleteDish(ids)) + this.msg.success(res.desc) + this.tableList.run() }, - }); + }) } } diff --git a/projects/admin/src/app/pages/standard/standard-form/standard-form.component.html b/projects/admin/src/app/pages/standard/standard-form/standard-form.component.html index 942b68a..ccfafc9 100644 --- a/projects/admin/src/app/pages/standard/standard-form/standard-form.component.html +++ b/projects/admin/src/app/pages/standard/standard-form/standard-form.component.html @@ -1,39 +1,65 @@ -
+ + + + 营养标准名称 + + + + - - - - 营养标准名称 - - - - - + + 默认溢出范围 + + + + + + - - - 溢出范围 - - - - - - - + + 营养素溢出范围 + + + + + 营养素 + 溢出范围 + + + + + + {{ item.value }} + + + + + + + + + + + - - -
- 适用单位 - - -
-
- - - - - - - -
- - - - - - - - - - - -
- - - + + + + + +
+
+ + + - - - - -
\ No newline at end of file +
+
+ + + + + +
+
+ diff --git a/projects/admin/src/app/pages/standard/standard-form/standard-form.component.ts b/projects/admin/src/app/pages/standard/standard-form/standard-form.component.ts index 5d667f7..7a3dca3 100644 --- a/projects/admin/src/app/pages/standard/standard-form/standard-form.component.ts +++ b/projects/admin/src/app/pages/standard/standard-form/standard-form.component.ts @@ -1,93 +1,84 @@ -import { Component } from "@angular/core"; -import { FormBuilder, FormGroup } from "@angular/forms"; -import { ActivatedRoute, Router } from "@angular/router"; -import { OrgDTO } from "@cdk/dtos"; -import { ApiService } from "@cdk/services"; -import { OptionItemInterface } from "@cdk/types"; -import { Utils } from "@cdk/utils"; -import { FormValidators } from "@cdk/validators"; -import { NzMessageService } from "ng-zorro-antd/message"; -import { Subject, debounceTime, distinctUntilChanged, filter, finalize, map, switchMap } from "rxjs"; +import { Component } from '@angular/core' +import { FormBuilder, FormGroup } from '@angular/forms' +import { ActivatedRoute, Router } from '@angular/router' +import { OrgDTO } from '@cdk/dtos' +import { ApiService } from '@cdk/services' +import { OptionItemInterface } from '@cdk/types' +import { Utils } from '@cdk/utils' +import { FormValidators } from '@cdk/validators' +import { NzMessageService } from 'ng-zorro-antd/message' +import { Subject, debounceTime, distinctUntilChanged, filter, finalize, map, switchMap } from 'rxjs' interface CheckboxItem { - value: number | string; - label: string; - checked?: boolean; + value: number | string + label: string + checked?: boolean } @Component({ - selector: "app-standard-form", - templateUrl: "./standard-form.component.html", - styleUrls: ["./standard-form.component.less"], + selector: 'app-standard-form', + templateUrl: './standard-form.component.html', + styleUrls: ['./standard-form.component.less'], }) export class StandardFormComponent { constructor( private fb: FormBuilder, private router: Router, private route: ActivatedRoute, - private api: ApiService, - private msg: NzMessageService + public api: ApiService, + private msg: NzMessageService, ) { - const id = this.route.snapshot.paramMap.get("id"); - if (id !== "create") { - const data = this.router.getCurrentNavigation()?.extras; + const id = this.route.snapshot.paramMap.get('id') + if (id !== 'create') { + const data = this.router.getCurrentNavigation()?.extras if (data) { - this.state = data.state; + this.state = data.state } else { - this.router.navigate(["/standard/list"]); + this.router.navigate(['/standard/list']) } } } - private orgSearch$ = new Subject(); + private orgSearch$ = new Subject() - formGroup!: FormGroup; + formGroup!: FormGroup - submitLoading = false; + submitLoading = false - orgList: OrgDTO[] = []; + orgList: OrgDTO[] = [] - state: any; + state: any - vendors: OrgDTO[] = []; + vendors: OrgDTO[] = [] // nzPopoverVisible = false; - listOfOption: (OrgDTO & CheckboxItem)[] = []; + listOfOption: (OrgDTO & CheckboxItem)[] = [] - nzFilterOption = (): boolean => true; + nzFilterOption = (): boolean => true + + overflows: Record = {} ngOnInit(): void { + console.log('this.api.globalEnum.nutrient', this.api.globalEnum.nutrient) this.formGroup = this.fb.group({ - id: this.fb.control("", []), - name: this.fb.control("", [FormValidators.required()]), + id: this.fb.control('', []), + name: this.fb.control('', [FormValidators.required()]), // vendors: this.fb.control([], [FormValidators.required()]), - overflow: this.fb.control("0", [FormValidators.required()]), - }); + overflow: this.fb.control('0', [FormValidators.required()]), + }) if (this.state) { - this.formGroup.patchValue(this.state); - // if (Array.isArray(this.state.vendors)) { - // this.api.getOrgList({ vendors: this.state.vendors }).subscribe((data) => { - // const listOfOption: Array<{ value: number; label: string }> = []; - // data.forEach((item) => { - // listOfOption.push({ - // value: item.id, - // label: item.name, - // }); - // }); - // this.listOfOption = listOfOption; - // this.formGroup.patchValue(this.state); - // }); - // } + this.formGroup.patchValue(this.state) + this.overflows = this.state?.overflows ?? {} } this.api.getOrgList().subscribe((res) => { - this.listOfOption = res as unknown as (OrgDTO & CheckboxItem)[]; + this.listOfOption = res as unknown as (OrgDTO & CheckboxItem)[] if (Array.isArray(this.state?.vendors)) { this.listOfOption = this.listOfOption.map((i) => { - return { ...i, checked: this.state.vendors.includes(i.id) }; - }); + return { ...i, checked: this.state.vendors.includes(i.id) } + }) } - }); + }) // this.orgSearch$ // .pipe( // filter((f) => !!f), @@ -108,8 +99,8 @@ export class StandardFormComponent { } searchOrg = (k: string) => { - this.orgSearch$.next(k); - }; + this.orgSearch$.next(k) + } // onSelectOrg(v: OptionItemInterface[]) { // v.forEach((i) => { @@ -128,27 +119,28 @@ export class StandardFormComponent { onSubmit(gotoSetting?: boolean) { if (Utils.validateFormGroup(this.formGroup)) { - this.submitLoading = true; + this.submitLoading = true this.api .saveStandard({ foodCategoryDay: this.state?.foodCategoryDay, foodCategoryWeek: this.state?.foodCategoryWeek, ingredient: this.state?.ingredient, + overflows: this.overflows, ...this.formGroup.value, vendors: this.listOfOption.filter((f) => f.checked).map((i) => i.id), }) .pipe( finalize(() => { - this.submitLoading = false; - }) + this.submitLoading = false + }), ) .subscribe((res) => { - this.msg.success(res.desc); - const redirectTo = gotoSetting ? ["/", "standard", "setting", res.body.id] : ["/standard/list"]; + this.msg.success(res.desc) + const redirectTo = gotoSetting ? ['/', 'standard', 'setting', res.body.id] : ['/standard/list'] this.router.navigate(redirectTo, { state: res.body, - }); - }); + }) + }) } } } diff --git a/projects/admin/src/app/pages/standard/standard-list/standard-list.component.ts b/projects/admin/src/app/pages/standard/standard-list/standard-list.component.ts index ca84f29..55a7439 100644 --- a/projects/admin/src/app/pages/standard/standard-list/standard-list.component.ts +++ b/projects/admin/src/app/pages/standard/standard-list/standard-list.component.ts @@ -1,93 +1,97 @@ -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 { DishFormComponent } from "@admin/app/components"; -import { ApiService } from "@cdk/services"; -import { NzModalService } from "ng-zorro-antd/modal"; -import { lastValueFrom } from "rxjs"; -import { NzMessageService } from "ng-zorro-antd/message"; -import { Router } from "@angular/router"; +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 { DishFormComponent } from '@admin/app/components' +import { ApiService } from '@cdk/services' +import { NzModalService } from 'ng-zorro-antd/modal' +import { lastValueFrom } from 'rxjs' +import { NzMessageService } from 'ng-zorro-antd/message' +import { Router } from '@angular/router' +import { StandardService } from '../standard.service' @Component({ - selector: "app-standard-list", - templateUrl: "./standard-list.component.html", - styleUrls: ["./standard-list.component.less"], + selector: 'app-standard-list', + templateUrl: './standard-list.component.html', + styleUrls: ['./standard-list.component.less'], }) export class StandardListComponent { constructor( private api: ApiService, private modal: NzModalService, private msg: NzMessageService, - private router: Router + private router: Router, + private standard: StandardService, ) {} public tableList = new TableListOption(this.fetchData.bind(this), { frontPagination: false, - }); + }) public queryForm = new FormGroup({ - keyword: new FormControl(""), - }); + keyword: new FormControl(''), + }) ngOnInit(): void { - this.initTableList(); + this.initTableList() } initTableList() { - this.tableList.scroll = { x: null }; + this.tableList.scroll = { x: null } this.tableList = this.tableList.setColumns([ - { key: "name", title: "营养标准名称" }, - { key: "people", title: "人群细分" }, - { key: "vendors", title: "适用单位" }, - { key: "modify", title: "更新时间" }, - ]); + { key: 'name', title: '营养标准名称' }, + { key: 'people', title: '人群细分' }, + { key: 'vendors', title: '适用单位' }, + { key: 'modify', title: '更新时间' }, + ]) this.tableList = this.tableList.setOptions([ { - title: "标准设置", + title: '标准设置', premissions: [], onClick: this.toSetting.bind(this), }, { - title: "编辑", + title: '编辑', premissions: [], onClick: this.toEdit.bind(this), }, { - title: "删除", + title: '删除', premissions: [], onClick: this.deleteItem.bind(this), }, - ]); + ]) } fetchData(query: AnyObject, pager: AnyObject) { - return this.api.getStandardPage(pager, query); + return this.api.getStandardPage(pager, query) } toEdit(d: AnyObject) { - this.router.navigate([`/standard/form/${d["id"]}`], { + // this.standard.settingData$.next(d) + this.router.navigate([`/standard/form/${d['id']}`], { state: d, - }); + }) } toSetting(d: AnyObject) { - this.router.navigate([`/standard/setting/${d["id"]}`], { + // this.standard.settingData$.next(d) + this.router.navigate([`/standard/setting/${d['id']}`], { state: d, - }); + }) } deleteItem(v: any) { this.modal.confirm({ - nzTitle: "警告", + nzTitle: '警告', nzContent: `是否要删除该营养标准?`, nzOkDanger: true, nzOnOk: async () => { - const res = await lastValueFrom(this.api.deleteStandard(v.id)); - this.msg.success(res.desc); - this.tableList.run(); + const res = await lastValueFrom(this.api.deleteStandard(v.id)) + this.msg.success(res.desc) + this.tableList.run() }, - }); + }) } } diff --git a/projects/admin/src/app/pages/standard/standard-setting/standard-setting.component.html b/projects/admin/src/app/pages/standard/standard-setting/standard-setting.component.html index 808e816..22b7574 100644 --- a/projects/admin/src/app/pages/standard/standard-setting/standard-setting.component.html +++ b/projects/admin/src/app/pages/standard/standard-setting/standard-setting.component.html @@ -198,248 +198,272 @@ --> -
- - - -
- 计算单位: -
-
- - - -
-
-
- - -
-
- - - - - -
-
-
-
-
-
- -
-
- - - - -
-
-
-
- -
-
- ~ -
-
- -
-
-
-
- {{calcTypeText}} -
-
- -
-
-
- -
-
-
-
-
-
- - - - - -
-
-
-
-
-
- -
-
- - - - -
-
-
-
- -
-
- ~ -
-
- -
-
-
-
- {{calcTypeText}} -
-
- -
-
-
- -
-
-
-
-
-
-
- - - - - - -
- - 人群名称: - -
- -
-
-
- - - - - - - - -

每人每天能量和营养素供给量标准

-
-
-
-
- - - - -
-
-
- -
- ~ -
- -
-
-
- -
- -
-
- - - -
-
-
-
- -
-
-
- -
-
-
-
-
+
+ + +
计算单位:
+
+ + + +
+
+
+ +
+
+ + + + + +
+
+
+
+
+
+ +
+
+ + + + +
+
+
+
+ +
+
~
+
+ +
+
+
+
+ {{ calcTypeText }} +
+
+ +
+
+
+
+
+
+
+
+
+ + + + + +
+
+
+
+
+
+ +
+
+ + + + +
+
+
+
+ +
+
~
+
+ +
+
+
+
+ {{ calcTypeText }} +
+
+ +
+
+
+
+
+
+
+
+
+
- - - + +
+ + + + +
+ 人群名称: +
+ +
+
+
+ + + + + + + + + +
+ + +

每人每天能量和营养素供给量标准

+
+
+
+
+ + + + +
+
+
+ +
~
+ +
+
+
+ +
+ +
+
+ + + +
+
+
+
+ +
+
+
+
+
+
+
+
+
-
- - - + + + +
+ + + -
-
- - - - -
-
-
\ No newline at end of file +
+
+ + + + +
+
+ diff --git a/projects/admin/src/app/pages/standard/standard-setting/standard-setting.component.ts b/projects/admin/src/app/pages/standard/standard-setting/standard-setting.component.ts index d442999..2947f5e 100644 --- a/projects/admin/src/app/pages/standard/standard-setting/standard-setting.component.ts +++ b/projects/admin/src/app/pages/standard/standard-setting/standard-setting.component.ts @@ -1,204 +1,283 @@ -import { Component } 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 { 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[]; -}; + min: number + max: number | null + name: string + type: string + category: string[] +} export type StandardPeopleInterface = { - ul?: number; - hasUl: boolean; - max: number; - min: number; - nutrition: string; -}; + 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"], + selector: 'app-standard-setting', + templateUrl: './standard-setting.component.html', + styleUrls: ['./standard-setting.component.less'], }) -export class StandardSettingComponent { +export class StandardSettingComponent implements AfterViewInit, OnDestroy { constructor( private fb: FormBuilder, private router: Router, private route: ActivatedRoute, private api: ApiService, - private msg: NzMessageService + private msg: NzMessageService, + private standard: StandardService, ) { - const id = this.route.snapshot.paramMap.get("id"); - if (id !== "create") { - const data = this.router.getCurrentNavigation()?.extras; + const id = this.route.snapshot.paramMap.get('id') + if (id !== 'create') { + const data = this.router.getCurrentNavigation()?.extras if (data) { - this.state = data.state; + this.state = data.state } 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() { - 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() + + @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?.ingredient); + 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) { - return []; + if (!data?.ingredient) { + 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 { - name: k, + name: peopleName, nutritions: !v ? [] - : Object.entries(v).map(([kn, vn]) => { + : 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 []; + return [] } if (Array.isArray(data) && data.length > 0) { - this.calcType = data[0]?.type; + this.calcType = data[0]?.type } - return data; + return data } onSubmit() { - if (this.foodCategoryDay.some((s) => !s.name || typeof s.min !== "number" || s.category.length === 0)) { - this.msg.error("请设置正确的食物种类及数量标准(日)"); - return; + 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.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; + this.msg.error('请设置正确的营养标准人群') + return } - const foodCategoryDay = this.foodCategoryDay; - - const foodCategoryWeek = this.foodCategoryWeek; + const foodCategoryDay = this.foodCategoryDay - 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 { ...a, [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 { ...an, + // idx, [cn.nutrition]: { min: cn.min, max: cn.max, ...ul, }, - }; + } }, {} as AnyObject), - }; - }, {} as AnyObject); + } + }, {} as AnyObject) - this.api.saveStandard({ ...this.state, foodCategoryDay, foodCategoryWeek, ingredient }, true).subscribe((res) => { - this.msg.success(res.desc); - this.router.navigate(["/standard/list"]); - }); + 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 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: "", + name: '', type: this.calcType, - }); + }) } removeFoodType(type: string, idx: number) { - if (type === "day") { - this.foodCategoryDay = this.foodCategoryDay.filter((f, i) => idx !== i); + if (type === 'day') { + this.foodCategoryDay = this.foodCategoryDay.filter((f, i) => idx !== i) } else { - this.foodCategoryWeek = this.foodCategoryWeek.filter((f, i) => idx !== i); + this.foodCategoryWeek = this.foodCategoryWeek.filter((f, i) => idx !== i) } } addPeopleGroup() { this.ingredient.push({ - name: "", + name: '', nutritions: [], - }); + }) } removePeopleGroup(idx: number) { - this.ingredient = this.ingredient.filter((_, i) => i !== idx); + 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 })); + 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]; + const current = this.ingredient[idx] + this.expanded.add(idx) 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({ - nutrition: withoutSelectNutritions?.key ?? "", + 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); + 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; - }); + return i.nutrition === nutrition ? { ...i, ul: checked ? 1 : void 0 } : i + }) } } diff --git a/projects/admin/src/app/pages/standard/standard.service.ts b/projects/admin/src/app/pages/standard/standard.service.ts new file mode 100644 index 0000000..527dcbd --- /dev/null +++ b/projects/admin/src/app/pages/standard/standard.service.ts @@ -0,0 +1,11 @@ +import { Injectable } from '@angular/core' +import { BehaviorSubject } from 'rxjs' + +@Injectable({ + providedIn: 'root', +}) +export class StandardService { + constructor() {} + + settingData$ = new BehaviorSubject(null) +} diff --git a/projects/cdk/src/ingredient/ingredient-analysis/ingredient-analysis.component.html b/projects/cdk/src/ingredient/ingredient-analysis/ingredient-analysis.component.html index 18f5c38..95f4e4a 100644 --- a/projects/cdk/src/ingredient/ingredient-analysis/ingredient-analysis.component.html +++ b/projects/cdk/src/ingredient/ingredient-analysis/ingredient-analysis.component.html @@ -1,230 +1,186 @@ - -
-
- - - - - -
-
- - - - - -
-
-
- - 餐次: - -
- {{item}} -
-
- -
- - - - - - - - - - - - 能量占比 - - - 要求(%) - - - 实际摄入(%) - - - 评价 - - - - - - - {{e.name}} - - - {{e.standard}} - - - {{e.value}} - - - - -
- - {{e.conclusion}} -
-
- -
- - {{e.conclusion}} -
-
- -
- - {{e.conclusion}} -
-
- {{e.conclusion}} -
- - - -
-
-
- -
-
- -
-
- - - - - -
-
- -

- 周规则 -

-
- - - - - 种类名称 - - - 至少需要 - - - 当前含有 - - - 还需 - - - - - - - {{w.name}} - - - {{w.standard}} - - - {{w.supplied}} - - - - -
- -
-
- - -
- 超量 -
-
- - {{w.lack}} - -
-
- - - - -
-
-

- 日规则 -

-
-
- - - - - - - 种类名称 - - - 至少需要 - - - 当前含有 - - - 还需 - - - - - - - 周{{d.day}} - - - {{d.name}} - - - {{d.standard}} - - - {{d.supplied}} - - - - -
- -
-
- - -
- 超量 -
-
- - {{d.lack}} - -
-
- - - -
- -
-
-
-
- + +
+
+ + + + + +
+
+ + + +
+
+
+ 餐次: +
+ {{ item }} +
+
+ +
+ + + + + + + + + + + 能量占比 + 要求(%) + 实际摄入(%) + 评价 + + + + + + {{ e.name }} + + + {{ e.standard }} + + + {{ e.value }} + + + + +
+ + {{ e.conclusion }} +
+
+ +
+ + {{ e.conclusion }} +
+
+ +
+ + {{ e.conclusion }} +
+
+ {{ e.conclusion }} +
+ + + +
+
+
+
+
+ + + +

周规则

+
+ + + + 种类名称 + 至少需要 + 当前含有 + 还需 + + + + + + {{ w.name }} + + + {{ w.standard }} + + + {{ w.supplied }} + + + + +
+ +
+
+ + +
超量
+
+ + {{ w.lack }} + +
+
+ + + +
+
+

日规则

+
+
+ + + + + 种类名称 + 至少需要 + 当前含有 + 还需 + + + + + 周{{ d.day }} + + {{ d.name }} + + + {{ d.standard }} + + + {{ d.supplied }} + + + + +
+ +
+
+ + +
超量
+
+ + {{ d.lack }} + +
+
+ + + +
+
+
+
+
+ + + +
+

总计

+
+ + + + 烹饪方式 + 菜品数量 + + + + + + {{ w.name }} + + + {{ w.value }} + + + + +

每日统计

+
+ + + + + 烹饪方式 + 菜品数量 + + + + + + + {{ weekdayMap[$any(p.key)] }} + + + {{ w.name }} + + + {{ w.value }} + + + + + +
+
+
+
+
diff --git a/projects/cdk/src/ingredient/ingredient-analysis/ingredient-analysis.component.ts b/projects/cdk/src/ingredient/ingredient-analysis/ingredient-analysis.component.ts index ff7d652..dbea511 100644 --- a/projects/cdk/src/ingredient/ingredient-analysis/ingredient-analysis.component.ts +++ b/projects/cdk/src/ingredient/ingredient-analysis/ingredient-analysis.component.ts @@ -1,98 +1,98 @@ -import { Component, ElementRef, Input, OnInit, ViewChild } from "@angular/core"; -import { ActivatedRoute } from "@angular/router"; -import { ApiService } from "@cdk/services"; -import { finalize } from "rxjs"; -import { weekdayMap } from "../ingredient-form-basic/ingredient-form-basic.component"; -import { EChartsType, init } from "echarts"; +import { Component, ElementRef, Input, OnInit, ViewChild } from '@angular/core' +import { ActivatedRoute } from '@angular/router' +import { ApiService } from '@cdk/services' +import { finalize } from 'rxjs' +import { weekdayMap } from '../ingredient-form-basic/ingredient-form-basic.component' +import { EChartsType, init } from 'echarts' const sugerMap = new Map([ - ["salt", "盐"], - ["sugar", "糖"], - ["oil", "油"], -]); + ['salt', '盐'], + ['sugar', '糖'], + ['oil', '油'], +]) @Component({ - selector: "lib-ingredient-analysis", - templateUrl: "./ingredient-analysis.component.html", - styleUrls: ["./ingredient-analysis.component.less"], + selector: 'lib-ingredient-analysis', + templateUrl: './ingredient-analysis.component.html', + styleUrls: ['./ingredient-analysis.component.less'], }) export class IngredientAnalysisComponent implements OnInit { constructor(private api: ApiService, private route: ActivatedRoute) {} - @Input() menu: any; + @Input() menu: any - @Input() current: any; + @Input() current: any - @ViewChild("sugerTpl", { static: true }) sugerEl!: ElementRef; + @ViewChild('sugerTpl', { static: true }) sugerEl!: ElementRef - sugerRef?: EChartsType; + sugerRef?: EChartsType - currentDay: number = 1; + currentDay: number = 0 - currentPeople!: string; + currentPeople!: string - id!: string; + id!: string - analysis: any; + analysis: any - rules: any; + rules: any - energy: any; + energy: any poly = { total: [] as any[], days: {} as any, - }; + } - suger: any; + suger: any - analysisLoading = false; + analysisLoading = false - weekdayMap = weekdayMap; + weekdayMap = weekdayMap ngOnInit(): void { - this.currentDay = this.current?.day ?? this.menu.day[0]; - this.currentPeople = this.menu.crows[0]; - this.id = this.route.snapshot.queryParamMap.get("newId") ?? this.menu.id; - this.getAnalysis(); + // this.currentDay = this.current?.day ?? this.menu.day[0] + this.currentPeople = this.menu.crows[0] + this.id = this.route.snapshot.queryParamMap.get('newId') ?? this.menu.id + this.getAnalysis() } getAnalysis() { - this.analysisLoading = true; + this.analysisLoading = true this.api .getAnalysis(this.id, this.currentDay, this.currentPeople) .pipe( finalize(() => { - this.analysisLoading = false; - }) + this.analysisLoading = false + }), ) .subscribe((res) => { - this.analysis = res.body; - }); + this.analysis = res.body + }) - this.getEnergy(); - this.getRule(); - this.getSugar(); - this.getPoly(); + this.getEnergy() + this.getRule() + this.getSugar() + this.getPoly() } getEnergy() { this.api.getAnalysisEnergy(this.id, this.currentDay, this.currentPeople).subscribe((res) => { - this.energy = res.body; - }); + this.energy = res.body + }) } getRule() { this.api.getAnalysisRule(this.id, this.currentDay, this.currentPeople).subscribe((res) => { - this.rules = res.body; - }); + this.rules = res.body + }) } getSugar() { this.api.getAnalysisSugar(this.id, this.currentPeople).subscribe((res) => { - this.suger = res.body; - }); + this.suger = res.body + }) } getPoly() { @@ -100,45 +100,45 @@ export class IngredientAnalysisComponent implements OnInit { const poly = { total: [] as any[], days: {} as any, - }; + } Object.entries(res.body).forEach(([k, v]) => { - if (k === "0") { - poly.total = Object.entries(v as any).map((o) => ({ name: o[0], value: o[1] })); - } else if (k !== "crow") { - poly.days[k] = Object.entries(v as any).map((o) => ({ name: o[0], value: o[1] })); + if (k === '0') { + poly.total = Object.entries(v as any).map((o) => ({ name: o[0], value: o[1] })) + } else if (k !== 'crow') { + poly.days[k] = Object.entries(v as any).map((o) => ({ name: o[0], value: o[1] })) } - }); - this.poly = poly; - }); + }) + this.poly = poly + }) } nzSelectedIndexChange(d: any) { if (d === 2) { - const xAxis: string[] = Object.keys(this.suger["oil"]).map((i: any) => weekdayMap[i]); - const series: any[] = []; + const xAxis: string[] = Object.keys(this.suger['oil']).map((i: any) => weekdayMap[i]) + const series: any[] = [] Object.entries(this.suger).forEach(([k, v]) => { - if (k !== "crow") { + if (k !== 'crow') { series.push({ - type: "line", + type: 'line', name: sugerMap.get(k), data: Object.values(v as any), - }); + }) } - }); + }) const option = { legend: {}, - tooltip: { trigger: "axis" }, - xAxis: { type: "category", data: xAxis }, + tooltip: { trigger: 'axis' }, + xAxis: { type: 'category', data: xAxis }, yAxis: {}, series, - }; + } if (!this.sugerRef) { - this.sugerRef = init(this.sugerEl.nativeElement); + this.sugerRef = init(this.sugerEl.nativeElement) } - this.sugerRef.setOption(option); + this.sugerRef.setOption(option) } } } diff --git a/projects/cdk/src/ingredient/ingredient-dish/ingredient-dish.component.ts b/projects/cdk/src/ingredient/ingredient-dish/ingredient-dish.component.ts index 8e3d8fa..958562e 100644 --- a/projects/cdk/src/ingredient/ingredient-dish/ingredient-dish.component.ts +++ b/projects/cdk/src/ingredient/ingredient-dish/ingredient-dish.component.ts @@ -1,13 +1,13 @@ -import { Component, Input, OnChanges, SimpleChanges, TemplateRef } from "@angular/core"; +import { Component, Input, OnChanges, SimpleChanges, TemplateRef } from '@angular/core' // import { MealDishInterface } from "../ingredient-meals/ingredient-meals.component"; -import { NzModalService } from "ng-zorro-antd/modal"; -import { Augmented, OptionItemInterface } from "@cdk/types"; -import { NzMessageService } from "ng-zorro-antd/message"; -import { forkJoin } from "rxjs"; -import { ApiService } from "@cdk/services"; -import { NzDrawerService } from "ng-zorro-antd/drawer"; -import { IngredientAnalysisComponent } from "../ingredient-analysis/ingredient-analysis.component"; -import { weekdayMap } from "../ingredient-form-basic/ingredient-form-basic.component"; +import { NzModalService } from 'ng-zorro-antd/modal' +import { Augmented, OptionItemInterface } from '@cdk/types' +import { NzMessageService } from 'ng-zorro-antd/message' +import { forkJoin } from 'rxjs' +import { ApiService } from '@cdk/services' +import { NzDrawerService } from 'ng-zorro-antd/drawer' +import { IngredientAnalysisComponent } from '../ingredient-analysis/ingredient-analysis.component' +import { weekdayMap } from '../ingredient-form-basic/ingredient-form-basic.component' // export interface MenuObjectInterface { // [Day: number]: { @@ -16,47 +16,47 @@ import { weekdayMap } from "../ingredient-form-basic/ingredient-form-basic.compo // } export type DishInterface = Augmented<{ - dish: number; - day: number; - meal: string; - mark: string; + dish: number + day: number + meal: string + mark: string items: Array< Augmented<{ - key: string; - isMain: boolean; - value: Record; + key: string + isMain: boolean + value: Record }> - >; -}>; + > +}> @Component({ - selector: "app-ingredient-dish", - templateUrl: "./ingredient-dish.component.html", - styleUrls: ["./ingredient-dish.component.less"], + selector: 'app-ingredient-dish', + templateUrl: './ingredient-dish.component.html', + styleUrls: ['./ingredient-dish.component.less'], }) export class IngredientDishComponent implements OnChanges { constructor( private modal: NzModalService, private msg: NzMessageService, private api: ApiService, - private drawer: NzDrawerService + private drawer: NzDrawerService, ) {} - @Input() menuBaisc: any | null; + @Input() menuBaisc: any | null - @Input() client = false; + @Input() client = false - @Input() menuDishFormServer: any | null; + @Input() menuDishFormServer: any | null - expanded = new Set(); + expanded = new Set() - days: number[] = []; + days: number[] = [] - selectDay: OptionItemInterface[] = []; + selectDay: OptionItemInterface[] = [] - weekdayMap = weekdayMap; + weekdayMap = weekdayMap - mealCurrentIndex: Record = {}; + mealCurrentIndex: Record = {} // d = { // 1:{ @@ -67,19 +67,19 @@ export class IngredientDishComponent implements OnChanges { // } // menuObject!: MenuObjectInterface; - mealDishList: DishInterface[] = []; + mealDishList: DishInterface[] = [] ngOnChanges(changes: SimpleChanges): void { - if (changes["menuBaisc"]?.currentValue) { - this.initMenuBasic(); + if (changes['menuBaisc']?.currentValue) { + this.initMenuBasic() } - if (changes["menuDishFormServer"]?.currentValue) { - this.initMenuDish(); + if (changes['menuDishFormServer']?.currentValue) { + this.initMenuDish() } } initMenuDish() { - this.mealDishList = this.menuDishFormServer; + this.mealDishList = this.menuDishFormServer // const foodIds = new Set(); // this.menuDishFormServer.forEach((i: any) => { // i.ingredient.map((food: any) => { @@ -104,17 +104,17 @@ export class IngredientDishComponent implements OnChanges { initMenuBasic() { if (this.menuBaisc) { - const meals = this.menuBaisc.meals as string[]; - console.log("this.menuBaisc", this.menuBaisc); - const day = this.menuBaisc.day as number[]; + const meals = this.menuBaisc.meals as string[] + console.log('this.menuBaisc', this.menuBaisc) + const day = this.menuBaisc.day as number[] this.days = day.map((i) => { - const d = weekdayMap[i]; + const d = weekdayMap[i] this.selectDay.push({ label: d, value: String(i), - }); - this.mealCurrentIndex[i] = 0; - this.expanded.add(i); + }) + this.mealCurrentIndex[i] = 0 + this.expanded.add(i) // if (!this.menuObject) { // this.menuObject = {}; // } @@ -124,50 +124,49 @@ export class IngredientDishComponent implements OnChanges { // [idx]: [], // }; // }, {} as Record); - return i; - }); + return i + }) } } expandChange(i: number) { if (this.expanded.has(i)) { - this.expanded.delete(i); + this.expanded.delete(i) } else { - this.expanded.add(i); + this.expanded.add(i) } } onSaveDish(v: DishInterface[], day: number, mealIndex: number) { - this.mealDishList = JSON.parse(JSON.stringify(v)); + this.mealDishList = JSON.parse(JSON.stringify(v)) // this.menuObject[day][mealIndex] = JSON.parse(JSON.stringify(v)); } reuse(day: number, nzContent: TemplateRef<{}>) { - const thisDayDishs = this.mealDishList.filter((f) => f.day === day); - console.log("dayDishs", day, this.mealDishList, thisDayDishs, this.selectDay); + const thisDayDishs = this.mealDishList.filter((f) => f.day === day) + console.log('dayDishs', day, this.mealDishList, thisDayDishs, this.selectDay) this.modal.create({ - nzTitle: "请选择应用到的日期", + nzTitle: '请选择应用到的日期', nzContent, nzOnOk: () => { this.selectDay.forEach((i) => { - if (i["checked"]) { + if (i['checked']) { thisDayDishs.forEach((reused) => { - this.mealDishList.push(JSON.parse(JSON.stringify({ ...reused, day: Number(i.value) }))); - }); + this.mealDishList.push(JSON.parse(JSON.stringify({ ...reused, day: Number(i.value) }))) + }) } - i["checked"] = false; - }); - this.mealDishList = JSON.parse(JSON.stringify(this.mealDishList)); - this.msg.success("操作成功"); + i['checked'] = false + }) + this.mealDishList = JSON.parse(JSON.stringify(this.mealDishList)) + this.msg.success('操作成功') }, - }); + }) } analysis(day: number) { - console.log("this.days", this.days); this.drawer.create({ nzWidth: 720, - nzWrapClassName: "analysis-drawer", + nzWrapClassName: 'analysis-drawer', nzContent: IngredientAnalysisComponent, nzContentParams: { menu: { @@ -178,6 +177,6 @@ export class IngredientDishComponent implements OnChanges { day, }, }, - }); + }) } } diff --git a/projects/cdk/src/ingredient/ingredient-meals/ingredient-meals.component.html b/projects/cdk/src/ingredient/ingredient-meals/ingredient-meals.component.html index b020fa7..f7b9ab1 100644 --- a/projects/cdk/src/ingredient/ingredient-meals/ingredient-meals.component.html +++ b/projects/cdk/src/ingredient/ingredient-meals/ingredient-meals.component.html @@ -1,17 +1,13 @@
-
- - - - -
- - - - - -   - - - 重量/克 - - - - - + +   + + 重量/克 + - - - - 菜品 - - - 食材 - - - {{p}} - - - - - - - - - - -
- - {{dish['dishName']}} - - - - + -
- - - -
- - {{food['foodName']}} - - -
- - - - - - -
- -
- -
- - - 本餐生重总量 - - - {{$any(totalObj[p])?.toFixed(2)}} - - - - -
- +
+ + + + + + + + + + 本餐生重总量 + + {{ $any(totalObj[p])?.toFixed(2) }} + + + + - + - - - - - \ No newline at end of file + + + + + diff --git a/projects/cdk/src/ingredient/ingredient-meals/ingredient-meals.component.less b/projects/cdk/src/ingredient/ingredient-meals/ingredient-meals.component.less index 08c41a0..b146d3b 100644 --- a/projects/cdk/src/ingredient/ingredient-meals/ingredient-meals.component.less +++ b/projects/cdk/src/ingredient/ingredient-meals/ingredient-meals.component.less @@ -13,4 +13,12 @@ .placeholder-th { border-right: none !important; +} + +.dish-table { + ::ng-deep { + *[nzLeft] { + z-index: 100; + } + } } \ No newline at end of file diff --git a/projects/cdk/src/ingredient/ingredient-meals/ingredient-meals.component.ts b/projects/cdk/src/ingredient/ingredient-meals/ingredient-meals.component.ts index c34b378..c632543 100644 --- a/projects/cdk/src/ingredient/ingredient-meals/ingredient-meals.component.ts +++ b/projects/cdk/src/ingredient/ingredient-meals/ingredient-meals.component.ts @@ -8,122 +8,125 @@ import { SimpleChanges, TemplateRef, ViewChild, -} from "@angular/core"; -import { NzModalService } from "ng-zorro-antd/modal"; +} from '@angular/core' +import { NzModalService } from 'ng-zorro-antd/modal' import { AddDishToIngredientComponent, FoodInDishInterface, -} from "../add-dish-to-ingredient/add-dish-to-ingredient.component"; -import { NzDrawerRef, NzDrawerService } from "ng-zorro-antd/drawer"; -import { NzMessageService } from "ng-zorro-antd/message"; -import { Augmented } from "@cdk/types"; -import { DishInterface } from "../ingredient-dish/ingredient-dish.component"; +} from '../add-dish-to-ingredient/add-dish-to-ingredient.component' +import { NzDrawerRef, NzDrawerService } from 'ng-zorro-antd/drawer' +import { NzMessageService } from 'ng-zorro-antd/message' +import { Augmented } from '@cdk/types' +import { DishInterface } from '../ingredient-dish/ingredient-dish.component' export type MealDishInterface = Augmented<{ - dishId: number; - dishName: string; - mark: string; - foods: FoodInDishInterface[]; -}>; + dishId: number + dishName: string + mark: string + foods: FoodInDishInterface[] +}> @Component({ - selector: "app-ingredient-meals", - templateUrl: "./ingredient-meals.component.html", - styleUrls: ["./ingredient-meals.component.less"], + selector: 'app-ingredient-meals', + templateUrl: './ingredient-meals.component.html', + styleUrls: ['./ingredient-meals.component.less'], }) export class IngredientMealsComponent implements OnChanges, OnInit { constructor(private modal: NzModalService, private msg: NzMessageService, private drawer: NzDrawerService) {} - @Input() day!: number; + @Input() day!: number - @Input() mealIndex!: number; + @Input() mealIndex!: number - @Input() peopleGroups: string[] = []; + @Input() peopleGroups: string[] = [] - @Input() meals: string[] = []; + @Input() meals: string[] = [] - @Input() mealDishs: DishInterface[] = []; + @Input() mealDishs: DishInterface[] = [] - @Output() onSaveDish = new EventEmitter(); + @Output() onSaveDish = new EventEmitter() - @ViewChild("addDishFooter") addDishFooter!: TemplateRef<{}>; + @ViewChild('addDishFooter') addDishFooter!: TemplateRef<{}> - drawerRef?: NzDrawerRef; + drawerRef?: NzDrawerRef - submitLoading = false; + submitLoading = false // currentDishs: DishInterface[] = []; - totalObj: Record = {}; + totalObj: Record = {} ngOnInit(): void { - this.init(); + this.init() } ngOnChanges(changes: SimpleChanges): void { - if (changes["mealDishs"]?.currentValue) { - this.init(); + if (changes['mealDishs']?.currentValue) { + this.init() } } init() { - this.calcTotal(); + 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.totalObj = {} this.mealDishs.forEach((dish) => { - if (dish.day === this.day && this.mealIndex === dish["mealIndex"]) { + if (dish.day === this.day && this.mealIndex === dish['mealIndex']) { dish.items.forEach((food) => { - food["groupValues"].forEach((p: any) => { + food['groupValues'].forEach((p: any) => { if (!this.totalObj[p.peopleName]) { - this.totalObj[p.peopleName] = p.value; + this.totalObj[p.peopleName] = p.value } else { - this.totalObj[p.peopleName] = this.totalObj[p.peopleName] + p.value; + this.totalObj[p.peopleName] = this.totalObj[p.peopleName] + p.value } - }); - }); + }) + }) } - }); + }) } shopDishForm() { this.drawerRef = this.drawer.create({ - nzTitle: "添加菜品", + nzTitle: '添加菜品', nzWidth: 1200, nzContent: AddDishToIngredientComponent, nzFooter: this.addDishFooter, nzContentParams: { peopleGroups: this.peopleGroups, }, - }); + }) } clearThisMeal() { this.modal.confirm({ - nzTitle: "警告", - nzContent: "是否要清空本餐?", + nzTitle: '警告', + nzContent: '是否要清空本餐?', nzOkDanger: true, nzOnOk: () => { - this.mealDishs = this.mealDishs.filter((f) => !(f.day === this.day && f["mealIndex"] === this.mealIndex)); - this.onSaveDish.emit(this.mealDishs); - this.calcTotal(); - return true; + this.mealDishs = this.mealDishs.filter( + (f) => !(f.day === this.day && f['mealIndex'] === this.mealIndex), + ) + this.onSaveDish.emit(this.mealDishs) + this.calcTotal() + return true }, - }); + }) } cancelForm() { - this.drawerRef?.close(); + this.drawerRef?.close() } onSubmit() { if (this.drawerRef) { - const { dish, foods } = this.drawerRef.getContentComponent() as AddDishToIngredientComponent; + const { dish, foods } = this.drawerRef.getContentComponent() as AddDishToIngredientComponent this.mealDishs.push({ + dishLabel: dish.dishLabel, day: this.day, mealIndex: this.mealIndex, meal: this.meals[this.mealIndex], @@ -131,24 +134,24 @@ export class IngredientMealsComponent implements OnChanges, OnInit { dishName: dish.name, mark: dish.marks, items: foods, - }); + }) - this.onSaveDish.emit(this.mealDishs); + this.onSaveDish.emit(this.mealDishs) } - this.cancelForm(); + this.cancelForm() } 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); + 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(); + this.calcTotal() } } diff --git a/projects/cdk/src/ingredient/ingredient-preview/ingredient-preview.component.html b/projects/cdk/src/ingredient/ingredient-preview/ingredient-preview.component.html index 43ca26f..a7f78bc 100644 --- a/projects/cdk/src/ingredient/ingredient-preview/ingredient-preview.component.html +++ b/projects/cdk/src/ingredient/ingredient-preview/ingredient-preview.component.html @@ -1,123 +1,128 @@ -
+
- -
- - - {{basic.name}} - -
+ +
+ + + {{ basic.name }} + +
-
- - {{basic.standardName ?? '-'}} - - - {{weekdayMap[item]}} - - - -
- - - 全年 - - - - - {{monthText[item]}} - - -
-
- - - {{p}} - - - - - {{c}} - - - - 点击查看 - -
-
-
+
+ + {{ basic.standardName ?? '-' }} + + + {{ weekdayMap[item] }} + + + +
+ + 全年 + + + + {{ monthText[item] }} + + +
+
+ + {{ basic.crows.length }} + +
+ + {{ p }} + +
+
+
+ + + {{ c }} + + + + 点击查看 + +
+
+
-
- - - - +
+
diff --git a/projects/cdk/src/services/api.service.ts b/projects/cdk/src/services/api.service.ts index 16d8c0d..3a2a87e 100644 --- a/projects/cdk/src/services/api.service.ts +++ b/projects/cdk/src/services/api.service.ts @@ -1,9 +1,9 @@ -import { HttpClient, HttpParams, HttpResponse } from "@angular/common/http"; -import { Inject, Injectable, InjectionToken } from "@angular/core"; -import { AnyObject, Augmented, OptionItemInterface, PageResult, ResponseType } from "@cdk/types"; -import { format, addDays } from "date-fns"; -import { Utils } from "@cdk/utils"; -import { Observable, map, of, tap } from "rxjs"; +import { HttpClient, HttpParams, HttpResponse } from '@angular/common/http' +import { Inject, Injectable, InjectionToken } from '@angular/core' +import { AnyObject, Augmented, OptionItemInterface, PageResult, ResponseType } from '@cdk/types' +import { format, addDays } from 'date-fns' +import { Utils } from '@cdk/utils' +import { Observable, map, of, tap } from 'rxjs' import { PermItemDTO, UserDTO, @@ -15,185 +15,187 @@ import { OrgConfigDTO, CategoryDTO, NutrientDTO, -} from "@cdk/public-api"; +} from '@cdk/public-api' -export const PROJECT_NAME = new InjectionToken("projectName"); +export const PROJECT_NAME = new InjectionToken('projectName') @Injectable({ - providedIn: "root", + providedIn: 'root', }) export class ApiService { constructor(private http: HttpClient, @Inject(PROJECT_NAME) public project: string) { - this.initAccount(); + this.initAccount() } - public account!: ClientAccountDTO; + public account!: ClientAccountDTO - public adminAccount!: AdminAccountDTO; + public adminAccount!: AdminAccountDTO - public accountKey = this.project === "admin" ? "CATERING_ADMIN_ACCOUNT" : "CATERING_CLIENT_ACCOUNT"; + public accountKey = this.project === 'admin' ? 'CATERING_ADMIN_ACCOUNT' : 'CATERING_CLIENT_ACCOUNT' - globalEnum!: GlobalEnum; + globalEnum!: GlobalEnum // 能量、蛋白质、脂肪、碳水化合物、糖、钠/食盐、钙、铁、锌、维生素A、维生素B1、维生素B2、维生素C、膳食纤维 nutrientSort = new Map([ - ["energy", { sort: 0 }], - ["protein", { sort: 1 }], - ["fat", { sort: 2 }], - ["carbs", { sort: 3 }], - ["sugar", { sort: 4 }], - ["sodium", { sort: 5 }], - ["calcium", { sort: 6 }], - ["iron", { sort: 7 }], - ["zinc", { sort: 8 }], - ["va", { sort: 9 }], - ["vb1", { sort: 10 }], - ["vb2", { sort: 11 }], - ["vc", { sort: 12 }], - ["fiber", { sort: 13 }], - ]); + ['energy', { sort: 0 }], + ['protein', { sort: 1 }], + ['fat', { sort: 2 }], + ['carbs', { sort: 3 }], + ['sugar', { sort: 4 }], + ['sodium', { sort: 5 }], + ['calcium', { sort: 6 }], + ['iron', { sort: 7 }], + ['zinc', { sort: 8 }], + ['va', { sort: 9 }], + ['vb1', { sort: 10 }], + ['vb2', { sort: 11 }], + ['vc', { sort: 12 }], + ['fiber', { sort: 13 }], + ]) initAccount() { try { - const stragedAccount = localStorage.getItem(this.accountKey); + const stragedAccount = localStorage.getItem(this.accountKey) if (stragedAccount) { - if (this.project === "admin") { - this.adminAccount = JSON.parse(stragedAccount); + if (this.project === 'admin') { + this.adminAccount = JSON.parse(stragedAccount) } else { - this.account = JSON.parse(stragedAccount); + this.account = JSON.parse(stragedAccount) } } } catch (error) { - console.error("获取用户信息失败", error); + console.error('获取用户信息失败', error) } } upload(data: FormData) { - return this.http.put("/api/icon", data); + return this.http.put('/api/icon', data) } private _formatEnum(v: CategoryDTO[]): OptionItemInterface[] { - return v.map((i) => ({ label: i.key, value: i.value })); + return v.map((i) => ({ label: i.key, value: i.value })) } private _sortNutrient(n: NutrientDTO[]) { - return n.map((i) => { - return { ...i, ...this.nutrientSort.get(i.key) }; - }); + return n + .map((i) => { + return { ...i, ...(this.nutrientSort.get(i.key) ?? { sort: 100 }) } + }) + .sort((a, b) => a.sort - b.sort) } getAllEnum(force?: boolean): Observable { if (this.globalEnum && !force) { - return of(this.globalEnum); + return of(this.globalEnum) } - return this.http.get>("/api/enum").pipe( + return this.http.get>('/api/enum').pipe( map((res) => { return { ...res.body, mealType: this._formatEnum(res.body.mealType), menuStatus: this._formatEnum(res.body.menuStatus), nutrient: this._sortNutrient(res.body.nutrient), - }; + } }), tap((r) => { - this.globalEnum = r; - }) - ); + this.globalEnum = r + }), + ) } login(v: AnyObject) { - v["admin"] = this.project === "admin"; - const params = Utils.objectToHttpParams(v); - return this.http.get("/api/login", { params }).pipe( + v['admin'] = this.project === 'admin' + const params = Utils.objectToHttpParams(v) + return this.http.get('/api/login', { params }).pipe( tap((res) => { - localStorage.setItem(this.accountKey, JSON.stringify(res.body)); - this.initAccount(); - }) - ); + localStorage.setItem(this.accountKey, JSON.stringify(res.body)) + this.initAccount() + }), + ) } logout() { - return this.http.get("/api/logout").pipe( + return this.http.get('/api/logout').pipe( tap((res) => { if (res.success) { - localStorage.removeItem(this.accountKey); + localStorage.removeItem(this.accountKey) } - }) - ); + }), + ) } getOrgInfo() { - return this.http.get("/api/vender/info").pipe( + return this.http.get('/api/vender/info').pipe( tap((res) => { - this.account["vender"] = res.body; - }) - ); + this.account['vender'] = res.body + }), + ) } getOrgConfig() { - return this.http.get>("/api/vender/config"); + return this.http.get>('/api/vender/config') } saveOrgConfig(config: AnyObject) { - const body = Utils.objectToFormData(config); - return this.http.post("/api/vender/config", body); + const body = Utils.objectToFormData(config) + return this.http.post('/api/vender/config', body) } updatePassword(v: {}) { - const body = Utils.objectToFormData(v); - return this.http.post("/api/password", body); + const body = Utils.objectToFormData(v) + return this.http.post('/api/password', body) } getRoleList() { - return this.http.get>("/api/role"); + return this.http.get>('/api/role') } deleteRole(roleId: string) { - const params = new HttpParams().set("roleId", roleId); - return this.http.delete("/api/role", { + const params = new HttpParams().set('roleId', roleId) + return this.http.delete('/api/role', { params, - }); + }) } updateRole(rule: AnyObject) { - const body = Utils.objectToFormData(rule, true); - const method = rule["roleId"] ? "post" : "put"; - return this.http[method]("/api/role", body); + const body = Utils.objectToFormData(rule, true) + const method = rule['roleId'] ? 'post' : 'put' + return this.http[method]('/api/role', body) } getRolePerms() { - return this.http.get>("/api/role/item"); + return this.http.get>('/api/role/item') } getUserList() { - return this.http.get>("/api/user"); + return this.http.get>('/api/user') } checkUid(uid: string) { - const params = new HttpParams().set("uid", uid); - return this.http.delete("/api/user/check", { + const params = new HttpParams().set('uid', uid) + return this.http.delete('/api/user/check', { params, - }); + }) } saveUser(user: AnyObject, edit: boolean) { - const body = Utils.objectToFormData(user); - const method = edit ? "post" : "put"; - return this.http[method]("/api/user", body); + const body = Utils.objectToFormData(user) + const method = edit ? 'post' : 'put' + return this.http[method]('/api/user', body) } deleteUser(uid: string) { - const params = new HttpParams().set("uid", uid); - return this.http.delete("/api/user", { + const params = new HttpParams().set('uid', uid) + return this.http.delete('/api/user', { params, - }); + }) } - orgList: (OrgDTO & { value: string; text: string })[] = []; + orgList: (OrgDTO & { value: string; text: string })[] = [] getOrgList(query?: { vendors?: number[]; keyword?: string }, force?: boolean) { if (this.orgList.length && !force) { - return of(this.orgList); + return of(this.orgList) } // const q = Utils.objectStringify(query); return this.http.get>(`/api/vender/select?keyword= `).pipe( @@ -203,45 +205,45 @@ export class ApiService { value: i.id.toString(), text: i.name, label: i.name, - })); + })) }), tap((r) => { - this.orgList = r; - }) - ); + this.orgList = r + }), + ) } getOrgPage(p: {}, q: {}) { - let params = Utils.objectStringify({ ...p, ...q }, { skipEmptyString: false, skipNull: false }); + let params = Utils.objectStringify({ ...p, ...q }, { skipEmptyString: false, skipNull: false }) - return this.http.get>>(`/api/vender?${params}`); + return this.http.get>>(`/api/vender?${params}`) } checkOrgAccount(account: string) { - const params = new HttpParams().set("account", account); - return this.http.get>("/api/vender/check/account", { + const params = new HttpParams().set('account', account) + return this.http.get>('/api/vender/check/account', { params, - }); + }) } checkOrgName(name: string) { - const params = new HttpParams().set("name", name); - return this.http.get>("/api/vender/check/name", { + const params = new HttpParams().set('name', name) + return this.http.get>('/api/vender/check/name', { params, - }); + }) } deleteOrg(id: number) { - const params = Utils.objectToFormData({ venderId: id }); - return this.http.delete("/api/vender", { + const params = Utils.objectToFormData({ venderId: id }) + return this.http.delete('/api/vender', { body: params, - }); + }) } saveOrg(org: AnyObject) { - const body = Utils.objectToFormData(org); - const method = org["id"] ? "post" : "put"; - return this.http[method]("/api/vender", body); + const body = Utils.objectToFormData(org) + const method = org['id'] ? 'post' : 'put' + return this.http[method]('/api/vender', body) } // getOrgConfig() { @@ -249,7 +251,7 @@ export class ApiService { // } getFoodPage(p: {}, q: {}) { - const params = Utils.objectStringify({ ...p, ...q }); + const params = Utils.objectStringify({ ...p, ...q }) return this.http.get>(`/api/ingredient?${params}`).pipe( map((r) => { if (Array.isArray(r.body.content)) { @@ -257,86 +259,86 @@ export class ApiService { return { ...o, nutrientArr: Object.entries(o.nutrient).map(([k, v]) => { - const nutrient = this.globalEnum.nutrient.find((f) => f.key === k); + const nutrient = this.globalEnum.nutrient.find((f) => f.key === k) return { key: k, value: v, label: nutrient?.value, measurement: nutrient?.measurement, - }; + } }), - }; - }); + } + }) } - return r; - }) - ); + return r + }), + ) } getFoodList(query: {}) { - const q = Utils.objectStringify(query); - return this.http.get>(`/api/ingredient/select?${q}`); + const q = Utils.objectStringify(query) + return this.http.get>(`/api/ingredient/select?${q}`) } getFoodExcelTemplate() { - return this.http.get("/api/ingredient/excel", { observe: "response", responseType: "blob" as "json" }).pipe( + return this.http.get('/api/ingredient/excel', { observe: 'response', responseType: 'blob' as 'json' }).pipe( tap((res) => { - this.downLoadFile(res); - }) - ); + this.downLoadFile(res) + }), + ) } downLoadFile(response: HttpResponse, defaultName = `${Date.now()}.xlsx`) { - const fileNameFromHeader = response.headers.get("Content-Disposition"); + const fileNameFromHeader = response.headers.get('Content-Disposition') if (fileNameFromHeader) { - const fileName = fileNameFromHeader.trim()?.split("''")?.[1]?.replace(/"/g, "") ?? defaultName; - const blob = new Blob([response.body as any]); - const downloadLink = document.createElement("a"); - downloadLink.href = URL.createObjectURL(blob); - downloadLink.download = decodeURIComponent(fileName); - document.body.appendChild(downloadLink); - downloadLink.click(); - document.body.removeChild(downloadLink); + const fileName = fileNameFromHeader.trim()?.split("''")?.[1]?.replace(/"/g, '') ?? defaultName + const blob = new Blob([response.body as any]) + const downloadLink = document.createElement('a') + downloadLink.href = URL.createObjectURL(blob) + downloadLink.download = decodeURIComponent(fileName) + document.body.appendChild(downloadLink) + downloadLink.click() + document.body.removeChild(downloadLink) } } saveFood(food: AnyObject, isEdit?: boolean) { - const body = Utils.objectToFormData(food); - const method = isEdit ? "post" : "put"; - return this.http[method]("/api/ingredient", body); + const body = Utils.objectToFormData(food) + const method = isEdit ? 'post' : 'put' + return this.http[method]('/api/ingredient', body) } deleteFoods(ids: number[]) { - const params = Utils.objectToFormData({ keys: ids.join(",") }); - return this.http.delete(`/api/ingredient`, { body: params }); + const params = Utils.objectToFormData({ keys: ids.join(',') }) + return this.http.delete(`/api/ingredient`, { body: params }) } importFood(f: FormData) { // return this.http.put("/api/ingredient/upload", f); return this.http - .put("/api/ingredient/excel", f, { - observe: "response", - responseType: "blob" as "json", + .put('/api/ingredient/excel', f, { + observe: 'response', + responseType: 'blob' as 'json', }) .pipe // tap((res) => { // this.downLoadFile(res); // }) - (); + () } markFood(mark: string, key: string) { - const params = Utils.objectToFormData({ mark, key }); - return this.http.put("/api/ingredient/mark", params); + const params = Utils.objectToFormData({ mark, key }) + return this.http.put('/api/ingredient/mark', params) } removeFoodMark(key: string) { - const params = Utils.objectToFormData({ key }); - return this.http.delete("/api/ingredient/mark", { body: params }); + const params = Utils.objectToFormData({ key }) + return this.http.delete('/api/ingredient/mark', { body: params }) } getStandardPage(p: {}, q: {}) { - const params = Utils.objectStringify({ ...p, ...q }); + const params = Utils.objectStringify({ ...p, ...q }) return this.http.get>(`/api/nutrition?${params}`).pipe( map((r) => { if (Array.isArray(r.body.content)) { @@ -347,54 +349,54 @@ export class ApiService { return { peopleGroupName: k, ...((v as any) ?? {}), - }; + } }), - }; - }); + } + }) } - return r; - }) - ); + return r + }), + ) } - standardList: (AnyObject & OptionItemInterface)[] = []; + standardList: (AnyObject & OptionItemInterface)[] = [] getStandard(q?: { id?: string; name?: string }, force?: boolean) { // if (this.standardList.length && !force) { // return of(this.standardList); // } - const query = q ? Utils.objectStringify(q) : "keyword=&name="; + const query = q ? Utils.objectStringify(q) : 'keyword=&name=' return this.http.get>(`/api/nutrition/select?${query}`).pipe( map((r) => { return r.body.map((i: any) => ({ ...i, value: i.id.toString(), label: i.name, - })); + })) }), tap((r) => { - this.standardList = r; - }) - ); + this.standardList = r + }), + ) } getStandardById(q: { id?: string; name?: string }) { - const query = Utils.objectStringify(q); - return this.http.get>(`/api/nutrition/select?${query}`); + const query = Utils.objectStringify(q) + return this.http.get>(`/api/nutrition/select?${query}`) } saveStandard(v: AnyObject, isEdit?: boolean) { - const body = Utils.objectToFormData({ ...v, vendors: v["vendors"]?.join(",") }); - const method = v["id"] ? "post" : "put"; - return this.http[method]("/api/nutrition", body); + const body = Utils.objectToFormData({ ...v, vendors: v['vendors']?.join(',') }) + const method = v['id'] ? 'post' : 'put' + return this.http[method]('/api/nutrition', body) } deleteStandard(id: string) { - const params = Utils.objectToFormData({ id }); - return this.http.delete(`/api/nutrition`, { body: params }); + const params = Utils.objectToFormData({ id }) + return this.http.delete(`/api/nutrition`, { body: params }) } getDishPage(p: {}, q: {}) { - const params = Utils.objectStringify({ ...p, ...q }); + const params = Utils.objectStringify({ ...p, ...q }) return this.http.get>(`/api/dish?${params}`).pipe( map((r) => { if (Array.isArray(r.body.content)) { @@ -411,13 +413,13 @@ export class ApiService { // }; // }); } - return r; - }) - ); + return r + }), + ) } getDishLabel(ids: (string | number)[]) { - const query = Utils.objectStringify({ ids }); + const query = Utils.objectStringify({ ids }) return this.http.get>(`/api/dish/label?${query}`).pipe( map((res) => { return { @@ -429,156 +431,159 @@ export class ApiService { .map((c) => { return { ...c, - ...this.nutrientSort.get(c["key"]), - }; + ...this.nutrientSort.get(c['key']), + } }) - .sort((a, b) => a["sort"]! - b["sort"]!), - }; + .sort((a, b) => a['sort']! - b['sort']!), + } }), - }; - }) - ); + } + }), + ) } saveDish(v: AnyObject) { - const body = Utils.objectToFormData(v); - const method = v["id"] ? "post" : "put"; - return this.http[method]("/api/dish", body); + const body = Utils.objectToFormData(v) + const method = v['id'] ? 'post' : 'put' + return this.http[method]('/api/dish', body) } deleteDish(ids: string[]) { - const params = Utils.objectToFormData({ ids: ids.join(",") }); - return this.http.delete(`/api/dish`, { body: params }); + const params = Utils.objectToFormData({ ids: ids.join(',') }) + return this.http.delete(`/api/dish`, { body: params }) } getMenuStatusPage(p: {}, q: {}) { - const params = Utils.objectStringify({ ...p, ...q }); - return this.http.get>(`/api/menu/review?${params}`); + const params = Utils.objectStringify({ ...p, ...q }) + return this.http.get>(`/api/menu/review?${params}`) } getMenuPage(p: {}, q: {}) { - const params = Utils.objectStringify({ ...p, ...q }); - return this.http.get>(`/api/menu?${params}`); + const params = Utils.objectStringify({ ...p, ...q }) + return this.http.get>(`/api/menu?${params}`) } getMenuItem(id: string | number) { - const params = Utils.objectStringify({ id }); - return this.http.get(`/api/menu?${params}`); + const params = Utils.objectStringify({ id }) + return this.http.get(`/api/menu?${params}`) } getCountByStatus() { - return this.http.get(`/api/menu/review/count`); + return this.http.get(`/api/menu/review/count`) } saveMenu(v: AnyObject) { - const body = Utils.objectToFormData(v); - const method = v["id"] ? "post" : "put"; - return this.http[method]("/api/menu", body); + const body = Utils.objectToFormData(v) + const method = v['id'] ? 'post' : 'put' + return this.http[method]('/api/menu', body) } // 提交审核 submitMenuForReview(id: string | number) { - const params = Utils.objectToFormData({ id }); - return this.http.put(`/api/menu/review`, params); + const params = Utils.objectToFormData({ id }) + return this.http.put(`/api/menu/review`, params) } disableMenu(id: string | number) { - const params = Utils.objectToFormData({ id }); - return this.http.delete(`/api/menu/review`, { body: params }); + const params = Utils.objectToFormData({ id }) + return this.http.delete(`/api/menu/review`, { body: params }) } reviewMenu(id: number, pass: boolean, reason?: string) { - const params = Utils.objectToFormData({ id, pass, reason }); - return this.http.post(`/api/menu/review`, params); + const params = Utils.objectToFormData({ id, pass, reason }) + return this.http.post(`/api/menu/review`, params) } release(id: string | number, startTime: Date, amount: number) { // const endTime = addDays(startTime, amount); const params = Utils.objectToFormData({ id, - startTime: format(startTime, "yyyy-MM-dd"), + startTime: format(startTime, 'yyyy-MM-dd'), // endTime: format(endTime, "yyyy-MM-dd"), - }); - return this.http.put(`/api/menu/release`, params); + }) + return this.http.put(`/api/menu/release`, params) } cancelRelease(id: string | number) { - const params = Utils.objectToFormData({ id }); - return this.http.delete(`/api/menu/release`, { body: params }); + const params = Utils.objectToFormData({ id }) + return this.http.delete(`/api/menu/release`, { body: params }) } deleteMenu(id: string | number) { - const params = Utils.objectToFormData({ id }); - return this.http.delete(`/api/menu`, { body: params }); + const params = Utils.objectToFormData({ id }) + return this.http.delete(`/api/menu`, { body: params }) } getMenuDist(menuId: number | string) { - return this.http.get(`/api/menu/dish?menuId=${menuId}`); + return this.http.get(`/api/menu/dish?menuId=${menuId}`) } saveMenuDist(d: {}) { - return this.http.put(`/api/menu/dish/batch`, d); + return this.http.put(`/api/menu/dish/batch`, d) } getMenuReleasePage(p: {}, q: {}) { - const params = Utils.objectStringify({ ...p, ...q }); + const params = Utils.objectStringify({ ...p, ...q }) return this.http.get>(`/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")}`, - })); + dateRange: `${format(new Date(i.startTime), 'yyyy-MM-dd')}至${format( + new Date(i.endTime), + 'yyyy-MM-dd', + )}`, + })) } - return res; - }) - ); + return res + }), + ) } exportMenu(id: number | string) { return this.http .get(`/api/menu/dish/export?id=${id}`, { - observe: "response", - responseType: "blob" as "json", + observe: 'response', + responseType: 'blob' as 'json', }) .pipe( tap((res) => { - this.downLoadFile(res); - }) - ); + this.downLoadFile(res) + }), + ) } getAnalysis(id: string, day?: number, crow?: string) { - const params = Utils.objectStringify({ id, day, crow }); - return this.http.get(`/api/menu/analysis?${params}`); + const params = Utils.objectStringify({ id, day, crow }) + return this.http.get(`/api/menu/analysis?${params}`) } getAnalysisEnergy(id: string, day?: number, crow?: string) { - const params = Utils.objectStringify({ id, day, crow }); - return this.http.get(`/api/menu/analysis/energy?${params}`); + const params = Utils.objectStringify({ id, day, crow }) + return this.http.get(`/api/menu/analysis/energy?${params}`) } getAnalysisSugar(id: string, crow?: string) { - const params = Utils.objectStringify({ id, crow }); - return this.http.get(`/api/menu/analysis/sugar?${params}`); + const params = Utils.objectStringify({ id, crow }) + return this.http.get(`/api/menu/analysis/sugar?${params}`) } getAnalysisPoly(id: string, crow?: string) { - const params = Utils.objectStringify({ id, crow }); - return this.http.get(`/api/menu/analysis/poly?${params}`); + const params = Utils.objectStringify({ id, crow }) + return this.http.get(`/api/menu/analysis/poly?${params}`) } getAnalysisRule(id: string, day?: number, crow?: string) { - const params = Utils.objectStringify({ id, day, crow }); - return this.http.get(`/api/menu/analysis/types?${params}`); + const params = Utils.objectStringify({ id, day, crow }) + return this.http.get(`/api/menu/analysis/types?${params}`) } getCurrentDayDataVisList() { - return this.http.get(`/api/menu/display`); + return this.http.get(`/api/menu/display`) } getMenuDataVis(menuId: number) { // return this.http.get(`/api/menu/dish`); - return this.http.get(`/api/menu/display?menuId=${menuId}`); + return this.http.get(`/api/menu/display?menuId=${menuId}`) } } diff --git a/projects/cdk/src/shared/components/dish-select/dish-select.component.ts b/projects/cdk/src/shared/components/dish-select/dish-select.component.ts index 035d20e..79f6272 100644 --- a/projects/cdk/src/shared/components/dish-select/dish-select.component.ts +++ b/projects/cdk/src/shared/components/dish-select/dish-select.component.ts @@ -1,13 +1,13 @@ -import { Component, OnInit } from "@angular/core"; -import { ControlValueAccessor, NG_VALUE_ACCESSOR } from "@angular/forms"; -import { ApiService } from "@cdk/services"; -import { OptionItemInterface } from "@cdk/types"; -import { Subject, debounceTime, distinctUntilChanged, filter, finalize, switchMap, takeUntil, tap } from "rxjs"; +import { Component, OnInit } from '@angular/core' +import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms' +import { ApiService } from '@cdk/services' +import { OptionItemInterface } from '@cdk/types' +import { Subject, debounceTime, distinctUntilChanged, filter, finalize, switchMap, takeUntil, tap } from 'rxjs' @Component({ - selector: "app-dish-select", - templateUrl: "./dish-select.component.html", - styleUrls: ["./dish-select.component.less"], + selector: 'app-dish-select', + templateUrl: './dish-select.component.html', + styleUrls: ['./dish-select.component.less'], providers: [ { provide: NG_VALUE_ACCESSOR, @@ -19,17 +19,17 @@ import { Subject, debounceTime, distinctUntilChanged, filter, finalize, switchMa export class DishSelectComponent implements OnInit, ControlValueAccessor { constructor(private api: ApiService) {} - private destroy$ = new Subject(); + private destroy$ = new Subject() - private dishSearch$ = new Subject(); + private dishSearch$ = new Subject() - nzFilterOption = (): boolean => true; + nzFilterOption = (): boolean => true - value?: string | string[]; + value?: string | string[] - listOfOption: OptionItemInterface[] = []; + listOfOption: OptionItemInterface[] = [] - loading = false; + loading = false ngOnInit(): void { this.dishSearch$ @@ -39,59 +39,60 @@ export class DishSelectComponent implements OnInit, ControlValueAccessor { distinctUntilChanged(), takeUntil(this.destroy$), tap(() => { - this.loading = true; + this.loading = true }), switchMap((term: string) => this.api.getDishPage({ pageNo: 0, pageSize: 5 }, { keyword: term }).pipe( finalize(() => { - this.loading = false; - }) - ) - ) + this.loading = false + }), + ), + ), ) .subscribe((data) => { - const listOfOption: Array = []; + const listOfOption: Array = [] data.body.content.forEach((item) => { listOfOption.push({ ...item, + dishLabel: item.label, value: String(item.id), label: item.name, - }); - }); - this.listOfOption = listOfOption; - }); + }) + }) + this.listOfOption = listOfOption + }) } ngOnDestroy(): void { - this.destroy$.next(); - this.destroy$.complete(); + this.destroy$.next() + this.destroy$.complete() } onSelectChange(v: any) { - const item = this.listOfOption.find((f) => f.value === v); + const item = this.listOfOption.find((f) => f.value === v) // console.log("v", item); if (item) { - this.onChange(item); + this.onChange(item) } } search = (k: string) => { - this.dishSearch$.next(k); - }; + this.dishSearch$.next(k) + } onChange(v: OptionItemInterface) {} ontouch(v: any) {} writeValue(v?: string[] | string): void { - this.value = v; + this.value = v } registerOnChange(fn: any): void { - this.onChange = fn; + this.onChange = fn } registerOnTouched(fn: any): void { - this.ontouch = fn; + this.ontouch = fn } } diff --git a/projects/client/src/app/components/dish-form/dish-form.component.html b/projects/client/src/app/components/dish-form/dish-form.component.html index 1ecf046..e7d3f4c 100644 --- a/projects/client/src/app/components/dish-form/dish-form.component.html +++ b/projects/client/src/app/components/dish-form/dish-form.component.html @@ -1,64 +1,70 @@
+ + +
每份菜品各类食材建议使用量为:
+
    +
  • ● 肉类30~50克
  • +
  • ● 素菜50~100克
  • +
  • ● 食用油3~5克
  • +
  • ● 精盐0.5克
  • +
+
如需用到除盐外的其他调味品,建议:
+
    +
  • ● 味精、鸡精1克
  • +
  • ● 豆瓣酱、酱油等3~5克
  • +
  • ● 醋、料酒、小葱、干辣椒、花椒、五香粉等香料不必填写
  • +
+
汤类菜品:
+
    +
  • ● 每份建议添加饮用水200克
  • +
+
+
+ + 菜品名称 + + + + + + 菜品标签 + + + + + + + + 烹饪方式 + + + + + + + + 适用月份 + + + + - - - 菜品名称 - - - - - - - - 菜品标签 - - - - - - - - - - 烹饪方式 - - - - - - - - - - - 适用月份 - - - - - + + 菜品图片 + + +
+ +
+ +
+
- - - 菜品图片 - - - -
- -
- -
-
- - - - -
- - 食材名称 - - -
-
- - - - - - -
    -
  • -
    - -
    - - - -
    -
    - - - 是否主料 -
    - -
    -
  • -
-
-
+ + + + +
- - \ No newline at end of file + + diff --git a/projects/client/src/app/pages/data-vis/data-vis.component.html b/projects/client/src/app/pages/data-vis/data-vis.component.html index a3b92ac..56af7d0 100644 --- a/projects/client/src/app/pages/data-vis/data-vis.component.html +++ b/projects/client/src/app/pages/data-vis/data-vis.component.html @@ -1,112 +1,96 @@
-
- -

{{orgName}}食谱营养报告

-
{{showTime}}
-
-
- - -
-
-
-
- 今日带量食谱 - - 【{{currentMenu.name}}】 - -
-
- - - - - - - - - - - - - - - - - - - - - -
- - - 菜品名称 - -
- {{p}} -
-
- {{meal.label}} - -
- {{ item.name}} -
-
-
- {{item.people[p]}}g -
-
-
-
-
-
-
-
今日食材种类
-
-
-
-
- {{type.key}} : {{type.value}} 种 -
-
-
-
-
-
-
-
-
-
- - 今日营养分析 - - - - -
-
-
- - - - -
-
-
-
- - - -
-
\ No newline at end of file +
+
+
+
+ 今日带量食谱 + 【{{ currentMenu.name }}】 +
+
+ + + + + + + + + + + + + + + + + + + + + +
菜品名称三低标识 +
+ {{ p }} +
+
+ {{ meal.label }} + +
+ {{ item.name }} +
+
123 +
{{ item.people[p] }}g
+
+
+
+
+
+
+
今日食材种类
+
+
+
+
+ {{ type.key }} : {{ type.value }} 种 +
+
+
+
+
+
+
+
+
+
+ 今日营养分析 + + + +
+
+
+ + + + +
+
+
+
+ + diff --git a/projects/client/src/app/pages/data-vis/data-vis.component.ts b/projects/client/src/app/pages/data-vis/data-vis.component.ts index 18ba50d..649151b 100644 --- a/projects/client/src/app/pages/data-vis/data-vis.component.ts +++ b/projects/client/src/app/pages/data-vis/data-vis.component.ts @@ -1,184 +1,186 @@ -import { AfterViewInit, Component, ElementRef, Renderer2, ViewChild } from "@angular/core"; -import { ApiService } from "@cdk/services"; -import { format } from "date-fns"; -import { Subject, Subscription, finalize, interval, takeUntil } from "rxjs"; +import { AfterViewInit, Component, ElementRef, Renderer2, ViewChild } from '@angular/core' +import { ApiService } from '@cdk/services' +import { format } from 'date-fns' +import { Subject, Subscription, finalize, interval, takeUntil } from 'rxjs' interface MenuDisplayItem { - name: string; - id: number; + name: string + id: number } -const changeTime = 1000 * 60 * 3; +const changeTime = 1000 * 60 * 3 @Component({ - selector: "app-data-vis", - templateUrl: "./data-vis.component.html", - styleUrls: ["./data-vis.component.less"], + selector: 'app-data-vis', + templateUrl: './data-vis.component.html', + styleUrls: ['./data-vis.component.less'], }) export class DataVisComponent implements AfterViewInit { constructor(private api: ApiService, private rd2: Renderer2) {} - @ViewChild("tableEl") tableEl!: ElementRef; + @ViewChild('tableEl') tableEl!: ElementRef - @ViewChild("nutritionEl") nutritionEl!: ElementRef; + @ViewChild('nutritionEl') nutritionEl!: ElementRef - destroy$ = new Subject(); + destroy$ = new Subject() - showTime: string = ""; + showTime: string = '' - orgName = ""; + orgName = '' 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 = {}; + scroll: Record = {} - 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 { this.api.getOrgInfo().subscribe((res) => { - const account = this.api.account; + const account = this.api.account - this.orgName = account?.vender?.name ?? ""; - this.logo = account?.vender?.icon ?? ""; - }); + this.orgName = account?.vender?.name ?? '' + this.logo = account?.vender?.icon ?? '' + }) interval(1000) .pipe(takeUntil(this.destroy$)) .subscribe(() => { - const now = new Date(); - this.showTime = format(new Date(), "yyyy-MM-dd HH:mm:ss"); + const now = new Date() + this.showTime = format(new Date(), 'yyyy-MM-dd HH:mm:ss') if (now.getTime() - this.lastTime > changeTime) { - const currentIndex = this.menus.findIndex((f) => f.id === this.currentMenu?.id); - let idx = currentIndex + 1; + const currentIndex = this.menus.findIndex((f) => f.id === this.currentMenu?.id) + let idx = currentIndex + 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) => { if (Array.isArray(r.body)) { - this.menus = r.body; + this.menus = r.body } - }); + }) } ngAfterViewInit(): void {} ngOnDestroy(): void { - this.destroy$.next(null); - this.destroy$.complete(); + this.destroy$.next(null) + this.destroy$.complete() } getDataVisData(id: number) { - this.analysis = null; - this.peoples = []; - this.people = ""; - this.dishs = {}; - this.scroll = {}; + this.analysis = null + this.peoples = [] + this.people = '' + this.dishs = {} + this.scroll = {} this.api.getMenuDataVis(id).subscribe((res) => { - const dishs = res.body; + const dishs = res.body if (Array.isArray(dishs)) { - this.peoples = Object.keys(dishs?.[0]?.ingredient?.[0]?.value); - this.people = this.peoples[0]; + this.peoples = Object.keys(dishs?.[0]?.ingredient?.[0]?.value) + this.people = this.peoples[0] if (!this.peoples) { - console.error("dishs?.[0]?.ingredient?.[0]?.value 数据错误:", dishs); - return; + console.error('dishs?.[0]?.ingredient?.[0]?.value 数据错误:', dishs) + return } - this.menuId = dishs?.[0]?.menu; - this.getAnalysis(); + this.menuId = dishs?.[0]?.menu + this.getAnalysis() dishs.forEach((i: any) => { // 把每个食材按照不同的人群将重量加起来 this.peoples.forEach((people) => { - const foods = i.ingredient as any[]; + const foods = i.ingredient as any[] const c = foods.reduce((a, c) => { - return a + c.value[people]; - }, 0); + return a + c.value[people] + }, 0) if (!i.people) { - i.people = {}; + i.people = {} } - i.people[people] = c; - }); + i.people[people] = c + }) if (Array.isArray(this.dishs[i.meal])) { - this.dishs[i.meal].push(i); + this.dishs[i.meal].push(i) } else { - this.dishs[i.meal] = [i]; + this.dishs[i.meal] = [i] } - }); + }) setTimeout(() => { - this.autoScroll(this.tableEl.nativeElement, "1"); - }, 1000); + this.autoScroll(this.tableEl.nativeElement, '1') + }, 1000) } - }); + }) } - scrollSubs$?: Subscription; + scrollSubs$?: Subscription autoScroll(el: HTMLElement, scroll: string) { - this.scrollSubs$?.unsubscribe(); - const child = el.children[0]; + this.scrollSubs$?.unsubscribe() + const child = el.children[0] if (!child) { - return; + return } - const elHeight = el.clientHeight; - const childHeight = child.clientHeight; + const elHeight = el.clientHeight + const childHeight = child.clientHeight if (childHeight <= elHeight) { - return; + return } this.scrollSubs$ = interval(60) .pipe(takeUntil(this.destroy$)) .subscribe(() => { - this.scroll[scroll] = (this.scroll[scroll] ?? 0) + 1; - const paddingBottom = 100; + this.scroll[scroll] = (this.scroll[scroll] ?? 0) + 1 + const paddingBottom = 100 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() { if (!this.menuId) { - return; + return } this.api .getAnalysis(this.menuId, void 0, this.people) .pipe( finalize(() => { - this.analysisLoading = false; - }) + this.analysisLoading = false + }), ) .subscribe((res) => { - this.analysis = res.body; + this.analysis = res.body // setTimeout(() => { // this.autoScroll(this.nutritionEl.nativeElement, "2"); // }, 1000); - }); + }) } } diff --git a/projects/client/src/app/pages/dish/dish.component.html b/projects/client/src/app/pages/dish/dish.component.html index 5bc9db4..f93e72c 100644 --- a/projects/client/src/app/pages/dish/dish.component.html +++ b/projects/client/src/app/pages/dish/dish.component.html @@ -1,7 +1,6 @@ - -
- -
- - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-
- - {{ tableOrg[data] ? tableOrg[data].name : '-'}} - - -
- - - {{tableFoods[item.key]['name']}}:{{item.value}} g - - -
-
- - {{data}} - -
-
-
-
-
- -
-
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + {{ tableOrg[data] ? tableOrg[data].name : '-' }} + + + + {{ item }} + + + +
+ + + {{ tableFoods[item.key]['name'] }}:{{ item.value }} g + + +
+
+ + {{ data }} + +
+
+
+
+
+
+
- - - - + + + + - - - + - -
- - - - - - - - - - - - - - - - - - - - - - - - -
- 主要原料:{{item.ingredients.join(',')}} -
-
- 1毫克(mg)钠相当于2.5毫克食盐 -
-
-
\ No newline at end of file +
+ + + + + + + + + + + + + + + + + + + + + + +
主要原料:{{ item.ingredients.join(',') }}
+
1毫克(mg)钠相当于2.5毫克食盐
+
+ diff --git a/projects/client/src/app/pages/dish/dish.component.ts b/projects/client/src/app/pages/dish/dish.component.ts index 87c5080..bf447e7 100644 --- a/projects/client/src/app/pages/dish/dish.component.ts +++ b/projects/client/src/app/pages/dish/dish.component.ts @@ -1,9 +1,9 @@ -import { Component, OnInit, TemplateRef, ViewChild } from "@angular/core"; -import { FormControl, FormGroup } from "@angular/forms"; -import { NzDrawerRef, NzDrawerService } from "ng-zorro-antd/drawer"; -import { AnyObject, OrgDTO, TableListOption } from "@cdk/public-api"; -import { DishFormComponent } from "@client/app/components"; -import { ApiService } from "@cdk/services"; +import { Component, OnInit, TemplateRef, ViewChild } from '@angular/core' +import { FormControl, FormGroup } from '@angular/forms' +import { NzDrawerRef, NzDrawerService } from 'ng-zorro-antd/drawer' +import { AnyObject, OrgDTO, TableListOption } from '@cdk/public-api' +import { DishFormComponent } from '@client/app/components' +import { ApiService } from '@cdk/services' import { Subject, debounceTime, @@ -14,124 +14,125 @@ import { switchMap, takeUntil, tap, -} from "rxjs"; -import { NzModalService } from "ng-zorro-antd/modal"; -import { NzMessageService } from "ng-zorro-antd/message"; -import { ResponseType } from "@cdk/types"; -import { PrintComponent } from "@cdk/shared/components"; +} from 'rxjs' +import { NzModalService } from 'ng-zorro-antd/modal' +import { NzMessageService } from 'ng-zorro-antd/message' +import { ResponseType } from '@cdk/types' +import { PrintComponent } from '@cdk/shared/components' @Component({ - selector: "app-dish", - templateUrl: "./dish.component.html", - styleUrls: ["./dish.component.less"], + selector: 'app-dish', + templateUrl: './dish.component.html', + styleUrls: ['./dish.component.less'], }) export class DishComponent { constructor( private drawer: NzDrawerService, private api: ApiService, private modal: NzModalService, - private msg: NzMessageService + private msg: NzMessageService, ) {} - @ViewChild("formFooterTpl") formFooterTpl!: TemplateRef<{}>; + @ViewChild('formFooterTpl') formFooterTpl!: TemplateRef<{}> - @ViewChild("print") printRef!: PrintComponent; + @ViewChild('print') printRef!: PrintComponent - private drawerRef?: NzDrawerRef; + private drawerRef?: NzDrawerRef - private destroy$ = new Subject(); + private destroy$ = new Subject() - private orgSearch$ = new Subject(); + private orgSearch$ = new Subject() - public globalEnum = this.api.globalEnum; + public globalEnum = this.api.globalEnum - public printData: any | null; + public printData: any | null public tableList = new TableListOption(this.fetchData.bind(this), { selectable: true, frontPagination: false, - }); + }) public queryForm = new FormGroup({ - keyword: new FormControl(""), - mark: new FormControl(""), - vendors: new FormControl(""), - }); + keyword: new FormControl(''), + mark: new FormControl(''), + vendors: new FormControl(''), + }) - public selectedIds: string[] = []; + public selectedIds: string[] = [] - tableOrg: { [k: number]: OrgDTO } = {}; + tableOrg: { [k: number]: OrgDTO } = {} - tableFoods: { [k: string]: any } = {}; + tableFoods: { [k: string]: any } = {} - listOfOption: Array<{ value: number; text: string }> = []; + listOfOption: Array<{ value: number; text: string }> = [] - nzFilterOption = (): boolean => true; + nzFilterOption = (): boolean => true - submitLoading = false; + submitLoading = false ngOnInit(): void { - this.initTableList(); + this.initTableList() this.tableList.getState$.pipe(takeUntil(this.destroy$)).subscribe((res) => { - this.selectedIds = res.selectedKeys as Array; - }); + this.selectedIds = res.selectedKeys as Array + }) } searchOrg = (k: string) => { - this.orgSearch$.next(k); - }; + this.orgSearch$.next(k) + } ngOnDestroy(): void { - this.destroy$.next(); - this.destroy$.complete(); + this.destroy$.next() + this.destroy$.complete() } initTableList() { - this.tableList.scroll = { x: null }; + this.tableList.scroll = { x: null } this.tableList = this.tableList.setColumns([ - { key: "icon", title: "菜品图片", width: "66px" }, - { key: "name", title: "菜品名称" }, - { key: "marks", title: "菜品标签" }, - { key: "poly", title: "烹饪方式" }, - { key: "ingredient", title: "食材及含量", width: "30%" }, - ]); + { key: 'icon', title: '菜品图片', width: '66px' }, + { key: 'name', title: '菜品名称' }, + { key: 'marks', title: '菜品标签' }, + { key: 'label', title: '三低菜品标识' }, + { key: 'poly', title: '烹饪方式' }, + { key: 'ingredient', title: '食材及含量', width: '30%' }, + ]) this.tableList = this.tableList.setOptions([ { - title: "打印营养标签", + title: '打印营养标签', premissions: [], onClick: this.printTag.bind(this), }, { - title: "编辑", + title: '编辑', premissions: [], onClick: this.showFoodForm.bind(this), }, { - title: "删除", + title: '删除', premissions: [], onClick: this.deleteItem.bind(this), }, - ]); + ]) } fetchData(query: AnyObject, pager: AnyObject) { return this.api.getDishPage(pager, query).pipe( tap((res) => { - this.getTableColumData(res); - }) - ); + this.getTableColumData(res) + }), + ) } getTableColumData(res: ResponseType) { if (Array.isArray(res.body.content)) { - const vendors = res.body.content.map((i: any) => i.vender); + const vendors = res.body.content.map((i: any) => i.vender) const foodKeys = new Set( res.body.content.reduce((a: string[], c: any) => { - return a.concat(c.ingredient.map((i: any) => i.key)); - }, [] as string[]) - ); + return a.concat(c.ingredient.map((i: any) => i.key)) + }, [] as string[]), + ) if (foodKeys.size > 0) { this.api.getFoodList({ keys: Array.from(foodKeys) }).subscribe((foods) => { @@ -140,37 +141,37 @@ export class DishComponent { return { ...a, [c.key]: c, - }; - }, {} as AnyObject); + } + }, {} as AnyObject) } - }); + }) } } } printTag(v?: any) { - this.msg.loading("数据请求中,请不要刷新页面", { + this.msg.loading('数据请求中,请不要刷新页面', { nzDuration: 0, - }); - const ids = v ? [v.id] : this.selectedIds; + }) + const ids = v ? [v.id] : this.selectedIds this.api .getDishLabel(ids) .pipe( finalize(() => { setTimeout(() => { - this.msg.remove(); - }, 1000); - }) + this.msg.remove() + }, 1000) + }), ) .subscribe((res) => { - this.printData = res.body; - this.printRef.print(); - }); + this.printData = res.body + this.printRef.print() + }) } showFoodForm(data?: any) { this.drawerRef = this.drawer.create({ - nzTitle: data ? "编辑菜品" : "新增菜品", + nzTitle: data ? '编辑菜品' : '新增菜品', nzWidth: 700, nzContent: DishFormComponent, nzContentParams: { @@ -179,46 +180,46 @@ export class DishComponent { foods: Object.values(this.tableFoods), }, nzFooter: this.formFooterTpl, - }); + }) } cancelForm() { - this.drawerRef?.close(); + this.drawerRef?.close() } onSubmit() { if (this.drawerRef) { - const com = this.drawerRef.getContentComponent() as DishFormComponent; - const val = com.getValues(); + const com = this.drawerRef.getContentComponent() as DishFormComponent + const val = com.getValues() if (val) { - this.submitLoading = true; + this.submitLoading = true this.api .saveDish(val) .pipe( finalize(() => { - this.submitLoading = false; - }) + this.submitLoading = false + }), ) .subscribe((res) => { - this.msg.success(res.desc); - this.tableList.run(); - this.cancelForm(); - }); + this.msg.success(res.desc) + this.tableList.run() + this.cancelForm() + }) } } } deleteItem(v?: any) { - const ids = v ? [v.id] : this.selectedIds; + const ids = v ? [v.id] : this.selectedIds this.modal.confirm({ - nzTitle: "警告", + nzTitle: '警告', nzContent: `是否要删除${ids.length}个菜品?`, nzOkDanger: true, nzOnOk: async () => { - const res = await lastValueFrom(this.api.deleteDish(ids)); - this.msg.success(res.desc); - this.tableList.run(); + const res = await lastValueFrom(this.api.deleteDish(ids)) + this.msg.success(res.desc) + this.tableList.run() }, - }); + }) } } diff --git a/projects/client/src/app/pages/system/org-info/org-info.component.html b/projects/client/src/app/pages/system/org-info/org-info.component.html index b0c5755..dfad971 100644 --- a/projects/client/src/app/pages/system/org-info/org-info.component.html +++ b/projects/client/src/app/pages/system/org-info/org-info.component.html @@ -1,158 +1,116 @@ - - - - 单位基础信息 - - - - 编辑 - - - -
- - - 单位名称 - - - {{org.name}} - - - - - 单位Logo - - -
- -
-
-
- - - 地址 - - - {{org.address ?? '-'}} - - - - - 联系人 - - - {{org.contacts ?? '-'}} - - - - - 联系电话 - - - {{org.phone ?? '-'}} - - - - - 邮箱 - - - {{org.email ?? '-'}} - - -
-
+ + + 单位基础信息 + + 编辑 + + +
+ + 单位名称 + + {{ org.name }} + + + + 单位Logo + +
+ +
+
+
+ + 地址 + + {{ org.address ?? '-' }} + + + + 联系人 + + {{ org.contacts ?? '-' }} + + + + 联系电话 + + {{ org.phone ?? '-' }} + + + + 邮箱 + + {{ org.email ?? '-' }} + + +
+
- - - - 账号信息 - - - 仅支持主账号操作 - - -
- - - 账号 - - - {{account?.uid}} - - 修改账号 - - - + + + 账号信息 + 仅支持主账号操作 + +
+ + 账号 + + {{ account?.uid }} + 修改账号 + + - - - 密码 - - - - 修改密码 - - - - - - 账号到期时间 - - - {{org?.expire | date:'yyyy-MM-dd'}} - - 续费 - - - - -
-
+ + 密码 + + 修改密码 + + + + 账号到期时间 + + {{ org?.expire | date : 'yyyy-MM-dd' }} + 续费 + + +
+
-
- +
+ + 028-85463212 +
-
- - - 原密码 - - - - - - - - 新密码 - - - - - - - - 确认密码 - - - - - -
+
+ + 原密码 + + + + + + 新密码 + + + + + + 确认密码 + + + + +
- - - \ No newline at end of file + +