123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378 |
- import { Component, OnInit, signal, computed } from '@angular/core';
- import { CommonModule } from '@angular/common';
- import { FormsModule } from '@angular/forms';
- import { RouterModule } from '@angular/router';
- import { ProjectService } from '../../../services/project.service';
- import { Project, ProjectStatus, ProjectStage } from '../../../models/project.model';
- // 定义项目列表项接口,包含计算后的属性
- interface ProjectListItem extends Project {
- progress: number;
- daysUntilDeadline: number;
- isUrgent: boolean;
- tagDisplayText: string;
- }
- @Component({
- selector: 'app-project-list',
- standalone: true,
- imports: [CommonModule, FormsModule, RouterModule],
- templateUrl: './project-list.html',
- styleUrls: ['./project-list.scss', '../customer-service-styles.scss']
- })
- export class ProjectList implements OnInit {
- // 项目列表数据
- projects = signal<ProjectListItem[]>([]);
-
- // 原始项目数据(用于筛选)
- allProjects = signal<Project[]>([]);
- // 添加toggleSidebar方法
- toggleSidebar(): void {
- // 侧边栏切换逻辑
- console.log('Toggle sidebar');
- }
-
- // 筛选和排序状态
- searchTerm = signal('');
- statusFilter = signal<string>('all');
- stageFilter = signal<string>('all');
- sortBy = signal<string>('deadline');
-
- // 当前页码
- currentPage = signal(1);
-
- // 每页显示数量
- pageSize = 8;
-
- // 分页后的项目列表
- paginatedProjects = computed(() => {
- const filteredProjects = this.projects();
- const startIndex = (this.currentPage() - 1) * this.pageSize;
- return filteredProjects.slice(startIndex, startIndex + this.pageSize);
- });
-
- // 总页数
- totalPages = computed(() => {
- return Math.ceil(this.projects().length / this.pageSize);
- });
-
- // 筛选和排序选项
- statusOptions = [
- { value: 'all', label: '全部状态' },
- { value: '进行中', label: '进行中' },
- { value: '已完成', label: '已完成' },
- { value: '已暂停', label: '已暂停' },
- { value: '已延期', label: '已延期' }
- ];
-
- stageOptions = [
- { value: 'all', label: '全部阶段' },
- { value: '前期沟通', label: '前期沟通' },
- { value: '建模', label: '建模' },
- { value: '软装', label: '软装' },
- { value: '渲染', label: '渲染' },
- { value: '后期', label: '后期' },
- { value: '完成', label: '完成' }
- ];
-
- sortOptions = [
- { value: 'deadline', label: '截止日期' },
- { value: 'createdAt', label: '创建时间' },
- { value: 'name', label: '项目名称' }
- ];
-
- constructor(private projectService: ProjectService) {}
-
- ngOnInit(): void {
- this.loadProjects();
- }
-
- // 加载项目列表
- loadProjects(): void {
- this.projectService.getProjects().subscribe(projects => {
- this.allProjects.set(projects);
- // 添加模拟数据以丰富列表
- const enrichedProjects = [...projects, ...this.generateMockProjects()];
- this.processProjects(enrichedProjects);
- });
- }
-
- // 处理项目数据,添加计算属性
- processProjects(projects: Project[]): void {
- const processedProjects = projects.map(project => {
- // 计算项目进度(模拟)
- const progress = this.calculateProjectProgress(project);
-
- // 计算距离截止日期的天数
- const daysUntilDeadline = this.calculateDaysUntilDeadline(project.deadline);
-
- // 判断是否紧急(截止日期前3天或已逾期)
- const isUrgent = daysUntilDeadline <= 3 && project.status === '进行中';
-
- // 生成标签显示文本
- const tagDisplayText = this.generateTagDisplayText(project);
-
- return {
- ...project,
- progress,
- daysUntilDeadline,
- isUrgent,
- tagDisplayText
- };
- });
-
- this.projects.set(this.applyFiltersAndSorting(processedProjects));
- }
-
- // 应用筛选和排序
- applyFiltersAndSorting(projects: ProjectListItem[]): ProjectListItem[] {
- let filteredProjects = [...projects];
-
- // 搜索筛选
- if (this.searchTerm().trim()) {
- const searchLower = this.searchTerm().toLowerCase().trim();
- filteredProjects = filteredProjects.filter(project =>
- project.name.toLowerCase().includes(searchLower) ||
- project.customerName.toLowerCase().includes(searchLower)
- );
- }
-
- // 状态筛选
- if (this.statusFilter() !== 'all') {
- filteredProjects = filteredProjects.filter(project =>
- project.status === this.statusFilter()
- );
- }
-
- // 阶段筛选
- if (this.stageFilter() !== 'all') {
- filteredProjects = filteredProjects.filter(project =>
- project.currentStage === this.stageFilter()
- );
- }
-
- // 排序
- filteredProjects.sort((a, b) => {
- switch (this.sortBy()) {
- case 'deadline':
- return new Date(a.deadline).getTime() - new Date(b.deadline).getTime();
- case 'createdAt':
- return new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime();
- case 'name':
- return a.name.localeCompare(b.name);
- default:
- return 0;
- }
- });
-
- return filteredProjects;
- }
-
- // 生成标签显示文本
- generateTagDisplayText(project: Project): string {
- if (!project.customerTags || project.customerTags.length === 0) {
- return '普通项目';
- }
-
- const tag = project.customerTags[0];
- return `${tag.preference}${tag.needType}`;
- }
-
- // 计算项目进度(模拟)
- calculateProjectProgress(project: Project): number {
- if (project.status === '已完成') return 100;
- if (project.status === '已暂停' || project.status === '已延期') return 0;
-
- // 基于当前阶段计算进度
- const stageProgress: Record<ProjectStage, number> = {
- '前期沟通': 20,
- '建模': 40,
- '软装': 60,
- '渲染': 80,
- '后期': 90,
- '完成': 100
- };
-
- return stageProgress[project.currentStage] || 0;
- }
-
- // 计算距离截止日期的天数
- calculateDaysUntilDeadline(deadline: Date): number {
- const now = new Date();
- const deadlineDate = new Date(deadline);
- const diffTime = deadlineDate.getTime() - now.getTime();
- return Math.ceil(diffTime / (1000 * 60 * 60 * 24));
- }
-
- // 生成模拟项目数据
- generateMockProjects(): Project[] {
- const statuses: ProjectStatus[] = ['进行中', '已完成', '已暂停', '已延期'];
- const stages: ProjectStage[] = ['前期沟通', '建模', '软装', '渲染', '后期', '完成'];
- const preferences: ('现代' | '宋式' | '欧式')[] = ['现代', '宋式', '欧式'];
- const needTypes: ('硬装' | '软装')[] = ['硬装', '软装'];
- const sources: ('朋友圈' | '信息流')[] = ['朋友圈', '信息流'];
-
- const mockProjects: Project[] = [];
-
- for (let i = 1; i <= 12; i++) {
- const baseDate = new Date();
- const createdDate = new Date(baseDate.setDate(baseDate.getDate() - Math.floor(Math.random() * 30)));
- baseDate.setDate(baseDate.getDate() + Math.floor(Math.random() * 15) + 5);
- const deadlineDate = new Date(baseDate);
-
- const preference = preferences[Math.floor(Math.random() * preferences.length)];
- const needType = needTypes[Math.floor(Math.random() * needTypes.length)];
- const source = sources[Math.floor(Math.random() * sources.length)];
- const stage = stages[Math.floor(Math.random() * stages.length)];
- const status = stage === '完成' ? '已完成' : statuses[Math.floor(Math.random() * 3)];
-
- mockProjects.push({
- id: `mock-${i}`,
- name: `${preference}风格${needType === '硬装' ? '全屋' : '客厅'}设计`,
- customerName: `客户${String.fromCharCode(64 + i)}`,
- customerTags: [
- {
- source: source,
- needType: needType,
- preference: preference,
- colorAtmosphere: i % 2 === 0 ? '简约明亮' : '温馨舒适'
- }
- ],
- highPriorityNeeds: i % 3 === 0 ? ['需快速交付', '重要客户'] : [],
- status: status,
- currentStage: stage,
- createdAt: createdDate,
- deadline: deadlineDate,
- assigneeId: `designer${i % 3 + 1}`,
- assigneeName: `设计师${String.fromCharCode(64 + (i % 3 + 1))}`,
- skillsRequired: [preference + '风格', needType]
- });
- }
-
- return mockProjects;
- }
-
- // 处理搜索
- onSearch(): void {
- this.currentPage.set(1);
- this.processProjects(this.allProjects());
- }
-
- // 处理状态筛选
- onStatusChange(event: Event): void {
- const selectElement = event.target as HTMLSelectElement;
- this.statusFilter.set(selectElement.value);
- this.currentPage.set(1);
- this.processProjects(this.allProjects());
- }
-
- // 处理阶段筛选
- onStageChange(event: Event): void {
- const selectElement = event.target as HTMLSelectElement;
- this.stageFilter.set(selectElement.value);
- this.currentPage.set(1);
- this.processProjects(this.allProjects());
- }
-
- // 处理排序变化
- onSortChange(event: Event): void {
- const selectElement = event.target as HTMLSelectElement;
- this.sortBy.set(selectElement.value);
- this.processProjects(this.allProjects());
- }
-
- // 分页导航
- goToPage(page: number): void {
- if (page >= 1 && page <= this.totalPages() && page !== this.currentPage()) {
- this.currentPage.set(page);
- // 不需要重新加载整个项目列表,currentPage变更后computed属性会自动更新
- }
- }
- prevPage(): void {
- if (this.currentPage() > 1) {
- this.goToPage(this.currentPage() - 1);
- }
- }
- nextPage(): void {
- if (this.currentPage() < this.totalPages()) {
- this.goToPage(this.currentPage() + 1);
- }
- }
- // 计算当前显示的页码数组
- pageNumbers = computed(() => {
- const maxVisible = 5;
- const total = this.totalPages();
- const current = this.currentPage();
- const pages: number[] = [];
- if (total <= maxVisible) {
- // 如果总页数不超过最大可见页数,显示所有页码
- for (let i = 1; i <= total; i++) {
- pages.push(i);
- }
- } else {
- // 处理中间页码显示
- if (current <= Math.ceil(maxVisible / 2)) {
- // 当前页在前面部分
- for (let i = 1; i <= maxVisible; i++) {
- pages.push(i);
- }
- } else if (current >= total - Math.floor(maxVisible / 2)) {
- // 当前页在后面部分
- for (let i = total - (maxVisible - 1); i <= total; i++) {
- pages.push(i);
- }
- } else {
- // 当前页在中间部分
- for (let i = current - Math.floor(maxVisible / 2); i <= current + Math.floor(maxVisible / 2); i++) {
- pages.push(i);
- }
- }
- }
- return pages;
- });
- // 计算绝对值的辅助方法(用于模板中)
- getAbsValue(value: number): number {
- return Math.abs(value);
- }
-
- // 格式化日期
- formatDate(date: Date): string {
- return new Date(date).toLocaleDateString('zh-CN', {
- year: 'numeric',
- month: '2-digit',
- day: '2-digit'
- });
- }
-
- // 获取状态样式类
- getStatusClass(status: string): string {
- const statusClasses: Record<string, string> = {
- '进行中': 'status-active',
- '已完成': 'status-completed',
- '已暂停': 'status-paused',
- '已延期': 'status-overdue'
- };
-
- return statusClasses[status] || '';
- }
-
- // 获取阶段样式类
- getStageClass(stage: string): string {
- const stageClasses: Record<string, string> = {
- '前期沟通': 'stage-communication',
- '建模': 'stage-modeling',
- '软装': 'stage-decoration',
- '渲染': 'stage-rendering',
- '后期': 'stage-postproduction',
- '完成': 'stage-completed'
- };
-
- return stageClasses[stage] || '';
- }
- }
|