# 微信认证API开发说明手册

## 概述

本文档为前端开发工程师提供微信认证相关API的详细使用说明，包括路由路径、请求参数、响应格式、错误码说明以及前端示例代码。

**重要说明**：本系统已升级为符合微信官方规范的授权流程，使用15分钟有效期的微信授权码换取长期有效的openid作为用户唯一标识。

## 微信授权流程说明

1. **前端获取授权码**：通过微信小程序API获取临时授权码（15分钟有效期）
2. **后端换取openid**：使用授权码调用微信API获取用户openid
3. **用户身份管理**：以openid作为用户唯一标识进行注册、登录等操作

## 基础信息

- **API基础路径**: `/api/parse`
- **Content-Type**: `application/json`
- **字符编码**: `UTF-8`
- **响应格式**: JSON

## 统一响应格式

所有API接口都遵循统一的JSON响应格式：

```json
{
  "reason": "successed|failed",
  "return_code": 200,
  "result": {
    // 具体数据对象
  },
  "error": "错误信息（仅在失败时返回）"
}
```

## HTTP状态码说明

| 状态码 | 说明 |
|--------|------|
| 200 | 请求成功 |
| 201 | 创建成功 |
| 400 | 请求参数错误 |
| 401 | 认证失败 |
| 404 | 资源不存在 |
| 409 | 资源冲突（如用户已存在） |
| 500 | 服务器内部错误 |

---

## 1. 用户注册

### 接口信息
- **路径**: `POST /api/parse/wechat-register`
- **功能**: 注册新的微信用户
- **认证**: 无需认证

### 请求参数

| 参数名 | 类型 | 必填 | 说明 | 示例 |
|--------|------|------|------|------|
| wechat_code | string | 是 | 微信授权码（15分钟有效期） | "wx_code_12345abcde" |
| phone_number | string | 否 | 手机号码 | "13800138000" |
| id_card_number | string | 否 | 身份证号码 | "110101199001011234" |
| platform | string | 否 | 微信平台类型，默认为小程序 | "miniprogram" |

### 请求示例

```json
{
  "wechat_code": "wx_code_12345abcde",
  "phone_number": "13800138000",
  "id_card_number": "110101199001011234",
  "platform": "miniprogram"
}
```

### 响应示例

#### 成功响应 (201)
```json
{
  "reason": "successed",
  "return_code": 201,
  "result": {
    "id": "1",
    "openid": "wx_openid_abcd1234567890123456",
    "phone_number": "13800138000",
    "id_card_number": "110101199001011234",
    "login_status": false,
    "user_status": "active",
    "created_at": "2024-01-15T10:30:00+08:00"
  }
}
```

#### 失败响应 (409)
```json
{
  "reason": "failed",
  "return_code": 409,
  "result": null,
  "error": "用户已存在，openid: wx_openid_abcd1234567890123456"
}
```

### 前端示例代码

#### JavaScript (Fetch API)
```javascript
async function registerWechatUser(wechatCode, phoneNumber = null, idCardNumber = null, platform = 'miniprogram') {
  try {
    const response = await fetch('/api/parse/wechat-register', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        wechat_code: wechatCode,
        phone_number: phoneNumber,
        id_card_number: idCardNumber,
        platform: platform
      })
    });
    
    const data = await response.json();
    
    if (data.return_code === 201) {
      console.log('注册成功:', data.result);
      return { success: true, data: data.result };
    } else {
      console.error('注册失败:', data.error);
      return { success: false, error: data.error };
    }
  } catch (error) {
    console.error('网络错误:', error);
    return { success: false, error: '网络请求失败' };
  }
}

// 使用示例
registerWechatUser('wx_code_12345abcde', '13800138000', '110101199001011234')
  .then(result => {
    if (result.success) {
      // 注册成功处理
      alert('注册成功！');
    } else {
      // 注册失败处理
      alert('注册失败: ' + result.error);
    }
  });
```

#### jQuery
```javascript
function registerWechatUser(wechatCode, phoneNumber, idCardNumber) {
  $.ajax({
    url: '/api/parse/wechat-register',
    type: 'POST',
    contentType: 'application/json',
    data: JSON.stringify({
      wechat_code: wechatCode,
      phone_number: phoneNumber,
      id_card_number: idCardNumber
    }),
    success: function(data) {
      if (data.return_code === 201) {
        console.log('注册成功:', data.result);
        alert('注册成功！');
      } else {
        console.error('注册失败:', data.error);
        alert('注册失败: ' + data.error);
      }
    },
    error: function(xhr, status, error) {
      console.error('请求失败:', error);
      alert('网络请求失败');
    }
  });
}
```

---

## 2. 用户登录

### 接口信息
- **路径**: `POST /api/parse/wechat-login`
- **功能**: 微信用户登录，通过授权码获取openid并更新登录状态和时间
- **认证**: 无需认证

### 请求参数

| 参数名 | 类型 | 必填 | 说明 | 示例 |
|--------|------|------|------|------|
| wechat_code | string | 是 | 微信授权码（15分钟有效期） | "wx_code_12345abcde" |
| platform | string | 否 | 微信平台类型，默认为小程序 | "miniprogram" |

### 请求示例

```json
{
  "wechat_code": "wx_code_12345abcde",
  "platform": "miniprogram"
}
```

### 响应示例

#### 成功响应 (200)
```json
{
  "reason": "successed",
  "return_code": 200,
  "result": {
    "id": "1",
    "openid": "wx_openid_abcd1234567890123456",
    "phone_number": "13800138000",
    "id_card_number": "110101199001011234",
    "login_status": true,
    "login_time": "2024-01-15T14:30:00+08:00",
    "user_status": "active"
  }
}
```

#### 失败响应 (401)
```json
{
  "reason": "failed",
  "return_code": 401,
  "result": null,
  "error": "用户不存在或账户状态异常"
}
```

### 前端示例代码

#### JavaScript (Fetch API)
```javascript
async function loginWechatUser(wechatCode, platform = 'miniprogram') {
  try {
    const response = await fetch('/api/parse/wechat-login', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        wechat_code: wechatCode,
        platform: platform
      })
    });
    
    const data = await response.json();
    
    if (data.return_code === 200) {
      console.log('登录成功:', data.result);
      // 保存用户信息到本地存储
      localStorage.setItem('wechat_user', JSON.stringify(data.result));
      return { success: true, data: data.result };
    } else {
      console.error('登录失败:', data.error);
      return { success: false, error: data.error };
    }
  } catch (error) {
    console.error('网络错误:', error);
    return { success: false, error: '网络请求失败' };
  }
}

// 使用示例
loginWechatUser('wx_code_12345abcde')
  .then(result => {
    if (result.success) {
      // 登录成功处理
      window.location.href = '/dashboard';
    } else {
      // 登录失败处理
      alert('登录失败: ' + result.error);
    }
  });
```

#### Axios
```javascript
import axios from 'axios';

async function loginWechatUser(wechatCode) {
  try {
    const response = await axios.post('/api/parse/wechat-login', {
      wechat_code: wechatCode
    });
    
    if (response.data.return_code === 200) {
      // 登录成功
      return { success: true, data: response.data.result };
    } else {
      return { success: false, error: response.data.error };
    }
  } catch (error) {
    console.error('登录请求失败:', error);
    return { success: false, error: '网络请求失败' };
  }
}
```

---

## 3. 用户登出

### 接口信息
- **路径**: `POST /api/parse/wechat-logout`
- **功能**: 微信用户登出，更新登录状态
- **认证**: 无需认证

### 请求参数

| 参数名 | 类型 | 必填 | 说明 | 示例 |
|--------|------|------|------|------|
| openid | string | 是 | 微信用户openid | "wx_openid_abcd1234567890123456" |

### 请求示例

```json
{
  "openid": "wx_openid_abcd1234567890123456"
}
```

### 响应示例

#### 成功响应 (200)
```json
{
  "reason": "successed",
  "return_code": 200,
  "result": {
    "message": "用户已成功登出"
  }
}
```

#### 失败响应 (404)
```json
{
  "reason": "failed",
  "return_code": 404,
  "result": null,
  "error": "用户不存在"
}
```

### 前端示例代码

#### JavaScript (Fetch API)
```javascript
async function logoutWechatUser(openid) {
  try {
    const response = await fetch('/api/parse/wechat-logout', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        openid: openid
      })
    });
    
    const data = await response.json();
    
    if (data.return_code === 200) {
      console.log('登出成功');
      // 清除本地存储的用户信息
      localStorage.removeItem('wechat_user');
      return { success: true };
    } else {
      console.error('登出失败:', data.error);
      return { success: false, error: data.error };
    }
  } catch (error) {
    console.error('网络错误:', error);
    return { success: false, error: '网络请求失败' };
  }
}

// 使用示例
logoutWechatUser('wx_openid_abcd1234567890123456')
  .then(result => {
    if (result.success) {
      // 登出成功处理
      window.location.href = '/login';
    } else {
      // 登出失败处理
      console.error('登出失败:', result.error);
    }
  });
```

---

## 4. 获取用户信息

### 接口信息
- **路径**: `GET /api/parse/wechat-user`
- **功能**: 获取指定微信用户的详细信息
- **认证**: 无需认证

### 请求参数

| 参数名 | 类型 | 必填 | 传递方式 | 说明 | 示例 |
|--------|------|------|----------|------|------|
| openid | string | 是 | Query参数 | 微信用户openid | "wx_openid_abcd1234567890123456" |

### 请求示例

```
GET /api/parse/wechat-user?openid=wx_openid_abcd1234567890123456
```

### 响应示例

#### 成功响应 (200)
```json
{
  "reason": "successed",
  "return_code": 200,
  "result": {
    "id": "1",
    "openid": "wx_openid_abcd1234567890123456",
    "phone_number": "13800138000",
    "id_card_number": "110101199001011234",
    "login_status": true,
    "login_time": "2024-01-15T14:30:00+08:00",
    "user_status": "active",
    "created_at": "2024-01-15T10:30:00+08:00",
    "updated_at": "2024-01-15T14:30:00+08:00"
  }
}
```

#### 失败响应 (404)
```json
{
  "reason": "failed",
  "return_code": 404,
  "result": null,
  "error": "未找到openid为 wx_openid_abcd1234567890123456 的用户"
}
```

### 前端示例代码

#### JavaScript (Fetch API)
```javascript
async function getWechatUserInfo(openid) {
  try {
    const url = `/api/parse/wechat-user?openid=${encodeURIComponent(openid)}`;
    const response = await fetch(url, {
      method: 'GET',
      headers: {
        'Content-Type': 'application/json',
      }
    });
    
    const data = await response.json();
    
    if (data.return_code === 200) {
      console.log('获取用户信息成功:', data.result);
      return { success: true, data: data.result };
    } else {
      console.error('获取用户信息失败:', data.error);
      return { success: false, error: data.error };
    }
  } catch (error) {
    console.error('网络错误:', error);
    return { success: false, error: '网络请求失败' };
  }
}

// 使用示例
getWechatUserInfo('wx_openid_abcd1234567890123456')
  .then(result => {
    if (result.success) {
      // 显示用户信息
      displayUserInfo(result.data);
    } else {
      // 处理错误
      alert('获取用户信息失败: ' + result.error);
    }
  });

function displayUserInfo(userInfo) {
  document.getElementById('user-id').textContent = userInfo.id;
  document.getElementById('user-phone').textContent = userInfo.phone_number || '未设置';
  document.getElementById('user-status').textContent = userInfo.login_status ? '在线' : '离线';
}
```

#### jQuery
```javascript
function getWechatUserInfo(openid) {
  $.ajax({
    url: '/api/parse/wechat-user',
    type: 'GET',
    data: { openid: openid },
    success: function(data) {
      if (data.return_code === 200) {
        console.log('获取用户信息成功:', data.result);
        displayUserInfo(data.result);
      } else {
        console.error('获取用户信息失败:', data.error);
        alert('获取用户信息失败: ' + data.error);
      }
    },
    error: function(xhr, status, error) {
      console.error('请求失败:', error);
      alert('网络请求失败');
    }
  });
}
```

---

## 5. 更新用户信息

### 接口信息
- **路径**: `PUT /api/parse/wechat-user`
- **功能**: 更新微信用户的个人信息
- **认证**: 无需认证

### 请求参数

| 参数名 | 类型 | 必填 | 说明 | 示例 |
|--------|------|------|------|------|
| openid | string | 是 | 微信用户openid | "wx_openid_abcd1234567890123456" |
| phone_number | string | 否 | 要更新的手机号码 | "13900139000" |
| id_card_number | string | 否 | 要更新的身份证号码 | "110101199001011234" |

### 请求示例

```json
{
  "openid": "wx_openid_abcd1234567890123456",
  "phone_number": "13900139000",
  "id_card_number": "110101199001011234"
}
```

### 响应示例

#### 成功响应 (200)
```json
{
  "reason": "successed",
  "return_code": 200,
  "result": {
    "id": "1",
    "openid": "wx_openid_abcd1234567890123456",
    "phone_number": "13900139000",
    "id_card_number": "110101199001011234",
    "login_status": true,
    "login_time": "2024-01-15T14:30:00+08:00",
    "user_status": "active",
    "created_at": "2024-01-15T10:30:00+08:00",
    "updated_at": "2024-01-15T16:45:00+08:00"
  }
}
```

#### 失败响应 (404)
```json
{
  "reason": "failed",
  "return_code": 404,
  "result": null,
  "error": "未找到openid为 wx_openid_abcd1234567890123456 的用户"
}
```

### 前端示例代码

#### JavaScript (Fetch API)
```javascript
async function updateWechatUserInfo(openid, updateData) {
  try {
    const requestData = {
      openid: openid,
      ...updateData
    };
    
    const response = await fetch('/api/parse/wechat-user', {
      method: 'PUT',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify(requestData)
    });
    
    const data = await response.json();
    
    if (data.return_code === 200) {
      console.log('更新用户信息成功:', data.result);
      return { success: true, data: data.result };
    } else {
      console.error('更新用户信息失败:', data.error);
      return { success: false, error: data.error };
    }
  } catch (error) {
    console.error('网络错误:', error);
    return { success: false, error: '网络请求失败' };
  }
}

// 使用示例
const updateData = {
  phone_number: '13900139000',
  id_card_number: '110101199001011234'
};

updateWechatUserInfo('wx_openid_abcd1234567890123456', updateData)
  .then(result => {
    if (result.success) {
      // 更新成功处理
      alert('信息更新成功！');
      // 更新页面显示的用户信息
      displayUserInfo(result.data);
    } else {
      // 更新失败处理
      alert('更新失败: ' + result.error);
    }
  });
```

#### Vue.js 示例
```javascript
// 在Vue组件中使用
export default {
  data() {
    return {
      userForm: {
        openid: 'wx_openid_abcd1234567890123456',
        phoneNumber: '',
        idCardNumber: ''
      },
      loading: false
    };
  },
  methods: {
    async updateUserInfo() {
      this.loading = true;
      
      try {
        const response = await fetch('/api/parse/wechat-user', {
          method: 'PUT',
          headers: {
            'Content-Type': 'application/json',
          },
          body: JSON.stringify({
            openid: this.userForm.openid,
            phone_number: this.userForm.phoneNumber,
            id_card_number: this.userForm.idCardNumber
          })
        });
        
        const data = await response.json();
        
        if (data.return_code === 200) {
          this.$message.success('信息更新成功！');
          // 更新本地用户数据
          this.updateLocalUserData(data.result);
        } else {
          this.$message.error('更新失败: ' + data.error);
        }
      } catch (error) {
        this.$message.error('网络请求失败');
        console.error('更新用户信息失败:', error);
      } finally {
        this.loading = false;
      }
    },
    
    updateLocalUserData(userData) {
      // 更新本地存储的用户数据
      localStorage.setItem('wechat_user', JSON.stringify(userData));
    }
  }
};
```

---

## 前端集成指南

### 微信小程序获取授权码

在微信小程序中，需要先获取授权码，然后传递给后端API：

```javascript
// 微信小程序端代码
wx.login({
  success: function(res) {
    if (res.code) {
      // 将授权码发送给后端
      const wechatCode = res.code;
      
      // 调用注册或登录API
      registerOrLogin(wechatCode);
    } else {
      console.error('获取微信授权码失败');
    }
  },
  fail: function(err) {
    console.error('微信登录失败:', err);
  }
});

// 注册或登录函数
async function registerOrLogin(wechatCode) {
  // 先尝试登录
  const loginResult = await loginWechatUser(wechatCode);
  
  if (loginResult.success) {
    // 登录成功，保存用户信息
    wx.setStorageSync('user_info', loginResult.data);
    wx.showToast({ title: '登录成功', icon: 'success' });
  } else if (loginResult.error && loginResult.error.includes('不存在')) {
    // 用户不存在，尝试注册
    wx.showModal({
      title: '首次使用',
      content: '检测到您是首次使用，是否注册账号？',
      success: async function(modalRes) {
        if (modalRes.confirm) {
          const registerResult = await registerWechatUser(wechatCode);
          if (registerResult.success) {
            wx.setStorageSync('user_info', registerResult.data);
            wx.showToast({ title: '注册成功', icon: 'success' });
          } else {
            wx.showToast({ title: '注册失败', icon: 'error' });
          }
        }
      }
    });
  } else {
    wx.showToast({ title: '登录失败', icon: 'error' });
  }
}
```

### 用户状态管理

```javascript
// 检查用户登录状态
function checkUserLoginStatus() {
  const userInfo = wx.getStorageSync('user_info');
  if (userInfo && userInfo.openid) {
    // 验证用户状态是否仍然有效
    return getWechatUserInfo(userInfo.openid)
      .then(result => {
        if (result.success && result.data.login_status) {
          return { isLoggedIn: true, userInfo: result.data };
        } else {
          // 清除无效的本地数据
          wx.removeStorageSync('user_info');
          return { isLoggedIn: false };
        }
      });
  }
  return Promise.resolve({ isLoggedIn: false });
}

// 用户登出
async function logoutUser() {
  const userInfo = wx.getStorageSync('user_info');
  if (userInfo && userInfo.openid) {
    const result = await logoutWechatUser(userInfo.openid);
    if (result.success) {
      wx.removeStorageSync('user_info');
      wx.showToast({ title: '已退出登录', icon: 'success' });
      // 跳转到登录页面
      wx.redirectTo({ url: '/pages/login/login' });
    }
  }
}
```

### 环境配置

确保在不同环境中正确配置API基础路径：

```javascript
// config.js
const config = {
  development: {
    apiBaseUrl: 'http://localhost:5000/api/parse'
  },
  production: {
    apiBaseUrl: 'https://your-domain.com/api/parse'
  }
};

const currentEnv = 'development'; // 根据实际环境设置
export const API_BASE_URL = config[currentEnv].apiBaseUrl;

// 在API调用中使用
async function registerWechatUser(wechatCode, phoneNumber, idCardNumber, platform = 'miniprogram') {
  const response = await fetch(`${API_BASE_URL}/wechat-register`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      wechat_code: wechatCode,
      phone_number: phoneNumber,
      id_card_number: idCardNumber,
      platform: platform
    })
  });
  return response.json();
}
```

---

## 错误处理最佳实践

### 1. 统一错误处理函数

```javascript
function handleApiError(data) {
  const errorMessages = {
    400: '请求参数错误',
    401: '认证失败',
    404: '资源不存在',
    409: '资源冲突',
    500: '服务器内部错误'
  };
  
  const message = data.error || errorMessages[data.return_code] || '未知错误';
  return message;
}

// 使用示例
async function apiCall() {
  try {
    const response = await fetch('/api/parse/wechat-login', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ wechat_code: 'test' })
    });
    
    const data = await response.json();
    
    if (data.return_code === 200) {
      return { success: true, data: data.result };
    } else {
      const errorMessage = handleApiError(data);
      return { success: false, error: errorMessage };
    }
  } catch (error) {
    return { success: false, error: '网络连接失败' };
  }
}
```

### 2. 请求重试机制

```javascript
async function apiCallWithRetry(url, options, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      const response = await fetch(url, options);
      const data = await response.json();
      
      // 如果是服务器错误且还有重试次数，则重试
      if (data.return_code === 500 && i < maxRetries - 1) {
        await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1))); // 递增延迟
        continue;
      }
      
      return data;
    } catch (error) {
      if (i === maxRetries - 1) throw error;
      await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1)));
    }
  }
}
```

### 3. 请求拦截器示例 (Axios)

```javascript
import axios from 'axios';

// 创建axios实例
const apiClient = axios.create({
  baseURL: '/api/parse',
  timeout: 10000,
  headers: {
    'Content-Type': 'application/json'
  }
});

// 响应拦截器
apiClient.interceptors.response.use(
  response => {
    const data = response.data;
    
    if (data.return_code >= 200 && data.return_code < 300) {
      return data;
    } else {
      return Promise.reject(new Error(data.error || '请求失败'));
    }
  },
  error => {
    console.error('API请求失败:', error);
    return Promise.reject(error);
  }
);

// 使用示例
async function loginUser(wechatCode) {
  try {
    const data = await apiClient.post('/wechat-login', {
      wechat_code: wechatCode
    });
    return { success: true, data: data.result };
  } catch (error) {
    return { success: false, error: error.message };
  }
}
```

---

## 常见问题 (FAQ)

### Q1: 如何处理网络超时？
A: 建议设置合理的超时时间（如10秒），并提供重试机制：

```javascript
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 10000);

fetch('/api/parse/wechat-login', {
  signal: controller.signal,
  // ... 其他选项
}).finally(() => {
  clearTimeout(timeoutId);
});
```

### Q2: 如何存储用户登录状态？
A: 建议使用localStorage或sessionStorage存储用户信息：

```javascript
// 登录成功后存储
localStorage.setItem('wechat_user', JSON.stringify(userData));

// 检查登录状态
function isUserLoggedIn() {
  const user = localStorage.getItem('wechat_user');
  return user && JSON.parse(user).login_status;
}

// 登出时清除
localStorage.removeItem('wechat_user');
```

### Q3: 如何处理并发请求？
A: 对于同一用户的多个请求，建议使用请求队列或防抖机制：

```javascript
let pendingRequest = null;

async function loginWithDebounce(wechatCode) {
  if (pendingRequest) {
    return pendingRequest;
  }
  
  pendingRequest = loginWechatUser(wechatCode);
  
  try {
    const result = await pendingRequest;
    return result;
  } finally {
    pendingRequest = null;
  }
}
```

### Q4: 如何实现自动重新登录？
A: 可以在应用启动时检查本地存储的用户信息并验证：

```javascript
async function autoLogin() {
  const storedUser = localStorage.getItem('wechat_user');
  if (!storedUser) return false;
  
  const userData = JSON.parse(storedUser);
  
  // 验证用户状态是否仍然有效
  const result = await getWechatUserInfo(userData.wechat_code);
  
  if (result.success && result.data.login_status) {
    return true;
  } else {
    // 清除无效的本地数据
    localStorage.removeItem('wechat_user');
    return false;
  }
}

// 应用启动时调用
autoLogin().then(isLoggedIn => {
  if (isLoggedIn) {
    // 跳转到主页面
    window.location.href = '/dashboard';
  } else {
    // 跳转到登录页面
    window.location.href = '/login';
  }
});
```

---

## 版本信息

- **文档版本**: v2.0.0
- **API版本**: v2.0.0  
- **最后更新**: 2025-01-15
- **维护者**: DataOps团队
- **更新内容**: 升级为基于openid的微信认证系统，符合微信官方授权规范

## 环境配置要求

### 后端环境变量

在部署前，请确保设置以下环境变量：

```bash
# 微信小程序配置（必需）
WECHAT_MINIPROGRAM_APP_ID=your_miniprogram_app_id_here
WECHAT_MINIPROGRAM_APP_SECRET=your_miniprogram_app_secret_here

# 微信公众号配置（可选）
WECHAT_OFFICIAL_APP_ID=your_official_account_app_id_here  
WECHAT_OFFICIAL_APP_SECRET=your_official_account_app_secret_here

# 数据库配置
DATABASE_URL=postgresql://username:password@localhost:5432/dataops_db
```

### 数据库初始化

首次部署时，请执行以下SQL脚本：

```bash
# 创建微信用户表
psql -U username -d database_name -f database/create_wechat_users.sql

# 如果从旧版本升级，执行迁移脚本
psql -U username -d database_name -f database/migrate_wechat_code_to_openid.sql
```

---

## 联系支持

如有问题或建议，请联系：
- **技术支持**: tech-support@dataops.com
- **API文档**: https://docs.dataops.com/api
- **GitHub**: https://github.com/dataops/platform
