listing-overview-table.component.ts 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556
  1. import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core';
  2. import { CommonModule } from '@angular/common';
  3. import { RouterLink } from '@angular/router';
  4. import type { ListingDimension, ListingOverviewDirection, ListingOverviewRow, ListingOverviewSort } from '../../models/listing-ai.models';
  5. @Component({
  6. selector: 'app-listing-overview-table',
  7. standalone: true,
  8. imports: [CommonModule, RouterLink],
  9. templateUrl: './listing-overview-table.component.html',
  10. styleUrl: './listing-overview-table.component.scss',
  11. changeDetection: ChangeDetectionStrategy.OnPush,
  12. })
  13. export class ListingOverviewTableComponent {
  14. @Input() items: ListingOverviewRow[] = [];
  15. @Input() loading = false;
  16. @Input() nextCursor: string | null = null;
  17. @Input() currentCursor: string | undefined;
  18. @Input() sort: ListingOverviewSort = 'improvementPotential';
  19. @Input() direction: ListingOverviewDirection = 'desc';
  20. @Input() returnTo = '/listing-ai/overview';
  21. @Output() nextPage = new EventEmitter<void>();
  22. @Output() firstPage = new EventEmitter<void>();
  23. @Output() sortChange = new EventEmitter<{ sort: ListingOverviewSort; direction: ListingOverviewDirection }>();
  24. @Output() detailOpen = new EventEmitter<void>();
  25. readonly dimensions: Array<{ key: ListingDimension; label: string }> = [
  26. { key: 'title', label: '标题' }, { key: 'selling_points', label: '卖点' }, { key: 'images', label: '图片' },
  27. { key: 'description', label: '详情' }, { key: 'specifications', label: '规格' },
  28. ];
  29. readonly dimensionLabels: Record<ListingDimension, string> = {
  30. title: '商品标题', selling_points: '核心卖点', images: '图片资产', description: '商品详情', specifications: '规格与履约',
  31. };
  32. toggleSort(sort: ListingOverviewSort): void {
  33. this.sortChange.emit({ sort, direction: this.sort === sort && this.direction === 'desc' ? 'asc' : 'desc' });
  34. }
  35. sortIndicator(sort: ListingOverviewSort): string {
  36. return this.sort === sort ? (this.direction === 'asc' ? '↑' : '↓') : '';
  37. }
  38. overallText(item: ListingOverviewRow): string {
  39. if (item.overallScore !== null) return `${item.overallScore}`;
  40. return item.scoreNature === 'unscored' ? '未评分' : '总分缺失';
  41. }
  42. dimensionText(item: ListingOverviewRow, key: ListingDimension): string {
  43. const dimension = item.dimensions[key];
  44. return dimension.score === null ? '空维度' : `${dimension.score}/${dimension.maxScore}`;
  45. }
  46. rateText(rate: number | null): string {
  47. return rate === null ? '得分率未知' : `${Math.round(rate * 1000) / 10}%`;
  48. }
  49. }