add-comparison-dialog.component.ts 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. import { Component, Inject } from '@angular/core';
  2. import { CommonModule } from '@angular/common';
  3. import { FormsModule } from '@angular/forms';
  4. import { MatDialogRef, MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog';
  5. import { MatButtonModule } from '@angular/material/button';
  6. import { MatFormFieldModule } from '@angular/material/form-field';
  7. import { MatSelectModule } from '@angular/material/select';
  8. import { MatInputModule } from '@angular/material/input';
  9. import { MatIconModule } from '@angular/material/icon';
  10. import { MatChipsModule } from '@angular/material/chips';
  11. export interface ComparisonItemData {
  12. name: string;
  13. category: string;
  14. icon: string;
  15. iconClass: string;
  16. metrics: { [key: string]: string };
  17. }
  18. export interface DialogData {
  19. dimension: string;
  20. availableMetrics: string[];
  21. }
  22. @Component({
  23. selector: 'app-add-comparison-dialog',
  24. standalone: true,
  25. imports: [
  26. CommonModule,
  27. FormsModule,
  28. MatDialogModule,
  29. MatButtonModule,
  30. MatFormFieldModule,
  31. MatSelectModule,
  32. MatInputModule,
  33. MatIconModule,
  34. MatChipsModule
  35. ],
  36. template: `
  37. <h2 mat-dialog-title>
  38. <mat-icon>add_circle</mat-icon>
  39. 添加对比项
  40. </h2>
  41. <mat-dialog-content>
  42. <div class="form-section">
  43. <mat-form-field appearance="outline" class="full-width">
  44. <mat-label>项目名称</mat-label>
  45. <input matInput [(ngModel)]="itemData.name" placeholder="请输入项目名称">
  46. <mat-icon matSuffix>edit</mat-icon>
  47. </mat-form-field>
  48. </div>
  49. <div class="form-section">
  50. <mat-form-field appearance="outline" class="full-width">
  51. <mat-label>项目类别</mat-label>
  52. <mat-select [(value)]="itemData.category">
  53. <mat-option value="研发部门">研发部门</mat-option>
  54. <mat-option value="创意部门">创意部门</mat-option>
  55. <mat-option value="策略部门">策略部门</mat-option>
  56. <mat-option value="执行部门">执行部门</mat-option>
  57. <mat-option value="支持部门">支持部门</mat-option>
  58. <mat-option value="管理部门">管理部门</mat-option>
  59. </mat-select>
  60. </mat-form-field>
  61. </div>
  62. <div class="form-section">
  63. <mat-form-field appearance="outline" class="full-width">
  64. <mat-label>图标</mat-label>
  65. <mat-select [(value)]="itemData.icon" (selectionChange)="updateIconClass()">
  66. <mat-option value="code">
  67. <mat-icon>code</mat-icon>
  68. 代码 (技术)
  69. </mat-option>
  70. <mat-option value="palette">
  71. <mat-icon>palette</mat-icon>
  72. 调色板 (设计)
  73. </mat-option>
  74. <mat-option value="lightbulb">
  75. <mat-icon>lightbulb</mat-icon>
  76. 灯泡 (创意)
  77. </mat-option>
  78. <mat-option value="trending_up">
  79. <mat-icon>trending_up</mat-icon>
  80. 趋势 (运营)
  81. </mat-option>
  82. <mat-option value="groups">
  83. <mat-icon>groups</mat-icon>
  84. 团队 (人事)
  85. </mat-option>
  86. <mat-option value="analytics">
  87. <mat-icon>analytics</mat-icon>
  88. 分析 (数据)
  89. </mat-option>
  90. <mat-option value="campaign">
  91. <mat-icon>campaign</mat-icon>
  92. 营销 (市场)
  93. </mat-option>
  94. <mat-option value="support">
  95. <mat-icon>support</mat-icon>
  96. 支持 (客服)
  97. </mat-option>
  98. </mat-select>
  99. </mat-form-field>
  100. </div>
  101. <h3>绩效指标设置</h3>
  102. <div class="metrics-grid">
  103. @for (metric of data.availableMetrics; track metric) {
  104. <mat-form-field appearance="outline">
  105. <mat-label>{{ getMetricDisplayName(metric) }}</mat-label>
  106. <input
  107. matInput
  108. [(ngModel)]="itemData.metrics[metric]"
  109. placeholder="0-100%"
  110. pattern="[0-9]+%?"
  111. (blur)="formatMetricValue(metric)">
  112. <span matSuffix>%</span>
  113. </mat-form-field>
  114. }
  115. </div>
  116. <div class="preview-section">
  117. <h3>预览</h3>
  118. <div class="item-preview">
  119. <div class="preview-header">
  120. <mat-icon [class]="itemData.iconClass">{{ itemData.icon }}</mat-icon>
  121. <div class="preview-info">
  122. <h4>{{ itemData.name || '新项目' }}</h4>
  123. <span class="preview-category">{{ itemData.category || '未分类' }}</span>
  124. </div>
  125. </div>
  126. <div class="preview-metrics">
  127. @for (metric of data.availableMetrics; track metric) {
  128. <div class="metric-preview">
  129. <span class="metric-name">{{ getMetricDisplayName(metric) }}</span>
  130. <span class="metric-value">{{ itemData.metrics[metric] || '0%' }}</span>
  131. </div>
  132. }
  133. </div>
  134. </div>
  135. </div>
  136. </mat-dialog-content>
  137. <mat-dialog-actions align="end">
  138. <button mat-button (click)="onCancel()">取消</button>
  139. <button mat-raised-button color="primary" (click)="onConfirm()" [disabled]="!isValid()">
  140. <mat-icon>add</mat-icon>
  141. 添加
  142. </button>
  143. </mat-dialog-actions>
  144. `,
  145. styleUrls: ['../../../shared/styles/_hr-dialog.scss']
  146. })
  147. export class AddComparisonDialogComponent {
  148. itemData: ComparisonItemData = {
  149. name: '',
  150. category: '',
  151. icon: 'add_circle',
  152. iconClass: 'new-icon',
  153. metrics: {}
  154. };
  155. constructor(
  156. public dialogRef: MatDialogRef<AddComparisonDialogComponent>,
  157. @Inject(MAT_DIALOG_DATA) public data: DialogData
  158. ) {
  159. // 初始化指标数据
  160. this.data.availableMetrics.forEach(metric => {
  161. this.itemData.metrics[metric] = '0%';
  162. });
  163. }
  164. getMetricDisplayName(metric: string): string {
  165. const metricNames: { [key: string]: string } = {
  166. 'completion': '完成率',
  167. 'quality': '质量评分',
  168. 'efficiency': '效率指数',
  169. 'satisfaction': '满意度',
  170. 'innovation': '创新度'
  171. };
  172. return metricNames[metric] || metric;
  173. }
  174. updateIconClass(): void {
  175. const iconClassMap: { [key: string]: string } = {
  176. 'code': 'tech-icon',
  177. 'palette': 'design-icon',
  178. 'lightbulb': 'product-icon',
  179. 'trending_up': 'operation-icon',
  180. 'groups': 'hr-icon',
  181. 'analytics': 'data-icon',
  182. 'campaign': 'marketing-icon',
  183. 'support': 'support-icon'
  184. };
  185. this.itemData.iconClass = iconClassMap[this.itemData.icon] || 'new-icon';
  186. }
  187. formatMetricValue(metric: string): void {
  188. let value = this.itemData.metrics[metric];
  189. if (value && !value.endsWith('%')) {
  190. // 移除非数字字符,只保留数字
  191. const numericValue = value.replace(/[^\d]/g, '');
  192. if (numericValue) {
  193. // 确保值在0-100范围内
  194. const num = Math.min(100, Math.max(0, parseInt(numericValue)));
  195. this.itemData.metrics[metric] = num + '%';
  196. } else {
  197. this.itemData.metrics[metric] = '0%';
  198. }
  199. }
  200. }
  201. isValid(): boolean {
  202. return !!(this.itemData.name && this.itemData.category && this.itemData.icon);
  203. }
  204. onCancel(): void {
  205. this.dialogRef.close();
  206. }
  207. onConfirm(): void {
  208. if (this.isValid()) {
  209. this.dialogRef.close(this.itemData);
  210. }
  211. }
  212. }