15 changed files with 961 additions and 777 deletions
@ -1,210 +1,210 @@ |
|||||
import { FoodFormComponent } from "@admin/app/components"; |
import { FoodFormComponent } from '@admin/app/components' |
||||
import { ApiService } from "@cdk/services"; |
import { ApiService } from '@cdk/services' |
||||
import { Component, OnDestroy, OnInit, TemplateRef, ViewChild } from "@angular/core"; |
import { Component, OnDestroy, OnInit, TemplateRef, ViewChild } from '@angular/core' |
||||
import { FormControl, FormGroup } from "@angular/forms"; |
import { FormControl, FormGroup } from '@angular/forms' |
||||
import { AnyObject, TableListOption } from "@cdk/public-api"; |
import { AnyObject, TableListOption } from '@cdk/public-api' |
||||
import { NzDrawerRef, NzDrawerService } from "ng-zorro-antd/drawer"; |
import { NzDrawerRef, NzDrawerService } from 'ng-zorro-antd/drawer' |
||||
import { NzModalRef, NzModalService } from "ng-zorro-antd/modal"; |
import { NzModalRef, NzModalService } from 'ng-zorro-antd/modal' |
||||
import { Subject, finalize, lastValueFrom, map, takeUntil } from "rxjs"; |
import { Subject, finalize, lastValueFrom, map, takeUntil } from 'rxjs' |
||||
import { NzMessageService } from "ng-zorro-antd/message"; |
import { NzMessageService } from 'ng-zorro-antd/message' |
||||
|
|
||||
@Component({ |
@Component({ |
||||
selector: "app-food", |
selector: 'app-food', |
||||
templateUrl: "./food.component.html", |
templateUrl: './food.component.html', |
||||
styleUrls: ["./food.component.less"], |
styleUrls: ['./food.component.less'], |
||||
}) |
}) |
||||
export class FoodComponent implements OnInit, OnDestroy { |
export class FoodComponent implements OnInit, OnDestroy { |
||||
constructor( |
constructor( |
||||
private drawer: NzDrawerService, |
private drawer: NzDrawerService, |
||||
private api: ApiService, |
private api: ApiService, |
||||
private modal: NzModalService, |
private modal: NzModalService, |
||||
private msg: NzMessageService |
private msg: NzMessageService, |
||||
) {} |
) {} |
||||
|
|
||||
@ViewChild("foodFormFooterTpl") foodFormFooterTpl!: TemplateRef<{}>; |
@ViewChild('foodFormFooterTpl') foodFormFooterTpl!: TemplateRef<{}> |
||||
|
|
||||
private drawerRef?: NzDrawerRef; |
private drawerRef?: NzDrawerRef |
||||
|
|
||||
private importModalRef?: NzModalRef; |
private importModalRef?: NzModalRef |
||||
|
|
||||
public tableList = new TableListOption(this.fetchData.bind(this), { |
public tableList = new TableListOption(this.fetchData.bind(this), { |
||||
selectable: true, |
selectable: true, |
||||
frontPagination: false, |
frontPagination: false, |
||||
rowKey: "key", |
rowKey: 'key', |
||||
}); |
}) |
||||
|
|
||||
public globalEnum = this.api.globalEnum; |
public globalEnum = this.api.globalEnum |
||||
|
|
||||
public queryForm = new FormGroup({ |
public queryForm = new FormGroup({ |
||||
keyword: new FormControl(""), |
keyword: new FormControl(''), |
||||
type: new FormControl(""), |
type: new FormControl(''), |
||||
}); |
}) |
||||
|
|
||||
private destroy$ = new Subject<void>(); |
private destroy$ = new Subject<void>() |
||||
|
|
||||
public selectedIds: string[] = []; |
public selectedIds: string[] = [] |
||||
|
|
||||
submitLoading = false; |
submitLoading = false |
||||
|
|
||||
uploadLoading = false; |
uploadLoading = false |
||||
|
|
||||
editItem = null; |
editItem = null |
||||
|
|
||||
ngOnInit(): void { |
ngOnInit(): void { |
||||
this.initTableList(); |
this.initTableList() |
||||
this.tableList.getState$.pipe(takeUntil(this.destroy$)).subscribe((res) => { |
this.tableList.getState$.pipe(takeUntil(this.destroy$)).subscribe((res) => { |
||||
this.selectedIds = res.selectedKeys as Array<string>; |
this.selectedIds = res.selectedKeys as Array<string> |
||||
}); |
}) |
||||
} |
} |
||||
|
|
||||
ngOnDestroy(): void { |
ngOnDestroy(): void { |
||||
this.destroy$.next(); |
this.destroy$.next() |
||||
this.destroy$.complete(); |
this.destroy$.complete() |
||||
} |
} |
||||
|
|
||||
initTableList() { |
initTableList() { |
||||
this.tableList.scroll = { x: null }; |
this.tableList.scroll = { x: null } |
||||
this.tableList = this.tableList.setColumns([ |
this.tableList = this.tableList.setColumns([ |
||||
{ key: "key", title: "食材编号" }, |
{ key: 'key', title: '食材编号' }, |
||||
{ key: "name", title: "食材名称" }, |
{ key: 'name', title: '食材名称' }, |
||||
{ key: "type", title: "食材类型" }, |
{ key: 'type', title: '食材类型' }, |
||||
{ key: "nutrientArr", title: "营养素(每100g可食部)", width: "40%" }, |
{ key: 'nutrientArr', title: '营养素(每100g可食部)', width: '40%' }, |
||||
{ key: "modify", title: "更新日期" }, |
{ key: 'modify', title: '更新日期' }, |
||||
]); |
]) |
||||
|
|
||||
this.tableList = this.tableList.setOptions([ |
this.tableList = this.tableList.setOptions([ |
||||
{ |
{ |
||||
title: "编辑", |
title: '编辑', |
||||
premissions: [], |
premissions: [], |
||||
onClick: this.showFoodForm.bind(this), |
onClick: this.showFoodForm.bind(this), |
||||
}, |
}, |
||||
{ |
{ |
||||
title: "删除", |
title: '删除', |
||||
premissions: [], |
premissions: [], |
||||
onClick: this.deleteFood.bind(this), |
onClick: this.deleteFood.bind(this), |
||||
}, |
}, |
||||
]); |
]) |
||||
} |
} |
||||
|
|
||||
fetchData(query: AnyObject, pager: AnyObject) { |
fetchData(query: AnyObject, pager: AnyObject) { |
||||
return this.api.getFoodPage(pager, query).pipe(); |
return this.api.getFoodPage(pager, query).pipe() |
||||
} |
} |
||||
|
|
||||
onTypeChange(type: string) { |
onTypeChange(type: string) { |
||||
this.queryForm.patchValue({ type }); |
this.queryForm.patchValue({ type }) |
||||
this.tableList.reset(); |
this.tableList.reset() |
||||
} |
} |
||||
|
|
||||
showFoodForm(food?: any) { |
showFoodForm(food?: any) { |
||||
this.editItem = food; |
this.editItem = food |
||||
this.drawerRef = this.drawer.create({ |
this.drawerRef = this.drawer.create({ |
||||
nzTitle: food ? "编辑食材" : "新增食材", |
nzTitle: food ? '编辑食材' : '新增食材', |
||||
nzWidth: 520, |
nzWidth: 520, |
||||
nzContentParams: { |
nzContentParams: { |
||||
food, |
food, |
||||
}, |
}, |
||||
nzContent: FoodFormComponent, |
nzContent: FoodFormComponent, |
||||
nzFooter: this.foodFormFooterTpl, |
nzFooter: this.foodFormFooterTpl, |
||||
}); |
}) |
||||
} |
} |
||||
|
|
||||
onFoodSubmit() { |
onFoodSubmit() { |
||||
if (this.drawerRef) { |
if (this.drawerRef) { |
||||
const com = this.drawerRef.getContentComponent() as FoodFormComponent; |
const com = this.drawerRef.getContentComponent() as FoodFormComponent |
||||
const val = com.getValues(); |
const val = com.getValues() |
||||
if (val) { |
if (val) { |
||||
this.submitLoading = true; |
this.submitLoading = true |
||||
this.api |
this.api |
||||
.saveFood(val, !!this.editItem) |
.saveFood(val, !!this.editItem) |
||||
.pipe( |
.pipe( |
||||
finalize(() => { |
finalize(() => { |
||||
this.submitLoading = false; |
this.submitLoading = false |
||||
}) |
}), |
||||
) |
) |
||||
.subscribe((res) => { |
.subscribe((res) => { |
||||
this.msg.success(res.desc); |
this.msg.success(res.desc) |
||||
this.cancelFoodForm(); |
this.cancelFoodForm() |
||||
this.tableList.run(); |
this.tableList.run() |
||||
}); |
}) |
||||
} |
} |
||||
} |
} |
||||
} |
} |
||||
cancelFoodForm() { |
cancelFoodForm() { |
||||
this.drawerRef?.close(); |
this.drawerRef?.close() |
||||
} |
} |
||||
|
|
||||
deleteFood(v?: any) { |
deleteFood(v?: any) { |
||||
const ids = v ? [v.key] : this.selectedIds; |
const ids = v ? [v.key] : this.selectedIds |
||||
this.modal.confirm({ |
this.modal.confirm({ |
||||
nzTitle: "警告", |
nzTitle: '警告', |
||||
nzContent: `是否要删除${ids.length}个食材?`, |
nzContent: `是否要删除${ids.length}个食材?`, |
||||
nzOkDanger: true, |
nzOkDanger: true, |
||||
nzOnOk: async () => { |
nzOnOk: async () => { |
||||
const res = await lastValueFrom(this.api.deleteFoods(ids)); |
const res = await lastValueFrom(this.api.deleteFoods(ids)) |
||||
this.msg.success(res.desc); |
this.msg.success(res.desc) |
||||
this.tableList.run(); |
this.tableList.run() |
||||
}, |
}, |
||||
}); |
}) |
||||
} |
} |
||||
|
|
||||
downloadTemplate() { |
downloadTemplate() { |
||||
this.api.getFoodExcelTemplate().subscribe((res) => { |
this.api.getFoodExcelTemplate().subscribe((res) => { |
||||
console.log("res", res); |
console.log('res', res) |
||||
}); |
}) |
||||
} |
} |
||||
|
|
||||
showImportForm(nzContent: TemplateRef<{}>) { |
showImportForm(nzContent: TemplateRef<{}>) { |
||||
this.importModalRef = this.modal.create({ |
this.importModalRef = this.modal.create({ |
||||
nzTitle: "导入食材清单", |
nzTitle: '导入食材清单', |
||||
nzWidth: 520, |
nzWidth: 520, |
||||
nzContent, |
nzContent, |
||||
nzFooter: null, |
nzFooter: null, |
||||
}); |
}) |
||||
} |
} |
||||
|
|
||||
suppress(e: Event) { |
suppress(e: Event) { |
||||
e.stopPropagation(); |
e.stopPropagation() |
||||
e.preventDefault(); |
e.preventDefault() |
||||
} |
} |
||||
|
|
||||
handleDrop = (e: Event) => { |
handleDrop = (e: Event) => { |
||||
e.stopPropagation(); |
e.stopPropagation() |
||||
e.preventDefault(); |
e.preventDefault() |
||||
const event = e as DragEvent; |
const event = e as DragEvent |
||||
const files = event.dataTransfer?.files; |
const files = event.dataTransfer?.files |
||||
if (files) { |
if (files) { |
||||
this.onFileChange(files); |
this.onFileChange(files) |
||||
|
} |
||||
} |
} |
||||
}; |
|
||||
|
|
||||
onFileChange(e: FileList | Event) { |
onFileChange(e: FileList | Event) { |
||||
let files: FileList; |
let files: FileList |
||||
if (e instanceof FileList) { |
if (e instanceof FileList) { |
||||
files = e; |
files = e |
||||
} else { |
} else { |
||||
const target = e.target as HTMLInputElement; |
const target = e.target as HTMLInputElement |
||||
files = target.files!; |
files = target.files! |
||||
} |
} |
||||
if (files?.length > 0) { |
if (files?.length > 0) { |
||||
const formData = new FormData(); |
const formData = new FormData() |
||||
formData.append("file", files[0]); |
formData.append('file', files[0]) |
||||
this.uploadLoading = true; |
this.uploadLoading = true |
||||
this.api |
this.api |
||||
.importFood(formData) |
.importFood(formData) |
||||
.pipe( |
.pipe( |
||||
finalize(() => { |
finalize(() => { |
||||
this.uploadLoading = false; |
this.uploadLoading = false |
||||
}) |
}), |
||||
) |
) |
||||
.subscribe(() => { |
.subscribe(() => { |
||||
this.msg.success("导入成功"); |
this.msg.success('导入成功') |
||||
this.tableList.run(); |
this.tableList.run() |
||||
this.importModalRef?.close(); |
this.importModalRef?.close() |
||||
}); |
}) |
||||
} |
} |
||||
if (e instanceof Event) { |
if (e instanceof Event) { |
||||
const target = e.target as HTMLInputElement; |
const target = e.target as HTMLInputElement |
||||
target.value = ""; |
target.value = '' |
||||
} |
} |
||||
} |
} |
||||
} |
} |
||||
|
@ -0,0 +1,33 @@ |
|||||
|
<table-list |
||||
|
#tableRef |
||||
|
[props]="tableList" |
||||
|
[search]="searchTpl" |
||||
|
[formGroup]="queryForm" |
||||
|
[renderColumns]="renderColumnsTpl" |
||||
|
> |
||||
|
<ng-template #searchTpl> |
||||
|
<nz-form-item> |
||||
|
<nz-form-control> |
||||
|
<input nz-input placeholder="请输入食材名称/编号" formControlName="keyword" /> |
||||
|
</nz-form-control> |
||||
|
</nz-form-item> |
||||
|
</ng-template> |
||||
|
|
||||
|
<ng-template #renderColumnsTpl let-data let-key="key" let-row="row"> |
||||
|
<ng-container [ngSwitch]="key"> |
||||
|
<ng-container *ngSwitchCase="'nutrientArr'"> |
||||
|
<div class="flex flex-wrap"> |
||||
|
<nz-tag *ngFor="let item of data" class="m-1"> |
||||
|
{{ item.label }}:{{ item.value }}{{ item.measurement }} |
||||
|
</nz-tag> |
||||
|
</div> |
||||
|
</ng-container> |
||||
|
<ng-container *ngSwitchCase="'modify'"> |
||||
|
{{ data | date : 'yyyy-MM-dd HH:mm:ss' }} |
||||
|
</ng-container> |
||||
|
<ng-container *ngSwitchDefault> |
||||
|
{{ data }} |
||||
|
</ng-container> |
||||
|
</ng-container> |
||||
|
</ng-template> |
||||
|
</table-list> |
@ -0,0 +1,66 @@ |
|||||
|
import { Component, OnInit, ViewChild } from '@angular/core' |
||||
|
import { FormControl, FormGroup } from '@angular/forms' |
||||
|
import { AnyObject, TableListComponent, TableListOption } from '@cdk/public-api' |
||||
|
import { ApiService } from '@cdk/services' |
||||
|
import { Subject, takeUntil, tap } from 'rxjs' |
||||
|
|
||||
|
@Component({ |
||||
|
selector: 'lib-select-food', |
||||
|
templateUrl: './select-food.component.html', |
||||
|
styleUrls: ['./select-food.component.less'], |
||||
|
}) |
||||
|
export class SelectFoodComponent implements OnInit { |
||||
|
constructor(private api: ApiService) {} |
||||
|
|
||||
|
@ViewChild('tableRef') tableRef!: TableListComponent |
||||
|
|
||||
|
selectedIds: string[] = [] |
||||
|
|
||||
|
allFood: any[] = [] |
||||
|
|
||||
|
private destroy$ = new Subject<void>() |
||||
|
|
||||
|
public tableList = new TableListOption(this.fetchData.bind(this), { |
||||
|
selectable: true, |
||||
|
frontPagination: false, |
||||
|
rowKey: 'key', |
||||
|
}) |
||||
|
|
||||
|
public queryForm = new FormGroup({ |
||||
|
keyword: new FormControl(''), |
||||
|
type: new FormControl(''), |
||||
|
}) |
||||
|
|
||||
|
ngOnInit(): void { |
||||
|
this.tableList.getState$.pipe(takeUntil(this.destroy$)).subscribe((res) => { |
||||
|
this.selectedIds = res.selectedKeys as Array<string> |
||||
|
}) |
||||
|
this.initTableList() |
||||
|
} |
||||
|
|
||||
|
ngOnDestroy(): void { |
||||
|
this.destroy$.next() |
||||
|
this.destroy$.complete() |
||||
|
} |
||||
|
|
||||
|
fetchData(query: AnyObject, pager: AnyObject) { |
||||
|
return this.api.getFoodPage(pager, query).pipe( |
||||
|
tap((res) => { |
||||
|
this.allFood = this.allFood.concat(res.body.content) |
||||
|
}), |
||||
|
) |
||||
|
} |
||||
|
|
||||
|
getSelectedFoods() { |
||||
|
return this.allFood.filter((f) => this.selectedIds.includes(f['key'])) |
||||
|
} |
||||
|
|
||||
|
initTableList() { |
||||
|
this.tableList.scroll = { x: null } |
||||
|
this.tableList = this.tableList.setColumns([ |
||||
|
{ key: 'key', title: '食材编号' }, |
||||
|
{ key: 'name', title: '食材名称' }, |
||||
|
{ key: 'type', title: '食材类型' }, |
||||
|
]) |
||||
|
} |
||||
|
} |
Loading…
Reference in new issue