# 客服项目列表Parse Server数据集成完成 ## 📋 任务概述 完成客服项目列表页面与Parse Server真实数据的集成,实现项目数据的正确显示和渲染,并优化UI样式。 ## ✅ 完成内容 ### 1. Parse Server数据集成 #### 1.1 公司信息初始化 - **方法1(优先)**: 从`localStorage.getItem('company')`获取公司ID - **方法2(备用)**: 从`ProfileService.getCurrentProfile()`获取公司信息 - 参考了team-leader和admin的实现方式,确保数据加载的稳定性 ```typescript // 初始化用户和公司信息 private async initializeUserAndCompany(): Promise { try { // 方法1: 从localStorage获取公司ID(参考team-leader的实现) const companyId = localStorage.getItem('company'); if (companyId) { const CompanyClass = Parse.Object.extend('Company'); this.company = new CompanyClass(); this.company.id = companyId; console.log('✅ 从localStorage加载公司ID:', companyId); } else { // 方法2: 从Profile获取公司信息 this.currentProfile = await this.profileService.getCurrentProfile(); // ... } } catch (error) { console.error('❌ 初始化用户和公司信息失败:', error); this.loadError.set('加载用户信息失败,请刷新页面重试'); } } ``` #### 1.2 项目数据查询 - 使用Parse Query查询Project表 - 查询条件: - `company`: 等于当前公司指针 - `isDeleted`: 不等于true(兼容没有该字段的数据) - Include关联数据:`contact`, `assignee`, `owner` - 排序:按`updatedAt`降序 - 限制:最多500个项目 ```typescript const ProjectQuery = new Parse.Query('Project'); ProjectQuery.equalTo('company', this.getCompanyPointer()); ProjectQuery.notEqualTo('isDeleted', true); ProjectQuery.include('contact', 'assignee', 'owner'); ProjectQuery.descending('updatedAt'); ProjectQuery.limit(500); const projectObjects = await ProjectQuery.find(); ``` #### 1.3 数据转换 将Parse Server的Project对象转换为前端ProjectListItem格式: - `id`: 项目ID - `name`: 项目标题(title) - `customerName`: 联系人姓名(contact.name) - `status`: 项目状态(进行中、已完成、已暂停、已延期) - `currentStage`: 当前阶段(订单分配、需求沟通、建模、软装、渲染、后期、尾款结算、投诉处理等) - `assigneeName`: 负责人姓名(assignee.name) - `deadline`: 截止日期 - 等等 ### 2. 项目分组逻辑 按照业务需求,将项目分为四个阶段: #### 2.1 订单分配(order) - 未分配设计师(`!assigneeId || assigneeId.trim() === ''`) - 或者`currentStage === '订单分配'` #### 2.2 确认需求(requirements) - `currentStage`为:需求沟通、方案确认 - 排除售后和订单分配阶段 #### 2.3 交付执行(delivery) - `currentStage`为:建模、软装、渲染、后期、尾款结算 - 排除售后和订单分配阶段 #### 2.4 售后(aftercare) - `status === '已完成'` - 或`currentStage`为:投诉处理、客户评价 ```typescript // 看板分组逻辑 private isOrderAssignment(p: Project): boolean { return !p.assigneeId || p.assigneeId.trim() === '' || p.currentStage === '订单分配'; } private isRequirementsConfirmation(p: Project): boolean { const requirementStages: ProjectStage[] = ['需求沟通', '方案确认']; return !this.isAftercare(p) && !this.isOrderAssignment(p) && requirementStages.includes(p.currentStage); } private isDeliveryExecution(p: Project): boolean { const deliveryStages: ProjectStage[] = ['建模', '软装', '渲染', '后期', '尾款结算']; return !this.isAftercare(p) && !this.isOrderAssignment(p) && deliveryStages.includes(p.currentStage); } private isAftercare(p: Project): boolean { const aftercareStages: ProjectStage[] = ['投诉处理', '客户评价']; return p.status === '已完成' || aftercareStages.includes(p.currentStage); } ``` ### 3. UI/UX改进 #### 3.1 加载状态 添加了加载动画和提示: ```html @if (isLoading()) {

正在加载项目数据...

} ``` 样式特点: - 旋转加载动画 - 居中显示 - 最小高度400px #### 3.2 错误状态 添加了错误提示和重试按钮: ```html @if (loadError()) {
...

{{ loadError() }}

} ``` #### 3.3 空状态 每个看板列都有空状态提示: ```html @if (getProjectsByColumn(col.id).length === 0) {
...

暂无项目

} ``` #### 3.4 卡片样式优化 - **现代化设计**: - 圆角从8px增加到12px - 更柔和的阴影效果 - 边框使用半透明黑色 - **交互动画**: - 悬停时上移4px(原来2px) - 使用cubic-bezier缓动函数 - 顶部装饰条渐变效果 - 点击时轻微回弹 - **装饰元素**: - 卡片顶部3px渐变装饰条 - 悬停时显示,增强视觉反馈 ```scss .project-content .kanban-card { border-radius: 12px; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06); padding: 18px; transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1); &::before { content: ''; position: absolute; top: 0; left: 0; right: 0; height: 3px; background: linear-gradient(90deg, $primary-color, lighten($primary-color, 15%)); opacity: 0; transition: opacity 0.25s ease; } &:hover { transform: translateY(-4px); box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12); &::before { opacity: 1; } } } ``` #### 3.5 徽章样式优化 "待分配"徽章采用渐变背景和脉动动画: ```scss .project-content .pending-badge { background: linear-gradient(135deg, #fff8e1 0%, #ffecb3 100%); border-radius: 14px; box-shadow: 0 2px 4px rgba($warning-color, 0.1); animation: pulse-badge 2s ease-in-out infinite; } @keyframes pulse-badge { 0%, 100% { box-shadow: 0 2px 4px rgba($warning-color, 0.1); } 50% { box-shadow: 0 2px 8px rgba($warning-color, 0.25); } } ``` #### 3.6 文字排版优化 - 项目名称:字重600,行高1.4,字间距-0.01em - 项目ID:字重500,上边距4px - 更好的视觉层次和可读性 ### 4. 调试信息 添加了详细的控制台日志,便于调试: - ✅ 成功加载公司ID - ✅ 成功加载项目数据(显示数量) - ⚠️ 未找到项目数据时的提示 - ❌ 错误信息的详细输出 ```typescript console.log(`✅ 从Parse Server加载了 ${projectObjects.length} 个项目`); if (projectObjects.length === 0) { console.warn('⚠️ 未找到项目数据,请检查:'); console.warn('1. Parse Server中是否有Project数据'); console.warn('2. 当前公司ID:', this.company.id); console.warn('3. 数据是否正确关联到当前公司'); } ``` ## 📁 修改的文件 ### TypeScript - `yss-project/src/app/pages/customer-service/project-list/project-list.ts` - 优化公司信息初始化逻辑 - 改进项目数据查询(兼容isDeleted字段) - 添加详细的调试日志 ### HTML - `yss-project/src/app/pages/customer-service/project-list/project-list.html` - 添加加载状态组件 - 添加错误状态组件 - 添加空列状态提示 - 优化条件渲染逻辑 ### SCSS - `yss-project/src/app/pages/customer-service/project-list/project-list.scss` - 添加加载状态样式 - 添加错误状态样式 - 添加空列状态样式 - 优化卡片样式(圆角、阴影、动画) - 优化徽章样式(渐变、脉动动画) - 优化文字排版 ## 🔍 数据查询参考 本实现参考了以下文件的数据查询方式: - `yss-project/src/app/pages/team-leader/services/designer.service.ts` - `yss-project/src/app/pages/team-leader/services/dashboard-data.service.ts` - `yss-project/src/app/pages/admin/dashboard/dashboard.service.ts` - `yss-project/src/app/pages/admin/project-management/project-management.ts` ## 🎯 数据表使用 ### Project表 - **用途**: 项目主表 - **关键字段**: - `company`: 公司指针(用于筛选) - `title`: 项目标题 - `status`: 项目状态 - `currentStage`: 当前阶段 - `contact`: 联系人指针 - `assignee`: 负责人指针 - `deadline`: 截止日期 - `isDeleted`: 是否删除 ### ContactInfo表 - **用途**: 客户联系人信息 - **关键字段**: - `name`: 联系人姓名 ### Profile表 - **用途**: 用户信息(设计师等) - **关键字段**: - `name`: 用户姓名 ## 🚀 使用说明 ### 1. 确保Parse Server配置正确 检查`localStorage`中是否有`company`字段: ```javascript console.log('公司ID:', localStorage.getItem('company')); ``` ### 2. 访问页面 ``` http://localhost:4200/customer-service/project-list ``` ### 3. 查看控制台日志 打开浏览器开发者工具,查看控制台输出: - 如果显示"✅ 从Parse Server加载了 X 个项目",说明数据加载成功 - 如果显示"⚠️ 未找到项目数据",说明数据库中没有符合条件的项目 - 如果显示"❌ 初始化用户和公司信息失败",说明公司信息获取失败 ### 4. 数据调试 如果没有数据显示,请检查: 1. Parse Server是否正常运行 2. Project表中是否有数据 3. Project数据的`company`字段是否正确关联到当前公司 4. `localStorage.getItem('company')`是否有值 ## 📊 数据流程 ``` 1. 页面初始化 ↓ 2. initializeUserAndCompany() ├─ 从localStorage获取company ID └─ 或从ProfileService获取company ↓ 3. loadProjects() ├─ 创建Parse Query ├─ 设置查询条件(company, isDeleted) ├─ Include关联数据(contact, assignee) └─ 执行查询 ↓ 4. 数据转换 ├─ 将Parse Object转换为ProjectListItem └─ 映射status和stage ↓ 5. 项目分组 ├─ 订单分配 ├─ 确认需求 ├─ 交付执行 └─ 售后 ↓ 6. UI渲染 ├─ 看板视图(卡片) ├─ 列表视图 └─ 监控大盘 ``` ## ✨ 特色功能 1. **智能分组**: 根据项目状态和阶段自动分组到四个看板列 2. **实时数据**: 直接从Parse Server加载最新数据 3. **优雅加载**: 加载动画、错误提示、空状态提示 4. **精美UI**: 现代化卡片设计、流畅动画、渐变装饰 5. **调试友好**: 详细的控制台日志,便于问题排查 ## 🎨 设计亮点 1. **卡片悬停效果**: 上移动画 + 顶部渐变装饰条 2. **徽章脉动动画**: "待分配"徽章的呼吸效果 3. **柔和阴影**: 多层次阴影营造深度感 4. **圆角设计**: 12px圆角更加现代 5. **渐变背景**: 徽章使用渐变背景增强视觉效果 ## 📝 注意事项 1. 确保Parse Server已正确配置并运行 2. 确保Project表中有测试数据 3. 确保数据的`company`字段正确关联 4. 如果使用企业微信授权,确保已正确配置 5. 本地开发时,可能需要临时注释`WxworkAuthGuard` ## 🔗 相关文档 - [数据库表结构](../Database/database-tables-overview.md) - [项目数据模型](../../rules/schema/project.md) - [客服工作台数据集成](./20251024-customer-service-dashboard-integration-summary.md) --- **完成时间**: 2024-10-24 **开发者**: AI Assistant **状态**: ✅ 已完成