|
|
@@ -8,146 +8,56 @@
|
|
|
}
|
|
|
|
|
|
@if (!loading) {
|
|
|
- <!-- 审批历史记录展示 -->
|
|
|
+ <!-- 审批消息流(紧凑显示) -->
|
|
|
@if (project && approvalHistory.length > 0) {
|
|
|
- <div class="approval-history-card">
|
|
|
- <div class="card-header">
|
|
|
- <h3 class="card-title">
|
|
|
- <svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
|
|
|
- <path fill="currentColor" d="M336 64h32a48 48 0 0148 48v320a48 48 0 01-48 48H144a48 48 0 01-48-48V112a48 48 0 0148-48h32" opacity=".3"/>
|
|
|
- <path fill="currentColor" d="M336 64h-80a48 48 0 00-96 0h-80a48 48 0 00-48 48v320a48 48 0 0048 48h224a48 48 0 0048-48V112a48 48 0 00-48-48zM256 32a16 16 0 11-16 16 16 16 0 0116-16zm112 400H144V112h224z"/>
|
|
|
- <path fill="currentColor" d="M208 192h96v16h-96zm0 64h96v16h-96z"/>
|
|
|
- </svg>
|
|
|
- 审批流程记录
|
|
|
- </h3>
|
|
|
- <p class="card-subtitle">查看项目的完整审批历史</p>
|
|
|
+ <div class="approval-messages-container">
|
|
|
+ <div class="messages-header">
|
|
|
+ <svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="16" height="16">
|
|
|
+ <path fill="currentColor" d="M256 48C141.31 48 48 141.31 48 256s93.31 208 208 208 208-93.31 208-208S370.69 48 256 48zm-38 312.38L137.4 280.8a24 24 0 0133.94-33.94l50.2 50.2 95.74-95.74a24 24 0 0133.94 33.94z"/>
|
|
|
+ </svg>
|
|
|
+ <span>审批记录 ({{ approvalHistory.length }})</span>
|
|
|
</div>
|
|
|
- <div class="card-content">
|
|
|
- <div class="approval-timeline">
|
|
|
- @for (record of approvalHistory; track $index; let isFirst = $first; let isLast = $last) {
|
|
|
- <div class="timeline-item" [class.first]="isFirst" [class.last]="isLast">
|
|
|
- <!-- 时间线节点 -->
|
|
|
- <div class="timeline-node" [attr.data-status]="record.status">
|
|
|
+ <div class="approval-messages">
|
|
|
+ @for (record of approvalHistory; track $index) {
|
|
|
+ <div class="approval-message" [attr.data-status]="record.status">
|
|
|
+ <div class="message-icon">
|
|
|
+ @if (record.status === 'approved') {
|
|
|
+ <span class="icon-emoji">✅</span>
|
|
|
+ } @else if (record.status === 'rejected') {
|
|
|
+ <span class="icon-emoji">❌</span>
|
|
|
+ } @else {
|
|
|
+ <span class="icon-emoji">⏳</span>
|
|
|
+ }
|
|
|
+ </div>
|
|
|
+ <div class="message-content">
|
|
|
+ <div class="message-header">
|
|
|
+ <span class="message-stage">{{ record.stage }}</span>
|
|
|
+ <span class="message-time">{{ record.submitTime | date: 'MM-dd HH:mm' }}</span>
|
|
|
+ </div>
|
|
|
+ <div class="message-body">
|
|
|
+ <span class="message-user">{{ record.submitter?.name || '未知' }}</span>
|
|
|
@if (record.status === 'approved') {
|
|
|
- <svg class="icon status-icon" viewBox="0 0 512 512">
|
|
|
- <path fill="currentColor" d="M256 48C141.31 48 48 141.31 48 256s93.31 208 208 208 208-93.31 208-208S370.69 48 256 48zm-38 312.38L137.4 280.8a24 24 0 0133.94-33.94l50.2 50.2 95.74-95.74a24 24 0 0133.94 33.94z"/>
|
|
|
- </svg>
|
|
|
+ <span class="message-text">提交审批,已通过</span>
|
|
|
} @else if (record.status === 'rejected') {
|
|
|
- <svg class="icon status-icon" viewBox="0 0 512 512">
|
|
|
- <path fill="currentColor" d="M256 48C141.31 48 48 141.31 48 256s93.31 208 208 208 208-93.31 208-208S370.69 48 256 48zm52.697 283.697L256 279l-52.697 52.697-22.626-22.626L233.373 256l-52.696-52.697 22.626-22.626L256 233.373l52.697-52.696 22.626 22.626L278.627 256l52.696 52.697-22.626 22.626z"/>
|
|
|
- </svg>
|
|
|
+ <span class="message-text">提交审批,已驳回</span>
|
|
|
} @else {
|
|
|
- <svg class="icon status-icon" viewBox="0 0 512 512">
|
|
|
- <path fill="currentColor" d="M256 464c114.87 0 208-93.13 208-208S370.87 48 256 48 48 141.13 48 256s93.13 208 208 208zm0-384c97 0 176 79 176 176s-79 176-176 176S80 353 80 256 159 80 256 80z"/>
|
|
|
- <path fill="currentColor" d="M256 176a32 32 0 11-32 32 32 32 0 0132-32m0 160a32 32 0 11-32 32 32 32 0 0132-32"/>
|
|
|
- </svg>
|
|
|
+ <span class="message-text">提交审批,待处理</span>
|
|
|
+ }
|
|
|
+ @if (record.approver) {
|
|
|
+ <span class="message-approver">· 审批人: {{ record.approver.name }}</span>
|
|
|
}
|
|
|
</div>
|
|
|
-
|
|
|
- <!-- 时间线连接线 -->
|
|
|
- @if (!isLast) {
|
|
|
- <div class="timeline-connector"></div>
|
|
|
+ @if (record.comment) {
|
|
|
+ <div class="message-comment">{{ record.comment }}</div>
|
|
|
}
|
|
|
-
|
|
|
- <!-- 审批内容 -->
|
|
|
- <div class="timeline-content">
|
|
|
- <div class="approval-header">
|
|
|
- <div class="approval-stage-badge" [attr.data-status]="record.status">
|
|
|
- {{ record.stage }}
|
|
|
- </div>
|
|
|
- <div class="approval-status-badge" [attr.data-status]="record.status">
|
|
|
- @if (record.status === 'approved') {
|
|
|
- <span>✅ 已通过</span>
|
|
|
- } @else if (record.status === 'rejected') {
|
|
|
- <span>❌ 已驳回</span>
|
|
|
- } @else {
|
|
|
- <span>⏳ 待审批</span>
|
|
|
- }
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <div class="approval-details">
|
|
|
- <!-- 提交信息 -->
|
|
|
- <div class="approval-section">
|
|
|
- <div class="section-label">提交人</div>
|
|
|
- <div class="section-content">
|
|
|
- <div class="user-info">
|
|
|
- <span class="user-name">{{ record.submitter?.name || '未知' }}</span>
|
|
|
- <span class="user-role">{{ record.submitter?.role || '-' }}</span>
|
|
|
- </div>
|
|
|
- <div class="time-info">
|
|
|
- {{ record.submitTime | date: 'yyyy-MM-dd HH:mm' }}
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <!-- 审批人信息(如果已审批) -->
|
|
|
- @if (record.approver) {
|
|
|
- <div class="approval-section">
|
|
|
- <div class="section-label">审批人</div>
|
|
|
- <div class="section-content">
|
|
|
- <div class="user-info">
|
|
|
- <span class="user-name">{{ record.approver?.name || '未知' }}</span>
|
|
|
- <span class="user-role">{{ record.approver?.role || '-' }}</span>
|
|
|
- </div>
|
|
|
- <div class="time-info">
|
|
|
- {{ record.approvalTime | date: 'yyyy-MM-dd HH:mm' }}
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- }
|
|
|
-
|
|
|
- <!-- 报价信息 -->
|
|
|
- @if (record.quotationTotal) {
|
|
|
- <div class="approval-section">
|
|
|
- <div class="section-label">报价总额</div>
|
|
|
- <div class="section-content">
|
|
|
- <span class="quotation-amount">¥{{ record.quotationTotal | number: '1.2-2' }}</span>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- }
|
|
|
-
|
|
|
- <!-- 团队信息 -->
|
|
|
- @if (record.teams && record.teams.length > 0) {
|
|
|
- <div class="approval-section">
|
|
|
- <div class="section-label">分配团队 ({{ record.teams.length }}人)</div>
|
|
|
- <div class="section-content">
|
|
|
- <div class="team-members">
|
|
|
- @for (member of record.teams; track member.id) {
|
|
|
- <div class="team-member-chip">
|
|
|
- <span class="member-name">{{ member.name }}</span>
|
|
|
- @if (member.spaces && member.spaces.length > 0) {
|
|
|
- <span class="member-spaces">{{ member.spaces.join(', ') }}</span>
|
|
|
- }
|
|
|
- </div>
|
|
|
- }
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- }
|
|
|
-
|
|
|
- <!-- 审批意见/驳回原因 -->
|
|
|
- @if (record.comment || record.reason) {
|
|
|
- <div class="approval-section">
|
|
|
- <div class="section-label">
|
|
|
- {{ record.status === 'rejected' ? '驳回原因' : '审批意见' }}
|
|
|
- </div>
|
|
|
- <div class="section-content">
|
|
|
- <div class="approval-comment">
|
|
|
- {{ record.comment || record.reason || '-' }}
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- }
|
|
|
- </div>
|
|
|
- </div>
|
|
|
</div>
|
|
|
- }
|
|
|
- </div>
|
|
|
+ </div>
|
|
|
+ }
|
|
|
</div>
|
|
|
</div>
|
|
|
}
|
|
|
|
|
|
+
|
|
|
<!-- 场景Product选择标签 (第一层) -->
|
|
|
@if (isMultiProductProject) {
|
|
|
<div class="product-tabs-section">
|
|
|
@@ -331,42 +241,27 @@
|
|
|
<div class="file-uploader">上传: {{ file.uploadedBy }}</div>
|
|
|
}
|
|
|
|
|
|
- <!-- ✨ 审批状态显示(参考售后归档红框样式) -->
|
|
|
- <div class="file-approval-status" [ngClass]="'has-' + file.approvalStatus">
|
|
|
- <div class="status-row">
|
|
|
- <span class="status-badge" [ngClass]="getApprovalStatusClass(file.approvalStatus)">
|
|
|
- {{ getApprovalStatusText(file.approvalStatus) }}
|
|
|
+ <!-- ✨ 审批状态显示(紧凑单行样式) -->
|
|
|
+ @if (file.approvalStatus && file.approvalStatus !== 'unverified') {
|
|
|
+ <div class="file-approval-status" [ngClass]="'status-' + file.approvalStatus">
|
|
|
+ <span class="status-icon">
|
|
|
+ @if (file.approvalStatus === 'approved') {
|
|
|
+ ✅
|
|
|
+ } @else if (file.approvalStatus === 'rejected') {
|
|
|
+ ❌
|
|
|
+ } @else if (file.approvalStatus === 'pending') {
|
|
|
+ 🔍
|
|
|
+ }
|
|
|
</span>
|
|
|
+ <span class="status-text">{{ getApprovalStatusText(file.approvalStatus) }}</span>
|
|
|
+ @if (file.approvedBy) {
|
|
|
+ <span class="status-by">· {{ file.approvedBy }}</span>
|
|
|
+ }
|
|
|
+ @if (file.rejectionReason) {
|
|
|
+ <span class="status-reason">: {{ file.rejectionReason }}</span>
|
|
|
+ }
|
|
|
</div>
|
|
|
-
|
|
|
- @if (file.approvalStatus === 'approved') {
|
|
|
- <div class="approval-details">
|
|
|
- @if (file.approvedBy) {
|
|
|
- <div class="approval-info">
|
|
|
- <svg class="icon-small" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
|
|
|
- <path fill="currentColor" d="M258.9 48C141.92 46.42 46.42 141.92 48 258.9c1.56 112.19 92.91 203.54 205.1 205.1 117 1.6 212.48-93.9 210.88-210.88C462.44 140.91 371.09 49.56 258.9 48zm-16.79 192.47l51.55 51.55a12 12 0 010 17l-5.66 5.66a12 12 0 01-17 0l-51.55-51.55-51.55 51.55a12 12 0 01-17 0l-5.66-5.66a12 12 0 010-17l51.55-51.55-51.55-51.55a12 12 0 010-17l5.66-5.66a12 12 0 0117 0l51.55 51.55 51.55-51.55a12 12 0 0117 0l5.66 5.66a12 12 0 010 17z"/>
|
|
|
- </svg>
|
|
|
- <span>审批: {{ file.approvedBy }}</span>
|
|
|
- </div>
|
|
|
- }
|
|
|
- @if (file.approvedAt) {
|
|
|
- <div class="approval-time">{{ file.approvedAt | date: 'yyyy-MM-dd HH:mm' }}</div>
|
|
|
- }
|
|
|
- </div>
|
|
|
- }
|
|
|
-
|
|
|
- @if (file.approvalStatus === 'rejected' && file.rejectionReason) {
|
|
|
- <div class="rejection-reason">
|
|
|
- <div class="rejection-header">
|
|
|
- <svg class="icon-small" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
|
|
|
- <path fill="currentColor" d="M85.57 446.25h340.86a32 32 0 0028.17-47.17L284.18 82.58c-12.09-22.44-44.27-22.44-56.36 0L57.4 399.08a32 32 0 0028.17 47.17z"/>
|
|
|
- </svg>
|
|
|
- <span class="label">驳回原因</span>
|
|
|
- </div>
|
|
|
- <p class="reason">{{ file.rejectionReason }}</p>
|
|
|
- </div>
|
|
|
- }
|
|
|
- </div>
|
|
|
+ }
|
|
|
</div>
|
|
|
</div>
|
|
|
}
|