|
@@ -22,7 +22,7 @@
|
|
|
(ngModelChange)="selectedReportType.set($event)"
|
|
|
class="form-select"
|
|
|
>
|
|
|
- <option *ngFor="let type of reportTypes || []" [value]="type.value">
|
|
|
+ <option *ngFor="let type of reportTypes" [value]="type.value">
|
|
|
{{ type.label }}
|
|
|
</option>
|
|
|
</select>
|
|
@@ -36,7 +36,7 @@
|
|
|
(ngModelChange)="selectedTimePeriod.set($event)"
|
|
|
class="form-select"
|
|
|
>
|
|
|
- <option *ngFor="let period of timePeriods || []" [value]="period.value">
|
|
|
+ <option *ngFor="let period of timePeriods" [value]="period.value">
|
|
|
{{ period.label }}
|
|
|
</option>
|
|
|
</select>
|
|
@@ -72,7 +72,7 @@
|
|
|
(ngModelChange)="selectedChartType.set($event)"
|
|
|
class="form-select"
|
|
|
>
|
|
|
- <option *ngFor="let chart of chartTypes || []" [value]="chart.value">
|
|
|
+ <option *ngFor="let chart of chartTypes" [value]="chart.value">
|
|
|
{{ chart.label }}
|
|
|
</option>
|
|
|
</select>
|
|
@@ -106,134 +106,155 @@
|
|
|
</div>
|
|
|
|
|
|
<!-- 报表结果展示区域 -->
|
|
|
- <div class="reports-result" *ngIf="reportData()">
|
|
|
+ <div class="reports-result" *ngIf="filteredReportData">
|
|
|
<div class="result-header">
|
|
|
- <h2>{{ reportData()?.title }}</h2>
|
|
|
+ <h2>{{ filteredReportData.title }}</h2>
|
|
|
<div class="result-meta">
|
|
|
- <span>报表ID: {{ reportData()?.id }}</span>
|
|
|
- <span>生成时间: {{ formatDate(reportData()?.generatedAt) }}</span>
|
|
|
- <span>时间范围: {{ formatDate(reportData()?.dateRange?.start) }} - {{ formatDate(reportData()?.dateRange?.end) }}</span>
|
|
|
+ <span>报表ID: {{ filteredReportData.id }}</span>
|
|
|
+ <span>生成时间: {{ formatDate(filteredReportData.generatedAt) }}</span>
|
|
|
+ <span>时间范围: {{ formatDate(filteredReportData.dateRange.start) }} - {{ formatDate(filteredReportData.dateRange.end) }}</span>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
<!-- 报表汇总信息 -->
|
|
|
- <div class="summary-cards">
|
|
|
- <div class="summary-card" *ngIf="reportData()?.summary?.['totalRevenue'] !== undefined">
|
|
|
- <div class="summary-icon">💰</div>
|
|
|
- <div class="summary-content">
|
|
|
- <div class="summary-label">总收入</div>
|
|
|
- <div class="summary-value">{{ formatAmount(reportData()?.summary?.['totalRevenue'] || 0) }}</div>
|
|
|
+ <div class="summary-cards">
|
|
|
+ <div class="summary-card" *ngIf="filteredReportData.summary && filteredReportData.summary['totalRevenue'] !== undefined && userRole() === 'teamLead'">
|
|
|
+ <div class="summary-icon">💰</div>
|
|
|
+ <div class="summary-content">
|
|
|
+ <div class="summary-label">总收入</div>
|
|
|
+ <div class="summary-value">{{ formatAmount(filteredReportData.summary['totalRevenue'] || 0) }}</div>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <div class="summary-card" *ngIf="reportData()?.summary?.['totalExpense'] !== undefined">
|
|
|
- <div class="summary-icon">📉</div>
|
|
|
- <div class="summary-content">
|
|
|
- <div class="summary-label">总支出</div>
|
|
|
- <div class="summary-value">{{ formatAmount(reportData()?.summary?.['totalExpense'] || 0) }}</div>
|
|
|
+
|
|
|
+ <div class="summary-card" *ngIf="filteredReportData.summary && filteredReportData.summary['totalExpense'] !== undefined && userRole() === 'teamLead'">
|
|
|
+ <div class="summary-icon">📉</div>
|
|
|
+ <div class="summary-content">
|
|
|
+ <div class="summary-label">总支出</div>
|
|
|
+ <div class="summary-value">{{ formatAmount(filteredReportData.summary['totalExpense'] || 0) }}</div>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <div class="summary-card" *ngIf="reportData()?.summary?.['netProfit'] !== undefined">
|
|
|
- <div class="summary-icon">📊</div>
|
|
|
- <div class="summary-content">
|
|
|
- <div class="summary-label">净利润</div>
|
|
|
- <div class="summary-value profit">{{ formatAmount(reportData()?.summary?.['netProfit'] || 0) }}</div>
|
|
|
+
|
|
|
+ <div class="summary-card" *ngIf="filteredReportData.summary && filteredReportData.summary['netProfit'] !== undefined && userRole() === 'teamLead'">
|
|
|
+ <div class="summary-icon">📊</div>
|
|
|
+ <div class="summary-content">
|
|
|
+ <div class="summary-label">净利润</div>
|
|
|
+ <div class="summary-value profit">{{ formatAmount(filteredReportData.summary['netProfit'] || 0) }}</div>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <div class="summary-card" *ngIf="reportData()?.summary?.['profitMargin'] !== undefined">
|
|
|
- <div class="summary-icon">📈</div>
|
|
|
- <div class="summary-content">
|
|
|
- <div class="summary-label">利润率</div>
|
|
|
- <div class="summary-value">{{ formatPercentage(reportData()?.summary?.['profitMargin'] || 0) }}</div>
|
|
|
+
|
|
|
+ <div class="summary-card" *ngIf="filteredReportData.summary && filteredReportData.summary['profitMargin'] !== undefined && userRole() === 'teamLead'">
|
|
|
+ <div class="summary-icon">📈</div>
|
|
|
+ <div class="summary-content">
|
|
|
+ <div class="summary-label">利润率</div>
|
|
|
+ <div class="summary-value">{{ formatPercentage(filteredReportData.summary['profitMargin'] || 0) }}</div>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <div class="summary-card" *ngIf="reportData()?.summary?.['totalProjects'] !== undefined">
|
|
|
- <div class="summary-icon">📋</div>
|
|
|
- <div class="summary-content">
|
|
|
- <div class="summary-label">项目总数</div>
|
|
|
- <div class="summary-value">{{ reportData()?.summary?.['totalProjects'] || 0 }}</div>
|
|
|
+
|
|
|
+ <div class="summary-card" *ngIf="filteredReportData.summary && filteredReportData.summary['totalProjects'] !== undefined">
|
|
|
+ <div class="summary-icon">📋</div>
|
|
|
+ <div class="summary-content">
|
|
|
+ <div class="summary-label">项目总数</div>
|
|
|
+ <div class="summary-value">{{ filteredReportData.summary['totalProjects'] || 0 }}</div>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <div class="summary-card" *ngIf="reportData()?.summary?.['averageProfitMargin'] !== undefined">
|
|
|
- <div class="summary-icon">💰</div>
|
|
|
- <div class="summary-content">
|
|
|
- <div class="summary-label">平均利润率</div>
|
|
|
- <div class="summary-value">{{ formatPercentage(reportData()?.summary?.['averageProfitMargin'] || 0) }}</div>
|
|
|
+
|
|
|
+ <div class="summary-card" *ngIf="filteredReportData.summary && filteredReportData.summary['averageProfitMargin'] !== undefined && userRole() === 'teamLead'">
|
|
|
+ <div class="summary-icon">💰</div>
|
|
|
+ <div class="summary-content">
|
|
|
+ <div class="summary-label">平均利润率</div>
|
|
|
+ <div class="summary-value">{{ formatPercentage(filteredReportData.summary['averageProfitMargin'] || 0) }}</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="summary-card" *ngIf="filteredReportData.summary && filteredReportData.summary['profitableProjects'] !== undefined">
|
|
|
+ <div class="summary-icon">✅</div>
|
|
|
+ <div class="summary-content">
|
|
|
+ <div class="summary-label">盈利项目数</div>
|
|
|
+ <div class="summary-value">{{ filteredReportData.summary['profitableProjects'] || 0 }}</div>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
</div>
|
|
|
- </div>
|
|
|
|
|
|
<!-- 报表图表展示 -->
|
|
|
<div class="chart-container">
|
|
|
<div class="chart-header">
|
|
|
<h3>数据可视化</h3>
|
|
|
- <div class="chart-legend">
|
|
|
- <div class="legend-item" *ngFor="let data of reportData()?.chartData || []">
|
|
|
+ <div class="chart-legend" *ngIf="filteredReportData.chartData">
|
|
|
+ <div class="legend-item" *ngFor="let data of filteredReportData.chartData">
|
|
|
<span class="legend-color" [style.backgroundColor]="data.color"></span>
|
|
|
- <span class="legend-label">{{ data.label }}: {{ formatAmount(data.value) }}</span>
|
|
|
+ <span class="legend-label">
|
|
|
+ {{ data.label }}:
|
|
|
+ <span *ngIf="userRole() === 'teamLead' || data.value === 0; else hiddenValue">
|
|
|
+ {{ data.value > 0 ? formatAmount(data.value) : '--' }}
|
|
|
+ </span>
|
|
|
+ <ng-template #hiddenValue>
|
|
|
+ <span class="hidden-amount">--</span>
|
|
|
+ </ng-template>
|
|
|
+ </span>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
<!-- 柱状图展示 -->
|
|
|
- <div class="chart-content" *ngIf="reportData()?.chartType === 'bar'">
|
|
|
+ <div class="chart-content" *ngIf="filteredReportData.chartType === 'bar' && filteredReportData.chartData">
|
|
|
<div class="bar-chart">
|
|
|
<div
|
|
|
- *ngFor="let data of reportData()?.chartData || []"
|
|
|
+ *ngFor="let data of filteredReportData.chartData"
|
|
|
class="bar-item"
|
|
|
- [style.width.%]="(data.value / maxValue(reportData()?.chartData || []) * 100)"
|
|
|
+ [style.width.%]="(data.value / maxValue(filteredReportData.chartData) * 100)"
|
|
|
[style.backgroundColor]="data.color"
|
|
|
- title="{{ data.label }}: {{ formatAmount(data.value) }}"
|
|
|
+ title="{{ data.label }}: {{ userRole() === 'teamLead' && data.value > 0 ? formatAmount(data.value) : '--' }}"
|
|
|
>
|
|
|
<div class="bar-label">{{ data.label }}</div>
|
|
|
- <div class="bar-value">{{ formatAmount(data.value) }}</div>
|
|
|
+ <div class="bar-value" *ngIf="userRole() === 'teamLead' || data.value === 0; else hiddenBarValue">
|
|
|
+ {{ data.value > 0 ? formatAmount(data.value) : '--' }}
|
|
|
+ </div>
|
|
|
+ <ng-template #hiddenBarValue>
|
|
|
+ <div class="bar-value hidden-amount">--</div>
|
|
|
+ </ng-template>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
<!-- 饼图展示 -->
|
|
|
- <div class="chart-content" *ngIf="reportData()?.chartType === 'pie'">
|
|
|
+ <div class="chart-content" *ngIf="filteredReportData.chartType === 'pie' && filteredReportData.chartData">
|
|
|
<div class="pie-chart">
|
|
|
<!-- 简化的饼图实现 -->
|
|
|
<div class="pie-container">
|
|
|
<div
|
|
|
- *ngFor="let data of reportData()?.chartData || []; let i = index"
|
|
|
+ *ngFor="let data of filteredReportData.chartData; let i = index"
|
|
|
class="pie-slice"
|
|
|
[style.backgroundColor]="data.color"
|
|
|
- [style.transform]="getPieTransform(i, reportData()?.chartData || [])"
|
|
|
+ [style.transform]="getPieTransform(i, filteredReportData.chartData)"
|
|
|
></div>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
<!-- 表格展示 -->
|
|
|
- <div class="chart-content table-container" *ngIf="reportData()?.chartType === 'table'">
|
|
|
+ <div class="chart-content table-container" *ngIf="filteredReportData.chartType === 'table' && filteredReportData.chartData">
|
|
|
<table class="data-table">
|
|
|
<thead>
|
|
|
<tr>
|
|
|
<th>项目</th>
|
|
|
- <th>金额</th>
|
|
|
- <th>占比</th>
|
|
|
+ <th *ngIf="userRole() === 'teamLead'">金额</th>
|
|
|
+ <th *ngIf="userRole() === 'teamLead'">占比</th>
|
|
|
</tr>
|
|
|
</thead>
|
|
|
<tbody>
|
|
|
- <tr *ngFor="let data of reportData()?.chartData || []">
|
|
|
+ <tr *ngFor="let data of filteredReportData.chartData">
|
|
|
<td>
|
|
|
<div class="table-label">
|
|
|
<span class="label-color" [style.backgroundColor]="data.color"></span>
|
|
|
{{ data.label }}
|
|
|
</div>
|
|
|
</td>
|
|
|
- <td>{{ formatAmount(data.value) }}</td>
|
|
|
- <td>{{ formatPercentage((data.value / totalValue(reportData()?.chartData || [])) * 100) }}</td>
|
|
|
+ <td *ngIf="userRole() === 'teamLead'">{{ formatAmount(data.value) }}</td>
|
|
|
+ <td *ngIf="userRole() === 'teamLead'">{{ formatPercentage((data.value / totalValue(filteredReportData.chartData)) * 100) }}</td>
|
|
|
</tr>
|
|
|
- <tr class="table-total">
|
|
|
+ <tr class="table-total" *ngIf="userRole() === 'teamLead'">
|
|
|
<td>总计</td>
|
|
|
- <td>{{ formatAmount(totalValue(reportData()?.chartData || [])) }}</td>
|
|
|
+ <td>{{ formatAmount(totalValue(filteredReportData.chartData)) }}</td>
|
|
|
<td>100%</td>
|
|
|
</tr>
|
|
|
</tbody>
|
|
@@ -251,7 +272,7 @@
|
|
|
|
|
|
<div class="history-list">
|
|
|
<div
|
|
|
- *ngFor="let report of historicalReports() || []"
|
|
|
+ *ngFor="let report of historicalReports()"
|
|
|
class="history-item"
|
|
|
(click)="viewHistoricalReport(report)"
|
|
|
>
|
|
@@ -271,4 +292,12 @@
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
+
|
|
|
+ <!-- 角色权限提示 -->
|
|
|
+ <div *ngIf="userRole() === 'juniorMember'" class="permission-tip">
|
|
|
+ <div class="tip-icon">🔒</div>
|
|
|
+ <div class="tip-content">
|
|
|
+ <p>您当前以初级组员身份查看报表,部分敏感数据已隐藏。如需查看完整数据,请联系管理员提升权限。</p>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
</div>
|