|
@@ -8,53 +8,179 @@ import { FormsModule } from '@angular/forms';
|
|
|
standalone: true,
|
|
|
imports: [CommonModule, RouterModule, FormsModule],
|
|
|
template: `
|
|
|
- <div class="ios-container">
|
|
|
- <header class="ios-header">
|
|
|
- <button class="ios-back-btn" (click)="goBack()">
|
|
|
- <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor">
|
|
|
- <path d="M19 12H5M12 19l-7-7 7-7"/>
|
|
|
- </svg>
|
|
|
- </button>
|
|
|
- <h1>客户咨询记录</h1>
|
|
|
+ <div class="consultation-container">
|
|
|
+ <!-- 页面头部 -->
|
|
|
+ <header class="page-header">
|
|
|
+ <div class="header-left">
|
|
|
+ <button class="back-btn" (click)="goBack()">
|
|
|
+ <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
|
+ <path d="M19 12H5M12 19l-7-7 7-7"/>
|
|
|
+ </svg>
|
|
|
+ </button>
|
|
|
+ <div class="header-title">
|
|
|
+ <h1>客户咨询记录</h1>
|
|
|
+ <p class="subtitle">共 {{ filteredConsultations.length }} 条咨询记录</p>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="header-actions">
|
|
|
+ <button class="refresh-btn" (click)="refreshData()" [disabled]="isLoading">
|
|
|
+ <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" [class.spinning]="isLoading">
|
|
|
+ <polyline points="23 4 23 10 17 10"></polyline>
|
|
|
+ <polyline points="1 20 1 14 7 14"></polyline>
|
|
|
+ <path d="m20.49 9A9 9 0 0 0 5.64 5.64L1 10m22 4l-4.64 4.36A9 9 0 0 1 3.51 15"></path>
|
|
|
+ </svg>
|
|
|
+ 刷新
|
|
|
+ </button>
|
|
|
+ </div>
|
|
|
</header>
|
|
|
|
|
|
- <div class="ios-content">
|
|
|
- <div class="toolbar">
|
|
|
- <div class="search-bar">
|
|
|
- <input type="text" placeholder="搜索咨询记录..." [(ngModel)]="keyword" (input)="applyFilters()">
|
|
|
- <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor">
|
|
|
- <circle cx="11" cy="11" r="8"/>
|
|
|
- <line x1="21" y1="21" x2="16.65" y2="16.65"/>
|
|
|
+ <!-- 搜索和筛选区域 -->
|
|
|
+ <div class="search-filter-section">
|
|
|
+ <div class="search-container">
|
|
|
+ <div class="search-input-wrapper">
|
|
|
+ <svg class="search-icon" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
|
+ <circle cx="11" cy="11" r="8"></circle>
|
|
|
+ <path d="m21 21-4.35-4.35"></path>
|
|
|
</svg>
|
|
|
+ <input
|
|
|
+ type="text"
|
|
|
+ placeholder="搜索客户姓名、咨询内容..."
|
|
|
+ [(ngModel)]="keyword"
|
|
|
+ (input)="applyFilters()"
|
|
|
+ class="search-input"
|
|
|
+ >
|
|
|
+ <button *ngIf="keyword" class="clear-search" (click)="clearSearch()">
|
|
|
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
|
+ <line x1="18" y1="6" x2="6" y2="18"></line>
|
|
|
+ <line x1="6" y1="6" x2="18" y2="18"></line>
|
|
|
+ </svg>
|
|
|
+ </button>
|
|
|
</div>
|
|
|
- <div class="quick-filters">
|
|
|
- <label>
|
|
|
- <input type="checkbox" [(ngModel)]="filterUnrepliedOver1h" (change)="applyFilters()"> 未回复超1小时
|
|
|
- </label>
|
|
|
- <label>
|
|
|
- <input type="checkbox" [(ngModel)]="filterSensitive" (change)="applyFilters()"> 含敏感词
|
|
|
- </label>
|
|
|
- </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="filter-chips">
|
|
|
+ <button
|
|
|
+ class="filter-chip"
|
|
|
+ [class.active]="filterUnrepliedOver1h"
|
|
|
+ (click)="toggleFilter('unreplied')"
|
|
|
+ >
|
|
|
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
|
+ <circle cx="12" cy="12" r="10"></circle>
|
|
|
+ <polyline points="12 6 12 12 16 14"></polyline>
|
|
|
+ </svg>
|
|
|
+ 未回复超1小时
|
|
|
+ <span *ngIf="filterUnrepliedOver1h" class="chip-count">{{ getUnrepliedCount() }}</span>
|
|
|
+ </button>
|
|
|
+ <button
|
|
|
+ class="filter-chip"
|
|
|
+ [class.active]="filterSensitive"
|
|
|
+ (click)="toggleFilter('sensitive')"
|
|
|
+ >
|
|
|
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
|
+ <path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"></path>
|
|
|
+ </svg>
|
|
|
+ 含敏感词
|
|
|
+ <span *ngIf="filterSensitive" class="chip-count">{{ getSensitiveCount() }}</span>
|
|
|
+ </button>
|
|
|
+ <button
|
|
|
+ class="filter-chip"
|
|
|
+ [class.active]="filterHighPriority"
|
|
|
+ (click)="toggleFilter('priority')"
|
|
|
+ >
|
|
|
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
|
+ <path d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126zM12 15.75h.007v.008H12v-.008z"></path>
|
|
|
+ </svg>
|
|
|
+ 紧急咨询
|
|
|
+ <span *ngIf="filterHighPriority" class="chip-count">{{ getHighPriorityCount() }}</span>
|
|
|
+ </button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 咨询列表 -->
|
|
|
+ <div class="consultation-content">
|
|
|
+ <div *ngIf="isLoading" class="loading-state">
|
|
|
+ <div class="loading-spinner"></div>
|
|
|
+ <p>加载中...</p>
|
|
|
</div>
|
|
|
|
|
|
- <div class="consultation-list">
|
|
|
- <div class="consultation-card" *ngFor="let item of filteredConsultations">
|
|
|
- <div class="card-header">
|
|
|
- <div class="customer-info">
|
|
|
- <div class="avatar">{{item.customer.charAt(0)}}</div>
|
|
|
- <div>
|
|
|
- <h3>{{item.customer}}</h3>
|
|
|
- <p class="time">{{item.time}}</p>
|
|
|
+ <div *ngIf="!isLoading && filteredConsultations.length === 0" class="empty-state">
|
|
|
+ <svg width="64" height="64" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1">
|
|
|
+ <circle cx="11" cy="11" r="8"></circle>
|
|
|
+ <path d="m21 21-4.35-4.35"></path>
|
|
|
+ </svg>
|
|
|
+ <h3>暂无咨询记录</h3>
|
|
|
+ <p>{{ keyword ? '没有找到匹配的咨询记录' : '还没有客户咨询记录' }}</p>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div *ngIf="!isLoading && filteredConsultations.length > 0" class="consultation-list">
|
|
|
+ <div
|
|
|
+ class="consultation-item"
|
|
|
+ *ngFor="let item of filteredConsultations; trackBy: trackByConsultation"
|
|
|
+ [class.urgent]="item.priority === 'high'"
|
|
|
+ [class.sensitive]="containsSensitiveWords(item.content)"
|
|
|
+ [class.overdue]="isOverdue(item)"
|
|
|
+ >
|
|
|
+ <div class="item-header">
|
|
|
+ <div class="customer-section">
|
|
|
+ <div class="customer-avatar" [style.background-color]="getAvatarColor(item.customer)">
|
|
|
+ {{ item.customer.charAt(0) }}
|
|
|
+ </div>
|
|
|
+ <div class="customer-details">
|
|
|
+ <h3 class="customer-name">{{ item.customer }}</h3>
|
|
|
+ <div class="customer-meta">
|
|
|
+ <span class="consultation-time">{{ formatTime(item.time) }}</span>
|
|
|
+ <span class="separator">•</span>
|
|
|
+ <span class="reply-status" [class.overdue]="isOverdue(item)">
|
|
|
+ {{ getReplyStatus(item) }}
|
|
|
+ </span>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
</div>
|
|
|
- <span class="status-badge" [class.urgent]="item.priority === 'high'">
|
|
|
- {{item.priority === 'high' ? '紧急' : '普通'}}
|
|
|
- </span>
|
|
|
+ <div class="priority-badges">
|
|
|
+ <span *ngIf="item.priority === 'high'" class="priority-badge urgent">
|
|
|
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
|
+ <path d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126zM12 15.75h.007v.008H12v-.008z"></path>
|
|
|
+ </svg>
|
|
|
+ 紧急
|
|
|
+ </span>
|
|
|
+ <span *ngIf="containsSensitiveWords(item.content)" class="priority-badge sensitive">
|
|
|
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
|
+ <path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"></path>
|
|
|
+ </svg>
|
|
|
+ 敏感词
|
|
|
+ </span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="consultation-content-text">
|
|
|
+ <p [innerHTML]="highlightKeyword(item.content)"></p>
|
|
|
</div>
|
|
|
- <p class="content">{{item.content}}</p>
|
|
|
- <div class="card-footer">
|
|
|
- <button class="ios-btn" (click)="openWeCom(item)" title="跳转企业微信">同步到企微</button>
|
|
|
- <button class="ios-btn outline">查看详情</button>
|
|
|
+
|
|
|
+ <div class="item-actions">
|
|
|
+ <button
|
|
|
+ class="action-btn primary"
|
|
|
+ (click)="syncToWeChat(item)"
|
|
|
+ [disabled]="item.syncing"
|
|
|
+ >
|
|
|
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
|
+ <path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"></path>
|
|
|
+ </svg>
|
|
|
+ <span *ngIf="!item.syncing">同步到企微</span>
|
|
|
+ <span *ngIf="item.syncing">同步中...</span>
|
|
|
+ </button>
|
|
|
+ <button class="action-btn secondary" (click)="viewDetails(item)">
|
|
|
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
|
+ <path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"></path>
|
|
|
+ <circle cx="12" cy="12" r="3"></circle>
|
|
|
+ </svg>
|
|
|
+ 查看详情
|
|
|
+ </button>
|
|
|
+ <button class="action-btn tertiary" (click)="markAsReplied(item)">
|
|
|
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
|
+ <polyline points="20 6 9 17 4 12"></polyline>
|
|
|
+ </svg>
|
|
|
+ 标记已回复
|
|
|
+ </button>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
@@ -74,13 +200,67 @@ export class ConsultationListComponent implements OnInit {
|
|
|
keyword = '';
|
|
|
filterUnrepliedOver1h = false;
|
|
|
filterSensitive = false;
|
|
|
+ filterHighPriority = false;
|
|
|
+ isLoading = false;
|
|
|
|
|
|
- private sensitivePatterns = /(发手机|发邮箱|找不到人)/;
|
|
|
+ private sensitivePatterns = /(发手机|发邮箱|找不到人|微信|QQ|电话|联系方式)/;
|
|
|
|
|
|
consultations = [
|
|
|
- {customer: '张先生', time: '10:30', content: '咨询关于厨房改造的预算和工期', priority: 'normal', lastReplyMinutes: 30, weComUserId: 'zhangxiansheng'},
|
|
|
- {customer: '李女士', time: '11:45', content: '询问客厅设计风格建议,发手机给你', priority: 'high', lastReplyMinutes: 120, weComUserId: 'linnvshi'},
|
|
|
- {customer: '王先生', time: '14:20', content: '需要全屋设计方案咨询,发邮箱吧', priority: 'normal', lastReplyMinutes: 75, weComUserId: 'wangxiansheng'}
|
|
|
+ {
|
|
|
+ id: '1',
|
|
|
+ customer: '张先生',
|
|
|
+ time: '10:30',
|
|
|
+ content: '咨询关于厨房改造的预算和工期,希望能在下个月开始施工',
|
|
|
+ priority: 'normal',
|
|
|
+ lastReplyMinutes: 30,
|
|
|
+ weComUserId: 'zhangxiansheng',
|
|
|
+ syncing: false,
|
|
|
+ replied: false
|
|
|
+ },
|
|
|
+ {
|
|
|
+ id: '2',
|
|
|
+ customer: '李女士',
|
|
|
+ time: '11:45',
|
|
|
+ content: '询问客厅设计风格建议,发手机给你,希望尽快联系',
|
|
|
+ priority: 'high',
|
|
|
+ lastReplyMinutes: 120,
|
|
|
+ weComUserId: 'linnvshi',
|
|
|
+ syncing: false,
|
|
|
+ replied: false
|
|
|
+ },
|
|
|
+ {
|
|
|
+ id: '3',
|
|
|
+ customer: '王先生',
|
|
|
+ time: '14:20',
|
|
|
+ content: '需要全屋设计方案咨询,发邮箱吧,预算在20万左右',
|
|
|
+ priority: 'normal',
|
|
|
+ lastReplyMinutes: 75,
|
|
|
+ weComUserId: 'wangxiansheng',
|
|
|
+ syncing: false,
|
|
|
+ replied: false
|
|
|
+ },
|
|
|
+ {
|
|
|
+ id: '4',
|
|
|
+ customer: '陈女士',
|
|
|
+ time: '09:15',
|
|
|
+ content: '想了解卧室装修的具体流程和注意事项',
|
|
|
+ priority: 'normal',
|
|
|
+ lastReplyMinutes: 15,
|
|
|
+ weComUserId: 'chennvshi',
|
|
|
+ syncing: false,
|
|
|
+ replied: true
|
|
|
+ },
|
|
|
+ {
|
|
|
+ id: '5',
|
|
|
+ customer: '刘先生',
|
|
|
+ time: '16:30',
|
|
|
+ content: '紧急!明天要看房,需要设计师现场指导,找不到人联系',
|
|
|
+ priority: 'high',
|
|
|
+ lastReplyMinutes: 180,
|
|
|
+ weComUserId: 'liuxiansheng',
|
|
|
+ syncing: false,
|
|
|
+ replied: false
|
|
|
+ }
|
|
|
];
|
|
|
|
|
|
filteredConsultations = [...this.consultations];
|
|
@@ -98,30 +278,163 @@ export class ConsultationListComponent implements OnInit {
|
|
|
}
|
|
|
|
|
|
applyFilters(): void {
|
|
|
- const kw = this.keyword.trim().toLowerCase();
|
|
|
this.filteredConsultations = this.consultations.filter(item => {
|
|
|
- const matchKw = !kw || item.customer.toLowerCase().includes(kw) || item.content.toLowerCase().includes(kw);
|
|
|
- const matchUnreplied = !this.filterUnrepliedOver1h || (item.lastReplyMinutes ?? 0) > 60;
|
|
|
- const matchSensitive = !this.filterSensitive || this.sensitivePatterns.test(item.content);
|
|
|
- return matchKw && matchUnreplied && matchSensitive;
|
|
|
+ const matchesKeyword = !this.keyword ||
|
|
|
+ item.customer.toLowerCase().includes(this.keyword.toLowerCase()) ||
|
|
|
+ item.content.toLowerCase().includes(this.keyword.toLowerCase());
|
|
|
+ const matchesUnreplied = !this.filterUnrepliedOver1h || item.lastReplyMinutes > 60;
|
|
|
+ const matchesSensitive = !this.filterSensitive || this.containsSensitiveWords(item.content);
|
|
|
+ const matchesPriority = !this.filterHighPriority || item.priority === 'high';
|
|
|
+ return matchesKeyword && matchesUnreplied && matchesSensitive && matchesPriority;
|
|
|
});
|
|
|
}
|
|
|
|
|
|
- openWeCom(item: any): void {
|
|
|
- const userId = item.weComUserId || encodeURIComponent(item.customer);
|
|
|
- const wecomUrl = `wecom://message?username=${userId}`;
|
|
|
- const webUrl = `https://work.weixin.qq.com/wework_admin/frame#contacts`;
|
|
|
+ toggleFilter(type: string): void {
|
|
|
+ switch (type) {
|
|
|
+ case 'unreplied':
|
|
|
+ this.filterUnrepliedOver1h = !this.filterUnrepliedOver1h;
|
|
|
+ break;
|
|
|
+ case 'sensitive':
|
|
|
+ this.filterSensitive = !this.filterSensitive;
|
|
|
+ break;
|
|
|
+ case 'priority':
|
|
|
+ this.filterHighPriority = !this.filterHighPriority;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ this.applyFilters();
|
|
|
+ }
|
|
|
+
|
|
|
+ clearSearch(): void {
|
|
|
+ this.keyword = '';
|
|
|
+ this.applyFilters();
|
|
|
+ }
|
|
|
+
|
|
|
+ refreshData(): void {
|
|
|
+ this.isLoading = true;
|
|
|
+ // 模拟数据刷新
|
|
|
+ setTimeout(() => {
|
|
|
+ this.isLoading = false;
|
|
|
+ this.applyFilters();
|
|
|
+ }, 1000);
|
|
|
+ }
|
|
|
+
|
|
|
+ containsSensitiveWords(content: string): boolean {
|
|
|
+ return this.sensitivePatterns.test(content);
|
|
|
+ }
|
|
|
+
|
|
|
+ isOverdue(item: any): boolean {
|
|
|
+ return item.lastReplyMinutes > 60 && !item.replied;
|
|
|
+ }
|
|
|
+
|
|
|
+ getReplyStatus(item: any): string {
|
|
|
+ if (item.replied) {
|
|
|
+ return '已回复';
|
|
|
+ }
|
|
|
+ if (item.lastReplyMinutes > 60) {
|
|
|
+ return `超时 ${Math.floor(item.lastReplyMinutes / 60)} 小时`;
|
|
|
+ }
|
|
|
+ return `${item.lastReplyMinutes} 分钟前`;
|
|
|
+ }
|
|
|
+
|
|
|
+ formatTime(time: string): string {
|
|
|
+ return `今天 ${time}`;
|
|
|
+ }
|
|
|
+
|
|
|
+ getAvatarColor(name: string): string {
|
|
|
+ const colors = ['#007AFF', '#34C759', '#FF9500', '#FF3B30', '#AF52DE', '#5AC8FA'];
|
|
|
+ const index = name.charCodeAt(0) % colors.length;
|
|
|
+ return colors[index];
|
|
|
+ }
|
|
|
+
|
|
|
+ highlightKeyword(content: string): string {
|
|
|
+ if (!this.keyword) return content;
|
|
|
+ const regex = new RegExp(`(${this.keyword})`, 'gi');
|
|
|
+ return content.replace(regex, '<mark>$1</mark>');
|
|
|
+ }
|
|
|
+
|
|
|
+ trackByConsultation(index: number, item: any): string {
|
|
|
+ return item.id;
|
|
|
+ }
|
|
|
+
|
|
|
+ getUnrepliedCount(): number {
|
|
|
+ return this.consultations.filter(item => item.lastReplyMinutes > 60 && !item.replied).length;
|
|
|
+ }
|
|
|
+
|
|
|
+ getSensitiveCount(): number {
|
|
|
+ return this.consultations.filter(item => this.containsSensitiveWords(item.content)).length;
|
|
|
+ }
|
|
|
+
|
|
|
+ getHighPriorityCount(): number {
|
|
|
+ return this.consultations.filter(item => item.priority === 'high').length;
|
|
|
+ }
|
|
|
+
|
|
|
+ syncToWeChat(item: any): void {
|
|
|
+ item.syncing = true;
|
|
|
+
|
|
|
try {
|
|
|
- window.location.href = wecomUrl;
|
|
|
+ // 尝试打开企业微信应用
|
|
|
+ const wecomUrl = `wxwork://message/?username=${item.weComUserId}`;
|
|
|
+ window.open(wecomUrl, '_blank');
|
|
|
+
|
|
|
+ // 模拟同步过程
|
|
|
+ setTimeout(() => {
|
|
|
+ item.syncing = false;
|
|
|
+ // 显示成功提示
|
|
|
+ this.showToast('已成功同步到企业微信');
|
|
|
+ }, 2000);
|
|
|
+
|
|
|
+ // 备选方案:打开企业微信网页版
|
|
|
setTimeout(() => {
|
|
|
+ const webUrl = `https://work.weixin.qq.com/wework_admin/frame#index`;
|
|
|
window.open(webUrl, '_blank');
|
|
|
- }, 800);
|
|
|
- } catch (_) {
|
|
|
- window.open(webUrl, '_blank');
|
|
|
+ }, 1000);
|
|
|
+ } catch (error) {
|
|
|
+ console.error('同步到企业微信失败:', error);
|
|
|
+ item.syncing = false;
|
|
|
+ this.showToast('同步失败,请检查企业微信客户端', 'error');
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ viewDetails(item: any): void {
|
|
|
+ // 这里可以导航到详情页面或打开模态框
|
|
|
+ console.log('查看详情:', item);
|
|
|
+ this.showToast(`正在查看 ${item.customer} 的咨询详情`);
|
|
|
+ }
|
|
|
+
|
|
|
+ markAsReplied(item: any): void {
|
|
|
+ item.replied = true;
|
|
|
+ this.showToast(`已标记 ${item.customer} 的咨询为已回复`);
|
|
|
+ this.applyFilters();
|
|
|
+ }
|
|
|
+
|
|
|
+ private showToast(message: string, type: 'success' | 'error' = 'success'): void {
|
|
|
+ // 简单的提示实现,实际项目中可以使用更完善的提示组件
|
|
|
+ const toast = document.createElement('div');
|
|
|
+ toast.textContent = message;
|
|
|
+ toast.style.cssText = `
|
|
|
+ position: fixed;
|
|
|
+ top: 20px;
|
|
|
+ right: 20px;
|
|
|
+ background: ${type === 'success' ? '#34C759' : '#FF3B30'};
|
|
|
+ color: white;
|
|
|
+ padding: 12px 20px;
|
|
|
+ border-radius: 8px;
|
|
|
+ z-index: 10000;
|
|
|
+ font-size: 14px;
|
|
|
+ box-shadow: 0 4px 12px rgba(0,0,0,0.15);
|
|
|
+ `;
|
|
|
+ document.body.appendChild(toast);
|
|
|
+
|
|
|
+ setTimeout(() => {
|
|
|
+ document.body.removeChild(toast);
|
|
|
+ }, 3000);
|
|
|
+ }
|
|
|
+
|
|
|
+ openWeCom(item: any): void {
|
|
|
+ this.syncToWeChat(item);
|
|
|
+ }
|
|
|
+
|
|
|
goBack() {
|
|
|
- history.back();
|
|
|
+ window.history.back();
|
|
|
}
|
|
|
}
|