完成H5后端管理第一版。
parent
d6de752645
commit
d0aa47cae2
@ -1 +1,6 @@
|
|||||||
package price_default
|
package price_default
|
||||||
|
|
||||||
|
type PriceDefaultRepository interface {
|
||||||
|
Save(price *PriceDefault) error
|
||||||
|
Get() (*PriceDefault, error)
|
||||||
|
}
|
||||||
|
@ -0,0 +1,32 @@
|
|||||||
|
package price_default
|
||||||
|
|
||||||
|
import (
|
||||||
|
"cls-server/internal/domain/price_default"
|
||||||
|
"cls-server/pkg/xorm_engine"
|
||||||
|
"xorm.io/builder"
|
||||||
|
)
|
||||||
|
|
||||||
|
type PriceDefaultRepositoryORM struct {
|
||||||
|
engine *xorm_engine.Engine
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ price_default.PriceDefaultRepository = (*PriceDefaultRepositoryORM)(nil)
|
||||||
|
|
||||||
|
func NewPriceRepositoryORM(engine *xorm_engine.Engine) price_default.PriceDefaultRepository {
|
||||||
|
return &PriceDefaultRepositoryORM{engine}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p PriceDefaultRepositoryORM) Save(pd *price_default.PriceDefault) error {
|
||||||
|
if pd.Id > 0 {
|
||||||
|
_, err := p.engine.Update(pd)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err := p.engine.Insert(pd)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p PriceDefaultRepositoryORM) Get() (*price_default.PriceDefault, error) {
|
||||||
|
data := &price_default.PriceDefault{}
|
||||||
|
_, err := p.engine.Where(builder.Eq{"id": 1}).Get(data)
|
||||||
|
return data, err
|
||||||
|
}
|
@ -1,11 +1,40 @@
|
|||||||
|
import { Article } from "./article";
|
||||||
|
import { Column } from "./column";
|
||||||
export interface Price {
|
export interface Price {
|
||||||
id: number;
|
id: number;
|
||||||
targetId: number;
|
targetId: number;
|
||||||
type: string;
|
type: PriceType;
|
||||||
amount: number;
|
amount: number;
|
||||||
|
firstMontDiscount:number;
|
||||||
oneMonthPrice: number;
|
oneMonthPrice: number;
|
||||||
threeMonthsPrice: number;
|
threeMonthsPrice: number;
|
||||||
sixMonthsPrice: number;
|
sixMonthsPrice: number;
|
||||||
oneYearPrice: number;
|
oneYearPrice: number;
|
||||||
discount: number;
|
discount: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum PriceType {
|
||||||
|
TypeArticle = 1,
|
||||||
|
TypeColumn = 2
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PriceDefault {
|
||||||
|
id: number;
|
||||||
|
amount: number;
|
||||||
|
firstMontDiscount:number;
|
||||||
|
oneMonthPrice: number;
|
||||||
|
threeMonthsPrice: number;
|
||||||
|
sixMonthsPrice: number;
|
||||||
|
oneYearPrice: number;
|
||||||
|
discount: number;
|
||||||
|
}
|
||||||
|
export interface ArticlePrice {
|
||||||
|
article: Article;
|
||||||
|
price: Price;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ColumnPrice {
|
||||||
|
column: Column;
|
||||||
|
price: Price;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -1,37 +1,34 @@
|
|||||||
<form *ngIf="validateForm" nz-form [formGroup]="validateForm">
|
<form nz-form [formGroup]="validateForm" nzLayout="vertical">
|
||||||
<nz-form-item>
|
<nz-form-item>
|
||||||
<nz-form-label [nzSpan]="6" >专栏名</nz-form-label>
|
<nz-form-label>专栏名称</nz-form-label>
|
||||||
<nz-form-control [nzSpan]="14" >
|
<nz-form-control>
|
||||||
<input nz-input type="text" formControlName="name" [disabled]="true" />
|
<input nz-input formControlName="title" [disabled]="true" />
|
||||||
</nz-form-control>
|
</nz-form-control>
|
||||||
</nz-form-item>
|
</nz-form-item>
|
||||||
|
|
||||||
<nz-form-item>
|
<nz-form-item>
|
||||||
<nz-form-label [nzSpan]="6" nzRequired>专栏描述</nz-form-label>
|
<nz-form-label nzRequired>专栏描述</nz-form-label>
|
||||||
<nz-form-control [nzSpan]="14" [nzErrorTip]="errorTpl1" nzHasFeedback>
|
<nz-form-control nzErrorTip="请输入专栏描述">
|
||||||
<input nz-input type="text" formControlName="brief"/>
|
<input nz-input formControlName="brief" />
|
||||||
<ng-template #errorTpl1 let-control>
|
|
||||||
<ng-container *ngIf="control.hasError('required')">
|
|
||||||
描述不能为空
|
|
||||||
</ng-container>
|
|
||||||
</ng-template>
|
|
||||||
</nz-form-control>
|
</nz-form-control>
|
||||||
</nz-form-item>
|
</nz-form-item>
|
||||||
|
|
||||||
<nz-form-item>
|
<nz-form-item>
|
||||||
<nz-form-label [nzSpan]="6" nzRequired>专栏封面</nz-form-label>
|
<nz-form-label nzRequired>关注人数</nz-form-label>
|
||||||
<nz-form-control [nzSpan]="14" [nzErrorTip]="errorTpl1" nzHasFeedback>
|
<nz-form-control nzErrorTip="请输入有效的关注人数">
|
||||||
<input nz-input type="text" formControlName="cover"/>
|
<input nz-input type="number" formControlName="followNum" />
|
||||||
</nz-form-control>
|
</nz-form-control>
|
||||||
</nz-form-item>
|
</nz-form-item>
|
||||||
|
|
||||||
<nz-form-item>
|
<nz-form-item>
|
||||||
<nz-form-label [nzSpan]="6" nzRequired>关注人数</nz-form-label>
|
<nz-form-label nzRequired>购买人数</nz-form-label>
|
||||||
<nz-form-control [nzSpan]="14" [nzErrorTip]="errorTpl1" nzHasFeedback>
|
<nz-form-control nzErrorTip="请输入有效的购买人数">
|
||||||
<input nz-input type="number" formControlName="followNum"/>
|
<input nz-input type="number" formControlName="purchaseNum" />
|
||||||
</nz-form-control>
|
|
||||||
</nz-form-item>
|
|
||||||
<nz-form-item>
|
|
||||||
<nz-form-label [nzSpan]="6" nzRequired>购买人数</nz-form-label>
|
|
||||||
<nz-form-control [nzSpan]="14" [nzErrorTip]="errorTpl1" nzHasFeedback>
|
|
||||||
<input nz-input type="number" formControlName="purchaseNum"/>
|
|
||||||
</nz-form-control>
|
</nz-form-control>
|
||||||
</nz-form-item>
|
</nz-form-item>
|
||||||
|
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button nz-button nzType="default" (click)="handleCancel()">取消</button>
|
||||||
|
<button nz-button nzType="primary" (click)="handleOk()" [nzLoading]="isSaving" [disabled]="!validateForm.valid">保存</button>
|
||||||
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
@ -0,0 +1,27 @@
|
|||||||
|
.modal-footer {
|
||||||
|
margin-top: 24px;
|
||||||
|
text-align: right;
|
||||||
|
|
||||||
|
button {
|
||||||
|
margin-left: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:host {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
padding: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
nz-form-item {
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
nz-form-label {
|
||||||
|
font-weight: 500;
|
||||||
|
color: rgba(0, 0, 0, 0.85);
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
width: 100%;
|
||||||
|
}
|
@ -0,0 +1,59 @@
|
|||||||
|
<nz-card>
|
||||||
|
<!-- 搜索区域 -->
|
||||||
|
<div class="search-area">
|
||||||
|
<nz-input-group [nzSuffix]="suffixIconSearch">
|
||||||
|
<input type="text" nz-input placeholder="搜索文章名称" [(ngModel)]="searchParams['search_like_username']" (ngModelChange)="onValueChange.next($event)" />
|
||||||
|
</nz-input-group>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- 表格区域 -->
|
||||||
|
<nz-table #basicTable
|
||||||
|
style="width: 100%"
|
||||||
|
nzSize="middle"
|
||||||
|
nzHideOnSinglePage
|
||||||
|
[nzLoading]="loading"
|
||||||
|
[nzShowTotal]="totalTemplate"
|
||||||
|
[nzFrontPagination]="false"
|
||||||
|
[nzPageSizeOptions]="[10,20,30]"
|
||||||
|
[nzShowSizeChanger]="true"
|
||||||
|
[nzPageIndex]="pageData?.pageNumber! +1 "
|
||||||
|
[nzPageSize]="pageData?.pageSize!"
|
||||||
|
[nzTotal]="pageData?.totalElements!"
|
||||||
|
[nzShowPagination]="true"
|
||||||
|
[nzData]="pageData?.items!"
|
||||||
|
(nzPageIndexChange)="changePaginationPage($event)"
|
||||||
|
(nzPageSizeChange)="changePaginationSize($event)">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>文章ID</th>
|
||||||
|
<th>文章名称</th>
|
||||||
|
<th>发布时间</th>
|
||||||
|
<th>价格(元)</th>
|
||||||
|
<th>折扣</th>
|
||||||
|
<th>操作</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr *ngFor="let data of basicTable.data">
|
||||||
|
<td>{{ data?.article?.eventId }}</td>
|
||||||
|
<td>{{ data?.article?.title }}</td>
|
||||||
|
<td>{{ data?.article?.releaseDate }} {{ data?.article?.releaseTime }}</td>
|
||||||
|
<td>{{ data?.price?.amount ? data.price.amount / 100:'默认价格' }}</td>
|
||||||
|
<td>{{ data?.price?.discount ? data.price.discount * 100 :'默认折扣'}}%</td>
|
||||||
|
<td>
|
||||||
|
<a (click)="editPrice(data)">编辑价格</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</nz-table>
|
||||||
|
<ng-template #totalTemplate let-range="range" let-total>
|
||||||
|
第<span style="padding: 0 0.5em;font-weight: bolder">{{range[0]}}-{{range[1]}}</span>个,共<span
|
||||||
|
style="padding: 0 0.5em;font-weight: bolder">{{total}}</span>个
|
||||||
|
</ng-template>
|
||||||
|
</nz-card>
|
||||||
|
|
||||||
|
<ng-template #suffixIconSearch>
|
||||||
|
<span nz-icon nzType="search"></span>
|
||||||
|
</ng-template>
|
@ -0,0 +1,155 @@
|
|||||||
|
import { Component, OnDestroy, OnInit } from '@angular/core';
|
||||||
|
import { Page } from '../../../core/models/page';
|
||||||
|
import { ArticlePrice } from '../../../core/models/price';
|
||||||
|
import { PriceService } from '../price.service';
|
||||||
|
import { debounceTime, distinctUntilChanged, Subject } from 'rxjs';
|
||||||
|
import { takeUntil } from 'rxjs/operators';
|
||||||
|
import { ChangeDetectorRef } from '@angular/core';
|
||||||
|
import { NzMessageModule, NzMessageService } from 'ng-zorro-antd/message';
|
||||||
|
import { NzModalModule, NzModalService } from 'ng-zorro-antd/modal';
|
||||||
|
import { NzFormModule } from 'ng-zorro-antd/form';
|
||||||
|
import { NzInputModule } from 'ng-zorro-antd/input';
|
||||||
|
import { NzInputNumberModule } from 'ng-zorro-antd/input-number';
|
||||||
|
import { NzCardModule } from 'ng-zorro-antd/card';
|
||||||
|
import { NzTableModule } from 'ng-zorro-antd/table';
|
||||||
|
import { NzIconModule } from 'ng-zorro-antd/icon';
|
||||||
|
import { FormsModule } from '@angular/forms';
|
||||||
|
import { FormBuilder, FormGroup, Validators, ReactiveFormsModule } from '@angular/forms';
|
||||||
|
import { NgForOf } from "@angular/common";
|
||||||
|
import { SetArticlePriceComponent } from "./set-article-price/set-article-price.component";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-article',
|
||||||
|
standalone: true,
|
||||||
|
imports: [
|
||||||
|
NzMessageModule,
|
||||||
|
NzModalModule,
|
||||||
|
NzFormModule,
|
||||||
|
NzInputModule,
|
||||||
|
NzInputNumberModule,
|
||||||
|
NzCardModule,
|
||||||
|
NzTableModule,
|
||||||
|
NzIconModule,
|
||||||
|
FormsModule,
|
||||||
|
ReactiveFormsModule,
|
||||||
|
NgForOf,
|
||||||
|
SetArticlePriceComponent
|
||||||
|
],
|
||||||
|
templateUrl: './article.component.html',
|
||||||
|
styleUrl: './article.component.scss'
|
||||||
|
})
|
||||||
|
export class ArticleComponent implements OnInit, OnDestroy {
|
||||||
|
pageData: Page<ArticlePrice> = new Page<ArticlePrice>();
|
||||||
|
searchParams: { [param: string]: any } = {
|
||||||
|
page: 0,
|
||||||
|
size: 10,
|
||||||
|
search_like_username: ''
|
||||||
|
};
|
||||||
|
onValueChange = new Subject<string>();
|
||||||
|
loading = false;
|
||||||
|
destroy$ = new Subject();
|
||||||
|
editForm: FormGroup;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private priceService: PriceService,
|
||||||
|
private cdr: ChangeDetectorRef,
|
||||||
|
private message: NzMessageService,
|
||||||
|
private modal: NzModalService,
|
||||||
|
private fb: FormBuilder
|
||||||
|
) {
|
||||||
|
this.onValueChange.pipe(
|
||||||
|
debounceTime(300),
|
||||||
|
distinctUntilChanged(),
|
||||||
|
takeUntil(this.destroy$)
|
||||||
|
).subscribe(() => {
|
||||||
|
this.searchParams['page'] = 0;
|
||||||
|
this.cdr.markForCheck();
|
||||||
|
this.loadData();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.editForm = this.fb.group({
|
||||||
|
price: [null, [Validators.required, Validators.min(0)]],
|
||||||
|
discount: [1, [Validators.required, Validators.min(0), Validators.max(1)]]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
console.log('Component initialized');
|
||||||
|
this.onValueChange
|
||||||
|
.pipe(debounceTime(500))
|
||||||
|
.subscribe(() => {
|
||||||
|
this.loadData();
|
||||||
|
});
|
||||||
|
this.loadData();
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
this.destroy$.next(null);
|
||||||
|
this.destroy$.complete();
|
||||||
|
}
|
||||||
|
|
||||||
|
loadData() {
|
||||||
|
console.log('Loading data with params:', this.searchParams);
|
||||||
|
this.loading = true;
|
||||||
|
this.cdr.detectChanges();
|
||||||
|
|
||||||
|
this.priceService.pageOfArticle(this.searchParams)
|
||||||
|
.pipe(takeUntil(this.destroy$))
|
||||||
|
.subscribe({
|
||||||
|
next: data => {
|
||||||
|
console.log('Raw response data:', data);
|
||||||
|
this.pageData = data;
|
||||||
|
console.log('Processed pageData:', this.pageData);
|
||||||
|
if (this.pageData?.items?.length > 0) {
|
||||||
|
console.log('First item:', this.pageData.items[0]);
|
||||||
|
console.log('First item article:', this.pageData.items[0]?.article);
|
||||||
|
console.log('First item price:', this.pageData.items[0]?.price);
|
||||||
|
}
|
||||||
|
this.loading = false;
|
||||||
|
this.cdr.detectChanges();
|
||||||
|
},
|
||||||
|
error: error => {
|
||||||
|
console.error('Error loading data:', error);
|
||||||
|
this.loading = false;
|
||||||
|
this.message.error("获取文章数据失败!");
|
||||||
|
this.cdr.detectChanges();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
changePaginationPage(page: number): void {
|
||||||
|
console.log('Changing page to:', page);
|
||||||
|
this.searchParams['page'] = page - 1;
|
||||||
|
this.cdr.detectChanges();
|
||||||
|
this.loadData();
|
||||||
|
}
|
||||||
|
|
||||||
|
changePaginationSize(size: number): void {
|
||||||
|
console.log('Changing page size to:', size);
|
||||||
|
this.searchParams['page'] = 0;
|
||||||
|
this.searchParams['size'] = size;
|
||||||
|
this.cdr.detectChanges();
|
||||||
|
this.loadData();
|
||||||
|
}
|
||||||
|
|
||||||
|
editPrice(article: ArticlePrice) {
|
||||||
|
console.log('Editing article:', article);
|
||||||
|
const modalRef = this.modal.create<SetArticlePriceComponent>({
|
||||||
|
nzTitle: '编辑文章价格',
|
||||||
|
nzContent: SetArticlePriceComponent,
|
||||||
|
nzData: article,
|
||||||
|
nzFooter: null
|
||||||
|
});
|
||||||
|
|
||||||
|
modalRef.afterClose.subscribe(result => {
|
||||||
|
if (result) {
|
||||||
|
this.loadData();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将元转换为分
|
||||||
|
private convertYuanToCents(yuan: number): number {
|
||||||
|
return Math.round(yuan * 100);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
<form nz-form [formGroup]="editForm" nzLayout="vertical">
|
||||||
|
<nz-form-item>
|
||||||
|
<nz-form-label>价格(元)</nz-form-label>
|
||||||
|
<nz-form-control>
|
||||||
|
<nz-input-number formControlName="price" [nzMin]="0" [nzStep]="0.01"></nz-input-number>
|
||||||
|
</nz-form-control>
|
||||||
|
</nz-form-item>
|
||||||
|
|
||||||
|
<nz-form-item>
|
||||||
|
<nz-form-label>折扣</nz-form-label>
|
||||||
|
<nz-form-control>
|
||||||
|
<nz-input-number formControlName="discount" [nzMin]="0" [nzMax]="1" [nzStep]="0.1"></nz-input-number>
|
||||||
|
</nz-form-control>
|
||||||
|
</nz-form-item>
|
||||||
|
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button nz-button nzType="default" (click)="handleCancel()">取消</button>
|
||||||
|
<button nz-button nzType="primary" (click)="handleOk()" [disabled]="!editForm.valid">保存</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
@ -0,0 +1,21 @@
|
|||||||
|
:host {
|
||||||
|
display: block;
|
||||||
|
padding: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
nz-form-item {
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
nz-input-number {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-footer {
|
||||||
|
margin-top: 24px;
|
||||||
|
text-align: right;
|
||||||
|
|
||||||
|
button {
|
||||||
|
margin-left: 8px;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,71 @@
|
|||||||
|
import { Component, Inject } from '@angular/core';
|
||||||
|
import { FormBuilder, FormGroup, Validators, ReactiveFormsModule } from '@angular/forms';
|
||||||
|
import { NzFormModule } from 'ng-zorro-antd/form';
|
||||||
|
import { NzInputNumberModule } from 'ng-zorro-antd/input-number';
|
||||||
|
import { NzModalRef, NZ_MODAL_DATA } from 'ng-zorro-antd/modal';
|
||||||
|
import {ArticlePrice, Price, PriceType} from '../../../../core/models/price';
|
||||||
|
import { PriceService } from '../../price.service';
|
||||||
|
import { NzMessageService } from 'ng-zorro-antd/message';
|
||||||
|
import { NzButtonModule } from 'ng-zorro-antd/button';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-set-article-price',
|
||||||
|
standalone: true,
|
||||||
|
imports: [
|
||||||
|
ReactiveFormsModule,
|
||||||
|
NzFormModule,
|
||||||
|
NzInputNumberModule,
|
||||||
|
NzButtonModule
|
||||||
|
],
|
||||||
|
templateUrl: './set-article-price.component.html',
|
||||||
|
styleUrls: ['./set-article-price.component.scss']
|
||||||
|
})
|
||||||
|
export class SetArticlePriceComponent {
|
||||||
|
editForm: FormGroup;
|
||||||
|
article: ArticlePrice;
|
||||||
|
priceType = PriceType;
|
||||||
|
constructor(
|
||||||
|
private fb: FormBuilder,
|
||||||
|
private modalRef: NzModalRef,
|
||||||
|
private priceService: PriceService,
|
||||||
|
private message: NzMessageService,
|
||||||
|
@Inject(NZ_MODAL_DATA) data: ArticlePrice
|
||||||
|
) {
|
||||||
|
this.article = data;
|
||||||
|
console.log(this.article)
|
||||||
|
const price = data?.price?.amount || 0;
|
||||||
|
const discount = data?.price?.discount || 1;
|
||||||
|
|
||||||
|
this.editForm = this.fb.group({
|
||||||
|
price: [price / 100, [Validators.required, Validators.min(0)]],
|
||||||
|
discount: [discount, [Validators.required, Validators.min(0), Validators.max(1)]]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
handleOk(): void {
|
||||||
|
if (this.editForm.valid) {
|
||||||
|
const formValue = this.editForm.value;
|
||||||
|
const priceData = {
|
||||||
|
targetId:this.article.article.eventId,
|
||||||
|
type:this.priceType.TypeArticle,
|
||||||
|
amount: Math.round(formValue.price * 100),
|
||||||
|
discount: formValue.discount
|
||||||
|
};
|
||||||
|
|
||||||
|
this.priceService.update(priceData as Price).subscribe({
|
||||||
|
next: () => {
|
||||||
|
this.message.success('价格更新成功');
|
||||||
|
this.modalRef.close(true);
|
||||||
|
},
|
||||||
|
error: (error) => {
|
||||||
|
this.message.error('价格更新失败');
|
||||||
|
console.error('Error updating price:', error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handleCancel(): void {
|
||||||
|
this.modalRef.close();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,63 @@
|
|||||||
|
<nz-card>
|
||||||
|
<!-- 搜索区域 -->
|
||||||
|
<div class="search-area">
|
||||||
|
<nz-input-group [nzSuffix]="suffixIconSearch">
|
||||||
|
<input type="text" nz-input placeholder="搜索专栏名称" [(ngModel)]="searchParams['search_like_username']" (ngModelChange)="onValueChange.next($event)" />
|
||||||
|
</nz-input-group>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 表格区域 -->
|
||||||
|
<nz-table #basicTable
|
||||||
|
style="width: 100%"
|
||||||
|
nzSize="middle"
|
||||||
|
nzHideOnSinglePage
|
||||||
|
[nzLoading]="loading"
|
||||||
|
[nzShowTotal]="totalTemplate"
|
||||||
|
[nzFrontPagination]="false"
|
||||||
|
[nzPageSizeOptions]="[10,20,30]"
|
||||||
|
[nzShowSizeChanger]="true"
|
||||||
|
[nzPageIndex]="pageData?.pageNumber! +1 "
|
||||||
|
[nzPageSize]="pageData?.pageSize!"
|
||||||
|
[nzTotal]="pageData?.totalElements!"
|
||||||
|
[nzShowPagination]="true"
|
||||||
|
[nzData]="pageData?.items!"
|
||||||
|
(nzPageIndexChange)="changePaginationPage($event)"
|
||||||
|
(nzPageSizeChange)="changePaginationSize($event)">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>专栏ID</th>
|
||||||
|
<th>专栏名称</th>
|
||||||
|
<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.column.id }}</td>
|
||||||
|
<td>{{ data.column.title }}</td>
|
||||||
|
<td>{{ data.price?.oneMonthPrice ? data.price.oneMonthPrice / 100 :'默认价格' }}</td>
|
||||||
|
<td>{{ data.price?.threeMonthsPrice ? data.price.threeMonthsPrice / 100 :'默认价格'}}</td>
|
||||||
|
<td>{{ data.price?.sixMonthsPrice ? data.price.sixMonthsPrice / 100 :'默认价格'}}</td>
|
||||||
|
<td>{{ data.price?.oneYearPrice ? data.price.oneYearPrice / 100 :'默认价格'}}</td>
|
||||||
|
<td>{{ data.price?.firstMontDiscount ? data.price.firstMontDiscount * 100 :'默认折扣'}}</td>
|
||||||
|
<td>{{ data.price?.discount ? data.price.discount * 100 :'默认折扣'}}</td>
|
||||||
|
<td>
|
||||||
|
<a (click)="editPrice(data)">编辑价格</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</nz-table>
|
||||||
|
<ng-template #totalTemplate let-range="range" let-total>
|
||||||
|
第<span style="padding: 0 0.5em;font-weight: bolder">{{range[0]}}-{{range[1]}}</span>个,共<span
|
||||||
|
style="padding: 0 0.5em;font-weight: bolder">{{total}}</span>个
|
||||||
|
</ng-template>
|
||||||
|
</nz-card>
|
||||||
|
|
||||||
|
<ng-template #suffixIconSearch>
|
||||||
|
<span nz-icon nzType="search"></span>
|
||||||
|
</ng-template>
|
@ -0,0 +1,137 @@
|
|||||||
|
import { Component, OnDestroy, OnInit } from '@angular/core';
|
||||||
|
import { Page } from '../../../core/models/page';
|
||||||
|
import { ColumnPrice } from '../../../core/models/price';
|
||||||
|
import { PriceService } from '../price.service';
|
||||||
|
import { debounceTime, distinctUntilChanged, Subject } from 'rxjs';
|
||||||
|
import { takeUntil } from 'rxjs/operators';
|
||||||
|
import { ChangeDetectorRef } from '@angular/core';
|
||||||
|
import { NzMessageModule, NzMessageService } from 'ng-zorro-antd/message';
|
||||||
|
import { NzModalModule, NzModalService } from 'ng-zorro-antd/modal';
|
||||||
|
import { NzFormModule } from 'ng-zorro-antd/form';
|
||||||
|
import { NzInputModule } from 'ng-zorro-antd/input';
|
||||||
|
import { NzInputNumberModule } from 'ng-zorro-antd/input-number';
|
||||||
|
import { NzCardModule } from 'ng-zorro-antd/card';
|
||||||
|
import { NzTableModule } from 'ng-zorro-antd/table';
|
||||||
|
import { NzIconModule } from 'ng-zorro-antd/icon';
|
||||||
|
import { FormsModule } from '@angular/forms';
|
||||||
|
import { FormBuilder, FormGroup, Validators, ReactiveFormsModule } from '@angular/forms';
|
||||||
|
import {SetColumnPriceComponent} from "./set-column-price/set-column-price.component";
|
||||||
|
import {NgForOf} from "@angular/common";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-column',
|
||||||
|
standalone: true,
|
||||||
|
imports: [
|
||||||
|
NzMessageModule,
|
||||||
|
NzModalModule,
|
||||||
|
NzFormModule,
|
||||||
|
NzInputModule,
|
||||||
|
NzInputNumberModule,
|
||||||
|
NzCardModule,
|
||||||
|
NzTableModule,
|
||||||
|
NzIconModule,
|
||||||
|
FormsModule,
|
||||||
|
ReactiveFormsModule,
|
||||||
|
NgForOf
|
||||||
|
],
|
||||||
|
templateUrl: './column.component.html',
|
||||||
|
styleUrl: './column.component.scss'
|
||||||
|
})
|
||||||
|
export class ColumnComponent implements OnInit, OnDestroy {
|
||||||
|
pageData: Page<ColumnPrice> = new Page<ColumnPrice>();
|
||||||
|
searchParams: { [param: string]: any } = {
|
||||||
|
page: 0,
|
||||||
|
size: 10,
|
||||||
|
search_like_username: ''
|
||||||
|
};
|
||||||
|
onValueChange = new Subject<string>();
|
||||||
|
loading = false;
|
||||||
|
destroy$ = new Subject();
|
||||||
|
editForm: FormGroup;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private priceService: PriceService,
|
||||||
|
private cdr: ChangeDetectorRef,
|
||||||
|
private message: NzMessageService,
|
||||||
|
private modal: NzModalService,
|
||||||
|
private fb: FormBuilder
|
||||||
|
) {
|
||||||
|
this.onValueChange.pipe(
|
||||||
|
debounceTime(300),
|
||||||
|
distinctUntilChanged(),
|
||||||
|
takeUntil(this.destroy$)
|
||||||
|
).subscribe(() => {
|
||||||
|
this.searchParams['page'] = 0;
|
||||||
|
this.cdr.markForCheck();
|
||||||
|
this.loadData();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.editForm = this.fb.group({
|
||||||
|
oneMonthPrice: [null, [Validators.required, Validators.min(0)]],
|
||||||
|
threeMonthsPrice: [null, [Validators.required, Validators.min(0)]],
|
||||||
|
sixMonthsPrice: [null, [Validators.required, Validators.min(0)]],
|
||||||
|
oneYearPrice: [null, [Validators.required, Validators.min(0)]]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.loadData();
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
this.destroy$.next(null);
|
||||||
|
this.destroy$.complete();
|
||||||
|
}
|
||||||
|
|
||||||
|
loadData() {
|
||||||
|
this.loading = true;
|
||||||
|
this.cdr.detectChanges();
|
||||||
|
this.priceService.pageOfColumn(this.searchParams)
|
||||||
|
.pipe(takeUntil(this.destroy$))
|
||||||
|
.subscribe({
|
||||||
|
next: data => {
|
||||||
|
this.loading = false;
|
||||||
|
this.pageData = data;
|
||||||
|
},
|
||||||
|
error: data => {
|
||||||
|
console.log(data)
|
||||||
|
this.loading = false;
|
||||||
|
this.message.error("获取专栏数据失败!");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
changePaginationPage(page: number): void {
|
||||||
|
this.searchParams['page'] = page - 1;
|
||||||
|
this.cdr.detectChanges();
|
||||||
|
this.loadData();
|
||||||
|
}
|
||||||
|
|
||||||
|
changePaginationSize(size: number): void {
|
||||||
|
this.searchParams['page'] = 0;
|
||||||
|
this.searchParams['size'] = size;
|
||||||
|
this.cdr.detectChanges();
|
||||||
|
this.loadData();
|
||||||
|
}
|
||||||
|
|
||||||
|
editPrice(columnPrice: ColumnPrice) {
|
||||||
|
console.log('Editing column:', columnPrice);
|
||||||
|
const modalRef = this.modal.create<SetColumnPriceComponent>({
|
||||||
|
nzTitle: '编辑专栏价格',
|
||||||
|
nzContent: SetColumnPriceComponent,
|
||||||
|
nzData: columnPrice,
|
||||||
|
nzFooter: null
|
||||||
|
});
|
||||||
|
|
||||||
|
modalRef.afterClose.subscribe(result => {
|
||||||
|
if (result) {
|
||||||
|
this.loadData();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将元转换为分
|
||||||
|
private convertYuanToCents(yuan: number): number {
|
||||||
|
return Math.round(yuan * 100);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,48 @@
|
|||||||
|
<form nz-form [formGroup]="editForm" nzLayout="vertical">
|
||||||
|
<nz-form-item>
|
||||||
|
<nz-form-label>一个月价格</nz-form-label>
|
||||||
|
<nz-form-control nzErrorTip="请输入有效的价格">
|
||||||
|
<nz-input-number class="full-width" formControlName="oneMonthPrice" [nzMin]="0" [nzStep]="0.01" [nzPrecision]="2" [nzPlaceHolder]="'请输入价格'" [nzFormatter]="yuanFormatter" [nzParser]="yuanParser"></nz-input-number>
|
||||||
|
</nz-form-control>
|
||||||
|
</nz-form-item>
|
||||||
|
|
||||||
|
<nz-form-item>
|
||||||
|
<nz-form-label>三个月价格</nz-form-label>
|
||||||
|
<nz-form-control nzErrorTip="请输入有效的价格">
|
||||||
|
<nz-input-number class="full-width" formControlName="threeMonthsPrice" [nzMin]="0" [nzStep]="0.01" [nzPrecision]="2" [nzPlaceHolder]="'请输入价格'" [nzFormatter]="yuanFormatter" [nzParser]="yuanParser"></nz-input-number>
|
||||||
|
</nz-form-control>
|
||||||
|
</nz-form-item>
|
||||||
|
|
||||||
|
<nz-form-item>
|
||||||
|
<nz-form-label>半年价格</nz-form-label>
|
||||||
|
<nz-form-control nzErrorTip="请输入有效的价格">
|
||||||
|
<nz-input-number class="full-width" formControlName="sixMonthsPrice" [nzMin]="0" [nzStep]="0.01" [nzPrecision]="2" [nzPlaceHolder]="'请输入价格'" [nzFormatter]="yuanFormatter" [nzParser]="yuanParser"></nz-input-number>
|
||||||
|
</nz-form-control>
|
||||||
|
</nz-form-item>
|
||||||
|
|
||||||
|
<nz-form-item>
|
||||||
|
<nz-form-label>一年价格</nz-form-label>
|
||||||
|
<nz-form-control nzErrorTip="请输入有效的价格">
|
||||||
|
<nz-input-number class="full-width" formControlName="oneYearPrice" [nzMin]="0" [nzStep]="0.01" [nzPrecision]="2" [nzPlaceHolder]="'请输入价格'" [nzFormatter]="yuanFormatter" [nzParser]="yuanParser"></nz-input-number>
|
||||||
|
</nz-form-control>
|
||||||
|
</nz-form-item>
|
||||||
|
|
||||||
|
<nz-form-item>
|
||||||
|
<nz-form-label>首月折扣</nz-form-label>
|
||||||
|
<nz-form-control nzErrorTip="请输入0-1之间的折扣">
|
||||||
|
<nz-input-number class="full-width" formControlName="firstMontDiscount" [nzMin]="0" [nzMax]="1" [nzStep]="0.1" [nzPrecision]="2" [nzPlaceHolder]="'请输入折扣'" [nzFormatter]="percentFormatter" [nzParser]="percentParser"></nz-input-number>
|
||||||
|
</nz-form-control>
|
||||||
|
</nz-form-item>
|
||||||
|
|
||||||
|
<nz-form-item>
|
||||||
|
<nz-form-label>折扣</nz-form-label>
|
||||||
|
<nz-form-control nzErrorTip="请输入0-1之间的折扣">
|
||||||
|
<nz-input-number class="full-width" formControlName="discount" [nzMin]="0" [nzMax]="1" [nzStep]="0.1" [nzPrecision]="2" [nzPlaceHolder]="'请输入折扣'" [nzFormatter]="percentFormatter" [nzParser]="percentParser"></nz-input-number>
|
||||||
|
</nz-form-control>
|
||||||
|
</nz-form-item>
|
||||||
|
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button nz-button nzType="default" (click)="handleCancel()">取消</button>
|
||||||
|
<button nz-button nzType="primary" (click)="handleOk()" [disabled]="!editForm.valid">保存</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
@ -0,0 +1,31 @@
|
|||||||
|
.modal-footer {
|
||||||
|
margin-top: 24px;
|
||||||
|
text-align: right;
|
||||||
|
|
||||||
|
button {
|
||||||
|
margin-left: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:host {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
padding: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.full-width {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
nz-form-item {
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
nz-form-label {
|
||||||
|
font-weight: 500;
|
||||||
|
color: rgba(0, 0, 0, 0.85);
|
||||||
|
}
|
||||||
|
|
||||||
|
nz-input-number {
|
||||||
|
width: 100%;
|
||||||
|
}
|
@ -0,0 +1,94 @@
|
|||||||
|
import { Component, Inject } from '@angular/core';
|
||||||
|
import { FormBuilder, FormGroup, Validators, ReactiveFormsModule } from '@angular/forms';
|
||||||
|
import { NzFormModule } from 'ng-zorro-antd/form';
|
||||||
|
import { NzInputNumberModule } from 'ng-zorro-antd/input-number';
|
||||||
|
import { NzModalRef, NZ_MODAL_DATA } from 'ng-zorro-antd/modal';
|
||||||
|
import { ColumnPrice } from '../../../../core/models/price';
|
||||||
|
import { PriceService } from '../../price.service';
|
||||||
|
import { NzMessageService } from 'ng-zorro-antd/message';
|
||||||
|
import { NzButtonModule } from 'ng-zorro-antd/button';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-set-column-price',
|
||||||
|
standalone: true,
|
||||||
|
imports: [
|
||||||
|
ReactiveFormsModule,
|
||||||
|
NzFormModule,
|
||||||
|
NzInputNumberModule,
|
||||||
|
NzButtonModule
|
||||||
|
],
|
||||||
|
templateUrl: './set-column-price.component.html',
|
||||||
|
styleUrls: ['./set-column-price.component.scss']
|
||||||
|
})
|
||||||
|
export class SetColumnPriceComponent {
|
||||||
|
editForm: FormGroup;
|
||||||
|
column: ColumnPrice;
|
||||||
|
|
||||||
|
// 价格格式化器
|
||||||
|
yuanFormatter = (value: number): string => {
|
||||||
|
return value ? `¥ ${value}` : '';
|
||||||
|
};
|
||||||
|
|
||||||
|
yuanParser = (value: string): string => {
|
||||||
|
return value.replace(/[^0-9.]/g, '');
|
||||||
|
};
|
||||||
|
|
||||||
|
// 百分比格式化器
|
||||||
|
percentFormatter = (value: number): string => {
|
||||||
|
return value ? `${(value * 100).toFixed(0)}%` : '';
|
||||||
|
};
|
||||||
|
|
||||||
|
percentParser = (value: string): string => {
|
||||||
|
return value.replace('%', '').trim();
|
||||||
|
};
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private fb: FormBuilder,
|
||||||
|
private modalRef: NzModalRef,
|
||||||
|
private priceService: PriceService,
|
||||||
|
private message: NzMessageService,
|
||||||
|
@Inject(NZ_MODAL_DATA) data: ColumnPrice
|
||||||
|
) {
|
||||||
|
this.column = data;
|
||||||
|
const price = data?.price || {};
|
||||||
|
|
||||||
|
this.editForm = this.fb.group({
|
||||||
|
oneMonthPrice: [price?.oneMonthPrice ? price.oneMonthPrice / 100 : 0, [Validators.required, Validators.min(0)]],
|
||||||
|
threeMonthsPrice: [price?.threeMonthsPrice ? price.threeMonthsPrice / 100 : 0, [Validators.required, Validators.min(0)]],
|
||||||
|
sixMonthsPrice: [price?.sixMonthsPrice ? price.sixMonthsPrice / 100 : 0, [Validators.required, Validators.min(0)]],
|
||||||
|
oneYearPrice: [price?.oneYearPrice ? price.oneYearPrice / 100 : 0, [Validators.required, Validators.min(0)]],
|
||||||
|
firstMontDiscount: [price?.firstMontDiscount || 1, [Validators.required, Validators.min(0), Validators.max(1)]],
|
||||||
|
discount: [price?.discount || 1, [Validators.required, Validators.min(0), Validators.max(1)]]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
handleOk(): void {
|
||||||
|
if (this.editForm.valid) {
|
||||||
|
const formValue = this.editForm.value;
|
||||||
|
const priceData = {
|
||||||
|
...this.column.price,
|
||||||
|
oneMonthPrice: Math.round(formValue.oneMonthPrice * 100),
|
||||||
|
threeMonthsPrice: Math.round(formValue.threeMonthsPrice * 100),
|
||||||
|
sixMonthsPrice: Math.round(formValue.sixMonthsPrice * 100),
|
||||||
|
oneYearPrice: Math.round(formValue.oneYearPrice * 100),
|
||||||
|
firstMontDiscount: formValue.firstMontDiscount,
|
||||||
|
discount: formValue.discount
|
||||||
|
};
|
||||||
|
|
||||||
|
this.priceService.update(priceData).subscribe({
|
||||||
|
next: () => {
|
||||||
|
this.message.success('价格更新成功');
|
||||||
|
this.modalRef.close(true);
|
||||||
|
},
|
||||||
|
error: (error) => {
|
||||||
|
this.message.error('价格更新失败');
|
||||||
|
console.error('Error updating price:', error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handleCancel(): void {
|
||||||
|
this.modalRef.close();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,122 @@
|
|||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { FormsModule, ReactiveFormsModule, FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||||
|
import { NzFormModule } from 'ng-zorro-antd/form';
|
||||||
|
import { NzInputModule } from 'ng-zorro-antd/input';
|
||||||
|
import { NzButtonModule } from 'ng-zorro-antd/button';
|
||||||
|
import { NzMessageService } from 'ng-zorro-antd/message';
|
||||||
|
import { PriceService } from '../price.service';
|
||||||
|
import { PriceDefault } from '../../../core/models/price';
|
||||||
|
import { NzInputNumberModule } from 'ng-zorro-antd/input-number';
|
||||||
|
import { NzCardModule } from 'ng-zorro-antd/card';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-price-default',
|
||||||
|
standalone: true,
|
||||||
|
imports: [
|
||||||
|
CommonModule,
|
||||||
|
FormsModule,
|
||||||
|
ReactiveFormsModule,
|
||||||
|
NzFormModule,
|
||||||
|
NzInputModule,
|
||||||
|
NzButtonModule,
|
||||||
|
NzInputNumberModule,
|
||||||
|
NzCardModule,
|
||||||
|
],
|
||||||
|
templateUrl: './price-default.component.html',
|
||||||
|
styleUrl: './price-default.component.scss'
|
||||||
|
})
|
||||||
|
export class PriceDefaultComponent implements OnInit {
|
||||||
|
priceForm: FormGroup;
|
||||||
|
loading = false;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private fb: FormBuilder,
|
||||||
|
private priceService: PriceService,
|
||||||
|
private message: NzMessageService
|
||||||
|
) {
|
||||||
|
this.priceForm = this.fb.group({
|
||||||
|
amount: [null, [Validators.required, Validators.min(0)]],
|
||||||
|
firstMontDiscount: [null, [Validators.required, Validators.min(0), Validators.max(100)]],
|
||||||
|
oneMonthPrice: [null, [Validators.required, Validators.min(0)]],
|
||||||
|
threeMonthsPrice: [null, [Validators.required, Validators.min(0)]],
|
||||||
|
sixMonthsPrice: [null, [Validators.required, Validators.min(0)]],
|
||||||
|
oneYearPrice: [null, [Validators.required, Validators.min(0)]],
|
||||||
|
discount: [null, [Validators.required, Validators.min(0), Validators.max(100)]]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.loadDefaultPrice();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将分转换为元
|
||||||
|
private convertCentsToYuan(cents: number): number {
|
||||||
|
return cents / 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将元转换为分
|
||||||
|
private convertYuanToCents(yuan: number): number {
|
||||||
|
return Math.round(yuan * 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
loadDefaultPrice() {
|
||||||
|
this.loading = true;
|
||||||
|
this.priceService.getDefaultPrice().subscribe({
|
||||||
|
next: (data) => {
|
||||||
|
// 将后端返回的分转换为元
|
||||||
|
const formData = {
|
||||||
|
...data,
|
||||||
|
amount: this.convertCentsToYuan(data.amount),
|
||||||
|
oneMonthPrice: this.convertCentsToYuan(data.oneMonthPrice),
|
||||||
|
threeMonthsPrice: this.convertCentsToYuan(data.threeMonthsPrice),
|
||||||
|
sixMonthsPrice: this.convertCentsToYuan(data.sixMonthsPrice),
|
||||||
|
oneYearPrice: this.convertCentsToYuan(data.oneYearPrice)
|
||||||
|
};
|
||||||
|
this.priceForm.patchValue(formData);
|
||||||
|
this.loading = false;
|
||||||
|
},
|
||||||
|
error: (error) => {
|
||||||
|
this.message.error('获取默认价格失败');
|
||||||
|
this.loading = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onSubmit() {
|
||||||
|
if (this.priceForm.valid) {
|
||||||
|
this.loading = true;
|
||||||
|
const formValue = this.priceForm.value;
|
||||||
|
|
||||||
|
// 将表单中的元转换为分
|
||||||
|
const priceData: PriceDefault = {
|
||||||
|
id: 1,
|
||||||
|
amount: this.convertYuanToCents(formValue.amount),
|
||||||
|
firstMontDiscount: formValue.firstMontDiscount,
|
||||||
|
oneMonthPrice: this.convertYuanToCents(formValue.oneMonthPrice),
|
||||||
|
threeMonthsPrice: this.convertYuanToCents(formValue.threeMonthsPrice),
|
||||||
|
sixMonthsPrice: this.convertYuanToCents(formValue.sixMonthsPrice),
|
||||||
|
oneYearPrice: this.convertYuanToCents(formValue.oneYearPrice),
|
||||||
|
discount: formValue.discount
|
||||||
|
};
|
||||||
|
|
||||||
|
this.priceService.updateDefaultPrice(priceData).subscribe({
|
||||||
|
next: () => {
|
||||||
|
this.message.success('更新默认价格成功');
|
||||||
|
this.loadDefaultPrice();
|
||||||
|
},
|
||||||
|
error: (error) => {
|
||||||
|
this.message.error('更新默认价格失败');
|
||||||
|
this.loading = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
Object.values(this.priceForm.controls).forEach(control => {
|
||||||
|
if (control.invalid) {
|
||||||
|
control.markAsTouched();
|
||||||
|
control.updateValueAndValidity({ onlySelf: true });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,11 +1,28 @@
|
|||||||
|
|
||||||
<nz-page-header nzTitle="Title" nzSubtitle="This is a subtitle">
|
<nz-page-header nzTitle="价格管理" nzSubtitle="专栏和文章价格管理界面">
|
||||||
<nz-breadcrumb nz-page-header-breadcrumb>
|
<nz-breadcrumb nz-page-header-breadcrumb>
|
||||||
<nz-breadcrumb-item>First-level Menu</nz-breadcrumb-item>
|
<nz-breadcrumb-item>后台管理</nz-breadcrumb-item>
|
||||||
<nz-breadcrumb-item>
|
<nz-breadcrumb-item>
|
||||||
<a>Second-level Menu</a>
|
<a>价格管理</a>
|
||||||
</nz-breadcrumb-item>
|
</nz-breadcrumb-item>
|
||||||
<nz-breadcrumb-item>Third-level Menu</nz-breadcrumb-item>
|
<nz-breadcrumb-item>价格管理</nz-breadcrumb-item>
|
||||||
</nz-breadcrumb>
|
</nz-breadcrumb>
|
||||||
</nz-page-header>
|
</nz-page-header>
|
||||||
|
<br />
|
||||||
|
<nz-card style="width: 100%;">
|
||||||
|
<nz-card-tab>
|
||||||
|
<nz-tabset nzSize="large" >
|
||||||
|
<nz-tab nzTitle="默认价格">
|
||||||
|
<app-price-default></app-price-default>
|
||||||
|
</nz-tab>
|
||||||
|
<nz-tab nzTitle="专栏">
|
||||||
|
<app-column></app-column>
|
||||||
|
</nz-tab>
|
||||||
|
<nz-tab nzTitle="文章">
|
||||||
|
<app-article></app-article>
|
||||||
|
</nz-tab>
|
||||||
|
</nz-tabset>
|
||||||
|
</nz-card-tab>
|
||||||
|
|
||||||
|
</nz-card>
|
||||||
|
|
@ -1,22 +0,0 @@
|
|||||||
import { fakeAsync, ComponentFixture, TestBed } from '@angular/core/testing';
|
|
||||||
import { PriceComponent } from './price.component';
|
|
||||||
|
|
||||||
describe('PriceComponent', () => {
|
|
||||||
let component: PriceComponent;
|
|
||||||
let fixture: ComponentFixture<PriceComponent>;
|
|
||||||
|
|
||||||
beforeEach(fakeAsync(() => {
|
|
||||||
TestBed.configureTestingModule({
|
|
||||||
declarations: [ PriceComponent ]
|
|
||||||
})
|
|
||||||
.compileComponents();
|
|
||||||
|
|
||||||
fixture = TestBed.createComponent(PriceComponent);
|
|
||||||
component = fixture.componentInstance;
|
|
||||||
fixture.detectChanges();
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should compile', () => {
|
|
||||||
expect(component).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
@ -0,0 +1,53 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import {HttpClient} from "@angular/common/http";
|
||||||
|
import {Observable} from "rxjs";
|
||||||
|
import {Price, PriceDefault} from "../../core/models/price";
|
||||||
|
import {extractData, Page} from "../../core/models/page";
|
||||||
|
import {map} from "rxjs/operators";
|
||||||
|
import {HttpUtils} from "../../core/until/http.utils";
|
||||||
|
import { ArticlePrice, ColumnPrice } from '../../core/models/price';
|
||||||
|
import {Article} from "../../core/models/article";
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class PriceService {
|
||||||
|
|
||||||
|
constructor(private http:HttpClient) { }
|
||||||
|
|
||||||
|
// auth.POST("/create", h.create)
|
||||||
|
// auth.GET("/get-default", h.getPriceDefault)
|
||||||
|
// auth.POST("/update-default", h.updatePriceDefault)
|
||||||
|
// auth.POST("/update", h.update)
|
||||||
|
// auth.GET("/page-article", h.getPriceArticle)
|
||||||
|
// auth.GET("/page-column", h.getPriceColumn)
|
||||||
|
// pageOfArticle(searchParams: { [key: string]: string }):Observable<Page<ArticlePrice>> {
|
||||||
|
// return this.http.get<Page<ArticlePrice>>('/api/price/page-article"',
|
||||||
|
// {params:HttpUtils.getSearchParams(searchParams)}).pipe(
|
||||||
|
// map(response=> extractData<ArticlePrice>(response))
|
||||||
|
// )
|
||||||
|
// }
|
||||||
|
|
||||||
|
pageOfArticle(searchParams:{[key:string]:string}):Observable<Page<ArticlePrice>> {
|
||||||
|
return this.http.get<Page<ArticlePrice>>('/api/price/page-article',{
|
||||||
|
params:HttpUtils.getSearchParams(searchParams)
|
||||||
|
}).pipe(map(response => extractData<ArticlePrice>(response)))
|
||||||
|
}
|
||||||
|
|
||||||
|
pageOfColumn(searchParams:{[key:string]:string}):Observable<Page<ColumnPrice>> {
|
||||||
|
console.log("come in")
|
||||||
|
return this.http.get<Page<ColumnPrice>>('/api/price/page-column',{
|
||||||
|
params:HttpUtils.getSearchParams(searchParams)
|
||||||
|
}).pipe(
|
||||||
|
map(response => extractData<ColumnPrice>(response ))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
getDefaultPrice():Observable<PriceDefault> {
|
||||||
|
return this.http.get<PriceDefault>('/api/price/get-default')
|
||||||
|
}
|
||||||
|
updateDefaultPrice(pd:PriceDefault):Observable<null> {
|
||||||
|
return this.http.post<null>('/api/price/update-default',pd)
|
||||||
|
}
|
||||||
|
update(price: Price): Observable<any> {
|
||||||
|
return this.http.post('/api/price/update', price);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue