Browse Source

食谱菜品支持修改食材

main
kkerwin 2 years ago
parent
commit
6087548d00
  1. 207
      projects/admin/src/app/pages/food/food.component.html
  2. 182
      projects/admin/src/app/pages/food/food.component.ts
  3. 149
      projects/admin/src/app/pages/ingredients/ingredient-form/ingredient-form.component.ts
  4. 135
      projects/cdk/src/ingredient/add-dish-to-ingredient/add-dish-to-ingredient.component.html
  5. 98
      projects/cdk/src/ingredient/add-dish-to-ingredient/add-dish-to-ingredient.component.ts
  6. 51
      projects/cdk/src/ingredient/ingredient-analysis/ingredient-analysis.component.ts
  7. 51
      projects/cdk/src/ingredient/ingredient-meals/ingredient-meals.component.html
  8. 40
      projects/cdk/src/ingredient/ingredient-meals/ingredient-meals.component.ts
  9. 4
      projects/cdk/src/ingredient/ingredient-preview/ingredient-preview.component.less
  10. 23
      projects/cdk/src/ingredient/ingredient.module.ts
  11. 33
      projects/cdk/src/ingredient/select-food/select-food.component.html
  12. 0
      projects/cdk/src/ingredient/select-food/select-food.component.less
  13. 66
      projects/cdk/src/ingredient/select-food/select-food.component.ts
  14. 408
      projects/cdk/src/table-list/table-list/table-list.component.html
  15. 285
      projects/cdk/src/table-list/table-list/table-list.component.ts

207
projects/admin/src/app/pages/food/food.component.html

@ -1,114 +1,111 @@
<app-page [scroll]="false"> <app-page [scroll]="false">
<ng-template #pageExtraTpl> <ng-template #pageExtraTpl>
<nz-space> <nz-space>
<button *nzSpaceItem nz-button [disabled]="!selectedIds.length" (click)="deleteFood()">批量删除</button> <button *nzSpaceItem nz-button [disabled]="!selectedIds.length" (click)="deleteFood()">批量删除</button>
<button *nzSpaceItem nz-button (click)="showImportForm(importFormTpl)">导入食材清单</button> <button *nzSpaceItem nz-button (click)="showImportForm(importFormTpl)">导入食材清单</button>
<button *nzSpaceItem nz-button nzType="primary" (click)="showFoodForm()"> <button *nzSpaceItem nz-button nzType="primary" (click)="showFoodForm()">
<i nz-icon nzType="plus"></i> <i nz-icon nzType="plus"></i>
新增食材 新增食材
</button> </button>
</nz-space> </nz-space>
</ng-template> </ng-template>
<div nz-row class="h-full overflow-hidden bg-white rounded-lg"> <div nz-row class="h-full overflow-hidden bg-white rounded-lg">
<div nz-col nzFlex="220px" class="food-type h-full"> <div nz-col nzFlex="220px" class="food-type h-full">
<nz-card class="h-full" [nzBordered]="false" nzTitle="食材类型" <nz-card
[nzBodyStyle]="{padding:'1px 0 0 0', height:'100%',overflow:'auto'}"> class="h-full"
<ul nz-menu nzMode="inline"> [nzBordered]="false"
<li nz-menu-item (click)="onTypeChange('')" [nzSelected]="!queryForm.get('type')?.value"> nzTitle="食材类型"
<a> [nzBodyStyle]="{ padding: '1px 0 0 0', height: '100%', overflow: 'auto' }"
全部 >
</a> <ul nz-menu nzMode="inline">
</li> <li nz-menu-item (click)="onTypeChange('')" [nzSelected]="!queryForm.get('type')?.value">
<li nz-menu-item [nzSelected]="cate.key === queryForm.get('type')?.value" <a> 全部 </a>
*ngFor="let cate of globalEnum.category" (click)="onTypeChange(cate.key)"> </li>
<a> <li
{{cate.key}} nz-menu-item
</a> [nzSelected]="cate.key === queryForm.get('type')?.value"
</li> *ngFor="let cate of globalEnum.category"
</ul> (click)="onTypeChange(cate.key)"
</nz-card> >
</div> <a>
<div nz-col nzFlex="1" class="flex-1 overflow-hidden bg-white h-full"> {{ cate.key }}
</a>
</li>
</ul>
</nz-card>
</div>
<div nz-col nzFlex="1" class="flex-1 overflow-hidden bg-white h-full">
<nz-card [nzBordered]="false" nzTitle="食材管理" class="scroll-card-body">
<div class="m-4">
<table-list
[props]="tableList"
[search]="searchTpl"
[action]="pageExtraTpl"
[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>
<nz-card [nzBordered]="false" nzTitle="食材管理" class="scroll-card-body"> <ng-template #renderColumnsTpl let-data let-key="key" let-row="row">
<div class="m-4"> <ng-container [ngSwitch]="key">
<table-list <ng-container *ngSwitchCase="'nutrientArr'">
[props]="tableList" <div class="flex flex-wrap">
[search]="searchTpl" <nz-tag *ngFor="let item of data" class="m-1">
[action]="pageExtraTpl" {{ item.label }}:{{ item.value }}{{ item.measurement }}
[formGroup]="queryForm" </nz-tag>
[renderColumns]="renderColumnsTpl"> </div>
</ng-container>
<ng-template #searchTpl> <ng-container *ngSwitchCase="'modify'">
<nz-form-item> {{ data | date : 'yyyy-MM-dd HH:mm:ss' }}
<nz-form-control> </ng-container>
<input nz-input placeholder="请输入食材名称/编号" formControlName="keyword" /> <ng-container *ngSwitchDefault>
</nz-form-control> {{ data }}
</nz-form-item> </ng-container>
</ng-template> </ng-container>
</ng-template>
<ng-template #renderColumnsTpl let-data let-key="key" let-row="row"> </table-list>
<ng-container [ngSwitch]="key"> </div>
<ng-container *ngSwitchCase="'nutrientArr'"> </nz-card>
<div class=" flex flex-wrap"> </div>
<nz-tag *ngFor="let item of data" class="m-1"> </div>
{{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>
</div>
</nz-card>
</div>
</div>
</app-page> </app-page>
<ng-template #importFormTpl> <ng-template #importFormTpl>
<p class=" text-slate-400"> <p class="text-slate-400">
提示:<a (click)="downloadTemplate()">下载示例模版</a>,进行编辑,导入Excel文件,批量导入食材 提示:<a (click)="downloadTemplate()">下载示例模版</a>,进行编辑,导入Excel文件,批量导入食材
</p> </p>
<div> <div>
<nz-spin [nzSpinning]="uploadLoading"> <nz-spin [nzSpinning]="uploadLoading">
<div class="upload-area flex-col" <div
(drop)="handleDrop($event)" class="upload-area flex-col"
(dragenter)="suppress($event)" (drop)="handleDrop($event)"
(dragover)="suppress($event)"> (dragenter)="suppress($event)"
<input type="file" id="file" (change)="onFileChange($event)" accept=".xlsx,.xls" /> (dragover)="suppress($event)"
<div class="text-center"> >
<p class="text-4xl mb-1"> <input type="file" id="file" (change)="onFileChange($event)" accept=".xlsx,.xls" />
<a nz-icon nzType="upload" nzTheme="outline"></a> <div class="text-center">
</p> <p class="text-4xl mb-1">
<p class="mb-1"> <a nz-icon nzType="upload" nzTheme="outline"></a>
点击或将文件拖拽到这里上传 </p>
</p> <p class="mb-1">点击或将文件拖拽到这里上传</p>
<p class="text-slate-400"> <p class="text-slate-400">支持扩展名:.xls .xlsx</p>
支持扩展名:.xls .xlsx </div>
</p> </div>
</div> </nz-spin>
</div> </div>
</nz-spin>
</div>
</ng-template> </ng-template>
<ng-template #foodFormFooterTpl> <ng-template #foodFormFooterTpl>
<nz-space> <nz-space>
<button *nzSpaceItem nz-button (click)="cancelFoodForm()" type="button"> <button *nzSpaceItem nz-button (click)="cancelFoodForm()" type="button">取消</button>
取消 <button *nzSpaceItem nz-button nzType="primary" [nzLoading]="submitLoading" (click)="onFoodSubmit()">
</button> 保存
<button *nzSpaceItem nz-button nzType="primary" [nzLoading]="submitLoading" (click)="onFoodSubmit()"> </button>
保存 </nz-space>
</button>
</nz-space>
</ng-template> </ng-template>

182
projects/admin/src/app/pages/food/food.component.ts

@ -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 = ''
} }
} }
} }

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

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

135
projects/cdk/src/ingredient/add-dish-to-ingredient/add-dish-to-ingredient.component.html

@ -1,28 +1,28 @@
<div nz-form> <div nz-form>
<div nz-row [nzGutter]="12"> <div nz-row [nzGutter]="12">
<div nz-col nzSpan="14"> <div nz-col nzSpan="14">
<nz-form-item> <nz-form-item>
<nz-form-label nzRequired="">菜品名称</nz-form-label> <nz-form-label nzRequired="">菜品名称</nz-form-label>
<nz-form-control> <nz-form-control>
<!-- 请输入菜品名称搜索 --> <!-- 请输入菜品名称搜索 -->
<app-dish-select [(ngModel)]="dish" (ngModelChange)="onDishChange($event)"></app-dish-select> <app-dish-select [(ngModel)]="dish" (ngModelChange)="onDishChange($event)"></app-dish-select>
</nz-form-control> </nz-form-control>
</nz-form-item> </nz-form-item>
</div> </div>
<div nz-col nzSpan="10"> <div nz-col nzSpan="10">
<nz-form-item> <nz-form-item>
<nz-form-label nzRequired="">菜品标签</nz-form-label> <nz-form-label nzRequired="">菜品标签</nz-form-label>
<nz-form-control> <nz-form-control>
<nz-select nzPlaceHolder="请选择菜品标签" [(ngModel)]="mark"> <nz-select nzPlaceHolder="请选择菜品标签" [(ngModel)]="mark">
<nz-option *ngFor="let item of globalEnum.mark" [nzValue]="item.value" <nz-option *ngFor="let item of globalEnum.mark" [nzValue]="item.value" [nzLabel]="item.key">
[nzLabel]="item.key"></nz-option> </nz-option>
</nz-select> </nz-select>
</nz-form-control> </nz-form-control>
</nz-form-item> </nz-form-item>
</div> </div>
</div> </div>
<!-- <nz-form-item> <!-- <nz-form-item>
<nz-form-label nzRequired="">食材搜索方式</nz-form-label> <nz-form-label nzRequired="">食材搜索方式</nz-form-label>
<nz-form-control> <nz-form-control>
<nz-radio-group nzButtonStyle="solid"> <nz-radio-group nzButtonStyle="solid">
@ -32,44 +32,47 @@
</nz-form-control> </nz-form-control>
</nz-form-item> --> </nz-form-item> -->
<div>
<nz-table nzTemplateMode [nzBordered]="true" nzSize="small" [nzScroll]="{ x: '1000px' }">
<thead>
<tr>
<!-- <th nzWidth="80px" nzLeft>删除</th> -->
<th nzWidth="200px" nzLeft>食材</th>
<th nzWidth="80px" nzLeft>是否主料</th>
<th *ngFor="let p of peopleGroups" nzWidth="120px">
{{ p }}
</th>
<div> <!-- <th nzRight nzWidth="150px">
<nz-table nzTemplateMode [nzBordered]="true" nzSize="small" [nzScroll]="{ x: '1000px' }">
<thead>
<tr>
<th nzWidth="200px">
食材
</th>
<th nzWidth="80px">
是否主料
</th>
<th *ngFor="let p of peopleGroups" nzWidth="120px">
{{p}}
</th>
<!-- <th nzRight nzWidth="150px">
操作 操作
</th> --> </th> -->
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr *ngFor="let item of foods"> <tr *ngFor="let item of foods">
<td> <!-- <td nzLeft>
{{item.foodName}} <button nz-button nzType="link" (click)="deleteFood(item)">
</td> <i nz-icon nzType="delete"></i>
<td> </button>
<nz-switch </td> -->
[(ngModel)]="item.isMain" <td nzLeft>
[nzDisabled]="true" {{ item.foodName }}
nzCheckedChildren="是" </td>
nzUnCheckedChildren="否"> <td nzLeft>
</nz-switch> <nz-switch
</td> [(ngModel)]="item.isMain"
<td *ngFor="let p of item.groupValues"> [nzDisabled]="true"
<nz-input-group nzAddOnAfter="g"> nzCheckedChildren="是"
<input nz-input type="number" min="0" placeholder="重量" [(ngModel)]="p.value" /> nzUnCheckedChildren="否"
</nz-input-group> >
</td> </nz-switch>
<!-- <td nzRight> </td>
<td *ngFor="let p of item.groupValues">
<nz-input-group nzAddOnAfter="g" class="w-28">
<input nz-input type="number" min="0" placeholder="重量" [(ngModel)]="p.value" />
</nz-input-group>
</td>
<!-- <td nzRight>
<nz-space nzSize="small"> <nz-space nzSize="small">
<button *nzSpaceItem nz-button nzType="link"> <button *nzSpaceItem nz-button nzType="link">
修改 修改
@ -79,10 +82,14 @@
</button> </button>
</nz-space> </nz-space>
</td> --> </td> -->
</tr> </tr>
<!-- <tr *ngIf="dish">
</tbody> <td [attr.colspan]="peopleGroups.length + 3">
</nz-table> <button nz-button [nzBlock]="true" (click)="addNewFood()">新增食材</button>
<nz-empty class="mt-4" *ngIf="foods.length === 0"></nz-empty> </td>
</div> </tr> -->
</tbody>
</nz-table>
<nz-empty class="mt-4" *ngIf="foods.length === 0"></nz-empty>
</div>
</div> </div>

98
projects/cdk/src/ingredient/add-dish-to-ingredient/add-dish-to-ingredient.component.ts

@ -1,34 +1,36 @@
import { Component, Input, OnInit } from "@angular/core"; import { Component, Input, OnInit } from '@angular/core'
import { ApiService } from "@cdk/services"; import { ApiService } from '@cdk/services'
import { NzModalService } from 'ng-zorro-antd/modal'
import { SelectFoodComponent } from '../select-food/select-food.component'
export interface FoodInDishInterface { export interface FoodInDishInterface {
foodName: string; foodName: string
key: string; key: string
isMain: boolean; isMain: boolean
groupValues: Array<{ groupValues: Array<{
peopleName: string; peopleName: string
value: number; value: number
}>; }>
value: Record<string, number>; value: Record<string, number>
} }
@Component({ @Component({
selector: "app-add-dish-to-ingredient", selector: 'app-add-dish-to-ingredient',
templateUrl: "./add-dish-to-ingredient.component.html", templateUrl: './add-dish-to-ingredient.component.html',
styleUrls: ["./add-dish-to-ingredient.component.less"], styleUrls: ['./add-dish-to-ingredient.component.less'],
}) })
export class AddDishToIngredientComponent implements OnInit { export class AddDishToIngredientComponent implements OnInit {
constructor(private api: ApiService) {} constructor(private api: ApiService, private modal: NzModalService) {}
@Input() peopleGroups: string[] = []; @Input() peopleGroups: string[] = []
globalEnum = this.api.globalEnum; globalEnum = this.api.globalEnum
dish: any = null; dish: any = null
mark: string = ""; mark: string = ''
foods: FoodInDishInterface[] = []; foods: FoodInDishInterface[] = []
ngOnInit(): void { ngOnInit(): void {
// console.log("this.peopleGroups", this.peopleGroups); // console.log("this.peopleGroups", this.peopleGroups);
@ -36,30 +38,50 @@ export class AddDishToIngredientComponent implements OnInit {
onDishChange(dish: any) { onDishChange(dish: any) {
if (dish) { if (dish) {
this.dish = dish; this.dish = dish
this.mark = dish.marks; this.mark = dish.marks
this.getFoodNameByKeys(dish.ingredient); this.getFoodNameByKeys(dish.ingredient)
} }
} }
getFoodNameByKeys(foods: any[]) { getFoodNameByKeys(foods: any[]) {
const keys = foods.map((i) => i.key); const keys = foods.map((i) => i.key)
this.api.getFoodList({ keys }).subscribe((res) => { this.api.getFoodList({ keys }).subscribe((res) => {
this.foods = res.body.map((i) => { this.foods = this.addPeopleToFood(res.body, foods)
const value = this.dish?.ingredient?.find((f: any) => f["key"] === i.key)?.value ?? 0; })
return { }
foodName: i.name,
key: i.key, addPeopleToFood(pureFoods: any[], foods: any[] = []): FoodInDishInterface[] {
isMain: foods.find((f) => f.key === i.key)?.isMain ?? false, return pureFoods.map((i) => {
groupValues: this.peopleGroups.map((p) => { const value = this.dish?.ingredient?.find((f: any) => f['key'] === i.key)?.value ?? 0
return { return {
peopleName: p, foodName: i.name,
value, key: i.key,
}; isMain: foods.find((f) => f.key === i.key)?.isMain ?? false,
}), groupValues: this.peopleGroups.map((p) => {
value: {}, return {
}; peopleName: p,
}); value,
}); }
}),
value: {},
}
})
}
deleteFood(food: FoodInDishInterface) {
this.foods = this.foods.filter((f) => f.key !== food.key)
}
addNewFood() {
this.modal.create({
nzTitle: '添加食材',
nzContent: SelectFoodComponent,
nzWidth: 800,
nzOnOk: (e) => {
const newSelectedFoods = e.getSelectedFoods()
this.foods = this.foods.concat(this.addPeopleToFood(newSelectedFoods, []))
},
})
} }
} }

51
projects/cdk/src/ingredient/ingredient-analysis/ingredient-analysis.component.ts

@ -113,32 +113,29 @@ export class IngredientAnalysisComponent implements OnInit {
} }
nzSelectedIndexChange(d: any) { nzSelectedIndexChange(d: any) {
if (d === 2) { // if (d === 2) {
const xAxis: string[] = Object.keys(this.suger['oil']).map((i: any) => weekdayMap[i]) // const xAxis: string[] = Object.keys(this.suger['oil']).map((i: any) => weekdayMap[i])
const series: any[] = [] // const series: any[] = []
Object.entries(this.suger).forEach(([k, v]) => { // Object.entries(this.suger).forEach(([k, v]) => {
if (k !== 'crow') { // if (k !== 'crow') {
series.push({ // series.push({
type: 'line', // type: 'line',
name: sugerMap.get(k), // name: sugerMap.get(k),
data: Object.values(v as any), // data: Object.values(v as any),
}) // })
} // }
}) // })
// const option = {
const option = { // legend: {},
legend: {}, // tooltip: { trigger: 'axis' },
tooltip: { trigger: 'axis' }, // xAxis: { type: 'category', data: xAxis },
xAxis: { type: 'category', data: xAxis }, // yAxis: {},
yAxis: {}, // series,
series, // }
} // if (!this.sugerRef) {
// this.sugerRef = init(this.sugerEl.nativeElement)
if (!this.sugerRef) { // }
this.sugerRef = init(this.sugerEl.nativeElement) // this.sugerRef.setOption(option)
} // }
this.sugerRef.setOption(option)
}
} }
} }

51
projects/cdk/src/ingredient/ingredient-meals/ingredient-meals.component.html

@ -17,7 +17,7 @@
</tr> --> </tr> -->
<tr> <tr>
<th nzWidth="200px" nzLeft class="placeholder-th">&nbsp;</th> <th nzWidth="300px" nzLeft class="placeholder-th">&nbsp;</th>
<th nzWidth="200px" nzLeft> <th nzWidth="200px" nzLeft>
<span class="absolute top-2 left-[500px] z-10 w-[150px] h-[40px]">重量/克</span> <span class="absolute top-2 left-[500px] z-10 w-[150px] h-[40px]">重量/克</span>
</th> </th>
@ -49,16 +49,18 @@
</nz-tag> </nz-tag>
</div> </div>
</div> </div>
<button nz-button nzType="text" (click)="onRemoveDish(dish, dishIndex)"> <button nz-button nzType="text" nz-dropdown [nzDropdownMenu]="dishOptions">
<i nz-icon nzType="delete"></i> <i nz-icon nzType="more"></i>
</button> </button>
<!-- nz-dropdown [nzDropdownMenu]="dishOptions" -->
<!-- <nz-dropdown-menu #dishOptions="nzDropdownMenu"> <nz-dropdown-menu #dishOptions="nzDropdownMenu">
<ul nz-menu nzSelectable class=" w-20"> <ul nz-menu nzSelectable class="w-20">
<li nz-menu-item>编辑</li> <li nz-menu-item (click)="addNewFood(dish)">新增食材</li>
<li nz-menu-item nzDanger>删除</li> <li nz-menu-item nzDanger (click)="onRemoveDish(dish, dishIndex)">
</ul> 删除菜品
</nz-dropdown-menu> --> </li>
</ul>
</nz-dropdown-menu>
</div> </div>
</td> </td>
<td nzLeft> <td nzLeft>
@ -66,19 +68,28 @@
<span> <span>
{{ food['foodName'] }} {{ food['foodName'] }}
</span> </span>
<!-- <button nz-button nzType="text" nz-dropdown [nzDropdownMenu]="foodOptions"> <button nz-button nzType="text" nz-dropdown [nzDropdownMenu]="foodOptions">
<i nz-icon nzType="more"></i> <i nz-icon nzType="more"></i>
</button> </button>
<nz-dropdown-menu #foodOptions="nzDropdownMenu"> <nz-dropdown-menu #foodOptions="nzDropdownMenu">
<ul nz-menu nzSelectable class="w-100"> <ul nz-menu nzSelectable class="w-100">
<li nz-menu-item>设置价格</li> <!-- <li nz-menu-item>设置价格</li> -->
<li nz-menu-item nzDanger>删除</li> <li nz-menu-item nzDanger (click)="removeFood(dish, food['key'])">
</ul> 删除食材
</nz-dropdown-menu> --> </li>
</ul>
</nz-dropdown-menu>
</div> </div>
</td> </td>
<td *ngFor="let g of food['groupValues']"> <td *ngFor="let g of food['groupValues']">
<input nz-input type="number" [(ngModel)]="g.value" (ngModelChange)="onValueChange()" /> <nz-input-group nzAddOnAfter="g" class="w-28">
<input
nz-input
type="number"
[(ngModel)]="g.value"
(ngModelChange)="onValueChange()"
/>
</nz-input-group>
</td> </td>
</tr> </tr>
</ng-container> </ng-container>

40
projects/cdk/src/ingredient/ingredient-meals/ingredient-meals.component.ts

@ -18,6 +18,7 @@ import { NzDrawerRef, NzDrawerService } from 'ng-zorro-antd/drawer'
import { NzMessageService } from 'ng-zorro-antd/message' import { NzMessageService } from 'ng-zorro-antd/message'
import { Augmented } from '@cdk/types' import { Augmented } from '@cdk/types'
import { DishInterface } from '../ingredient-dish/ingredient-dish.component' import { DishInterface } from '../ingredient-dish/ingredient-dish.component'
import { SelectFoodComponent } from '../select-food/select-food.component'
export type MealDishInterface = Augmented<{ export type MealDishInterface = Augmented<{
dishId: number dishId: number
@ -101,6 +102,45 @@ export class IngredientMealsComponent implements OnChanges, OnInit {
}) })
} }
addNewFood(d: DishInterface) {
this.modal.create({
nzTitle: '添加食材',
nzContent: SelectFoodComponent,
nzWidth: 800,
nzOnOk: (e) => {
const newSelectedFoods = e.getSelectedFoods()
d.items = d.items.concat(this.addPeopleToFood(newSelectedFoods))
this.calcTotal()
},
})
}
addPeopleToFood(pureFoods: any[]): FoodInDishInterface[] {
return pureFoods.map((i) => {
return {
foodName: i.name,
key: i.key,
isMain: false,
groupValues: this.peopleGroups.map((p) => {
return {
peopleName: p,
value: 0,
}
}),
value: {},
}
})
}
removeFood(d: DishInterface, foodKey: string) {
d.items = d.items.filter((f) => f.key !== foodKey)
if (d.items.length === 0) {
this.mealDishs = this.mealDishs.filter((d) => d.dish !== d.dish)
}
this.calcTotal()
}
clearThisMeal() { clearThisMeal() {
this.modal.confirm({ this.modal.confirm({
nzTitle: '警告', nzTitle: '警告',

4
projects/cdk/src/ingredient/ingredient-preview/ingredient-preview.component.less

@ -17,6 +17,10 @@
min-height: 200px; min-height: 200px;
padding-bottom: 42px; padding-bottom: 42px;
>div:not(:last-child) {
border-bottom: 1px solid #e8e8e8;
}
.total { .total {
position: absolute; position: absolute;
bottom: 0; bottom: 0;

23
projects/cdk/src/ingredient/ingredient.module.ts

@ -1,13 +1,14 @@
import { NgModule } from "@angular/core"; import { NgModule } from '@angular/core'
import { SharedModule } from "@cdk/shared/shared.module"; import { SharedModule } from '@cdk/shared/shared.module'
import { AddDishToIngredientComponent } from "./add-dish-to-ingredient/add-dish-to-ingredient.component"; import { AddDishToIngredientComponent } from './add-dish-to-ingredient/add-dish-to-ingredient.component'
import { IngredientMealsComponent } from "./ingredient-meals/ingredient-meals.component"; import { IngredientMealsComponent } from './ingredient-meals/ingredient-meals.component'
import { ConfirmIngredientComponent } from "./confirm-ingredient/confirm-ingredient.component"; import { ConfirmIngredientComponent } from './confirm-ingredient/confirm-ingredient.component'
import { IngredientDishComponent } from "./ingredient-dish/ingredient-dish.component"; import { IngredientDishComponent } from './ingredient-dish/ingredient-dish.component'
import { IngredientFormBasicComponent } from "./ingredient-form-basic/ingredient-form-basic.component"; import { IngredientFormBasicComponent } from './ingredient-form-basic/ingredient-form-basic.component'
import { IngredientPreviewComponent } from "./ingredient-preview/ingredient-preview.component"; import { IngredientPreviewComponent } from './ingredient-preview/ingredient-preview.component'
import { IngredientAnalysisComponent } from "./ingredient-analysis/ingredient-analysis.component"; import { IngredientAnalysisComponent } from './ingredient-analysis/ingredient-analysis.component'
import { NutritionTableComponent } from "./nutrition-table/nutrition-table.component"; import { NutritionTableComponent } from './nutrition-table/nutrition-table.component'
import { SelectFoodComponent } from './select-food/select-food.component'
@NgModule({ @NgModule({
declarations: [ declarations: [
@ -19,6 +20,7 @@ import { NutritionTableComponent } from "./nutrition-table/nutrition-table.compo
IngredientPreviewComponent, IngredientPreviewComponent,
IngredientAnalysisComponent, IngredientAnalysisComponent,
NutritionTableComponent, NutritionTableComponent,
SelectFoodComponent,
], ],
imports: [SharedModule], imports: [SharedModule],
exports: [ exports: [
@ -30,6 +32,7 @@ import { NutritionTableComponent } from "./nutrition-table/nutrition-table.compo
IngredientPreviewComponent, IngredientPreviewComponent,
IngredientAnalysisComponent, IngredientAnalysisComponent,
NutritionTableComponent, NutritionTableComponent,
SelectFoodComponent,
], ],
}) })
export class IngredientModule {} export class IngredientModule {}

33
projects/cdk/src/ingredient/select-food/select-food.component.html

@ -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
projects/cdk/src/ingredient/select-food/select-food.component.less

66
projects/cdk/src/ingredient/select-food/select-food.component.ts

@ -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: '食材类型' },
])
}
}

408
projects/cdk/src/table-list/table-list/table-list.component.html

@ -1,225 +1,221 @@
<form nz-form class="query-form mb-2" [formGroup]="formGroup" [nzLayout]="searchLayout"> <form nz-form class="query-form mb-2" [formGroup]="formGroup" [nzLayout]="searchLayout">
<div> <div>
<div nz-row> <div nz-row>
<div nz-col nzFlex="auto" nz-row [nzGutter]="[12,12]" class="search-row"> <div nz-col nzFlex="auto" nz-row [nzGutter]="[12, 12]" class="search-row">
<ng-container> <ng-container>
<ng-container [ngTemplateOutlet]="search!"></ng-container> <ng-container [ngTemplateOutlet]="search!"></ng-container>
<div nz-col nzFlex="120px"> <div nz-col nzFlex="120px">
<nz-form-item> <nz-form-item>
<nz-form-label nzNoColon></nz-form-label> <nz-form-label nzNoColon></nz-form-label>
<nz-form-control> <nz-form-control>
<nz-space> <nz-space>
<button nz-button nzGhost nzType="primary" *nzSpaceItem (click)="doQuery()"> <button nz-button nzGhost nzType="primary" *nzSpaceItem (click)="doQuery()">
查询 查询
</button> </button>
<button nz-button *nzSpaceItem (click)="reset()"> <button nz-button *nzSpaceItem (click)="reset()">重置</button>
重置 </nz-space>
</button> </nz-form-control>
</nz-space> </nz-form-item>
</nz-form-control> </div>
</nz-form-item> </ng-container>
</div> </div>
</ng-container> <div nz-col class="flex items-center justify-end">
</div> <ng-container *ngIf="action">
<div nz-col class="flex items-center justify-end"> <ng-container [ngTemplateOutlet]="action"></ng-container>
<ng-container *ngIf="action"> </ng-container>
<ng-container [ngTemplateOutlet]="action"></ng-container> </div>
</ng-container> </div>
</div> </div>
</div>
</div>
</form> </form>
<ng-template #renderTableTpl> <ng-template #renderTableTpl>
<div class="table-card table-list shadow-sm "> <div class="table-card table-list shadow-sm">
<div #tableEl class="overflow-auto"> <div #tableEl class="overflow-auto">
<nz-table <nz-table
#basicTable #basicTable
[nzData]="dataSource"
[nzData]="dataSource" [nzPageSizeOptions]="[5, 10, 20]"
[nzPageSizeOptions]="[5,10,20,]" [nzLoading]="props.pager.loading"
[nzLoading]="props.pager.loading" [(nzPageSize)]="props.pager.size"
[(nzPageSize)]="props.pager.size" [(nzPageIndex)]="props.pager.page"
[(nzPageIndex)]="props.pager.page" [nzTotal]="props.pager.total"
[nzTotal]="props.pager.total" [nzShowTotal]="totalTpl"
[nzShowTotal]="totalTpl" [nzFrontPagination]="props.frontPagination"
[nzFrontPagination]="props.frontPagination" [nzShowPagination]="true"
[nzShowPagination]="true" [nzShowSizeChanger]="true"
[nzShowSizeChanger]="true" [nzShowQuickJumper]="true"
[nzShowQuickJumper]="true" (nzPageIndexChange)="onPageChange()"
(nzPageIndexChange)="onPageChange()" (nzPageSizeChange)="onPageChange()"
(nzPageSizeChange)="onPageChange()" [nzTableLayout]="props.scroll.x ? 'fixed' : 'auto'"
[nzTableLayout]="props.scroll.x ? 'fixed' : 'auto' " [nzScroll]="props.scroll"
[nzScroll]="props.scroll"> >
<thead> <thead>
<tr> <tr>
<th <!-- [nzChecked]="dataSource && selection.selected.length === dataSource.length && dataSource.length !== 0" -->
*ngIf="props.selectable" <th
[nzChecked]="dataSource && selection.selected.length === dataSource.length && dataSource.length !== 0" *ngIf="props.selectable"
(nzCheckedChange)="onChecked($event)" [nzChecked]="checkedAll(dataSource)"
nzWidth="40px"> (nzCheckedChange)="onChecked($event)"
</th> nzWidth="40px"
<ng-container *ngFor="let col of columns"> ></th>
<th *ngIf="col.visible" <ng-container *ngFor="let col of columns">
[nzWidth]="col.width || null " <th
[nzShowSort]="col.sort" *ngIf="col.visible"
[nzSortDirections]="['ascend', 'descend']" [nzWidth]="col.width || null"
[nzSortOrder]="props.pager.sort[col.key] || null" [nzShowSort]="col.sort"
(nzSortOrderChange)="onSort($event,col.key)"> [nzSortDirections]="['ascend', 'descend']"
{{col.title}} [nzSortOrder]="props.pager.sort[col.key] || null"
</th> (nzSortOrderChange)="onSort($event, col.key)"
</ng-container> >
<th *ngIf="operation.length" [nzWidth]="optionWidth!" [nzRight]="!!props.scroll.x"> {{ col.title }}
操作 </th>
</th> </ng-container>
<th nzRight nzWidth="40px" *ngIf="props.theadSettable"> <th *ngIf="operation.length" [nzWidth]="optionWidth!" [nzRight]="!!props.scroll.x">操作</th>
<span (click)="toggleColumnVisible(columnVisibleSettingTpl)" <th nzRight nzWidth="40px" *ngIf="props.theadSettable">
class="cursor-pointer" <span
nz-icon (click)="toggleColumnVisible(columnVisibleSettingTpl)"
nzType="setting" class="cursor-pointer"
nzTheme="outline"> nz-icon
</span> nzType="setting"
</th> nzTheme="outline"
</tr> >
</thead> </span>
<tbody> </th>
<tr *ngFor="let dataItem of basicTable.data" (click)="onTrClick(dataItem)" </tr>
[ngClass]="rowClass"> </thead>
<td *ngIf="props.selectable" [nzChecked]="selection.isSelected(dataItem[props.rowKey])" <tbody>
(nzCheckedChange)="onChecked($event,dataItem[props.rowKey])"> <tr *ngFor="let dataItem of basicTable.data" (click)="onTrClick(dataItem)" [ngClass]="rowClass">
</td> <td
<ng-container *ngFor="let col of columns"> *ngIf="props.selectable"
<td *ngIf="col.visible" nzEllipsis> [nzChecked]="selection.isSelected(dataItem[props.rowKey])"
(nzCheckedChange)="onChecked($event, dataItem[props.rowKey])"
<ng-container [ngSwitch]="col.key"> ></td>
<ng-container *ngSwitchCase="'createTime'"> <ng-container *ngFor="let col of columns">
<ng-container <td *ngIf="col.visible" nzEllipsis>
[ngTemplateOutlet]="dateTimeTpl" <ng-container [ngSwitch]="col.key">
[ngTemplateOutletContext]="{$implicit:dataItem[col.key]}"> <ng-container *ngSwitchCase="'createTime'">
</ng-container> <ng-container
</ng-container> [ngTemplateOutlet]="dateTimeTpl"
<ng-container *ngSwitchCase="'updateTime'"> [ngTemplateOutletContext]="{ $implicit: dataItem[col.key] }"
<ng-container >
[ngTemplateOutlet]="dateTimeTpl" </ng-container>
[ngTemplateOutletContext]="{$implicit:dataItem[col.key]}"> </ng-container>
</ng-container> <ng-container *ngSwitchCase="'updateTime'">
</ng-container> <ng-container
[ngTemplateOutlet]="dateTimeTpl"
<ng-container *ngSwitchDefault> [ngTemplateOutletContext]="{ $implicit: dataItem[col.key] }"
<ng-container *ngIf="renderColumns else defaultTdTpl" >
[ngTemplateOutlet]="renderColumns" </ng-container>
[ngTemplateOutletContext]="{ </ng-container>
$implicit:dataItem[col.key],
key:col.key, <ng-container *ngSwitchDefault>
row:dataItem, <ng-container
column:col *ngIf="renderColumns; else defaultTdTpl"
}"> [ngTemplateOutlet]="renderColumns"
</ng-container> [ngTemplateOutletContext]="{
<ng-template #defaultTdTpl> $implicit: dataItem[col.key],
{{dataItem[col.key]}} key: col.key,
</ng-template> row: dataItem,
</ng-container> column: col
</ng-container> }"
</td> >
</ng-container> </ng-container>
<ng-template #defaultTdTpl>
<td *ngIf="operation.length" [nzRight]="!!props.scroll.x" class="operation"> {{ dataItem[col.key] }}
<dec-table-operation [rowData]="dataItem" [options]="operation"> </ng-template>
</dec-table-operation> </ng-container>
</td> </ng-container>
<td nzRight *ngIf="props.theadSettable"></td> </td>
</tr> </ng-container>
</tbody>
</nz-table> <td *ngIf="operation.length" [nzRight]="!!props.scroll.x" class="operation">
</div> <dec-table-operation [rowData]="dataItem" [options]="operation"> </dec-table-operation>
</td>
</div> <td nzRight *ngIf="props.theadSettable"></td>
</tr>
</tbody>
</nz-table>
</div>
</div>
</ng-template> </ng-template>
<ng-container *ngIf="renderItem; else renderTableTpl">
<ng-container *ngIf="props.pager.loading">
<ng-container *ngIf="renderItem else renderTableTpl"> <nz-card [nzBordered]="false">
<ng-container *ngIf="props.pager.loading"> <nz-skeleton [nzActive]="true"></nz-skeleton>
<nz-card [nzBordered]="false"> </nz-card>
<nz-skeleton [nzActive]="true"></nz-skeleton> </ng-container>
</nz-card> <div class="custom-render" *ngIf="!props.pager.loading">
</ng-container> <ng-container *ngIf="dataSource.length > 0; else emptyTpl">
<div class="custom-render" *ngIf="!props.pager.loading"> <div>
<ng-container *ngIf="dataSource.length > 0 else emptyTpl"> <ng-container [ngTemplateOutlet]="renderItem" [ngTemplateOutletContext]="{ $implicit: dataSource }">
<div> </ng-container>
<ng-container </div>
[ngTemplateOutlet]="renderItem" <div class="mt-4 flex justify-end">
[ngTemplateOutletContext]="{$implicit:dataSource}"> <nz-pagination
</ng-container> [nzPageSizeOptions]="[10, 20, 50, 100]"
</div> [(nzPageSize)]="props.pager.size"
<div class="mt-4 flex justify-end"> [(nzPageIndex)]="props.pager.page"
<nz-pagination [nzPageSizeOptions]="[10,20,50,100]" [nzTotal]="props.pager.total"
[(nzPageSize)]="props.pager.size" [nzShowTotal]="totalTpl"
[(nzPageIndex)]="props.pager.page" [nzShowSizeChanger]="true"
[nzTotal]="props.pager.total" [nzShowQuickJumper]="true"
[nzShowTotal]="totalTpl" (nzPageIndexChange)="onPageChange()"
[nzShowSizeChanger]="true" (nzPageSizeChange)="onPageChange()"
[nzShowQuickJumper]="true" >
(nzPageIndexChange)="onPageChange()" </nz-pagination>
(nzPageSizeChange)="onPageChange()"> </div>
</nz-pagination> </ng-container>
</div> <ng-template #emptyTpl>
</ng-container> <nz-card [nzBordered]="false">
<ng-template #emptyTpl> <nz-empty></nz-empty>
<nz-card [nzBordered]="false"> </nz-card>
<nz-empty></nz-empty> </ng-template>
</nz-card> </div>
</ng-template>
</div>
</ng-container> </ng-container>
<ng-template #columnVisibleSettingTpl> <ng-template #columnVisibleSettingTpl>
<nz-checkbox-wrapper class="w-full"> <nz-checkbox-wrapper class="w-full">
<ul cdkDropList (cdkDropListDropped)="colunmsSort($event)" class="columns-list"> <ul cdkDropList (cdkDropListDropped)="colunmsSort($event)" class="columns-list">
<li *ngFor="let item of columns" <li *ngFor="let item of columns" class="table-setting-item cursor-pointer" cdkDrag>
class="table-setting-item cursor-pointer" cdkDrag> <div class="columns-item-placeholder" *cdkDragPlaceholder></div>
<div class="columns-item-placeholder" *cdkDragPlaceholder></div> <div class="flex items-center justify-between p-2">
<div class="flex items-center justify-between p-2"> <div class="flex-shrink-0">
<div class="flex-shrink-0"> <span nz-icon nzType="holder" nzTheme="outline"></span>
<span nz-icon nzType="holder" nzTheme="outline"></span> </div>
</div> <div class="flex-1 pl-1">
<div class="flex-1 pl-1"> {{ item.title }}
{{item.title}} </div>
</div> <div class="flex-shrink-0">
<div class="flex-shrink-0"> <nz-switch
<nz-switch nzSize="small"
nzSize="small" [disabled]="!!item.disabled"
[disabled]="!!item.disabled" [(ngModel)]="item.visible"
[(ngModel)]="item.visible" (ngModelChange)="onColumnsChange()"
(ngModelChange)="onColumnsChange()"> >
</nz-switch> </nz-switch>
</div> </div>
</div> </div>
</li> </li>
</ul> </ul>
</nz-checkbox-wrapper> </nz-checkbox-wrapper>
</ng-template> </ng-template>
<ng-template #totalTpl let-total> <ng-template #totalTpl let-total>
<ng-container *ngIf="showTotal"> <ng-container *ngIf="showTotal">
<ng-template [ngTemplateOutlet]="showTotal" [ngTemplateOutletContext]="{$implicit:props.pager}"></ng-template> <ng-template
</ng-container> [ngTemplateOutlet]="showTotal"
<ng-container *ngIf="!showTotal"> [ngTemplateOutletContext]="{ $implicit: props.pager }"
共{{total}}条 ></ng-template>
</ng-container> </ng-container>
<ng-container *ngIf="!showTotal"> 共{{ total }}条 </ng-container>
</ng-template> </ng-template>
<ng-template #dateTimeTpl let-date> <ng-template #dateTimeTpl let-date>
{{date| date:'yyyy-MM-dd HH:mm:ss'}} {{ date | date : 'yyyy-MM-dd HH:mm:ss' }}
</ng-template> </ng-template>
<!-- 为了计算操作栏的宽度 ---- start --> <!-- 为了计算操作栏的宽度 ---- start -->
<dec-table-operation #operationEl [rowData]="{}" [options]="operation" class="hidden-option"> <dec-table-operation #operationEl [rowData]="{}" [options]="operation" class="hidden-option"> </dec-table-operation>
</dec-table-operation>
<!-- 为了计算操作栏的宽度 ---- end --> <!-- 为了计算操作栏的宽度 ---- end -->

285
projects/cdk/src/table-list/table-list/table-list.component.ts

@ -17,36 +17,36 @@ import {
Renderer2, Renderer2,
ChangeDetectorRef, ChangeDetectorRef,
OnDestroy, OnDestroy,
} from "@angular/core"; } from '@angular/core'
import { CommonModule } from "@angular/common"; import { CommonModule } from '@angular/common'
import { SelectionModel } from "@angular/cdk/collections"; import { SelectionModel } from '@angular/cdk/collections'
import { CdkDragDrop, moveItemInArray } from "@angular/cdk/drag-drop"; import { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop'
import { Router } from "@angular/router"; import { Router } from '@angular/router'
import { debounceTime, finalize } from "rxjs/operators"; import { debounceTime, finalize } from 'rxjs/operators'
import { FormsModule, FormControl, FormGroup, AbstractControl } from "@angular/forms"; import { FormsModule, FormControl, FormGroup, AbstractControl } from '@angular/forms'
import { NzDrawerModule, NzDrawerService } from "ng-zorro-antd/drawer"; import { NzDrawerModule, NzDrawerService } from 'ng-zorro-antd/drawer'
import { DecSafeAny, PageResult, ResponseType, TableListColumns, TableOperation } from "../../types"; import { DecSafeAny, PageResult, ResponseType, TableListColumns, TableOperation } from '../../types'
import { TableListOption } from "../table-list-options"; import { TableListOption } from '../table-list-options'
import { CacheItem, CacheService, StorageService } from "../../storage"; import { CacheItem, CacheService, StorageService } from '../../storage'
import { TableOperationComponent } from "../table-operation/table-operation.component"; import { TableOperationComponent } from '../table-operation/table-operation.component'
@Pipe({ @Pipe({
name: "operationFilter", name: 'operationFilter',
}) })
export class OperationPipe implements PipeTransform { export class OperationPipe implements PipeTransform {
transform(operations: TableOperation[], rowItem: any): TableOperation[] { transform(operations: TableOperation[], rowItem: any): TableOperation[] {
return operations?.filter((f) => (f.visible ? f.visible(rowItem) : true)) ?? []; return operations?.filter((f) => (f.visible ? f.visible(rowItem) : true)) ?? []
} }
} }
const DATE_RANGE_FIELDS = ["createTime", "updateTime"]; const DATE_RANGE_FIELDS = ['createTime', 'updateTime']
@Component({ @Component({
selector: "table-list", selector: 'table-list',
templateUrl: "./table-list.component.html", templateUrl: './table-list.component.html',
styleUrls: ["./table-list.component.less"], styleUrls: ['./table-list.component.less'],
}) })
export class TableListComponent implements OnInit, OnChanges, AfterViewInit, OnDestroy { export class TableListComponent implements OnInit, OnChanges, AfterViewInit, OnDestroy {
constructor( constructor(
@ -56,13 +56,13 @@ export class TableListComponent implements OnInit, OnChanges, AfterViewInit, OnD
private router: Router, private router: Router,
private drawerService: NzDrawerService, private drawerService: NzDrawerService,
private storage: StorageService, private storage: StorageService,
private cacheService: CacheService private cacheService: CacheService,
) {} ) {}
@Input() props!: TableListOption; @Input() props!: TableListOption
// https://github.com/angular/angular/issues/13761 // https://github.com/angular/angular/issues/13761
@Input() formGroup = new FormGroup<any>({}); @Input() formGroup = new FormGroup<any>({})
/** /**
* *
@ -71,211 +71,218 @@ export class TableListComponent implements OnInit, OnChanges, AfterViewInit, OnD
* row:dataItem `当前行数据` * row:dataItem `当前行数据`
* column:col `当前列` * column:col `当前列`
*/ */
@Input() renderColumns?: TemplateRef<{}>; @Input() renderColumns?: TemplateRef<{}>
/** /**
* 使 * 使
*/ */
@Input() renderItem?: TemplateRef<{}>; @Input() renderItem?: TemplateRef<{}>
@Input() action?: TemplateRef<{}>; @Input() action?: TemplateRef<{}>
@Input() search?: TemplateRef<{}>; @Input() search?: TemplateRef<{}>
@Input() searchLayout: "horizontal" | "vertical" = "horizontal"; @Input() searchLayout: 'horizontal' | 'vertical' = 'horizontal'
/** /**
* @deprecated * @deprecated
*/ */
@Input() advanceSearch?: TemplateRef<{}>; @Input() advanceSearch?: TemplateRef<{}>
@Input() showTotal?: TemplateRef<{}>; @Input() showTotal?: TemplateRef<{}>
@Input() beforeReset?: Function; @Input() beforeReset?: Function
@Input() rowClass?: string; @Input() rowClass?: string
@Input() public optionWidth?: string; @Input() public optionWidth?: string
// @Input() resizeable?: boolean; // @Input() resizeable?: boolean;
@Output() onRowClick = new EventEmitter(); @Output() onRowClick = new EventEmitter()
dataSource: DecSafeAny[] = []; dataSource: DecSafeAny[] = []
totalPages = 0; totalPages = 0
public selection = new SelectionModel<number>(true); public selection = new SelectionModel<number>(true)
public advanceSearchVisible: boolean = false; public advanceSearchVisible: boolean = false
private cache?: CacheItem; private cache?: CacheItem
get columns(): TableListColumns[] { get columns(): TableListColumns[] {
return this.props.columns ?? []; return this.props.columns ?? []
} }
get operation(): TableOperation[] { get operation(): TableOperation[] {
return this.props.operations ?? []; return this.props.operations ?? []
} }
get createTime() { get createTime() {
return this.formGroup.get("createTime"); return this.formGroup.get('createTime')
} }
ngOnInit(): void { ngOnInit(): void {
this.props.trigger$.pipe(debounceTime(100)).subscribe((e?: any) => { this.props.trigger$.pipe(debounceTime(100)).subscribe((e?: any) => {
if (this.props.fetchData) { if (this.props.fetchData) {
this.props.pager.loading = true; this.props.pager.loading = true
this.selection.clear(); // this.selection.clear();
this.emitState(); this.emitState()
const query = this.formGroup.getRawValue(); const query = this.formGroup.getRawValue()
// console.log("query", query); // console.log("query", query);
// this.saveQueryDataToCache(query); // this.saveQueryDataToCache(query);
const pager = this.parsePager(); const pager = this.parsePager()
this.props this.props
.fetchData(pager, this.parseQueryValue(), e) .fetchData(pager, this.parseQueryValue(), e)
.pipe( .pipe(
finalize(() => { finalize(() => {
this.props.pager.loading = false; this.props.pager.loading = false
}) }),
) )
.subscribe((f: ResponseType<PageResult>) => { .subscribe((f: ResponseType<PageResult>) => {
// alert(f.body.totalElements); // alert(f.body.totalElements);
this.dataSource = f.body.content; this.dataSource = f.body.content
this.props.pager.total = f.body.totalElements; this.props.pager.total = f.body.totalElements
this.totalPages = Math.ceil(this.props.pager.total / this.props.pager.size); this.totalPages = Math.ceil(this.props.pager.total / this.props.pager.size)
console.log("this.props.pager.total", this.props.pager.total); console.log('this.props.pager.total', this.props.pager.total)
this.checkPage(); this.checkPage()
}); })
} }
}); })
setTimeout(() => { setTimeout(() => {
this.emitState(); this.emitState()
}, 10); }, 10)
// 初始化的时候? // 初始化的时候?
if (!this.props.manual) { if (!this.props.manual) {
this.props.run(); this.props.run()
} }
this.getCacheData(); this.getCacheData()
} }
ngOnDestroy(): void { ngOnDestroy(): void {
// console.log("ngOnDestroy"); // console.log("ngOnDestroy");
} }
checkedAll(d: any[]) {
if (!d || !Array.isArray(d) || d?.length === 0) {
return false
}
return d.every((d) => this.selection.isSelected(d[this.props.rowKey]))
}
ngAfterViewInit(): void { ngAfterViewInit(): void {
const opEl: HTMLDivElement = this.el.nativeElement.querySelector(".hidden-option"); const opEl: HTMLDivElement = this.el.nativeElement.querySelector('.hidden-option')
if (opEl) { if (opEl) {
setTimeout(() => { setTimeout(() => {
const paddingX = 2 * 24; const paddingX = 2 * 24
if (!this.optionWidth) { if (!this.optionWidth) {
this.optionWidth = Math.ceil(opEl.offsetWidth + paddingX) + "px"; this.optionWidth = Math.ceil(opEl.offsetWidth + paddingX) + 'px'
} }
this.cdr.detectChanges(); this.cdr.detectChanges()
}); })
} }
} }
ngOnChanges(changes: SimpleChanges): void { ngOnChanges(changes: SimpleChanges): void {
const props = changes["props"]; const props = changes['props']
const currentProps = props?.currentValue; const currentProps = props?.currentValue
const previousProps = props?.previousValue; const previousProps = props?.previousValue
if (currentProps) { if (currentProps) {
if (previousProps?.["cacheKey"] !== currentProps?.["cacheKey"]) { if (previousProps?.['cacheKey'] !== currentProps?.['cacheKey']) {
this.removeOldCache(); this.removeOldCache()
this.getCacheData(); this.getCacheData()
} }
this.parseColumus(currentProps?.["columns"]); this.parseColumus(currentProps?.['columns'])
this.parseFormControls(currentProps?.["queryForm"]); this.parseFormControls(currentProps?.['queryForm'])
} }
} }
private saveQueryDataToCache(query: {}) { private saveQueryDataToCache(query: {}) {
if (this.cache) { if (this.cache) {
const { page, size, sort, total } = this.props.pager; const { page, size, sort, total } = this.props.pager
this.cache.setItem({ page, size, sort, total, ...query }); this.cache.setItem({ page, size, sort, total, ...query })
} }
} }
private removeOldCache() { private removeOldCache() {
this.cache?.remove(); this.cache?.remove()
} }
private getCacheData() { private getCacheData() {
let { cacheKey, cacheTo = [] } = this.props; let { cacheKey, cacheTo = [] } = this.props
this.formGroup.reset(); this.formGroup.reset()
if (!cacheKey) { if (!cacheKey) {
cacheKey = `DATA_CACHE_${this.formatePathname()}`; cacheKey = `DATA_CACHE_${this.formatePathname()}`
} }
if (!this.cache) { if (!this.cache) {
this.cache = this.cacheService.initCache(cacheKey, [this.router.url, ...cacheTo]); this.cache = this.cacheService.initCache(cacheKey, [this.router.url, ...cacheTo])
} }
const cacheData = this.cache?.getItem(); const cacheData = this.cache?.getItem()
if (cacheData) { if (cacheData) {
const { page, size, sort, total, ...query } = cacheData; const { page, size, sort, total, ...query } = cacheData
this.props.pager = { this.props.pager = {
...this.props.pager, ...this.props.pager,
total, total,
page, page,
size, size,
sort, sort,
}; }
this.formGroup.patchValue(query); this.formGroup.patchValue(query)
} }
} }
private parsePager() { private parsePager() {
let { page, size } = this.props.pager; let { page, size } = this.props.pager
if (this.props.pageFromZero) { if (this.props.pageFromZero) {
page = page - 1; page = page - 1
} }
const pager = { pageNo: page, pageSize: size, sort: this.formatSort() }; const pager = { pageNo: page, pageSize: size, sort: this.formatSort() }
return pager; return pager
} }
private parseQueryValue(): {} { private parseQueryValue(): {} {
const o = Object.create(null); const o = Object.create(null)
Object.entries(this.formGroup.getRawValue()).forEach(([k, v]) => { Object.entries(this.formGroup.getRawValue()).forEach(([k, v]) => {
if (DATE_RANGE_FIELDS.includes(k) && Array.isArray(v)) { if (DATE_RANGE_FIELDS.includes(k) && Array.isArray(v)) {
const from = v?.[0] instanceof Date ? v?.[0]?.toISOString() : v[0]; const from = v?.[0] instanceof Date ? v?.[0]?.toISOString() : v[0]
const to = v?.[1] instanceof Date ? v?.[1]?.toISOString() : v[1]; const to = v?.[1] instanceof Date ? v?.[1]?.toISOString() : v[1]
o[k] = { from, to }; o[k] = { from, to }
} else { } else {
o[k] = v; o[k] = v
} }
}); })
return o; return o
} }
private checkPage() { private checkPage() {
const maxPages = this.totalPages === 0 ? 1 : this.totalPages; const maxPages = this.totalPages === 0 ? 1 : this.totalPages
if (maxPages < this.props.pager.page) { if (maxPages < this.props.pager.page) {
this.props.pager.page = maxPages; this.props.pager.page = maxPages
this.reload(); this.reload()
} }
} }
private emitState() { private emitState() {
this.props.getState$.emit({ selectedKeys: this.selection.selected }); this.props.getState$.emit({ selectedKeys: this.selection.selected })
} }
private parseColumus(currentCols: TableListColumns[]) { private parseColumus(currentCols: TableListColumns[]) {
if (this.props.columns.some((s) => s.coverStorage)) { if (this.props.columns.some((s) => s.coverStorage)) {
this.onColumnsChange(); this.onColumnsChange()
} }
const colsFormStorage: TableListColumns[] = this.storage.get(this.formatePathname()) ?? []; const colsFormStorage: TableListColumns[] = this.storage.get(this.formatePathname()) ?? []
this.props.columns = currentCols this.props.columns = currentCols
.map((i: TableListColumns) => { .map((i: TableListColumns) => {
const storageCol = colsFormStorage.find((f) => f.key === i.key); const storageCol = colsFormStorage.find((f) => f.key === i.key)
let visible = i.visible !== void 0 ? i.visible : true; let visible = i.visible !== void 0 ? i.visible : true
let width = i.width; let width = i.width
// if (["createTime", "updateTime"].includes(i.key)) { // if (["createTime", "updateTime"].includes(i.key)) {
// width = "180px"; // width = "180px";
// } // }
@ -284,9 +291,9 @@ export class TableListComponent implements OnInit, OnChanges, AfterViewInit, OnD
visible, visible,
width, width,
...(storageCol ?? {}), ...(storageCol ?? {}),
}; }
}) })
.sort((a, b) => (a.order ?? 0) - (b.order ?? 0)); .sort((a, b) => (a.order ?? 0) - (b.order ?? 0))
} }
private parseFormControls(formGroup?: FormGroup) { private parseFormControls(formGroup?: FormGroup) {
@ -297,95 +304,95 @@ export class TableListComponent implements OnInit, OnChanges, AfterViewInit, OnD
} }
formatSort() { formatSort() {
const { sort } = this.props.pager; const { sort } = this.props.pager
if (!sort) { if (!sort) {
return null; return null
} }
const sortArr = [...Object.entries(sort)]?.[0]; const sortArr = [...Object.entries(sort)]?.[0]
if (!sortArr) { if (!sortArr) {
return null; return null
} }
return `${sortArr[0]},${sortArr[1] === "ascend" ? "asc" : "desc"}`; return `${sortArr[0]},${sortArr[1] === 'ascend' ? 'asc' : 'desc'}`
} }
colunmsSort(event: unknown) { colunmsSort(event: unknown) {
const e = event as CdkDragDrop<TableListColumns[]>; const e = event as CdkDragDrop<TableListColumns[]>
moveItemInArray(this.props.columns, e.previousIndex, e.currentIndex); moveItemInArray(this.props.columns, e.previousIndex, e.currentIndex)
this.onColumnsChange(); this.onColumnsChange()
} }
reload() { reload() {
this.props.run(); this.props.run()
} }
onPageChange() { onPageChange() {
if (!this.props.frontPagination) { if (!this.props.frontPagination) {
this.props.run(); this.props.run()
} }
} }
doQuery() { doQuery() {
this.props.pager.page = 1; this.props.pager.page = 1
this.reload(); this.reload()
} }
reset() { reset() {
this.beforeReset?.(); this.beforeReset?.()
this.formGroup.reset(); this.formGroup.reset()
this.doQuery(); this.doQuery()
} }
onSort(v: string | null, fieldName: string) { onSort(v: string | null, fieldName: string) {
this.props.pager.sort = { [fieldName]: v as "ascend" | "descend" }; this.props.pager.sort = { [fieldName]: v as 'ascend' | 'descend' }
this.reload(); this.reload()
} }
toggleAdvanceSearch(show?: boolean) { toggleAdvanceSearch(show?: boolean) {
if (typeof show === "boolean") { if (typeof show === 'boolean') {
this.advanceSearchVisible = show; this.advanceSearchVisible = show
} else { } else {
this.advanceSearchVisible = !this.advanceSearchVisible; this.advanceSearchVisible = !this.advanceSearchVisible
} }
} }
filteroperation(dataItem: any): TableOperation[] { filteroperation(dataItem: any): TableOperation[] {
return this.operation?.filter((f) => (f.visible ? f.visible(dataItem) : true)) ?? []; return this.operation?.filter((f) => (f.visible ? f.visible(dataItem) : true)) ?? []
} }
toggleColumnVisible(nzContent: TemplateRef<DecSafeAny>) { toggleColumnVisible(nzContent: TemplateRef<DecSafeAny>) {
this.drawerService.create({ this.drawerService.create({
nzTitle: "设置展示项", nzTitle: '设置展示项',
nzWidth: 280, nzWidth: 280,
nzContent, nzContent,
nzWrapClassName: "table-settings", nzWrapClassName: 'table-settings',
}); })
} }
private formatePathname() { private formatePathname() {
return this.props.columnKey ?? this.router.url.replace(/\//g, "_"); return this.props.columnKey ?? this.router.url.replace(/\//g, '_')
} }
onColumnsChange() { onColumnsChange() {
const columnStorageKey = `COLUMN_${this.formatePathname()}`; const columnStorageKey = `COLUMN_${this.formatePathname()}`
this.storage.set( this.storage.set(
columnStorageKey, columnStorageKey,
this.columns.map((i, idx) => { this.columns.map((i, idx) => {
const { key, width, visible } = i; const { key, width, visible } = i
return { key, width, visible, order: idx }; return { key, width, visible, order: idx }
}) }),
); )
} }
onChecked(checked: boolean, rowKey?: DecSafeAny) { onChecked(checked: boolean, rowKey?: DecSafeAny) {
const fn = checked ? "select" : "deselect"; const fn = checked ? 'select' : 'deselect'
const rowKeys = rowKey ? [rowKey] : this.dataSource.map((i) => i[this.props.rowKey]); const rowKeys = rowKey ? [rowKey] : this.dataSource.map((i) => i[this.props.rowKey])
this.selection[fn](...rowKeys); this.selection[fn](...rowKeys)
this.emitState(); this.emitState()
} }
onTrClick(dataItem: DecSafeAny) { onTrClick(dataItem: DecSafeAny) {
if (this.onRowClick) { if (this.onRowClick) {
this.onRowClick.emit(dataItem); this.onRowClick.emit(dataItem)
} }
} }
} }

Loading…
Cancel
Save