customer-review-card.html 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. <div class="customer-review-card">
  2. <!-- 统计数据概览 -->
  3. <div class="stats-overview">
  4. <h4>客户评价概览</h4>
  5. <div class="stats-grid">
  6. <div class="stat-item total">
  7. <div class="stat-value">{{ stats().totalCount }}</div>
  8. <div class="stat-label">总评价数</div>
  9. </div>
  10. <div class="stat-item score">
  11. <div class="stat-value">{{ stats().averageScore }}<span class="score-suffix">/5</span></div>
  12. <div class="stat-label">平均评分</div>
  13. <div class="star-display">
  14. @for (star of getStarRating(stats().averageScore); track $index) {
  15. <span class="star">{{ star }}</span>
  16. }
  17. </div>
  18. </div>
  19. <div class="stat-item satisfied">
  20. <div class="stat-value">{{ stats().satisfiedCount }}</div>
  21. <div class="stat-label">满意评价</div>
  22. </div>
  23. <div class="stat-item pending">
  24. <div class="stat-value">{{ stats().pendingCount }}</div>
  25. <div class="stat-label">待处理</div>
  26. </div>
  27. </div>
  28. </div>
  29. <!-- 分类统计 -->
  30. <div class="category-stats">
  31. <h5>问题分类统计</h5>
  32. <div class="category-grid">
  33. @for (category of categories; track category.value) {
  34. <div class="category-item">
  35. <span class="category-label">{{ category.label }}</span>
  36. <span class="category-count">{{ stats().categoryStats[category.value] || 0 }}</span>
  37. </div>
  38. }
  39. </div>
  40. </div>
  41. <!-- 筛选区域 -->
  42. <div class="filter-section">
  43. <div class="filter-row">
  44. <div class="filter-group">
  45. <label>状态筛选:</label>
  46. <div class="filter-buttons">
  47. <button
  48. class="filter-btn"
  49. [class.active]="statusFilter() === 'all'"
  50. (click)="updateStatusFilter('all')">
  51. 全部
  52. </button>
  53. <button
  54. class="filter-btn pending"
  55. [class.active]="statusFilter() === '待处理'"
  56. (click)="updateStatusFilter('待处理')">
  57. 待处理
  58. </button>
  59. <button
  60. class="filter-btn satisfied"
  61. [class.active]="statusFilter() === 'satisfied'"
  62. (click)="updateStatusFilter('satisfied')">
  63. 满意
  64. </button>
  65. <button
  66. class="filter-btn unsatisfied"
  67. [class.active]="statusFilter() === 'unsatisfied'"
  68. (click)="updateStatusFilter('unsatisfied')">
  69. 不满意
  70. </button>
  71. </div>
  72. </div>
  73. </div>
  74. <div class="filter-row">
  75. <div class="filter-group">
  76. <label>分类筛选:</label>
  77. <select
  78. class="filter-select"
  79. [value]="categoryFilter()"
  80. (change)="updateCategoryFilter($event)">
  81. <option value="all">全部分类</option>
  82. @for (category of categories; track category.value) {
  83. <option [value]="category.value">{{ category.label }}</option>
  84. }
  85. </select>
  86. </div>
  87. <div class="filter-group">
  88. <label>评分筛选:</label>
  89. <select
  90. class="filter-select"
  91. [value]="scoreFilter()"
  92. (change)="updateScoreFilter($event)">
  93. <option value="all">全部评分</option>
  94. <option value="high">高分 (4-5分)</option>
  95. <option value="medium">中等 (2-4分)</option>
  96. <option value="low">低分 (1-2分)</option>
  97. </select>
  98. </div>
  99. </div>
  100. </div>
  101. <!-- 评价列表 -->
  102. <div class="reviews-list">
  103. @if (filteredFeedbacks() && filteredFeedbacks().length > 0) {
  104. <div class="list-body">
  105. @for (feedback of filteredFeedbacks(); track feedback.id) {
  106. <div class="review-item" [class]="getStatusClass(feedback)">
  107. <div class="review-header">
  108. <div class="customer-info">
  109. <span class="customer-name">{{ feedback.customerName || '客户' }}</span>
  110. <span class="category-tag">{{ getCategoryLabel(getFeedbackCategory(feedback)) }}</span>
  111. </div>
  112. <div class="review-meta">
  113. @if (feedback.rating !== undefined) {
  114. <div class="score-display" [class]="getScoreClass(feedback.rating)">
  115. <div class="score-stars">
  116. @for (star of getStarRating(feedback.rating); track $index) {
  117. <span class="star">{{ star }}</span>
  118. }
  119. </div>
  120. <span class="score-number">{{ feedback.rating }}/5</span>
  121. </div>
  122. }
  123. <span class="status-badge" [class]="getStatusClass(feedback)">
  124. {{ feedback.status }}
  125. </span>
  126. </div>
  127. </div>
  128. <div class="review-content">
  129. <p class="feedback-text">{{ feedback.content }}</p>
  130. @if (feedback.problemLocation) {
  131. <div class="problem-location">
  132. <strong>问题位置:</strong>{{ feedback.problemLocation }}
  133. </div>
  134. }
  135. @if (feedback.referenceCase) {
  136. <div class="reference-case">
  137. <strong>参考案例:</strong>{{ feedback.referenceCase }}
  138. </div>
  139. }
  140. </div>
  141. <div class="review-footer">
  142. <div class="time-info">
  143. <span class="created-time">{{ feedback.createdAt | date:'yyyy-MM-dd HH:mm' }}</span>
  144. @if (feedback.updatedAt && feedback.updatedAt !== feedback.createdAt) {
  145. <span class="updated-time">更新于 {{ feedback.updatedAt | date:'yyyy-MM-dd HH:mm' }}</span>
  146. }
  147. </div>
  148. <!-- 处理按钮区域 -->
  149. <div class="action-buttons">
  150. @if (feedback.status === '待处理') {
  151. <button
  152. class="action-btn process-btn"
  153. (click)="startProcessing(feedback.id)">
  154. 开始处理
  155. </button>
  156. <button
  157. class="action-btn reply-btn"
  158. (click)="openReplyModal(feedback)">
  159. 回复客户
  160. </button>
  161. } @else if (feedback.status === '处理中') {
  162. <button
  163. class="action-btn complete-btn"
  164. (click)="markAsResolved(feedback.id)">
  165. 标记完成
  166. </button>
  167. <button
  168. class="action-btn reply-btn"
  169. (click)="openReplyModal(feedback)">
  170. 回复客户
  171. </button>
  172. } @else {
  173. <button
  174. class="action-btn view-btn"
  175. (click)="viewDetails(feedback)">
  176. 查看详情
  177. </button>
  178. }
  179. </div>
  180. @if (feedback.response) {
  181. <div class="response-section">
  182. <strong>处理回复:</strong>
  183. <p class="response-text">{{ feedback.response }}</p>
  184. </div>
  185. }
  186. </div>
  187. </div>
  188. }
  189. </div>
  190. } @else {
  191. <div class="empty-state">
  192. <div class="empty-icon">💬</div>
  193. <div class="empty-title">暂无客户评价</div>
  194. <div class="empty-desc">当前筛选条件下没有找到相关的客户评价记录</div>
  195. </div>
  196. }
  197. </div>
  198. </div>