袁野 6 months ago
parent 00831186a5
commit de1efca190
  1. 6
      src/app/app.routes.ts
  2. 192
      src/app/pages/audit/audit-list/audit-list.component.html
  3. 15
      src/app/pages/audit/audit-list/audit-list.component.less
  4. 197
      src/app/pages/audit/audit-list/audit-list.component.ts
  5. 12
      src/app/pages/audit/audit.module.ts
  6. 6
      src/app/pages/audit/audit.routes.ts
  7. 13
      src/app/pages/goods/goods-list/goods-list.component.html
  8. 39
      src/app/pages/goods/goods-list/goods-list.component.ts
  9. 166
      src/app/pages/marketing/coupon-discount-list/coupon-discount-list.component.html
  10. 12
      src/app/pages/marketing/coupon-discount-list/coupon-discount-list.component.less
  11. 308
      src/app/pages/marketing/coupon-discount-list/coupon-discount-list.component.ts
  12. 1
      src/app/pages/marketing/discount-list/discount-list.component.ts
  13. 2
      src/app/pages/marketing/marketing.routes.ts
  14. 22
      src/app/pipes/audit/audit-status.pipe.ts
  15. 45
      src/app/services/audit/audit.service.ts
  16. 47
      src/app/services/common/validators.service.ts
  17. 11
      src/app/services/goods/goods.service.ts
  18. 72
      src/app/services/marketing/discount.service.ts

@ -1,6 +1,7 @@
import { Routes } from '@angular/router'; import { Routes } from '@angular/router';
import {IndexComponent} from "./pages/body/index/index.component"; import {IndexComponent} from "./pages/body/index/index.component";
import {InitGuardService} from "./utils/initGuard.service"; import {InitGuardService} from "./utils/initGuard.service";
import {AUDIT_ROUTES} from "./pages/audit/audit.routes";
export const routes: Routes = [ export const routes: Routes = [
{path: '', pathMatch: 'full', redirectTo: 'admin/index'}, {path: '', pathMatch: 'full', redirectTo: 'admin/index'},
{ {
@ -49,6 +50,11 @@ export const routes: Routes = [
loadChildren: () => import('./pages/marketing/marketing.routes').then(m => m.MARKETING_ROUTES), loadChildren: () => import('./pages/marketing/marketing.routes').then(m => m.MARKETING_ROUTES),
canActivate: [InitGuardService] canActivate: [InitGuardService]
}, },
{
path: 'audit',
loadChildren: () => import('./pages/audit/audit.routes').then(m => m.AUDIT_ROUTES),
canActivate: [InitGuardService]
},
] ]
} }
]; ];

@ -0,0 +1,192 @@
<form nz-form [formGroup]="searchForm" class="search_form" [nzLayout]="'vertical'">
<div nz-row [nzGutter]="24">
<div nz-col [nzSpan]="6">
<nz-form-item>
<nz-form-label>审核内容名称</nz-form-label>
<nz-form-control>
<input nzSize="large" nz-input formControlName="submitObjectName" placeholder="请输入" />
</nz-form-control>
</nz-form-item>
</div>
<div nz-col [nzSpan]="6">
<nz-form-item>
<nz-form-label>审核提交人</nz-form-label>
<nz-form-control>
<input nzSize="large" nz-input formControlName="submitOpName" placeholder="请输入" />
</nz-form-control>
</nz-form-item>
</div>
<div nz-col [nzSpan]="6">
<nz-form-item>
<nz-form-label>审核状态</nz-form-label>
<nz-form-control>
<nz-select nzSize="large" nzShowSearch nzAllowClear nzPlaceHolder="请选择" formControlName="status">
<nz-option nzLabel="驳回" nzValue="0"></nz-option>
<nz-option nzLabel="1通过" nzValue="1"></nz-option>
<nz-option nzLabel="待审批" nzValue="2"></nz-option>
</nz-select>
</nz-form-control>
</nz-form-item>
</div>
<div nz-col [nzSpan]="6" class="search-area">
<button nz-button [nzType]="'primary'" (click)="getRequest(true)">查询</button>
<button nz-button (click)="searchForm.reset()">重置</button>
</div>
</div>
</form>
<nz-table #basicTable
[nzBordered]="true"
[nzFrontPagination]="false"
[nzShowQuickJumper]="true"
[nzShowTotal]="totalTemplate"
[(nzPageIndex)]="tablePageNum"
(nzPageIndexChange)="getRequest(false)"
[nzTotal]="tableData.total"
[nzData]="tableData.list" >
<thead>
<tr>
<th>审核对象</th>
<th>提交人名称</th>
<th>审核流水号</th>
<th>创建时间</th>
<th>更新时间</th>
<th>状态</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let data of basicTable.data">
<td>{{data.submitObjectName}}</td>
<td>{{data.submitOpName}}</td>
<td>{{data.auditSerialNo}}</td>
<td>{{ data.createTime | date: 'yyyy-MM-dd HH:mm'}}</td>
<td>{{ data.updateTime | date: 'yyyy-MM-dd HH:mm'}}</td>
<td>{{data.status | auditStatus}}</td>
<td>
<a (click)="showDetail(data.id)">详情</a>
<nz-divider *ngIf="data.status == 2" nzType="vertical"></nz-divider>
<a *ngIf="data.status == 2" nz-dropdown [nzDropdownMenu]="menu">
更多
<span nz-icon nzType="down"></span>
</a>
<nz-dropdown-menu #menu="nzDropdownMenu">
<ul nz-menu nzSelectable>
<li nz-menu-item>
<a (click)="passOrOverrule(data.id , 1)">通过</a>
</li>
<li nz-menu-item nzDanger>
<a (click)="passOrOverrule(data.id , 0)">驳回</a>
</li>
</ul>
</nz-dropdown-menu>
</td>
</tr>
</tbody>
<ng-template #totalTemplate let-total>总计 {{ total }} 条</ng-template>
<!--添加弹出框-->
<nz-modal [nzWidth]="1400" [(nzVisible)]="isVisibleDetail" nzTitle="查看详情" (nzOnCancel)="isVisibleDetail = false">
<ng-container *nzModalContent>
<nz-descriptions nzTitle="产品详情" nzBordered>
<nz-descriptions-item nzTitle="审核流水号">{{ auditDetail.auditSerialNo }}</nz-descriptions-item>
<nz-descriptions-item nzTitle="提交人">{{ auditDetail.submitOpName }}</nz-descriptions-item>
<nz-descriptions-item nzTitle="审核人">{{ auditDetail.auditOpName }}</nz-descriptions-item>
<nz-descriptions-item nzTitle="产品名称">{{ auditDetail.submitObjectName }}</nz-descriptions-item>
<nz-descriptions-item nzTitle="分类">{{ auditDetail['goodsModel'].goodsTypeName + "/" + auditDetail['goodsModel'].goodsTypeParentName}}</nz-descriptions-item>
<nz-descriptions-item nzTitle="品牌">{{ auditDetail['goodsModel'].goodsBrandName }}</nz-descriptions-item>
<nz-descriptions-item nzTitle="商品类型">{{ auditDetail['goodsModel'].type == 1 ? '实物商品' : '虚拟商品' }}</nz-descriptions-item>
<nz-descriptions-item nzTitle="商品说明" [nzSpan]="2">{{ auditDetail['goodsModel'].goodsExplain}}</nz-descriptions-item>
<nz-descriptions-item nzTitle="创建时间">{{ auditDetail.createTime | date: 'yyyy-MM-dd HH:mm' }}</nz-descriptions-item>
<nz-descriptions-item nzTitle="商品标签" [nzSpan]="2">{{ auditDetail['goodsModel'].goodsLabel}}</nz-descriptions-item>
<nz-descriptions-item nzTitle="更新时间">{{ auditDetail.updateTime | date: 'yyyy-MM-dd HH:mm' }}</nz-descriptions-item>
<nz-descriptions-item nzTitle="审批批注" [nzSpan]="2">{{ auditDetail.remarks}}</nz-descriptions-item>
<nz-descriptions-item nzTitle="状态" [nzSpan]="3">
<nz-badge *ngIf="auditDetail.status == 0" nzStatus="error" nzText="{{auditDetail.status | auditStatus}}"></nz-badge>
<nz-badge *ngIf="auditDetail.status == 1" nzStatus="success" nzText="{{auditDetail.status | auditStatus}}"></nz-badge>
<nz-badge *ngIf="auditDetail.status == 2" nzStatus="processing" nzText="{{auditDetail.status | auditStatus}}"></nz-badge>
</nz-descriptions-item>
<nz-descriptions-item [nzSpan]="3" nzTitle="列表图">
<nz-image-group>
<img nz-image width="80px" *ngFor="let item of auditDetail['goodsModel']['listImg'].split(',') " [nzFallback]="fallbackImg" nzSrc="{{item}}" alt="" />
</nz-image-group>
</nz-descriptions-item>
<nz-descriptions-item [nzSpan]="3" nzTitle="轮播图">
<nz-image-group>
<img nz-image width="80px" style="margin-left: 10px" *ngFor="let item of auditDetail['goodsModel']['bannerImg'].split(',') " [nzFallback]="fallbackImg" nzSrc="{{item}}" alt="" />
</nz-image-group>
</nz-descriptions-item>
<nz-descriptions-item [nzSpan]="3" nzTitle="详情图">
<nz-image-group>
<img nz-image width="80px" style="margin-left: 10px" *ngFor="let item of auditDetail['goodsModel']['detailImg'].split(',') " [nzFallback]="fallbackImg" nzSrc="{{item}}" alt="" />
</nz-image-group>
</nz-descriptions-item>
</nz-descriptions>
<h2>规格列表</h2>
<nz-table [nzScroll]="{ x: '1980px' }" [nzBordered]="true" #basicTable [nzData]="auditDetail['goodsModel']['goodsModelSpecs']">
<thead>
<tr>
<th nzLeft rowspan="2">规格名称</th>
<th colspan="2">价格(RMB)</th>
<th rowspan="2">图片</th>
<th rowspan="2">限购(个)</th>
<th rowspan="2">库存(个)</th>
<th colspan="2">时间</th>
<th colspan="7" *ngIf="auditDetail['goodsModel']?.type == 2">虚拟产品</th>
</tr>
<tr>
<th rowspan="1">售价</th>
<th rowspan="1">原价</th>
<th rowspan="1">销售截止时间</th>
<th rowspan="1">创建时间</th>
<th *ngIf="auditDetail['goodsModel']?.type == 2" rowspan="1">卡密</th>
<th *ngIf="auditDetail['goodsModel']?.type == 2" rowspan="1">归库天数</th>
<th *ngIf="auditDetail['goodsModel']?.type == 2" rowspan="1">类型</th>
<th *ngIf="auditDetail['goodsModel']?.type == 2" rowspan="1">产品来源</th>
<th *ngIf="auditDetail['goodsModel']?.type == 2" rowspan="1">跳转类型</th>
<th *ngIf="auditDetail['goodsModel']?.type == 2" rowspan="1">跳转地址</th>
<th *ngIf="auditDetail['goodsModel']?.type == 2" rowspan="1">应用ID</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let data of basicTable.data">
<td nzLeft>{{data.name}}</td>
<td>
<span style="font-size: 24px;" nz-typography nzType="danger">¥{{data.salePrice}}</span>
</td>
<td>
<span nz-typography nzType="secondary">¥{{data.originalPrice}}</span>
</td>
<td>
<img nz-image width="60px" height="60px" nzSrc="{{imageUrl + data.showImg }}" [nzFallback]="fallbackImg" alt="" />
</td>
<td>{{data.purLimit}}</td>
<td>{{data.stock}}</td>
<td>{{ data.salesEndTime | date: 'yyyy-MM-dd HH:mm'}}</td>
<td>{{ data.createTime | date: 'yyyy-MM-dd HH:mm'}}</td>
<td *ngIf="auditDetail['goodsModel']?.type == 2">{{data.key}}</td>
<td *ngIf="auditDetail['goodsModel']?.type == 2">{{data.validDay}}</td>
<td *ngIf="auditDetail['goodsModel']?.type == 2">{{data.type == 1 ? '内部虚拟商品' : '外部虚拟产品'}}</td>
<td *ngIf="auditDetail['goodsModel']?.type == 2">{{data.source | dictionary: 'GOODS_VPD_SOURCE'}}</td>
<td *ngIf="auditDetail['goodsModel']?.type == 2">{{data.jumpType == 1 ? '小程序' : 'H5'}}</td>
<td *ngIf="auditDetail['goodsModel']?.type == 2">{{data.jumpUrl}}</td>
<td *ngIf="auditDetail['goodsModel']?.type == 2">{{data.appid}}</td>
</tr>
</tbody>
</nz-table>
</ng-container>
<div *nzModalFooter>
<button *ngIf="auditDetail.status == 2" nz-button nzType="default" (click)="passOrOverrule(auditDetail.id , 0)">驳回</button>
<button *ngIf="auditDetail.status == 2" nz-button nzType="primary" (click)="passOrOverrule(auditDetail.id , 1)">通过</button>
</div>
</nz-modal>
<nz-modal [(nzVisible)]="isVisibleAudit" nzTitle="审批" (nzOnCancel)="isVisibleAudit = false" (nzOnOk)="postAuditMsg()">
<ng-container *nzModalContent>
<textarea rows="4" nz-input [(ngModel)]="remarks"></textarea>
</ng-container>
</nz-modal>

@ -0,0 +1,15 @@
[nz-form-label] {
overflow: visible;
}
button {
margin-left: 8px;
}
.submit-btn {
width: 150px;
}
.search-area {
margin-top: 30px;
}
nz-select {
width: 100%;
}

@ -0,0 +1,197 @@
import { Component } from '@angular/core';
import {DatePipe, NgForOf, NgIf} from "@angular/common";
import {DictionaryPipe} from "../../../pipes/common/dictionary.pipe";
import {FormGroup, FormsModule, NonNullableFormBuilder, ReactiveFormsModule, Validators} from "@angular/forms";
import {NzButtonComponent} from "ng-zorro-antd/button";
import {
NzCellFixedDirective,
NzTableCellDirective,
NzTableComponent,
NzTbodyComponent, NzTheadComponent,
NzThMeasureDirective, NzTrDirective
} from "ng-zorro-antd/table";
import {NzColDirective, NzRowDirective} from "ng-zorro-antd/grid";
import {NzDatePickerComponent} from "ng-zorro-antd/date-picker";
import {NzDividerComponent} from "ng-zorro-antd/divider";
import {NzDropDownADirective, NzDropDownDirective, NzDropdownMenuComponent} from "ng-zorro-antd/dropdown";
import {NzFormControlComponent, NzFormDirective, NzFormItemComponent, NzFormLabelComponent} from "ng-zorro-antd/form";
import {NzIconDirective} from "ng-zorro-antd/icon";
import {NzImageDirective, NzImageGroupComponent, NzImageModule} from "ng-zorro-antd/image";
import {NzInputDirective} from "ng-zorro-antd/input";
import {
NzInputNumberComponent,
NzInputNumberGroupComponent,
NzInputNumberGroupWhitSuffixOrPrefixDirective
} from "ng-zorro-antd/input-number";
import {NzMenuDirective, NzMenuItemComponent} from "ng-zorro-antd/menu";
import {NzModalComponent, NzModalContentDirective, NzModalFooterDirective, NzModalModule} from "ng-zorro-antd/modal";
import {NzOptionComponent, NzSelectComponent} from "ng-zorro-antd/select";
import {NzPopconfirmDirective} from "ng-zorro-antd/popconfirm";
import {NzUploadComponent} from "ng-zorro-antd/upload";
import {environment} from "../../../../environments/environment";
import {NzMessageService} from "ng-zorro-antd/message";
import {DiscountService} from "../../../services/marketing/discount.service";
import { fallbackImg } from '../../../data/goods/goods.namespace';
import {AuditService} from "../../../services/audit/audit.service";
import {NzTreeSelectComponent} from "ng-zorro-antd/tree-select";
import {NzDescriptionsComponent, NzDescriptionsItemComponent} from "ng-zorro-antd/descriptions";
import {NzBadgeComponent} from "ng-zorro-antd/badge";
import {AuditStatusPipe} from "../../../pipes/audit/audit-status.pipe";
import {NzTypographyComponent} from "ng-zorro-antd/typography";
@Component({
selector: 'app-audit-list',
standalone: true,
imports: [
DatePipe,
DictionaryPipe,
FormsModule,
NgForOf,
NgIf,
NzButtonComponent,
NzCellFixedDirective,
NzColDirective,
NzDatePickerComponent,
NzDividerComponent,
NzDropDownADirective,
NzDropDownDirective,
NzDropdownMenuComponent,
NzFormControlComponent,
NzFormDirective,
NzFormItemComponent,
NzFormLabelComponent,
NzIconDirective,
NzImageDirective,
NzInputDirective,
NzInputNumberComponent,
NzInputNumberGroupComponent,
NzInputNumberGroupWhitSuffixOrPrefixDirective,
NzMenuDirective,
NzMenuItemComponent,
NzModalComponent,
NzOptionComponent,
NzPopconfirmDirective,
NzRowDirective,
NzModalModule,
NzImageModule,
NzSelectComponent,
NzTableCellDirective,
NzTableComponent,
NzTbodyComponent,
NzThMeasureDirective,
NzTheadComponent,
NzTrDirective,
NzUploadComponent,
ReactiveFormsModule,
NzTreeSelectComponent,
NzDescriptionsItemComponent,
NzBadgeComponent,
NzDescriptionsComponent,
NzModalFooterDirective,
NzModalContentDirective,
AuditStatusPipe,
NzImageGroupComponent,
NzTypographyComponent
],
templateUrl: './audit-list.component.html',
styleUrl: './audit-list.component.less'
})
export class AuditListComponent {
// 表单页数
tablePageNum = 1;
// 表单数据
tableData: any = {
total: 0,
loading: false,
list: [],
};
// 搜索表单
searchForm: FormGroup;
auditDetail: any = {
goodsModel: {}
};
baseUrl = environment.baseUrl;
imageUrl = environment.imageUrl;
isVisibleDetail = false;
isVisibleAudit = false;
postAudit:any;
remarks: string | undefined;
protected readonly fallbackImg = fallbackImg;
constructor(private fb: NonNullableFormBuilder,
private msg: NzMessageService,
private auditService: AuditService,
private discountService: DiscountService) {
// 初始化搜索框
this.searchForm = this.fb.group({
submitObjectName: [''],
submitOpName: [''],
status: [''],
});
this.getRequest();
}
showDetail(id: number): void {
this.isVisibleDetail = true;
let params = {
id: id,
time: new Date().getTime()
}
this.auditService.auditDetail(params , (data: any) => {
if (data['return_code'] == '000000') {
this.auditDetail = data['return_data'];
}
})
}
// 查询列表
public getRequest(reset: boolean = false) {
this.tableData.loading = true;
if (reset) {
this.tablePageNum = 1;
}
this.searchForm.value.pageNum = this.tablePageNum;
this.searchForm.value.pageSize = 10;
this.searchForm.value.time = new Date().getTime();
this.auditService.getListGoodsAudit(this.searchForm.value , (data: any) => {
if (data['return_code'] == '000000') {
this.tableData = data['return_data'];
} else {
this.msg.error(data['return_msg']);
}
this.tableData.loading = false;
});
}
passOrOverrule(id: number , auditStatus: number): void {
this.postAudit = {
id: id,
time: new Date().getTime(),
status: auditStatus
}
this.isVisibleAudit = true;
}
postAuditMsg(): void {
this.postAudit.remarks = this.remarks;
this.auditService.auditMsg(this.postAudit , (data: any) => {
if (data['return_code'] == '000000') {
this.getRequest(true);
this.msg.success("操作成功")
} else {
this.msg.error(data['return_msg']);
}
this.isVisibleAudit = false;
});
}
}

@ -0,0 +1,12 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
@NgModule({
declarations: [],
imports: [
CommonModule
]
})
export class AuditModule { }

@ -0,0 +1,6 @@
import { Routes } from '@angular/router';
import {AuditListComponent} from "./audit-list/audit-list.component";
export const AUDIT_ROUTES: Routes = [
{ path: 'audit-goods-list', component: AuditListComponent},
];

@ -98,7 +98,7 @@
<td>{{ data.updateTime | date: 'yyyy-MM-dd HH:mm'}}</td> <td>{{ data.updateTime | date: 'yyyy-MM-dd HH:mm'}}</td>
<td>{{data.status | goodsStatus}}</td> <td>{{data.status | goodsStatus}}</td>
<td> <td>
<a (click)="showEdit(data)">修改</a> <a *ngIf="data.status == 2" (click)="showEdit(data)">修改</a>
<nz-divider nzType="vertical"></nz-divider> <nz-divider nzType="vertical"></nz-divider>
<a nz-dropdown [nzDropdownMenu]="menu"> <a nz-dropdown [nzDropdownMenu]="menu">
更多 更多
@ -107,7 +107,10 @@
<nz-dropdown-menu #menu="nzDropdownMenu"> <nz-dropdown-menu #menu="nzDropdownMenu">
<ul nz-menu nzSelectable> <ul nz-menu nzSelectable>
<li nz-menu-item><a (click)="showSpecsList(data)">规格列表</a></li> <li nz-menu-item><a (click)="showSpecsList(data)">规格列表</a></li>
<li nz-menu-item nzDanger> <li *ngIf="data.status != 3" nz-menu-item>
<a nz-popconfirm nzPopconfirmTitle="是否确认{{ data.status == 1 ? '下线':'上线'}}?" (nzOnConfirm)="goodsAudit(data.id)">{{ data.status == 1 ? '下线':'上线'}}</a>
</li>
<li *ngIf="data.status == 2" nz-menu-item nzDanger>
<a nz-popconfirm nzPopconfirmTitle="是否确认删除?" (nzOnConfirm)="delete(data.id)">删除</a> <a nz-popconfirm nzPopconfirmTitle="是否确认删除?" (nzOnConfirm)="delete(data.id)">删除</a>
</li> </li>
@ -261,7 +264,7 @@
<nz-modal [nzWidth]="1400" [(nzVisible)]="isVisibleSpecs" nzTitle="{{goodsMsg?.title}}-规格列表" [nzFooter]="null" (nzOnCancel)="isVisibleSpecs= false"> <nz-modal [nzWidth]="1400" [(nzVisible)]="isVisibleSpecs" nzTitle="{{goodsMsg?.title}}-规格列表" [nzFooter]="null" (nzOnCancel)="isVisibleSpecs= false">
<!--列表--> <!--列表-->
<ng-container *nzModalContent> <ng-container *nzModalContent>
<button nz-button (click)="showEditSpecs()" nzType="primary">创建</button> <button *ngIf="goodsMsg?.status == 2" nz-button (click)="showEditSpecs()" nzType="primary">创建</button>
<button nz-button [nzType]="'default'" (click)="getSpecsList()">查询</button> <button nz-button [nzType]="'default'" (click)="getSpecsList()">查询</button>
<br /> <br />
<br /> <br />
@ -275,7 +278,7 @@
<th rowspan="2">库存(个)</th> <th rowspan="2">库存(个)</th>
<th colspan="2">时间</th> <th colspan="2">时间</th>
<th colspan="7" *ngIf="goodsMsg?.type == 2">虚拟产品</th> <th colspan="7" *ngIf="goodsMsg?.type == 2">虚拟产品</th>
<th rowspan="2" nzRight>操作</th> <th *ngIf="goodsMsg?.status == 2" rowspan="2" nzRight>操作</th>
</tr> </tr>
<tr> <tr>
<th rowspan="1">售价</th> <th rowspan="1">售价</th>
@ -316,7 +319,7 @@
<td *ngIf="goodsMsg?.type == 2">{{data.jumpUrl}}</td> <td *ngIf="goodsMsg?.type == 2">{{data.jumpUrl}}</td>
<td *ngIf="goodsMsg?.type == 2">{{data.appid}}</td> <td *ngIf="goodsMsg?.type == 2">{{data.appid}}</td>
<td nzRight> <td *ngIf="goodsMsg?.status == 2" nzRight>
<a (click)="showEditSpecs(data)">修改</a> <a (click)="showEditSpecs(data)">修改</a>
<nz-divider nzType="vertical"></nz-divider> <nz-divider nzType="vertical"></nz-divider>
<a nz-popconfirm nzPopconfirmTitle="是否确认删除?" (nzOnConfirm)="deleteGoodsSpecs(data.specsId)">删除</a> <a nz-popconfirm nzPopconfirmTitle="是否确认删除?" (nzOnConfirm)="deleteGoodsSpecs(data.specsId)">删除</a>

@ -234,25 +234,16 @@ export class GoodsListComponent {
handleEdit(): void { handleEdit(): void {
if (this.editForm.valid) { if (this.editForm.valid) {
if (this.listImg.length !== 0) {
this.editForm.value.listImg = this.commonService.imgList(this.listImg); if (this.listImg.length === 0 || this.bannerImg.length === 0 || this.detailImg.length === 0) {
} else { this.msg.error('相关图片未上传!');
this.msg.error("请上传列表图片");
return;
}
if (this.bannerImg.length !== 0) {
this.editForm.value.bannerImg = this.commonService.imgList(this.bannerImg);
} else {
this.msg.error("请上传轮播图片");
return;
}
if (this.detailImg.length !== 0) {
this.editForm.value.detailImg = this.commonService.imgList(this.detailImg);
} else {
this.msg.error("请上传详情图片");
return; return;
} }
this.editForm.value.listImg = this.commonService.postImg(this.listImg);
this.editForm.value.bannerImg = this.commonService.postImg(this.bannerImg);
this.editForm.value.detailImg = this.commonService.postImg(this.detailImg);
this.goodsService.editGoodsMsg(this.editForm.value , (data: any) => { this.goodsService.editGoodsMsg(this.editForm.value , (data: any) => {
if (data['return_code'] === '000000') { if (data['return_code'] === '000000') {
this.msg.success("成功!"); this.msg.success("成功!");
@ -460,6 +451,22 @@ export class GoodsListComponent {
this.editSpecsForm.controls['appid'].updateValueAndValidity(); this.editSpecsForm.controls['appid'].updateValueAndValidity();
} }
// 上下线
goodsAudit(id: number): void {
let params = {
id: id,
time: new Date().getTime()
}
this.goodsService.goodsAudit(params , (data: any) => {
if (data['return_code'] === '000000') {
this.msg.success("成功!");
this.getRequest();
} else {
this.msg.error(data['return_msg']);
}
});
}
} }

@ -0,0 +1,166 @@
<form nz-form [formGroup]="searchForm" class="search_form" [nzLayout]="'vertical'">
<div nz-row [nzGutter]="24">
<div nz-col [nzSpan]="6">
<nz-form-item>
<nz-form-label>名称</nz-form-label>
<nz-form-control>
<input nzSize="large" nz-input formControlName="title" placeholder="请输入" />
</nz-form-control>
</nz-form-item>
</div>
<div nz-col [nzSpan]="6" class="search-area">
<button nz-button [nzType]="'primary'" (click)="getRequest(true)">查询</button>
<button nz-button (click)="searchForm.reset()">重置</button>
<button nz-button [nzType]="'primary'" (click)="showEdit()">创建</button>
</div>
</div>
</form>
<nz-table #basicTable
[nzBordered]="true"
[nzFrontPagination]="false"
[nzShowQuickJumper]="true"
[nzShowTotal]="totalTemplate"
[(nzPageIndex)]="tablePageNum"
(nzPageIndexChange)="getRequest(false)"
[nzTotal]="tableData.total"
[nzData]="tableData.list" >
<thead>
<tr>
<th nzWidth="80px">编码</th>
<th nzWidth="80px">名称</th>
<th nzWidth="80px">库存(个)</th>
<th nzWidth="80px">有效期</th>
<th nzWidth="50px">创建时间</th>
<th nzWidth="50px">更新时间</th>
<th nzWidth="70px">操作</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let data of basicTable.data">
<td>{{data.key}}</td>
<td>{{data.title}}</td>
<td>{{data.surplusStock}}</td>
<td>{{ data.effectiveTime | date: 'yyyy-MM-dd HH:mm'}}</td>
<td>{{ data.createdTime | date: 'yyyy-MM-dd HH:mm'}}</td>
<td>{{ data.updatedTime | date: 'yyyy-MM-dd HH:mm'}}</td>
<td>
<a (click)="showEdit(data)">修改</a>
<nz-divider nzType="vertical"></nz-divider>
<a nz-dropdown [nzDropdownMenu]="menu">
更多
<span nz-icon nzType="down"></span>
</a>
<nz-dropdown-menu #menu="nzDropdownMenu">
<ul nz-menu nzSelectable>
<li nz-menu-item><a (click)="getDetailList(data.id)">详情列表</a></li>
<li nz-menu-item nzDanger>
<a (click)="giveDiscountPackageShow(data.id)">赠送券包</a>
</li>
<li nz-menu-item nzDanger>
<a nz-popconfirm nzPopconfirmTitle="是否确认删除?" (nzOnConfirm)="delete(data.id)">删除</a>
</li>
</ul>
</nz-dropdown-menu>
</td>
</tr>
</tbody>
<ng-template #totalTemplate let-total>总计 {{ total }} 条</ng-template>
<!--添加弹出框-->
<nz-modal [(nzVisible)]="isVisibleEdit" [nzMaskClosable] = false nzTitle="编辑" (nzOnCancel)="isVisibleEdit = false" (nzOnOk)="handleEdit()">
<ng-container *nzModalContent>
<form nz-form [formGroup]="editForm">
<nz-form-item >
<nz-form-label [nzSm]="6" [nzXs]="24" nzRequired>标题</nz-form-label>
<nz-form-control [nzSm]="14" [nzXs]="24" nzErrorTip="请输入标题!">
<input nzSize="large" nz-input formControlName="title" placeholder="请输入" />
</nz-form-control>
</nz-form-item>
<nz-form-item >
<nz-form-label [nzSm]="6" [nzXs]="24" nzRequired>有效期</nz-form-label>
<nz-form-control [nzSm]="14" [nzXs]="24" nzErrorTip="请选择有效期!">
<nz-date-picker
nzSize="large"
nzShowTime
nzFormat="yyyy-MM-dd HH:mm:ss"
formControlName="effectiveTime"
nzPlaceHolder="请选择领取最终时间"
></nz-date-picker>
</nz-form-control>
</nz-form-item>
<nz-form-item >
<nz-form-label [nzSm]="6" [nzXs]="24" nzRequired>库存</nz-form-label>
<nz-form-control [nzSm]="14" [nzXs]="24" nzErrorTip="请输入库存!">
<nz-input-number style="width: 100%" formControlName="surplusStock" [nzSize]="'large'" [nzMin]="1" [nzMax]="99999" [nzStep]="1" ></nz-input-number>
</nz-form-control>
</nz-form-item>
</form>
</ng-container>
</nz-modal>
<nz-modal [nzWidth]="1200" [(nzVisible)]="isVisibleDetail" nzTitle="绑定商品" (nzOnCancel)="isVisibleDetail= false" (nzOnOk)="isVisibleDetail= false" >
<!--列表-->
<ng-container *nzModalContent>
<button nz-button (click)="showEditDetail()" nzType="primary">创建</button>
<button nz-button [nzType]="'default'" (click)="getDetailList(discountPackageId)">查询</button>
<br />
<br />
<nz-table #basicTable [nzData]="discountPackage">
<thead>
<tr>
<th>优惠券名称</th>
<th>数量</th>
<th>创建时间</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let data of basicTable.data">
<td>{{data.discountName}}</td>
<td>{{data.num}}</td>
<td>{{data.createdTime}}</td>
<td>
<a nz-popconfirm nzPopconfirmTitle="是否确认删除?" (nzOnConfirm)="deleteDetail(data.id)">删除</a>
</td>
</tr>
</tbody>
</nz-table>
</ng-container>
</nz-modal>
<nz-modal [(nzVisible)]="isVisibleDetailEdit" [nzMaskClosable] = false nzTitle="编辑" (nzOnCancel)="isVisibleDetailEdit = false" (nzOnOk)="handleDetailEdit()">
<ng-container *nzModalContent>
<form nz-form [formGroup]="detailForm">
<nz-form-item>
<nz-form-label [nzSm]="6" [nzXs]="24" nzRequired>优惠券</nz-form-label>
<nz-form-control [nzSm]="14" [nzXs]="24" nzErrorTip="请选择优惠券!">
<nz-select nzSize="large" nzShowSearch nzAllowClear formControlName="discountId" nzPlaceHolder="请选择优惠券">
<nz-option *ngFor="let item of discountData" nzValue="{{item.id}}" nzLabel="{{item.name}}"></nz-option>
</nz-select>
</nz-form-control>
</nz-form-item>
<nz-form-item >
<nz-form-label [nzSm]="6" [nzXs]="24" nzRequired>数量</nz-form-label>
<nz-form-control [nzSm]="14" [nzXs]="24" nzErrorTip="请输入数量!">
<nz-input-number style="width: 100%" formControlName="num" [nzSize]="'large'" [nzMin]="1" [nzMax]="99999" [nzStep]="1" ></nz-input-number>
</nz-form-control>
</nz-form-item>
</form>
</ng-container>
</nz-modal>
<nz-modal [(nzVisible)]="isVisibleGive" [nzMaskClosable] = false nzTitle="编辑" (nzOnCancel)="isVisibleGive = false" (nzOnOk)="giveDiscountPackage()">
<ng-container *nzModalContent>
<form nz-form [formGroup]="giveForm">
<nz-form-item >
<nz-form-label [nzSm]="6" [nzXs]="24" nzRequired>赠送手机号</nz-form-label>
<nz-form-control [nzSm]="14" [nzXs]="24" nzErrorTip="请输入赠送手机号!">
<input nzSize="large" nz-input formControlName="phone" placeholder="请输入赠送手机号" />
</nz-form-control>
</nz-form-item>
</form>
</ng-container>
</nz-modal>

@ -0,0 +1,12 @@
[nz-form-label] {
overflow: visible;
}
button {
margin-left: 8px;
}
.submit-btn {
width: 150px;
}
.search-area {
margin-top: 30px;
}

@ -0,0 +1,308 @@
import { Component } from '@angular/core';
import {DatePipe, NgForOf, NgIf, NgOptimizedImage, NgStyle} from "@angular/common";
import {FormGroup,NonNullableFormBuilder, ReactiveFormsModule, Validators} from "@angular/forms";
import {NzButtonComponent} from "ng-zorro-antd/button";
import {NzColDirective, NzRowDirective} from "ng-zorro-antd/grid";
import {NzDividerComponent} from "ng-zorro-antd/divider";
import {NzFormControlComponent, NzFormDirective, NzFormItemComponent, NzFormLabelComponent} from "ng-zorro-antd/form";
import {NzIconDirective} from "ng-zorro-antd/icon";
import {NzImageModule} from "ng-zorro-antd/image";
import {NzInputDirective} from "ng-zorro-antd/input";
import {NzModalComponent, NzModalContentDirective, NzModalModule} from "ng-zorro-antd/modal";
import {NzPopconfirmDirective} from "ng-zorro-antd/popconfirm";
import {
NzTableCellDirective,
NzTableComponent,
NzTbodyComponent,
NzTheadComponent,
NzThMeasureDirective, NzTrDirective
} from "ng-zorro-antd/table";
import {NzUploadComponent, NzUploadFile} from "ng-zorro-antd/upload";
import {NzOptionComponent, NzSelectComponent} from "ng-zorro-antd/select";
import {NzTreeSelectComponent} from "ng-zorro-antd/tree-select";
import {environment} from "../../../../environments/environment";
import {NzMessageService} from "ng-zorro-antd/message";
import {CommonService} from "../../../services/common/common.service";
import {GoodsService} from "../../../services/goods/goods.service";
import {GoodsTypeData} from "../../../model/goods.interface";
import {DiscountService} from "../../../services/marketing/discount.service";
import {NzDatePickerComponent} from "ng-zorro-antd/date-picker";
import {NzInputNumberComponent} from "ng-zorro-antd/input-number";
import {NzDropDownADirective, NzDropDownDirective, NzDropdownMenuComponent} from "ng-zorro-antd/dropdown";
import {NzMenuDirective, NzMenuItemComponent} from "ng-zorro-antd/menu";
import {MyValidators} from "../../../services/common/validators.service";
@Component({
selector: 'app-coupon-discount-list',
standalone: true,
imports: [
NgForOf,
NzButtonComponent,
NzColDirective,
NzFormControlComponent,
NzFormDirective,
NzFormItemComponent,
NzFormLabelComponent,
NzInputDirective,
NzOptionComponent,
NzRowDirective,
NzModalModule,
NzSelectComponent,
ReactiveFormsModule,
NzIconDirective,
NzModalComponent,
NzTreeSelectComponent,
NzUploadComponent,
NzModalContentDirective,
NgStyle,
DatePipe,
NzDividerComponent,
NzTableCellDirective,
NzTableComponent,
NzTbodyComponent,
NzThMeasureDirective,
NzTheadComponent,
NzTrDirective,
NzPopconfirmDirective,
NzImageModule,
NgOptimizedImage,
NzDatePickerComponent,
NzInputNumberComponent,
NgIf,
NzDropDownADirective,
NzDropDownDirective,
NzDropdownMenuComponent,
NzMenuDirective,
NzMenuItemComponent
],
templateUrl: './coupon-discount-list.component.html',
styleUrl: './coupon-discount-list.component.less'
})
export class CouponDiscountListComponent {
// 表单页数
tablePageNum = 1;
// 表单数据
tableData: any = {
total: 0,
loading: false,
list: [],
};
// 搜索表单
searchForm: FormGroup;
// 图片
imgUrl: NzUploadFile[] = []
baseUrl = environment.baseUrl;
imageUrl = environment.imageUrl;
isVisibleDetail = false;
isVisibleGive = false;
// 编辑产品类型表单
editForm: FormGroup;
detailForm: FormGroup;
giveForm: FormGroup;
// 编辑弹出框
isVisibleEdit = false;
isVisibleDetailEdit = false;
discountPackageId: number = 0;
discountPackage: any;
discountData: any;
constructor(private fb: NonNullableFormBuilder,
private msg: NzMessageService,
private commonService: CommonService,
private discountService: DiscountService) {
// 初始化搜索框
this.searchForm = this.fb.group({
title: [''],
});
let params = {
status: 1,
pageNum: 1,
pageSize: 100000,
time: new Date().getTime()
}
this.discountService.getListDiscount(params , (data: any)=>{
if (data['return_code'] == '000000') {
this.discountData = data['return_data'].list;
}
});
const { required, maxLength, minLength, email, mobile } = MyValidators;
// 初始化
this.editForm = this.fb.group({
title: ['' , [Validators.required]],
surplusStock: ['' , [Validators.required]],
effectiveTime: ['' , [Validators.required]],
id: [null],
});
this.detailForm = this.fb.group({
discountId: ['' , [Validators.required]],
num: ['' , [Validators.required]],
discountPackageId: [''],
id: [null],
});
this.giveForm = this.fb.group({
phone: ['' , [required, mobile]],
discountPackageId: [''],
});
this.getRequest();
}
// 查询列表
public getRequest(reset: boolean = false) {
this.tableData.loading = true;
if (reset) {
this.tablePageNum = 1;
}
this.searchForm.value.pageNum = this.tablePageNum;
this.searchForm.value.pageSize = 10;
this.searchForm.value.time = new Date().getTime();
this.discountService.getDiscountPackageList(this.searchForm.value , (data: any) => {
if (data['return_code'] == '000000') {
this.tableData = data['return_data'];
} else {
this.msg.error(data['return_msg']);
}
this.tableData.loading = false;
});
}
// 唤醒编辑表单
showEdit(item?: GoodsTypeData) {
if (item != null) {
this.editForm.patchValue(item);
} else {
this.editForm.reset();
}
this.isVisibleEdit = true;
}
// 编辑表单提交
handleEdit(): void {
if (this.editForm.valid) {
this.discountService.editCouponPackageInfo(this.editForm.value , (data: any) => {
if (data['return_code'] === '000000') {
this.msg.success("成功!");
this.isVisibleEdit = false;
this.getRequest();
} else {
this.msg.error(data['return_msg']);
}
});
} else {
Object.values(this.editForm.controls).forEach(control => {
if (control.invalid) {
control.markAsDirty();
control.updateValueAndValidity({ onlySelf: true });
}
});
}
}
// 删除
delete(id: number): void {
this.discountService.deleteCouponDiscount(id , (data: any) => {
if (data['return_code'] === '000000') {
this.msg.success("成功!");
this.getRequest();
} else {
this.msg.error(data['return_msg']);
}
});
}
// 删除券包详情
deleteDetail(id: number): void {
this.discountService.deleteDetail(id , (data: any) => {
if (data['return_code'] === '000000') {
this.msg.success("成功!");
this.getDetailList(this.discountPackageId);
} else {
this.msg.error(data['return_msg']);
}
});
}
// 查询券包详情
getDetailList(id: number): void {
this.discountPackageId = id;
this.isVisibleDetail = true;
let params = {
discountPackageId: id,
time: new Date().getTime()
}
this.discountService.getDetailList(params, (data: any) => {
if (data['return_code'] === '000000') {
this.discountPackage = data['return_data'];
} else {
this.msg.error(data['return_msg']);
}
});
}
giveDiscountPackageShow(id: number): void {
this.discountPackageId = id;
this.isVisibleGive = true;
}
giveDiscountPackage(): void {
this.giveForm.value.discountPackageId = this.discountPackageId;
if (this.giveForm.valid) {
this.discountService.giveDiscountPackage(this.giveForm.value , (data: any) => {
if (data['return_code'] === '000000') {
this.msg.success("成功!");
this.getRequest(false);
this.isVisibleGive = false;
} else {
this.msg.error(data['return_msg']);
}
});
} else {
Object.values(this.giveForm.controls).forEach(control => {
if (control.invalid) {
control.markAsDirty();
control.updateValueAndValidity({ onlySelf: true });
}
});
}
}
// 创建详情
showEditDetail(): void {
this.detailForm.reset();
this.isVisibleDetailEdit = true;
}
handleDetailEdit(): void {
this.detailForm.value.discountPackageId = this.discountPackageId;
if (this.detailForm.valid) {
this.discountService.insertCouponPackageDetail(this.detailForm.value , (data: any) => {
if (data['return_code'] === '000000') {
this.msg.success("成功!");
this.isVisibleDetailEdit = false;
this.getDetailList(this.discountPackageId);
} else {
this.msg.error(data['return_msg']);
}
});
} else {
Object.values(this.detailForm.controls).forEach(control => {
if (control.invalid) {
control.markAsDirty();
control.updateValueAndValidity({ onlySelf: true });
}
});
}
}
}

@ -315,6 +315,7 @@ export class DiscountListComponent {
}); });
} }
handleOk(): void { handleOk(): void {
let params = { let params = {
discountId: this.discount?.id, discountId: this.discount?.id,

@ -1,9 +1,11 @@
import { Routes } from '@angular/router'; import { Routes } from '@angular/router';
import {DiscountListComponent} from "./discount-list/discount-list.component"; import {DiscountListComponent} from "./discount-list/discount-list.component";
import {CouponDiscountListComponent} from "./coupon-discount-list/coupon-discount-list.component";
export const MARKETING_ROUTES: Routes = [ export const MARKETING_ROUTES: Routes = [
{ path: 'discount-list', component: DiscountListComponent}, { path: 'discount-list', component: DiscountListComponent},
{ path: 'coupon-discount-list', component: CouponDiscountListComponent},
]; ];

@ -0,0 +1,22 @@
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({
name: 'auditStatus',
standalone: true
})
export class AuditStatusPipe implements PipeTransform {
transform(value: number): any {
switch (value) {
case 0:
return '驳回';
case 1:
return '通过';
case 2:
return '待审批';
default:
return '未知状态'
}
}
}

@ -0,0 +1,45 @@
import { Injectable } from '@angular/core';
import {environment} from "../../../environments/environment";
import {ObjectData} from "../../utils/objectData.service";
import {HttpClient} from "@angular/common/http";
@Injectable({
providedIn: 'root'
})
export class AuditService {
constructor(private http: HttpClient) { }
/**
*
* @param params
* @param callBack
*/
public auditMsg(params: object, callBack:any) {
this.http.post(environment.baseUrl + 'audit/auditMsg', params).subscribe(data => {
callBack(data);
});
}
/**
*
* @param params
* @param callBack
*/
public getListGoodsAudit(params: object, callBack:any) {
this.http.get(environment.baseUrl + 'audit/getListGoodsAudit?' + ObjectData.objectByString(params)).subscribe(data => {
callBack(data);
});
}
/**
*
* @param params
* @param callBack
*/
public auditDetail(params: object, callBack:any) {
this.http.get(environment.baseUrl + 'audit/auditDetail?' + ObjectData.objectByString(params)).subscribe(data => {
callBack(data);
});
}
}

@ -0,0 +1,47 @@
// current locale is key of the MyErrorsOptions
import {AbstractControl, ValidatorFn, Validators} from "@angular/forms";
import {NzSafeAny} from "ng-zorro-antd/core/types";
export type MyErrorsOptions = { 'zh-cn': string; en: string } & Record<string, NzSafeAny>;
export type MyValidationErrors = Record<string, MyErrorsOptions>;
export class MyValidators extends Validators {
static override minLength(minLength: number): ValidatorFn {
return (control: AbstractControl): MyValidationErrors | null => {
if (Validators.minLength(minLength)(control) === null) {
return null;
}
return { minlength: { 'zh-cn': `最小长度为 ${minLength}`, en: `MinLength is ${minLength}` } };
};
}
static override maxLength(maxLength: number): ValidatorFn {
return (control: AbstractControl): MyValidationErrors | null => {
if (Validators.maxLength(maxLength)(control) === null) {
return null;
}
return { maxlength: { 'zh-cn': `最大长度为 ${maxLength}`, en: `MaxLength is ${maxLength}` } };
};
}
static mobile(control: AbstractControl): MyValidationErrors | null {
const value = control.value;
if (isEmptyInputValue(value)) {
return null;
}
return isMobile(value)
? null
: { mobile: { 'zh-cn': `手机号码格式不正确`, en: `Mobile phone number is not valid` } };
}
}
function isEmptyInputValue(value: NzSafeAny): boolean {
return value == null || value.length === 0;
}
function isMobile(value: string): boolean {
return typeof value === 'string' && /(^1\d{10}$)/.test(value);
}

@ -159,5 +159,16 @@ export class GoodsService {
}); });
} }
/**
*
* @param params
* @param callBack
*/
public goodsAudit(params: object, callBack:any) {
this.http.get(environment.baseUrl + 'goods/goodsAudit?' + ObjectData.objectByString(params)).subscribe(data => {
callBack(data);
});
}
} }

@ -66,4 +66,76 @@ export class DiscountService {
}); });
} }
/**
*
* @param params
* @param callBack
*/
public getDiscountPackageList(params: object, callBack:any) {
this.http.get(environment.baseUrl + 'discountPackage/getDiscountPackageList?' + ObjectData.objectByString(params)).subscribe(data => {
callBack(data);
});
}
/**
*
* @param params
* @param callBack
*/
public editCouponPackageInfo(params: object, callBack:any) {
this.http.post(environment.baseUrl + 'discountPackage/editCouponPackageInfo', params).subscribe(data => {
callBack(data);
});
}
/**
*
* @param id
* @param callBack
*/
public deleteCouponDiscount(id: number, callBack:any) {
this.http.get(environment.baseUrl + 'discountPackage/delete?id=' + id ).subscribe(data => {
callBack(data);
});
}
/**
*
* @param params
* @param callBack
*/
public getDetailList(params: object, callBack:any) {
this.http.get(environment.baseUrl + 'discountPackage/getDetailList?' + ObjectData.objectByString(params)).subscribe(data => {
callBack(data);
});
}
/**
*
* @param id
* @param callBack
*/
public deleteDetail(id: number, callBack:any) {
this.http.get(environment.baseUrl + 'discountPackage/deleteDetail?detailId=' + id ).subscribe(data => {
callBack(data);
});
}
/**
*
* @param params
* @param callBack
*/
public insertCouponPackageDetail(params: object, callBack:any) {
this.http.post(environment.baseUrl + 'discountPackage/insertCouponPackageDetail', params).subscribe(data => {
callBack(data);
});
}
public giveDiscountPackage(params: object, callBack:any) {
this.http.post(environment.baseUrl + 'discountPackage/giveDiscountPackage', params).subscribe(data => {
callBack(data);
});
}
} }

Loading…
Cancel
Save