// 简道云API服务 const axios = require('axios'); const config = require('../config/config'); class JiandaoyunService { constructor() { // 简道云API基础配置 this.baseUrl = 'https://api.jiandaoyun.com'; this.apiKey = config.jiandaoyun.apiKey; this.appId = config.jiandaoyun.appId; this.entryId = config.jiandaoyun.entryId; } // 提交数据到简道云表单 async submitDataToForm(data) { try { console.log('准备提交数据到简道云:', JSON.stringify(data, null, 2)); // 简道云API v1的正确请求格式 - 使用data_create端点 const url = `${this.baseUrl}/api/v1/app/${this.appId}/entry/${this.entryId}/data_create`; const headers = { 'Content-Type': 'application/json', 'Authorization': `Bearer ${this.apiKey}` }; // 简道云API v1只需要在请求体中包含data字段 const payload = { data: data }; console.log('请求URL:', url); console.log('请求头:', headers); console.log('请求体:', JSON.stringify(payload, null, 2)); const response = await axios.post(url, payload, { headers }); console.log('简道云API调用成功:', response.data); return response.data; } catch (error) { console.error('简道云API调用失败:', error.message); if (error.response) { console.error('响应状态:', error.response.status); console.error('响应数据:', JSON.stringify(error.response.data, null, 2)); console.error('响应头:', JSON.stringify(error.response.headers, null, 2)); if (error.config) { console.error('请求URL:', error.config.url); console.error('请求头:', JSON.stringify(error.config.headers, null, 2)); console.error('请求数据:', error.config.data); } } throw error; } } // 将数据库数据转换为简道云表单所需格式 transformDataToJiandaoyunFormat(databaseData) { console.log('开始转换数据:', JSON.stringify(databaseData, null, 2)); const jiandaoyunData = {}; const mapping = config.fieldMapping; // 转换主表数据 const user = databaseData.user; console.log('用户数据:', JSON.stringify(user, null, 2)); console.log('字段映射:', JSON.stringify(mapping, null, 2)); // 使用简道云API v1的正确值格式,使用value字段来包装值 jiandaoyunData[mapping.userId] = { value: user.userId || '' }; jiandaoyunData[mapping.nickName] = { value: user.nickName || '' }; jiandaoyunData[mapping.phoneNumber] = { value: user.phoneNumber || '' }; jiandaoyunData[mapping.type] = { value: user.type || '' }; jiandaoyunData[mapping.authorizedRegion] = { value: user.authorizedRegion || '' }; // 转换负责人信息 const userManagement = databaseData.userManagement; console.log('负责人数据:', JSON.stringify(userManagement, null, 2)); if (userManagement) { jiandaoyunData[mapping.userName] = { value: userManagement.userName || '' }; } // 转换产品数据 const products = databaseData.products; console.log('产品数据:', JSON.stringify(products, null, 2)); if (products.length > 0) { const firstProduct = products[0]; jiandaoyunData[mapping.productName] = { value: firstProduct.productName || '' }; jiandaoyunData[mapping.specification] = { value: firstProduct.specification || '' }; jiandaoyunData[mapping.quantity] = { value: firstProduct.quantity || '' }; jiandaoyunData[mapping.grossWeight] = { value: firstProduct.grossWeight || '' }; jiandaoyunData[mapping.yolk] = { value: firstProduct.yolk || '' }; } console.log('转换后的数据:', JSON.stringify(jiandaoyunData, null, 2)); return jiandaoyunData; } // 查询简道云表单中是否存在指定电话号码的数据 async isPhoneNumberExists(phoneNumber) { try { const mapping = config.fieldMapping; console.log(`检查电话号码 ${phoneNumber} 是否存在于简道云表单中...`); console.log(`使用的字段映射: ${mapping.phoneNumber}`); const url = `${this.baseUrl}/api/v1/app/${this.appId}/entry/${this.entryId}/data_list`; const headers = { 'Content-Type': 'application/json', 'Authorization': `Bearer ${this.apiKey}` }; // 构建查询条件:电话号码字段等于指定值 const payload = { filter: { rel: 'and', cond: [ { field: mapping.phoneNumber, type: 'text', method: 'eq', value: phoneNumber } ] }, page_size: 10 // 返回更多结果以便调试 }; console.log('发送的查询请求:', JSON.stringify(payload, null, 2)); const response = await axios.post(url, payload, { headers }); console.log('查询响应状态:', response.status); console.log('查询响应数据:', JSON.stringify(response.data, null, 2)); // 如果返回的数据数量大于0,则表示该电话号码已存在 const exists = response.data.data.length > 0; console.log(`电话号码 ${phoneNumber} 存在: ${exists}`); return exists; } catch (error) { console.error('查询电话号码是否存在失败:', error.message); if (error.response) { console.error('响应状态:', error.response.status); console.error('响应数据:', error.response.data); } // 发生错误时,为了避免数据丢失,默认返回false,表示不存在该电话号码 return false; } } // 批量提交数据到简道云 async batchSubmitData(dataList, connection) { const results = []; for (const item of dataList) { try { // 检查数据库中是否已有简道云记录ID let recordId = null; if (item.user && 'jiandaoyun_record_id' in item.user) { recordId = item.user.jiandaoyun_record_id; console.log(`从数据库获取到简道云记录ID: ${recordId}`); } if (recordId) { console.log(`使用记录ID ${recordId} 更新数据`); // 转换数据格式 const jiandaoyunData = this.transformDataToJiandaoyunFormat(item); // 更新数据 const result = await this.updateDataInForm(recordId, jiandaoyunData); // 更新数据库中的同步状态 if (connection && item.user && item.user.userId) { try { console.log(`更新用户 ${item.user.userId} 的同步状态`); const [updateResult] = await connection.execute( `UPDATE ${config.tables.users.name} SET ${config.sync.statusField} = ${config.sync.syncedValue}, ${config.sync.timeField} = NOW() WHERE userId = ?`, [item.user.userId] ); if (updateResult.affectedRows > 0) { console.log(`✅ 成功更新用户 ${item.user.userId} 的同步状态`); } else { console.log(`⚠️ 更新用户 ${item.user.userId} 的同步状态失败: 未找到匹配的用户`); } } catch (updateError) { console.error(`❌ 更新数据库同步状态时发生错误:`, updateError.message); console.error(`错误堆栈:`, updateError.stack); } } results.push({ success: true, updated: true, data: result, originalData: item }); console.log('数据更新成功:', result); continue; } // 转换数据格式 const jiandaoyunData = this.transformDataToJiandaoyunFormat(item); // 提交数据 const result = await this.submitDataToForm(jiandaoyunData); // 保存返回的记录ID到数据库 console.log('检查返回结果结构:', JSON.stringify(result, null, 2)); if (result && result.data && result.data._id) { const newRecordId = result.data._id; console.log(`获取到简道云记录ID: ${newRecordId}`); if (connection && item.user && item.user.userId) { try { console.log(`准备更新用户 ${item.user.userId} 的jiandaoyun_record_id为 ${newRecordId} 并设置同步状态`); const [updateResult] = await connection.execute( `UPDATE ${config.tables.users.name} SET jiandaoyun_record_id = ?, ${config.sync.statusField} = ${config.sync.syncedValue}, ${config.sync.timeField} = NOW() WHERE userId = ?`, [newRecordId, item.user.userId] ); console.log(`数据库更新结果:`, updateResult); if (updateResult.affectedRows > 0) { console.log(`✅ 成功将简道云记录ID ${newRecordId} 保存到数据库并更新同步状态`); } else { console.log(`⚠️ 更新用户 ${item.user.userId} 的jiandaoyun_record_id和同步状态失败: 未找到匹配的用户`); } } catch (updateError) { console.error(`❌ 更新数据库jiandaoyun_record_id和同步状态时发生错误:`, updateError.message); console.error(`错误堆栈:`, updateError.stack); } } else { console.log(`⚠️ 无法更新数据库: 缺少connection或item.user.userId`); console.log(`connection存在: ${!!connection}`); console.log(`item.user存在: ${!!item.user}`); console.log(`item.user.userId存在: ${item.user ? !!item.user.userId : 'N/A'}`); } } else { console.log(`⚠️ 简道云API返回结果中没有包含有效的记录ID`); console.log(`result.data存在: ${!!result.data}`); console.log(`result.data._id存在: ${result.data ? !!result.data._id : 'N/A'}`); } results.push({ success: true, data: result, originalData: item }); console.log('数据提交成功:', result); } catch (error) { results.push({ success: false, error: error.message, originalData: item }); console.error('数据提交失败:', error.message); } } return results; } // 根据电话号码获取简道云记录ID async getRecordIdByPhoneNumber(phoneNumber) { try { const mapping = config.fieldMapping; const url = `${this.baseUrl}/api/v1/app/${this.appId}/entry/${this.entryId}/data_list`; const headers = { 'Content-Type': 'application/json', 'Authorization': `Bearer ${this.apiKey}` }; // 构建查询条件:电话号码字段等于指定值 const payload = { filter: { rel: 'and', cond: [ { field: mapping.phoneNumber, type: 'text', method: 'eq', value: phoneNumber } ] }, page_size: 1 // 只需要一条记录即可 }; const response = await axios.post(url, payload, { headers }); // 如果找到记录,返回第一条记录的_id if (response.data.data.length > 0) { return response.data.data[0]._id; } return null; } catch (error) { console.error('获取记录ID失败:', error.message); return null; } } // 更新简道云表单中的数据 async updateDataInForm(recordId, data) { try { const url = `${this.baseUrl}/api/v1/app/${this.appId}/entry/${this.entryId}/data_update`; const headers = { 'Content-Type': 'application/json', 'Authorization': `Bearer ${this.apiKey}` }; // 构建更新请求体:记录ID和要更新的数据 const payload = { entry_id: this.entryId, data_id: recordId, data: data }; const response = await axios.post(url, payload, { headers }); return response.data; } catch (error) { console.error('更新数据失败:', error.message); throw error; } } // 测试简道云API连接 async testApiConnection() { try { console.log('===== 测试简道云API连接 ====='); // 使用fieldMapping来构建测试数据,验证字段映射是否正确 const mapping = config.fieldMapping; const testData = { [mapping.userId]: { value: '123456' }, // 测试用户ID [mapping.company]: { value: '测试公司' }, [mapping.nickName]: { value: '测试联系人' }, [mapping.phoneNumber]: { value: '13800138000' }, [mapping.type]: { value: '零售客户' }, // 测试客户类型 [mapping.city]: { value: '北京' } // 测试地区 }; const response = await this.submitDataToForm(testData); console.log('简道云API连接成功'); return true; } catch (error) { console.error('简道云API连接失败:', error.message); if (error.response) { console.error('响应状态:', error.response.status); console.error('响应数据:', error.response.data); } console.error('错误堆栈:', error.stack); return false; } } } module.exports = new JiandaoyunService();