system-implementation.md 10 KB

智能打标系统第三方对接实现指南

概述

本文档详细说明 智能打标 系统如何实现与第三方系统的对接功能,包括路由配置、消息处理、数据验证等系统内部实现细节。

路由配置

1. 路由白名单配置

文件路径/src/router/router-filter.js

配置内容

const whiteList = ['/login', '/forgetPwd', '/about', '/externalPage'];

说明:将 /externalPage 添加到白名单,确保第三方系统可以直接访问该页面而不需要登录。

2. 路由定义

文件路径/src/router/index.js

配置内容

{
  path: '/externalPage',
  component: () => import('@/views/aiTagging/externalPage/index.vue'),
  meta: {
    title: '外部打标页面',
    noCache: true
  }
}

页面实现

1. 主页面结构

文件路径/src/views/aiTagging/externalPage/index.vue

核心功能

  • 页面加载完成后发送 externalPageLoaded 消息
  • 监听并处理第三方系统发送的 externalParams 消息
  • 验证数据完整性并发送 externalParamsReceived 确认消息
  • 显示数据接收状态和加载状态

2. 消息处理逻辑

初始化消息监听器

mounted() {
  // 监听来自第三方系统的消息
  window.addEventListener('message', this.handleMessage);
  
  // 页面加载完成后发送加载完成消息
  this.sendPageLoadedMessage();
},

beforeDestroy() {
  // 清理事件监听器
  window.removeEventListener('message', this.handleMessage);
}

页面加载完成消息

sendPageLoadedMessage() {
  const message = {
    type: 'externalPageLoaded',
    loadedAt: Date.now(),
    status: 'ready'
  };
  
  // 发送消息给父窗口(iframe 方式)
  if (window.parent !== window) {
    window.parent.postMessage(message, '*');
  }
}

处理第三方系统消息

handleMessage(event) {
  const data = event.data;
  
  if (data && data.type === 'externalParams') {
    this.processExternalParams(data);
  }
}

processExternalParams(params) {
  // 验证必填字段
  const missingFields = this.validateRequiredFields(params);
  
  if (missingFields.length > 0) {
    // 数据不完整,显示错误信息
    this.loadingStatus = 'error';
    this.errorMessage = '数据接收不完整,请检查缺失字段';
    this.missingFields = missingFields;
    this.receivedData = params;
  } else {
    // 数据完整,开始处理
    this.loadingStatus = 'processing';
    this.receivedData = params;
    
    // 存储参数
    this.businessAttr = params.business_attr;
    this.userData = {
      user_id: params.user_id,
      user_nm: params.user_nm,
      user_org: params.user_org || '',
      user_endpoint: params.user_endpoint || '',
      contract_no: params.contract_no || ''
    };
    
    // 发送确认消息
    this.sendConfirmationMessage(params);
    
    // 调用业务属性查询
    this.queryBusinessAttr();
  }
}

发送确认消息

sendConfirmationMessage(originalData) {
  const message = {
    type: 'externalParamsReceived',
    originalData: originalData,
    receivedAt: Date.now(),
    status: 'success'
  };
  
  // 发送消息给父窗口(iframe 方式)
  if (window.parent !== window) {
    window.parent.postMessage(message, '*');
  }
}

数据验证

1. 必填字段验证

验证函数

validateRequiredFields(params) {
  const missingFields = [];
  
  if (!params.business_attr) {
    missingFields.push('贷款申请编号');
  }
  
  if (!params.user_id) {
    missingFields.push('用户ID');
  }
  
  if (!params.user_nm) {
    missingFields.push('用户姓名');
  }
  
  if (!params.user_org) {
    missingFields.push('所属机构');
  }
  
  if (!params.user_endpoint) {
    missingFields.push('所属行社');
  }
  
  if (!params.contract_no) {
    missingFields.push('合同编号');
  }
  
  return missingFields;
}

API 调用

1. 业务属性查询

配置说明:API 请求不需要携带 token,需要设置 needToken: false

实现代码

queryBusinessAttr() {
  yufp.service.request({
    url: backend.tagServer + "/api/fastapi/query",
    method: 'get',
    data: {
      businessAttr: this.businessAttr
    },
    needToken: false,  // 确保设置为 false
    callback: (code, error, response) => {
      if (response.code == '0') {
        // 处理成功响应
        this.loadingStatus = 'success';
        this.taggingData = response.data;
      } else {
        // 处理错误
        this.loadingStatus = 'error';
        this.errorMessage = response.message || '查询业务属性失败';
      }
    }
  });
}

加载状态管理

1. 状态定义

data() {
  return {
    // 加载状态:loading, success, error, idle
    loadingStatus: 'idle',
    // 错误信息
    errorMessage: '',
    // 缺失字段
    missingFields: [],
    // 接收到的数据
    receivedData: {},
    // 业务属性
    businessAttr: '',
    // 用户数据
    userData: {},
    // 打标数据
    taggingData: {}
  };
}

2. 状态显示

加载中

<div v-if="loadingStatus === 'loading'" class="loading-container">
  <el-icon class="is-loading"><loading /></el-icon>
  <span>数据加载中...</span>
</div>

数据不完整

<div v-else-if="loadingStatus === 'error'" class="error-container">
  <el-alert
    title="数据接收不完整"
    type="error"
    :closable="false"
    show-icon
  >
    <div class="error-content">
      <p>{{ errorMessage }}</p>
      <div v-if="missingFields.length > 0" class="missing-fields">
        <span class="missing-label">缺失字段:</span>
        <el-tag v-for="field in missingFields" :key="field" type="danger" size="small">
          {{ field }}
        </el-tag>
      </div>
      <div v-if="Object.keys(receivedData).length > 0" class="received-data">
        <span class="received-label">已接收数据:</span>
        <pre>{{ JSON.stringify(receivedData, null, 2) }}</pre>
      </div>
    </div>
  </el-alert>
</div>

加载成功

<div v-else-if="loadingStatus === 'success'" class="success-container">
  <!-- 打标结果展示 -->
  <TaggingResult :tagging-data="taggingData" />
</div>

样式优化

1. 响应式布局

.external-page-container {
  min-height: 100vh;
  background-color: #f5f7fa;
  display: flex;
  flex-direction: column;
}

.content-wrapper {
  flex: 1;
  display: flex;
  flex-direction: column;
  padding: 20px;
}

.loading-container,
.error-container,
.success-container {
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  padding: 40px;
  background-color: #fff;
  border-radius: 4px;
  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
}

2. 滚动支持

确保 iframe 内容可以滚动

<iframe 
  src="http://your-domain.com/#/externalPage" 
  frameborder="0" 
  width="100%" 
  height="100%" 
  scrolling="auto"
></iframe>

错误处理

1. 网络错误处理

// 渐进式超时机制
const timeouts = [5000, 10000, 15000];
let currentTimeoutIndex = 0;

function checkPageLoaded() {
  if (pageLoaded) {
    return;
  }
  
  if (currentTimeoutIndex < timeouts.length) {
    setTimeout(() => {
      if (!pageLoaded) {
        showLoadingMessage(`页面加载中,已等待 ${timeouts[currentTimeoutIndex] / 1000} 秒...`);
        currentTimeoutIndex++;
        checkPageLoaded();
      }
    }, timeouts[currentTimeoutIndex]);
  } else {
    showErrorMessage('页面加载超时,请刷新重试');
  }
}

2. 消息处理错误

handleMessage(event) {
  try {
    const data = event.data;
    
    if (data && data.type === 'externalParams') {
      this.processExternalParams(data);
    }
  } catch (error) {
    console.error('处理消息时发生错误:', error);
    this.loadingStatus = 'error';
    this.errorMessage = '处理数据时发生错误';
  }
}

性能优化

1. 页面加载优化

  • 懒加载:使用 Vue 的异步组件
  • 资源压缩:压缩静态资源文件
  • 缓存策略:合理设置缓存策略

2. 通信优化

  • 消息批处理:合并多次消息为一次发送
  • 消息过滤:只处理必要的消息类型
  • 错误重试:实现自动重试机制

安全措施

1. 消息来源验证

// 验证消息来源
const trustedOrigins = ['https://trusted-third-party.com'];

window.addEventListener('message', (event) => {
  // 验证消息来源
  if (!trustedOrigins.includes(event.origin)) {
    console.warn('来自未知来源的消息:', event.origin);
    return;
  }
  
  // 处理消息
});

2. 数据验证

  • 输入验证:验证所有输入数据的合法性
  • 防 XSS:对用户输入进行转义处理
  • 数据脱敏:敏感数据脱敏处理

调试工具

1. 日志记录

// 详细的日志记录
console.log('页面加载完成,发送消息:', message);
console.log('接收到第三方消息:', event.data);
console.log('消息来源:', event.origin);
console.log('数据验证结果:', missingFields);

2. 开发模式提示

if (process.env.NODE_ENV === 'development') {
  console.log('开发模式:第三方对接功能');
  // 模拟数据
  setTimeout(() => {
    this.processExternalParams({
      type: 'externalParams',
      business_attr: 'TEST2024001',
      user_id: 'testuser001',
      user_nm: '测试用户',
      user_org: '测试机构',
      user_endpoint: '测试分行',
      contract_no: 'TESTCONTRACT001',
      timestamp: Date.now(),
      source: 'testSystem'
    });
  }, 1000);
}

版本兼容性

当前版本特性

  • ✅ 支持 iframe 和新窗口两种方式
  • ✅ 完整的消息通信协议
  • ✅ 必填字段验证
  • ✅ 渐进式超时机制
  • ✅ 错误处理和状态反馈
  • ✅ 支持 iframe 滚动

向后兼容

系统设计考虑了向后兼容性,新增消息类型不会影响现有功能。

更新日志

v1.0 (当前版本)

  • 初始版本发布
  • 实现完整的第三方对接功能
  • 支持 iframe 和新窗口两种方式
  • 完善的错误处理机制
  • 新增数据接收状态反馈功能
  • 实现 iframe 滚动支持
  • 补充详细的配置示例和最佳实践

本文档最后更新:2026年3月17日