Browse Source

食谱 审核 & 发布

main
kkerwin 2 years ago
parent
commit
88f42bd551
  1. 7
      README.md
  2. 2
      projects/admin/src/app/app.module.ts
  3. 1
      projects/admin/src/app/components/index.ts
  4. 4
      projects/admin/src/app/components/ingredient-form-basic/ingredient-form-basic.component.ts
  5. 68
      projects/admin/src/app/components/ingredient-status-list/ingredient-status-list.component.html
  6. 0
      projects/admin/src/app/components/ingredient-status-list/ingredient-status-list.component.less
  7. 139
      projects/admin/src/app/components/ingredient-status-list/ingredient-status-list.component.ts
  8. 2
      projects/admin/src/app/pages/ingredients/ingredient-form/ingredient-form.component.html
  9. 54
      projects/admin/src/app/pages/ingredients/ingredient-form/ingredient-form.component.ts
  10. 35
      projects/admin/src/app/pages/ingredients/ingredient-list/ingredient-list.component.html
  11. 116
      projects/admin/src/app/pages/ingredients/ingredient-list/ingredient-list.component.ts
  12. 44
      projects/admin/src/app/pages/ingredients/ingredient-review/ingredient-review.component.html
  13. 6
      projects/admin/src/app/pages/ingredients/ingredient-review/ingredient-review.component.ts
  14. 33
      projects/cdk/src/services/api.service.ts
  15. 1
      projects/cdk/src/types/index.ts

7
README.md

@ -57,3 +57,10 @@ To get more help on the Angular CLI use `ng help` or go check out the [Angular C
1. /api/basic/enum 中 markType 和 venderType 重复
2. /api/ingredient/select 需要 支持关键字
----------------
# 09/26
1. 食谱审核 列表需要 提交审核时间、提交人 字段

2
projects/admin/src/app/app.module.ts

@ -18,6 +18,7 @@ import {
IngredientFormBasicComponent,
UserListComponent,
RolePermissionComponent,
IngredientStatusListComponent,
} from "./components";
import {
HomeComponent,
@ -69,6 +70,7 @@ registerLocaleData(zh);
StandardListComponent,
StandardFormComponent,
StandardSettingComponent,
IngredientStatusListComponent,
],
imports: [
BrowserModule,

1
projects/admin/src/app/components/index.ts

@ -7,3 +7,4 @@ export * from "./ingredient-form-basic/ingredient-form-basic.component";
export * from "./user-list/user-list.component";
export * from "./role-permission/role-permission.component";
export * from "./ingredient-status-list/ingredient-status-list.component";

4
projects/admin/src/app/components/ingredient-form-basic/ingredient-form-basic.component.ts

@ -144,8 +144,8 @@ export class IngredientFormBasicComponent {
)
.subscribe((res) => {
this.msg.success(res.desc);
this.onSave.emit();
this.router.navigate(["/ingredient/item/list"]);
this.onSave.emit({ meals: this.meals, menuId: res.body, peoples: this.currentPeoples });
// this.router.navigate(["/ingredient/item/list"]);
});
}
}

68
projects/admin/src/app/components/ingredient-status-list/ingredient-status-list.component.html

@ -0,0 +1,68 @@
<table-list [props]="tableList" [search]="searchTpl" [formGroup]="queryForm"
[renderColumns]="renderColumnsTpl">
<ng-template #actionTpl>
<button nz-button>批量删除</button>
</ng-template>
<ng-template #searchTpl>
<nz-form-item class="w-40">
<nz-form-control>
<nz-select nzPlaceHolder="单位" [nzOptions]="[]"></nz-select>
</nz-form-control>
</nz-form-item>
<nz-form-item class="w-40">
<nz-form-control>
<nz-select nzPlaceHolder="状态" [nzOptions]="[]"></nz-select>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-control>
<input nz-input placeholder="请输入食谱名称" formControlName="name" />
</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="'modify'">
{{data | date:'yyyy-MM-dd HH:mm:ss'}}
</ng-container>
<ng-container *ngSwitchCase="'meals'">
<nz-tag *ngFor="let item of data">{{item}}</nz-tag>
</ng-container>
<ng-container *ngSwitchCase="'day'">
{{data}} 天
</ng-container>
<ng-container *ngSwitchCase="'month'">
<div class="flex flex-wrap">
<ng-container *ngIf="data.length === 12">
<nz-tag>
全年
</nz-tag>
</ng-container>
<ng-container *ngIf="data.length !== 12">
<nz-tag *ngFor="let item of data" class="mb-1">
{{monthText[item]}}
</nz-tag>
</ng-container>
</div>
</ng-container>
<ng-container *ngSwitchDefault>
{{data}}
</ng-container>
</ng-container>
</ng-template>
</table-list>
<ng-template #reviewFailMenuTpl>
<div nz-form>
<nz-form-item>
<nz-form-label nzSpan="6">
驳回原因
</nz-form-label>
<nz-form-control nzSpan="12">
<textarea nz-input placeholder="请输入驳回原因" [(ngModel)]="reason"></textarea>
</nz-form-control>
</nz-form-item>
</div>
</ng-template>

0
projects/admin/src/app/components/ingredient-status-list/ingredient-status-list.component.less

139
projects/admin/src/app/components/ingredient-status-list/ingredient-status-list.component.ts

@ -0,0 +1,139 @@
import { Component, Input, 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";
@Component({
selector: "app-ingredient-status-list",
templateUrl: "./ingredient-status-list.component.html",
styleUrls: ["./ingredient-status-list.component.less"],
})
export class IngredientStatusListComponent {
constructor(
private drawer: NzDrawerService,
private api: ApiService,
private modal: NzModalService,
private msg: NzMessageService
) {}
@Input() status!: number;
reason = "";
@ViewChild("reviewFailMenuTpl") reviewFailMenuTpl!: TemplateRef<{}>;
private drawerRef?: NzDrawerRef;
public tableList = new TableListOption(this.fetchData.bind(this), {
frontPagination: false,
});
public queryForm = new FormGroup({
name: new FormControl(""),
});
monthText = {
1: "一月",
2: "二月",
3: "三月",
4: "四月",
5: "五月",
6: "六月",
7: "七月",
8: "八月",
9: "九月",
10: "十月",
11: "十一月",
12: "十二月",
} as any;
ngOnInit(): void {
this.initTableList();
}
initTableList() {
this.tableList.scroll = { x: null };
this.tableList = this.tableList.setColumns([
{ key: "name", title: "食谱名称" },
{ key: "vender", title: "单位" },
{ key: "modify", title: "提交审核时间" },
{ key: "modify", title: "提交人" },
]);
this.tableList = this.tableList.setOptions([
{
title: "详情",
premissions: [],
onClick: this.showFoodForm.bind(this),
},
{
title: "导出",
premissions: [],
onClick: this.showFoodForm.bind(this),
},
{
title: "通过",
premissions: [],
onClick: this.reviewSuccessMenu.bind(this),
visible: () => {
return this.status === 1;
},
},
{
title: "驳回",
premissions: [],
onClick: this.reviewFailMenu.bind(this),
visible: () => {
return this.status === 1;
},
},
]);
}
fetchData(query: AnyObject, pager: AnyObject) {
return this.api.getMenuStatusPage(pager, { ...query, status: this.status });
}
showFoodForm(food?: any) {
this.drawerRef = this.drawer.create({
nzTitle: food ? "编辑菜品" : "新增菜品",
nzWidth: 700,
nzContent: DishFormComponent,
});
}
cancelFoodForm() {
this.drawerRef?.close();
}
reviewSuccessMenu({ id }: any) {
this.modal.confirm({
nzTitle: "警告",
nzContent: `是否要通过审核该食谱?`,
nzOkDanger: true,
nzOnOk: async () => {
const res = await lastValueFrom(this.api.reviewMenu(id, true));
this.msg.success(res.desc);
this.tableList.run();
},
});
}
reviewFailMenu({ id }: any) {
this.modal.create({
nzTitle: "审核驳回",
nzContent: this.reviewFailMenuTpl,
nzOnOk: async () => {
const res = await lastValueFrom(this.api.reviewMenu(id, false, this.reason));
this.msg.success(res.desc);
this.tableList.run();
},
});
}
}

2
projects/admin/src/app/pages/ingredients/ingredient-form/ingredient-form.component.html

@ -2,7 +2,7 @@
<div class="p-4" *ngIf="step === 0">
<nz-card nzTitle="录入食谱基础信息">
<app-ingredient-form-basic (onSave)="onStepChange()"></app-ingredient-form-basic>
<app-ingredient-form-basic (onSave)="onStepChange($event)"></app-ingredient-form-basic>
</nz-card>
</div>

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

@ -37,9 +37,9 @@ export class IngredientFormComponent implements OnInit {
});
}
onStepChange() {
onStepChange(basicInfo: any) {
this.step = 1;
console.log(456);
console.log(basicInfo);
}
shopDishForm() {}
@ -62,53 +62,3 @@ export class IngredientFormComponent implements OnInit {
});
}
}
const data = {
menuId: [1, 2, 3],
dishs: [
{
name: "番茄炒鸡蛋",
dishId: 1,
foods: [
{
key: "001001",
isMain: false,
ingredient: [
{ name: "轻体力", value: 500 },
{ name: "重体力", value: 200 },
],
},
{
key: "001002",
isMain: false,
ingredient: [
{ name: "轻体力", value: 100 },
{ name: "重体力", value: 200 },
],
},
],
},
{
name: "另一个菜品",
dishId: 1,
foods: [
{
key: "001001",
isMain: false,
ingredient: [
{ name: "轻体力", value: 500 },
{ name: "重体力", value: 200 },
],
},
{
key: "001002",
isMain: false,
ingredient: [
{ name: "轻体力", value: 100 },
{ name: "重体力", value: 200 },
],
},
],
},
],
};

35
projects/admin/src/app/pages/ingredients/ingredient-list/ingredient-list.component.html

@ -17,14 +17,18 @@
<button nz-button>批量删除</button>
</ng-template>
<ng-template #searchTpl>
<nz-form-item class="w-40">
<nz-form-item class="w-60">
<nz-form-control>
<nz-select nzPlaceHolder="单位" [nzOptions]="[]"></nz-select>
</nz-form-control>
</nz-form-item>
<nz-form-item class="w-40">
<nz-form-control>
<nz-select nzPlaceHolder="状态" [nzOptions]="[]"></nz-select>
<nz-select nzPlaceHolder="状态" formControlName="status" [nzAllowClear]="true">
<nz-option *ngFor="let item of globalEnum.menuStatus" [nzValue]="item.label"
[nzLabel]="item.value">
</nz-option>
</nz-select>
</nz-form-control>
</nz-form-item>
<nz-form-item>
@ -38,12 +42,19 @@
<ng-container *ngSwitchCase="'modify'">
{{data | date:'yyyy-MM-dd HH:mm:ss'}}
</ng-container>
<ng-container *ngSwitchCase="'vender'">
{{ tableOrg[data] ? tableOrg[data].name : '-'}}
</ng-container>
<ng-container *ngSwitchCase="'meals'">
<nz-tag *ngFor="let item of data">{{item}}</nz-tag>
</ng-container>
<ng-container *ngSwitchCase="'day'">
{{data}} 天
</ng-container>
<ng-container *ngSwitchCase="'status'">
{{statusTextMap[data]}}
</ng-container>
<ng-container *ngSwitchCase="'month'">
<div class="flex flex-wrap">
<ng-container *ngIf="data.length === 12">
@ -69,13 +80,15 @@
</app-page>
<ng-template #foofFormFooterTpl>
<nz-space>
<button *nzSpaceItem nz-button (click)="cancelFoodForm()">
取消
</button>
<button *nzSpaceItem nz-button nzType="primary">
保存
</button>
</nz-space>
<ng-template #releaseStartTimeTpl>
<div nz-form>
<nz-form-item>
<nz-form-label nzSpan="6" [nzRequired]="true">
发布日期
</nz-form-label>
<nz-form-control nzSpan="12">
<nz-date-picker class="w-full" nzPlaceHolder="请选择发布日期" [(ngModel)]="startTime"></nz-date-picker>
</nz-form-control>
</nz-form-item>
</div>
</ng-template>

116
projects/admin/src/app/pages/ingredients/ingredient-list/ingredient-list.component.ts

@ -1,9 +1,13 @@
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 { AnyObject, OrgDTO, 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, tap } from "rxjs";
import { NzMessageService } from "ng-zorro-antd/message";
import { MyResponse } from "@cdk/types";
@Component({
selector: "app-ingredient-list",
@ -11,9 +15,18 @@ import { ApiService } from "@cdk/services";
styleUrls: ["./ingredient-list.component.less"],
})
export class IngredientListComponent {
constructor(private drawer: NzDrawerService, private api: ApiService) {}
constructor(
private drawer: NzDrawerService,
private api: ApiService,
private modal: NzModalService,
private msg: NzMessageService
) {}
@ViewChild("foofFormFooterTpl") foofFormFooterTpl!: TemplateRef<{}>;
globalEnum = this.api.globalEnum;
statusTextMap: Record<string, string> = {};
@ViewChild("releaseStartTimeTpl") releaseStartTimeTpl!: TemplateRef<{}>;
private drawerRef?: NzDrawerRef;
@ -25,6 +38,10 @@ export class IngredientListComponent {
name: new FormControl(""),
});
startTime: Date | null = null;
tableOrg: { [k: number]: OrgDTO } = {};
monthText = {
1: "一月",
2: "二月",
@ -41,6 +58,12 @@ export class IngredientListComponent {
} as any;
ngOnInit(): void {
this.statusTextMap = this.globalEnum.menuStatus.reduce((a, c) => {
return {
...a,
[String(c.label)]: c.value,
};
}, {} as Record<string, string>);
this.initTableList();
}
@ -71,17 +94,31 @@ export class IngredientListComponent {
{
title: "审核",
premissions: [],
onClick: this.deleteItem.bind(this),
onClick: this.shenhe.bind(this),
visible(v) {
// 0 提交审核 编辑 删除
// 1 审核中 删除
// 2 发布 编辑 删除
// 3 提交审核 编辑 删除
// 4 提交审核 编辑 删除
return ["0", "3", "4"].includes(v.status);
},
},
{
title: "发布",
premissions: [],
onClick: this.deleteItem.bind(this),
onClick: this.release.bind(this),
visible(v) {
return ["2"].includes(v.status);
},
},
{
title: "编辑",
premissions: [],
onClick: this.deleteItem.bind(this),
visible(v) {
return v.status !== "1";
},
},
{
title: "删除",
@ -92,7 +129,30 @@ export class IngredientListComponent {
}
fetchData(query: AnyObject, pager: AnyObject) {
return this.api.getMenuPage(pager, query);
return this.api.getMenuPage(pager, query).pipe(
tap((res) => {
this.getTableColumData(res);
})
);
}
getTableColumData(res: MyResponse) {
if (Array.isArray(res.body.content)) {
const vendors = res.body.content.map((i: any) => i.vender);
if (vendors.length > 0) {
this.api.getOrgList({ vendors }).subscribe((org) => {
if (Array.isArray(org.body)) {
this.tableOrg = org.body.reduce((a, c) => {
return {
...a,
[c.id]: c,
};
}, {} as AnyObject);
}
});
}
}
}
showFoodForm(food?: any) {
@ -100,7 +160,7 @@ export class IngredientListComponent {
nzTitle: food ? "编辑菜品" : "新增菜品",
nzWidth: 700,
nzContent: DishFormComponent,
nzFooter: this.foofFormFooterTpl,
// nzFooter: this.foofFormFooterTpl,
});
}
@ -108,5 +168,45 @@ export class IngredientListComponent {
this.drawerRef?.close();
}
deleteItem() {}
shenhe({ id }: any) {
this.modal.confirm({
nzTitle: "警告",
nzContent: `是否要将该食谱提交审核?`,
nzOnOk: async () => {
const res = await lastValueFrom(this.api.submitMenuForReview(id));
this.msg.success(res.desc);
this.tableList.run();
},
});
}
release({ id, day }: any) {
this.modal.create({
nzTitle: "发布食谱",
nzContent: this.releaseStartTimeTpl,
nzOnOk: async () => {
if (!this.startTime) {
this.msg.error("请选择发布日期");
return false;
}
const res = await lastValueFrom(this.api.release(id, this.startTime, day));
this.msg.success(res.desc);
this.tableList.run();
return true;
},
});
}
deleteItem({ id }: any) {
this.modal.confirm({
nzTitle: "警告",
nzContent: `是否要删除该食谱?`,
nzOkDanger: true,
nzOnOk: async () => {
const res = await lastValueFrom(this.api.deleteMenu(id));
this.msg.success(res.desc);
this.tableList.run();
},
});
}
}

44
projects/admin/src/app/pages/ingredients/ingredient-review/ingredient-review.component.html

@ -2,52 +2,16 @@
<nz-card [nzBordered]="false"
class="h-full scroll-card-body ">
<nz-card-tab>
<nz-tabset nzSize="large" [nzSelectedIndex]="status" (nzSelectedIndexChange)="onStatusChange($event)">
<nz-tabset nzSize="large" [nzSelectedIndex]="statusIndex" (nzSelectedIndexChange)="onStatusChange($event)">
<nz-tab [nzTitle]="'待审核31'"></nz-tab>
<nz-tab [nzTitle]="'已审核24'"></nz-tab>
<nz-tab [nzTitle]="'审核失败24'"></nz-tab>
</nz-tabset>
</nz-card-tab>
<div class="p-4">
<ng-template #pageExtraTpl>
<nz-space>
<button *nzSpaceItem nz-button nzType="primary">
批量通过
</button>
</nz-space>
</ng-template>
<table-list [props]="tableList" [search]="searchTpl" [action]="pageExtraTpl" [formGroup]="queryForm"
[renderColumns]="renderColumnsTpl">
<ng-template #actionTpl>
<button nz-button>批量删除</button>
</ng-template>
<ng-template #searchTpl>
<nz-form-item class="w-60">
<nz-form-control>
<nz-select nzPlaceHolder="请选择单位" [nzOptions]="[]"></nz-select>
</nz-form-control>
</nz-form-item>
<nz-form-item class="w-60">
<nz-form-control>
<input nz-input placeholder="请输入食谱名称" />
</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="'img'">
</ng-container>
<ng-container *ngSwitchDefault>
{{data}}
</ng-container>
</ng-container>
</ng-template>
</table-list>
<app-ingredient-status-list *ngIf="statusIndex === 0" [status]="1"></app-ingredient-status-list>
<app-ingredient-status-list *ngIf="statusIndex === 1" [status]="3"></app-ingredient-status-list>
<app-ingredient-status-list *ngIf="statusIndex === 2" [status]="2"></app-ingredient-status-list>
</div>
</nz-card>

6
projects/admin/src/app/pages/ingredients/ingredient-review/ingredient-review.component.ts

@ -23,7 +23,7 @@ export class IngredientReviewComponent {
private drawerRef?: NzDrawerRef;
status = 0;
statusIndex = 0;
tempImg = "https://cdn.pixabay.com/photo/2023/08/08/18/01/butterfly-8177925_1280.jpg";
@ -36,7 +36,7 @@ export class IngredientReviewComponent {
});
ngOnInit(): void {
this.status = Number(this.route.snapshot.queryParamMap.get("status")) || 0;
this.statusIndex = Number(this.route.snapshot.queryParamMap.get("status")) || 0;
this.initTableList();
}
@ -89,7 +89,7 @@ export class IngredientReviewComponent {
deleteItem() {}
onStatusChange(index: number) {
this.status = index;
this.statusIndex = index;
this.router.navigate(["/ingredient/review"], {
queryParams: {
status: index,

33
projects/cdk/src/services/api.service.ts

@ -1,6 +1,7 @@
import { HttpClient, HttpParams, HttpResponse } from "@angular/common/http";
import { Inject, Injectable, InjectionToken } from "@angular/core";
import { AnyObject, 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 {
@ -72,6 +73,7 @@ export class ApiService {
return {
...res.body,
mealType: this._formatEnum(res.body.mealType),
menuStatus: this._formatEnum(res.body.menuStatus),
};
}),
tap((r) => {
@ -360,6 +362,11 @@ export class ApiService {
return this.http.delete<ResponseType>(`/api/dish`, { body: params });
}
getMenuStatusPage(p: {}, q: {}) {
const params = Utils.objectStringify({ ...p, ...q });
return this.http.get<ResponseType<PageResult>>(`/api/menu/review?${params}`);
}
getMenuPage(p: {}, q: {}) {
const params = Utils.objectStringify({ ...p, ...q });
return this.http.get<ResponseType<PageResult>>(`/api/menu?${params}`);
@ -375,4 +382,30 @@ export class ApiService {
const method = v["id"] ? "post" : "put";
return this.http[method]<ResponseType>("/api/menu", body);
}
// 提交审核
submitMenuForReview(id: string | number) {
const params = Utils.objectToFormData({ id });
return this.http.put<ResponseType>(`/api/menu/review`, params);
}
reviewMenu(id: number, pass: boolean, reason?: string) {
const params = Utils.objectToFormData({ id, pass, reason });
return this.http.post<ResponseType>(`/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"),
endTime: format(endTime, "yyyy-MM-dd"),
});
return this.http.put<ResponseType>(`/api/menu/release`, params);
}
deleteMenu(id: string | number) {
const params = Utils.objectToFormData({ id });
return this.http.delete<ResponseType>(`/api/menu`, { body: params });
}
}

1
projects/cdk/src/types/index.ts

@ -17,6 +17,7 @@ export interface ResponseType<T = any> {
desc: string;
success: boolean;
}
export type MyResponse<R = any> = ResponseType<R>;
export interface TableListColumns {
key: string;

Loading…
Cancel
Save