123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327 |
- import { Component, OnInit, signal } from '@angular/core';
- import { CommonModule } from '@angular/common';
- import { RouterModule } from '@angular/router';
- import { FormsModule } from '@angular/forms';
- import { MatButtonModule } from '@angular/material/button';
- import { MatIconModule } from '@angular/material/icon';
- import { MatTableModule } from '@angular/material/table';
- import { MatInputModule } from '@angular/material/input';
- import { MatSelectModule } from '@angular/material/select';
- import { MatPaginatorModule } from '@angular/material/paginator';
- import { MatDialogModule, MatDialog } from '@angular/material/dialog';
- import { MatSortModule } from '@angular/material/sort';
- import { ProjectDialogComponent } from './project-dialog/project-dialog';
- interface Project {
- id: string;
- name: string;
- customer: string;
- status: 'pending' | 'in-progress' | 'completed' | 'on-hold';
- designer: string;
- startDate: string;
- endDate: string;
- budget: number;
- progress: number;
- }
- @Component({
- selector: 'app-project-management',
- standalone: true,
- imports: [
- CommonModule,
- RouterModule,
- FormsModule,
- MatButtonModule,
- MatIconModule,
- MatTableModule,
- MatInputModule,
- MatSelectModule,
- MatPaginatorModule,
- MatDialogModule,
- MatSortModule,
- ProjectDialogComponent
- ],
- templateUrl: './project-management.html',
- styleUrl: './project-management.scss'
- })
- export class ProjectManagement implements OnInit {
- projects = signal<Project[]>([]);
- filteredProjects = signal<Project[]>([]);
- searchTerm = '';
- statusFilter = '';
- sortColumn = 'startDate';
- sortDirection = 'desc';
- pageSize = 10;
- currentPage = 0;
- // 状态颜色映射
- statusColors: Record<string, string> = {
- 'pending': '#FFAA00',
- 'in-progress': '#165DFF',
- 'completed': '#00B42A',
- 'on-hold': '#F53F3F'
- };
- // 状态文本映射
- statusTexts: Record<string, string> = {
- 'pending': '待开始',
- 'in-progress': '进行中',
- 'completed': '已完成',
- 'on-hold': '暂停中'
- };
- constructor(private dialog: MatDialog) {}
- ngOnInit(): void {
- this.loadProjects();
- }
- loadProjects(): void {
- // 模拟项目数据
- this.projects.set([
- {
- id: '1',
- name: '现代简约风格三居室设计',
- customer: '王先生',
- status: 'in-progress',
- designer: '张设计师',
- startDate: '2025-09-01',
- endDate: '2025-10-15',
- budget: 85000,
- progress: 65
- },
- {
- id: '2',
- name: '北欧风格两居室设计',
- customer: '李女士',
- status: 'completed',
- designer: '刘设计师',
- startDate: '2025-08-15',
- endDate: '2025-09-30',
- budget: 68000,
- progress: 100
- },
- {
- id: '3',
- name: '工业风办公室设计',
- customer: '赵先生',
- status: 'pending',
- designer: '王设计师',
- startDate: '2025-09-15',
- endDate: '2025-11-05',
- budget: 120000,
- progress: 0
- },
- {
- id: '4',
- name: '新中式别墅设计',
- customer: '钱女士',
- status: 'on-hold',
- designer: '张设计师',
- startDate: '2025-08-20',
- endDate: '2025-11-20',
- budget: 250000,
- progress: 40
- },
- {
- id: '5',
- name: '日式小户型设计',
- customer: '孙先生',
- status: 'in-progress',
- designer: '刘设计师',
- startDate: '2025-09-05',
- endDate: '2025-10-20',
- budget: 55000,
- progress: 35
- },
- {
- id: '6',
- name: '美式乡村风格设计',
- customer: '周女士',
- status: 'in-progress',
- designer: '王设计师',
- startDate: '2025-09-08',
- endDate: '2025-10-30',
- budget: 75000,
- progress: 25
- },
- {
- id: '7',
- name: '极简主义公寓设计',
- customer: '吴先生',
- status: 'pending',
- designer: '张设计师',
- startDate: '2025-09-20',
- endDate: '2025-11-10',
- budget: 60000,
- progress: 0
- },
- {
- id: '8',
- name: '地中海风格别墅设计',
- customer: '郑女士',
- status: 'completed',
- designer: '刘设计师',
- startDate: '2025-08-01',
- endDate: '2025-09-15',
- budget: 180000,
- progress: 100
- },
- {
- id: '9',
- name: '后现代风格办公室设计',
- customer: '王总',
- status: 'in-progress',
- designer: '王设计师',
- startDate: '2025-08-25',
- endDate: '2025-10-15',
- budget: 95000,
- progress: 50
- },
- {
- id: '10',
- name: '新古典主义住宅设计',
- customer: '陈女士',
- status: 'on-hold',
- designer: '张设计师',
- startDate: '2025-08-10',
- endDate: '2025-11-01',
- budget: 130000,
- progress: 30
- }
- ]);
-
- this.applyFilters();
- }
- applyFilters(): void {
- let result = [...this.projects()];
-
- // 搜索过滤
- if (this.searchTerm) {
- const term = this.searchTerm.toLowerCase();
- result = result.filter(project =>
- project.name.toLowerCase().includes(term) ||
- project.customer.toLowerCase().includes(term) ||
- project.designer.toLowerCase().includes(term)
- );
- }
-
- // 状态过滤
- if (this.statusFilter) {
- result = result.filter(project => project.status === this.statusFilter);
- }
-
- // 排序
- result.sort((a, b) => {
- if (this.sortColumn === 'startDate' || this.sortColumn === 'endDate') {
- const dateA = new Date(a[this.sortColumn]).getTime();
- const dateB = new Date(b[this.sortColumn]).getTime();
- return this.sortDirection === 'asc' ? dateA - dateB : dateB - dateA;
- } else if (this.sortColumn === 'budget' || this.sortColumn === 'progress') {
- return this.sortDirection === 'asc' ? a[this.sortColumn] - b[this.sortColumn] : b[this.sortColumn] - a[this.sortColumn];
- } else {
- const valueA = a[this.sortColumn as keyof Project]?.toString().toLowerCase() || '';
- const valueB = b[this.sortColumn as keyof Project]?.toString().toLowerCase() || '';
- return this.sortDirection === 'asc' ? valueA.localeCompare(valueB) : valueB.localeCompare(valueA);
- }
- });
-
- this.filteredProjects.set(result);
- }
- onSearch(): void {
- this.applyFilters();
- }
- onStatusFilterChange(): void {
- this.applyFilters();
- }
- onSort(column: string): void {
- if (this.sortColumn === column) {
- this.sortDirection = this.sortDirection === 'asc' ? 'desc' : 'asc';
- } else {
- this.sortColumn = column;
- this.sortDirection = 'asc';
- }
- this.applyFilters();
- }
- openProjectDialog(project?: Project): void {
- const dialogRef = this.dialog.open(ProjectDialogComponent, {
- width: '600px',
- data: project ? { ...project } : {
- id: '',
- name: '',
- client: '',
- designer: '',
- status: 'pending',
- priority: 'medium',
- startDate: new Date().toISOString().split('T')[0],
- endDate: '',
- budget: 0,
- progress: 0,
- description: '',
- tasks: []
- }
- });
- dialogRef.afterClosed().subscribe(result => {
- if (result) {
- if (result.id) {
- // 更新项目
- this.updateProject(result);
- } else {
- // 创建新项目
- this.createProject(result);
- }
- }
- });
- }
- createProject(projectData: Omit<Project, 'id'>): void {
- const newProject: Project = {
- ...projectData,
- id: (this.projects().length + 1).toString()
- };
-
- this.projects.set([newProject, ...this.projects()]);
- this.applyFilters();
- }
- updateProject(updatedProject: Project): void {
- this.projects.set(this.projects().map(project =>
- project.id === updatedProject.id ? updatedProject : project
- ));
- this.applyFilters();
- }
- deleteProject(id: string): void {
- if (confirm('确定要删除这个项目吗?')) {
- this.projects.set(this.projects().filter(project => project.id !== id));
- this.applyFilters();
- }
- }
- formatCurrency(amount: number): string {
- return new Intl.NumberFormat('zh-CN', {
- style: 'currency',
- currency: 'CNY',
- minimumFractionDigits: 0
- }).format(amount);
- }
- get paginatedProjects(): Project[] {
- const startIndex = this.currentPage * this.pageSize;
- return this.filteredProjects().slice(startIndex, startIndex + this.pageSize);
- }
- get totalPages(): number {
- return Math.ceil(this.filteredProjects().length / this.pageSize);
- }
- onPageChange(page: number): void {
- this.currentPage = page;
- }
- }
|