dynamic-data-integration.md 11 KB

动态数据对接和企业微信认证集成文档

概述

本文档说明了如何在 yss-project 中集成企业微信认证 (WxworkAuthGuard) 和动态数据服务 (FmodeParse)。

已完成的功能

1. 企业微信认证集成

路由守卫配置

已在 src/app/app.routes.ts 中为所有主要路由添加了 WxworkAuthGuard

import { WxworkAuthGuard } from 'fmode-ng/social';

// 客服路由
{
  path: 'customer-service',
  canActivate: [WxworkAuthGuard],
  children: [...]
}

// 设计师路由
{
  path: 'designer',
  canActivate: [WxworkAuthGuard],
  children: [...]
}

// 组长路由
{
  path: 'team-leader',
  canActivate: [WxworkAuthGuard],
  children: [...]
}

// 财务路由
{
  path: 'finance',
  canActivate: [WxworkAuthGuard],
  children: [...]
}

// 人事路由
{
  path: 'hr',
  canActivate: [WxworkAuthGuard],
  children: [...]
}

// 管理员路由
{
  path: 'admin',
  canActivate: [WxworkAuthGuard],
  children: [...]
}

组件级认证

已在主要页面组件中集成了 WxworkAuth 类:

管理员仪表板 (src/app/pages/admin/dashboard/dashboard.ts)

import { WxworkAuth, FmodeQuery, FmodeObject, FmodeUser } from 'fmode-ng/core';

private initAuth(): void {
  this.wxAuth = new WxworkAuth({
    cid: 'cDL6R1hgSi'  // 公司帐套ID
  });
}

private async authenticateAndLoadData(): Promise<void> {
  const { user } = await this.wxAuth.authenticateAndLogin();
  if (user) {
    console.log('✅ 管理员登录成功:', user.get('username'));
    await this.loadDashboardData();
  }
}

客服仪表板 (src/app/pages/customer-service/dashboard/dashboard.ts)

// 同样的认证模式,加载咨询统计数据
private async loadConsultationStats(): Promise<void> {
  const consultationQuery = new FmodeQuery('Consultation');
  consultationQuery.equalTo('status', 'new');
  const newConsultations = await consultationQuery.count();
  this.stats.newConsultations.set(newConsultations);
}

设计师仪表板 (src/app/pages/designer/dashboard/dashboard.ts)

// 同样的认证模式,加载任务数据

2. FmodeParse 初始化

已在 src/app/app.ts 中初始化了 FmodeParse:

import { FmodeParse } from 'fmode-ng/core';

private initParse(): void {
  try {
    const Parse = FmodeParse.with("nova");
    console.log('✅ FmodeParse 初始化成功');
  } catch (error) {
    console.error('❌ FmodeParse 初始化失败:', error);
  }
}

3. 动态数据对接

管理员仪表板数据源

项目统计

private async loadProjectStats(): Promise<void> {
  const projectQuery = new FmodeQuery('Project');

  // 总项目数
  const totalProjects = await projectQuery.count();
  this.stats.totalProjects.set(totalProjects);

  // 进行中项目数
  projectQuery.equalTo('status', '进行中');
  const activeProjects = await projectQuery.count();
  this.stats.activeProjects.set(activeProjects);
}

用户统计

private async loadUserStats(): Promise<void> {
  // 设计师统计
  const designerQuery = new FmodeQuery('Profile');
  designerQuery.equalTo('role', 'designer');
  const designers = await designerQuery.count();
  this.stats.totalDesigners.set(designers);
}

收入统计

private async loadRevenueStats(): Promise<void> {
  const orderQuery = new FmodeQuery('Order');
  orderQuery.equalTo('status', 'paid');
  const orders = await orderQuery.find();

  let totalRevenue = 0;
  for (const order of orders) {
    const amount = order.get('amount') || 0;
    totalRevenue += amount;
  }
  this.stats.totalRevenue.set(totalRevenue);
}

客服仪表板数据源

咨询统计

private async loadConsultationStats(): Promise<void> {
  // 新咨询数
  const consultationQuery = new FmodeQuery('Consultation');
  consultationQuery.equalTo('status', 'new');
  consultationQuery.greaterThanOrEqualTo('createdAt', new Date(new Date().setHours(0,0,0,0)));
  const newConsultations = await consultationQuery.count();
  this.stats.newConsultations.set(newConsultations);
}

4. NovaStorage 上传组件

上传组件 (src/app/shared/components/upload-component/)

直接使用 NovaStorage.withCid(cid).upload() 方法,无需额外服务层。

功能特性:

  • 拖拽上传支持
  • 多文件上传
  • 文件类型和大小验证
  • 上传进度显示
  • 预览功能
  • 错误处理
  • 自动文件路径生成

核心实现:

import { NovaStorage, NovaFile } from 'fmode-ng/core';

// 初始化存储服务
private async initStorage(): Promise<void> {
  const cid = localStorage.getItem('company') || 'cDL6R1hgSi';
  this.storage = await NovaStorage.withCid(cid);
}

// 上传文件
const uploaded: NovaFile = await this.storage.upload(file, {
  prefixKey: 'project/pid/', // 可选的路径前缀
  onProgress: (p) => console.log('进度:', p.total.percent),
});

使用示例:

import { UploadComponent, UploadResult } from './shared/components/upload-component/upload.component';

@Component({
  standalone: true,
  imports: [UploadComponent]
})
export class MyComponent {
  onUploadComplete(results: UploadResult[]) {
    results.forEach(result => {
      if (result.success) {
        console.log('上传成功:', result.file?.url);
        // 保存文件信息到数据库
        this.saveFileInfo(result.file);
      }
    });
  }

  private async saveFileInfo(file: NovaFile) {
    // 保存 key, url, name, type, size, metadata, md5 等信息
    console.log('文件信息:', {
      key: file.key,
      url: file.url,
      name: file.name,
      size: file.size
    });
  }
}
<app-upload-component
  [accept]="image/*"
  [multiple]="true"
  [maxSize]="10"
  [prefixKey]="'demo/images/'"
  [showPreview]="true"
  (uploadComplete)="onUploadComplete($event)">
</app-upload-component>

示例组件: src/app/shared/components/upload-example/ 提供了完整的使用示例和配置选项演示。

数据表结构

主要数据表

  1. Project - 项目表

    • name: 项目名称
    • status: 项目状态 (进行中, 已完成, 异常)
    • owner: 负责人 (Pointer to Profile)
    • startDate: 开始日期
    • endDate: 结束日期
  2. Profile - 用户档案表

    • name: 姓名
    • role: 角色 (designer, customer, admin)
    • level: 级别 (junior, mid, senior)
    • completedProjects: 完成项目数
    • activeProjects: 进行中项目数
  3. Consultation - 咨询表

    • status: 状态 (new, pending_assignment, processing)
    • customer: 客户 (Pointer to Profile)
    • createdAt: 创建时间
  4. Order - 订单表

    • status: 订单状态
    • amount: 金额
    • customer: 客户 (Pointer to Profile)
    • invoiceNo: 发票号
  5. AfterSales - 售后表

    • status: 状态
    • project: 项目 (Pointer to Project)
    • createdAt: 创建时间
  6. Images - 图片表

    • originalName: 原始文件名
    • url: 图片URL
    • thumbnailUrl: 缩略图URL
    • size: 文件大小

使用指南

1. 新页面添加认证

对于新页面,按以下步骤添加认证:

import { WxworkAuth, FmodeQuery, FmodeObject, FmodeUser } from 'fmode-ng/core';

@Component({...})
export class NewPageComponent {
  private wxAuth: WxworkAuth;
  private currentUser: FmodeUser | null = null;

  constructor() {
    this.initAuth();
  }

  private initAuth(): void {
    this.wxAuth = new WxworkAuth({
      cid: 'cDL6R1hgSi'
    });
  }

  async ngOnInit(): Promise<void> {
    await this.authenticateAndLoadData();
  }

  private async authenticateAndLoadData(): Promise<void> {
    const { user } = await this.wxAuth.authenticateAndLogin();
    if (user) {
      this.currentUser = user;
      await this.loadData();
    }
  }
}

2. 数据查询示例

// 基本查询
const query = new FmodeQuery('Project');
const projects = await query.find();

// 条件查询
query.equalTo('status', '进行中');
query.greaterThan('createdAt', new Date('2025-01-01'));

// 排序
query.descending('createdAt');

// 分页
query.limit(20);
query.skip(0);

// 计数
const count = await query.count();

// 关联查询
const userQuery = new FmodeQuery('Profile');
userQuery.include('projects');

3. 数据保存示例

// 创建新对象
const project = new FmodeObject('Project');
project.set('name', '新项目');
project.set('status', '进行中');
const savedProject = await project.save();

// 更新对象
savedProject.set('status', '已完成');
await savedProject.save();

// 删除对象
await savedProject.destroy();

4. NovaStorage 上传组件使用

import { UploadComponent, UploadResult } from '../shared/components/upload-component/upload.component';

@Component({
  standalone: true,
  imports: [UploadComponent]
})
export class MyComponent {
  async onUploadComplete(results: UploadResult[]) {
    // 处理上传结果
    for (const result of results) {
      if (result.success && result.file) {
        console.log('上传成功:', result.file.url);
        // 保存文件信息到数据库
        await this.saveFileInfo(result.file);
      }
    }
  }

  async onUploadError(error: string) {
    console.error('上传失败:', error);
  }

  private async saveFileInfo(file: NovaFile) {
    // 保存文件信息到 Attachment 表或其他相关表
    console.log('保存文件:', file.key, file.url);
  }
}

错误处理

所有数据操作都包含错误处理,在API调用失败时会自动降级到模拟数据:

try {
  await this.loadDashboardData();
} catch (error) {
  console.error('❌ 数据加载失败:', error);
  // 降级到模拟数据
  this.loadMockData();
}

注意事项

  1. 认证配置: 确保 cid: 'cDL6R1hgSi'WxworkSDK.companyMap 中有对应配置
  2. 数据表名: 确保后端数据表名与代码中使用的表名一致
  3. 权限设置: 确保企业微信用户有相应的数据访问权限
  4. NovaStorage: 使用 NovaStorage.withCid(cid) 自动初始化,无需手动配置 Provider
  5. 文件路径: 自动生成格式 storage/company/<cid>/<prefixKey>/<YYYYMMDD>/<HHmmss-rand>-<name>
  6. 文件大小: 默认上传文件大小限制为 10MB,可在组件中自定义
  7. prefixKey: 通过 prefixKey 参数指定文件存储路径前缀,如 'project/pid/'

后续优化建议

  1. 缓存机制: 为频繁查询的数据添加缓存
  2. 实时更新: 使用 WebSocket 实现数据实时更新
  3. 离线支持: 添加离线数据存储和同步功能
  4. 批量操作: 优化批量数据操作的性能
  5. 权限细化: 根据用户角色实现更细粒度的数据访问控制