npm package: @g7e6-fe/g7-tracker-h5
Description: H5地图定位数据收集上报SDK，支持微信js-sdk集成
Latest version: 1.2.6

# G7 Tracker H5 SDK

H5 地图定位数据收集上报 SDK，支持微信 JS-SDK 集成。提供单例模式、队列上报、G7 签名加密、守护进程自动上报等功能。

## 特性

- 📍 **多种定位方式**：支持微信定位和 HTML5 定位，自动降级
- 🔐 **数据加密**：使用 SM2 加密和 HMAC-SHA256 签名
- 📦 **队列上报**：自动批量上报，支持守护进程自动重试
- 💾 **配置缓存**：配置和队列数据自动保存到 localStorage
- 📝 **日志记录**：支持多级别日志记录和调试
- 🎯 **单例模式**：全局唯一实例，统一管理
- ⚡ **重试机制**：支持网络失败自动重试（可配置）
- 🛡️ **守护进程**：自动处理失败数据，支持指数退避重试
- 📊 **性能监控**：自动记录上报耗时（prepareDuration）

## 安装

### NPM 安装

```bash
npm install @g7e6-fe/g7-tracker-h5
```

### 直接引入

```html
<script src="https://g7cdn-product.oss-cn-hangzhou.aliyuncs.com/fe-cdn/g7e6/g7Tracker/index.umd.js"></script>
```

## 快速开始

### 基础使用

```javascript
import G7Tracker from '@g7e6-fe/g7-tracker-h5'

// 初始化 SDK
const tracker = G7Tracker.init({
  appKey: 'your-app-key',
  appSecret: 'your-app-secret',
  environment: 'product', // 'sandbox' 或 'product'
  uuid: 'user-123', // 用户唯一标识（可选）
  isDebug: false, // 生产环境建议关闭调试
})

// 上报数据
tracker.track({
  type: 'arrive', // 操作类型
  thirdId: 'SF1234567890', // 第三方ID（运单号）
  orgCode: 'ORG001', // 组织代码
  extraData: {
    remark: '备注信息',
  },
  callback: result => {
    if (result.code === 0) {
      console.log('上报成功')
    } else {
      console.error('上报失败:', result.msg)
    }
  },
})
```

### 静态方法调用

```javascript
// 先初始化
G7Tracker.init({
  appKey: 'your-app-key',
  appSecret: 'your-app-secret',
  environment: 'product',
})

// 直接使用静态方法上报
G7Tracker.track({
  type: 'arrive',
  thirdId: 'SF1234567890',
  orgCode: 'ORG001',
  callback: result => {
    if (result.code === 0) {
      console.log('上报成功')
    } else {
      console.error('上报失败:', result.msg)
    }
  },
})
```

### 使用 async/await

```javascript
try {
  await G7Tracker.track({
    type: 'arrive',
    thirdId: 'SF1234567890',
    orgCode: 'ORG001',
  })
  console.log('上报成功')
} catch (error) {
  console.error('上报失败:', error.code, error.msg)
}
```

### 微信环境使用

```javascript
// 在微信环境中，确保已引入微信 JS-SDK
wx.ready(() => {
  G7Tracker.init({
    appKey: 'your-app-key',
    appSecret: 'your-app-secret',
    environment: 'product',
    wx: window.wx, // 传入微信对象
    uuid: 'user-123',
    isDebug: false,
  })

  G7Tracker.track({
    type: 'arrive',
    thirdId: 'SF1234567890',
    orgCode: 'ORG001',
  })
})
```

## API 文档

### 初始化

#### `G7Tracker.init(options)`

初始化 SDK 实例（单例模式）。

**参数：**

| 参数名           | 类型      | 是否必填 | 默认值      | 说明                                                                                                        |
| ---------------- | --------- | -------- | ----------- | ----------------------------------------------------------------------------------------------------------- |
| `appKey`         | `string`  | ✅ 必填  | -           | 应用密钥（Access ID），用于 API 签名认证                                                                    |
| `appSecret`      | `string`  | ✅ 必填  | -           | 应用密钥（Secret），用于 API 签名认证                                                                       |
| `environment`    | `string`  | ❌ 可选  | `'sandbox'` | 运行环境，可选值：`'sandbox'`（沙盒环境）、`'product'`（生产环境）                                          |
| `wx`             | `object`  | ❌ 可选  | `null`      | 微信对象（wx），在微信 webview 环境下使用，用于调用微信定位接口。如果为空，SDK 会使用 HTML5 Geolocation API |
| `uuid`           | `string`  | ❌ 可选  | `''`        | 用户唯一标识符（UUID），用于标识用户身份                                                                    |
| `headers`        | `object`  | ❌ 可选  | `{}`        | 自定义请求头，会合并到所有 API 请求的 headers 中                                                            |
| `isDebug`        | `boolean` | ❌ 可选  | `true`      | 是否开启调试模式：`true` 开启调试，会在控制台输出详细日志；`false` 关闭调试，仅输出错误日志                 |
| `debugTimeoutMs` | `number`  | ❌ 可选  | `5000`      | 调试模式下的请求超时时间（毫秒）                                                                            |

**返回：** `G7Tracker` 实例

**示例：**

```javascript
const tracker = G7Tracker.init({
  appKey: 'your-app-key',
  appSecret: 'your-app-secret',
  environment: 'product',
  uuid: 'user-123',
  isDebug: false,
})
```

**详细文档：** [init 方法入参说明](./init方法入参说明.md)

#### `G7Tracker.getInstance()`

获取已初始化的 SDK 实例。

**返回：** `G7Tracker` 实例或 `null`

### 数据上报

#### `G7Tracker.track(options)` / `tracker.track(options)`

主动上报数据。支持静态方法和实例方法两种调用方式。

**参数：**

| 参数名      | 类型       | 是否必填 | 默认值 | 说明                                                                              |
| ----------- | ---------- | -------- | ------ | --------------------------------------------------------------------------------- |
| `type`      | `string`   | ✅ 必填  | -      | 操作类型，用于标识业务操作类型（如：'pickup'、'delivery'、'sign' 等）             |
| `thirdId`   | `string`   | ✅ 必填  | -      | 第三方 ID（运单号），用于标识业务单据的唯一标识                                   |
| `orgCode`   | `string`   | ❌ 可选  | `''`   | 组织代码，用于标识数据所属的组织                                                  |
| `extraData` | `object`   | ❌ 可选  | `{}`   | 额外数据对象，可以包含业务相关的自定义字段，会合并到上报数据中                    |
| `callback`  | `function` | ❌ 可选  | -      | 回调函数，用于接收上报结果。回调参数格式：`{ code: number, msg: string \| null }` |

**回调参数：**

```typescript
interface CallbackResult {
  code: number // 错误码，0 表示成功
  msg: string | null // 错误信息，成功时为 null
}
```

**返回：** `Promise<void>`

**示例：**

```javascript
// 静态方法
G7Tracker.track({
  type: 'arrive',
  thirdId: 'SF1234567890',
  orgCode: 'ORG001',
  extraData: {
    driverName: '张三',
    vehicleNo: '京A12345',
  },
  callback: result => {
    if (result.code === 0) {
      console.log('上报成功')
    } else {
      console.error('上报失败:', result.msg)
    }
  },
})
```

### 配置管理

#### `G7Tracker.setConfig(newConfig)`

更新 SDK 配置。支持静态方法和实例方法两种调用方式。

**参数：**

| 参数名        | 类型     | 说明                            |
| ------------- | -------- | ------------------------------- |
| `appKey`      | `string` | 应用密钥（Access ID）           |
| `appSecret`   | `string` | 应用密钥（Secret）              |
| `environment` | `string` | 运行环境（'sandbox'/'product'） |

**说明：**

- 配置更新采用**合并策略**，只会更新传入的配置项，未传入的配置项保持不变
- 更新 `appKey`、`appSecret` 或 `environment` 后，会自动重新创建签名服务实例
- 更新后的配置会自动保存到 `localStorage`，下次初始化时会自动读取

**示例：**

```javascript
// 更新环境为生产环境
G7Tracker.setConfig({
  environment: 'product',
})
```

### 实例管理

#### `tracker.destroy()`

销毁 SDK 实例，清除队列、定时器和单例引用。

**示例：**

```javascript
tracker.destroy()
// 销毁后，下次调用 init() 会创建新实例
```

## 错误码

| 错误码 | 说明             | 备注                           |
| ------ | ---------------- | ------------------------------ |
| `0`    | 成功             | 数据上报成功，且定位信息有效   |
| `1001` | SDK 未初始化     | 需要先调用 `G7Tracker.init()`  |
| `2001` | 权限被拒绝       | 用户拒绝了位置权限请求         |
| `2003` | 隐私协议未同意   | 用户未同意隐私协议             |
| `2004` | 位置权限未授权   | 位置权限未授权                 |
| `3001` | 数据采集失败     | 位置数据采集失败（非权限问题） |
| `3002` | 位置采集失败     | 位置采集失败                   |
| `3003` | 数据不在队列中   | 数据不在队列中                 |
| `4001` | 上报失败         | 网络异常导致上报失败           |
| `4002` | 网络错误         | 网络错误                       |
| `4003` | 服务器错误       | 服务器错误                     |
| `5001` | 业务异常         | 接口返回但业务逻辑失败         |
| `5004` | 接口上报失败     | 接口上报失败                   |
| `9002` | type 参数无效    | `type` 参数为必填              |
| `9003` | thirdId 参数无效 | `thirdId` 参数为必填           |

## 上报机制

### 守护进程

SDK 内置守护进程，自动处理失败数据：

1. **初始化启动**：SDK 初始化时，如果队列中有缓存数据，会自动启动守护进程
2. **自动重试**：守护进程会尝试上报所有缓存数据.
3. **指数退避**：如果 3 次重试都失败，会按延迟时间（30s、1min、2min、3min、4min、5min）重新启动
4. **永久停止**：如果连续 5 分钟都失败，守护进程会永久停止

### 数据加密

上报数据使用以下加密方式：

- **SM2 加密**：对 `data` 字段进行 SM2 国密加密
- **HMAC-SHA256 签名**：使用 HMAC-SHA256 对请求进行签名
- **MD5 摘要**：对请求体计算 MD5 摘要

### 数据持久化

- **配置缓存**：配置自动保存到 `localStorage`（key: `G7Tracker_Config`）
- **队列缓存**：上报队列自动保存到 `localStorage`（key: `G7Tracker_Queue`）
- **自动恢复**：下次初始化时会自动恢复配置和队列数据

## 配置说明

### 默认配置

```javascript
{
  reportUrl: 'v2/api/router/waybill-app/sdk_service/report',
  headers: {},
  isDebug: true,
  maxLogs: 100,
  logLevels: ['error', 'warn', 'info'],
  uuid: '',
  appKey: '',
  appSecret: '',
  wx: null,
  environment: 'sandbox',
  debugTimeoutMs: 5000,
  enableRetry: false,
}
```

### 配置优先级

1. 用户传入的配置（最高优先级）
2. localStorage 缓存的配置
3. 默认配置（最低优先级）

## 日志系统

SDK 内置日志系统，支持以下日志级别：

- `error` - 错误日志
- `warn` - 警告日志
- `info` - 信息日志

**配置日志：**

```javascript
G7Tracker.init({
  isDebug: true, // 开启调试模式，会在 console 输出日志
  logLevels: ['error', 'warn', 'info'], // 设置记录的日志级别
  maxLogs: 200, // 设置最大日志数量
})
```

## 浏览器兼容性

- Chrome 60+
- Firefox 55+
- Safari 11+
- Edge 79+
- 微信内置浏览器
- 移动端浏览器

## 注意事项

1. **HTTPS 要求**：生产环境建议使用 HTTPS，某些浏览器 API 需要安全上下文
2. **定位权限**：需要用户授权地理位置权限
3. **微信环境**：在微信中使用时，需要先配置微信 JS-SDK，并传入 `wx` 对象
4. **单例模式**：SDK 使用单例模式，多次调用 `init()` 会返回同一实例
5. **配置缓存**：配置会自动保存到 localStorage，下次初始化时会自动恢复
6. **队列管理**：失败的数据会保留在队列中，由守护进程自动重试
7. **环境选择**：生产环境请使用 `environment: 'product'`，避免使用沙盒环境

### 构建

```bash
# 生产构建
yarn build

# 开发模式（监听文件变化）
yarn dev
```

### 许可证

MIT