Files
CKB-Interface/application/store/controller/CustomerController.php
2026-03-24 10:39:16 +08:00

881 lines
35 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace app\store\controller;
use app\common\model\TrafficPoolCompany;
use think\Db;
use think\facade\Log;
/**
* 客户管理控制器
*/
class CustomerController extends BaseController
{
/**
* 获取客户列表
* GET /v2/store/customers
*
* @return \think\response\Json
*/
public function getList()
{
try {
$userId = $this->userInfo['id'] ?? 0;
$companyId = $this->userInfo['companyId'] ?? 0;
if (empty($userId) || empty($companyId)) {
return json(['code' => 401, 'msg' => '请先登录']);
}
// 获取设备信息
$device = $this->device;
if (empty($device) || empty($device['wechatId'])) {
return json(['code' => 404, 'msg' => '设备未绑定微信']);
}
$wechatId = $device['wechatId'];
// 获取微信账号ID
$wechatAccount = Db::table('s2_wechat_account')
->where('wechatId', $wechatId)
->field('id')
->find();
if (empty($wechatAccount)) {
return json(['code' => 404, 'msg' => '微信账号不存在']);
}
$accountId = $wechatAccount['id'];
// 分页参数
$page = intval($this->request->param('page', 1));
$limit = intval($this->request->param('limit', 10));
$pageSize = intval($this->request->param('pageSize', 10));
if ($page <= 0) $page = 1;
if ($limit <= 0) $limit = $pageSize > 0 ? $pageSize : 10;
if ($limit > 100) $limit = 100;
// 搜索关键词
$keyword = $this->request->param('keyword', '');
// 筛选条件
$status = $this->request->param('status', ''); // 状态:潜在、活跃、沉默、流失
$value = $this->request->param('value', ''); // 价值:高、中、低
$lifecycle = $this->request->param('lifecycle', ''); // 生命周期
// 构建查询条件
// 从流量池公司表查询,关联流量池总表和微信好友表
// 注意s2_wechat_friend 表没有 ck_ 前缀,使用数组形式 join 可以避免自动添加前缀
$query = Db::name('traffic_pool_company')
->alias('tpc')
->join('traffic_pool tp', 'tp.id = tpc.poolId', 'left')
->join(['s2_wechat_friend' => 'wf'], 'wf.wechatId = tp.wechatId AND wf.ownerWechatId = \'' . $wechatId . '\'', 'left')
->where([
['tpc.companyId', '=', $companyId],
['tpc.ownerAccountId', '=', $accountId], // 归属当前微信账号
['tpc.status', '=', TrafficPoolCompany::STATUS_NORMAL], // 正常状态
]);
// 关键词搜索(昵称、微信号、手机号)
if (!empty($keyword)) {
$query->where(function($query) use ($keyword) {
$query->where('tp.nickname', 'like', '%' . $keyword . '%')
->whereOr('tp.wechatAlias', 'like', '%' . $keyword . '%')
->whereOr('tp.mobile', 'like', '%' . $keyword . '%')
->whereOr('tpc.realName', 'like', '%' . $keyword . '%')
->whereOr('tpc.phone', 'like', '%' . $keyword . '%');
});
}
// 状态筛选(根据生命周期)
if (!empty($lifecycle)) {
$lifecycleMap = [
'潜在' => TrafficPoolCompany::LIFECYCLE_NEW,
'活跃' => TrafficPoolCompany::LIFECYCLE_FOLLOWING,
'沉默' => TrafficPoolCompany::LIFECYCLE_SILENT,
'流失' => TrafficPoolCompany::LIFECYCLE_LOST,
];
if (isset($lifecycleMap[$lifecycle])) {
$query->where('tpc.lifecycle', '=', $lifecycleMap[$lifecycle]);
}
}
// 价值筛选(根据意向度或等级)
if (!empty($value)) {
$valueMap = [
'高' => TrafficPoolCompany::INTENTION_HIGH,
'中' => TrafficPoolCompany::INTENTION_MEDIUM,
'低' => TrafficPoolCompany::INTENTION_LOW,
];
if (isset($valueMap[$value])) {
$query->where('tpc.intentionLevel', '=', $valueMap[$value]);
}
}
// 统计总数
$total = $query->count();
// 获取列表数据
$list = $query->field('tpc.id,tpc.poolId,tpc.companyId,tpc.ownerAccountId,tpc.realName,tpc.phone,tpc.email,tpc.lifecycle,tpc.intentionLevel,tpc.level,tpc.remark,tpc.createTime,tp.nickname,tp.avatar,tp.wechatId,tp.wechatAlias,tp.mobile,tp.gender,tp.region,tp.signature,wf.id as friendId,wf.alias as friendAlias,wf.nickname as friendNickname')
->order('tpc.id desc')
->page($page, $limit)
->select();
// 格式化数据
$result = [];
foreach ($list as $item) {
// 获取标签
$tags = Db::name('traffic_pool_tag')
->where([
['poolCompanyId', '=', $item['id']],
['isDel', '=', 0]
])
->column('tagName');
// 获取最后互动时间(从行为记录表)
$lastBehavior = Db::name('traffic_pool_behavior')
->where('poolCompanyId', $item['id'])
->order('behaviorTime desc')
->find();
$lastContact = '';
if (!empty($lastBehavior) && !empty($lastBehavior['behaviorTime'])) {
$lastContact = date('Y-m-d H:i:s', intval($lastBehavior['behaviorTime']));
}
// 获取价值评估从RFM或估值相关表这里先使用模拟数据
$valuation = $this->calculateCustomerValuation($item['id']);
// 状态映射
$lifecycleMap = [
TrafficPoolCompany::LIFECYCLE_NEW => '潜在',
TrafficPoolCompany::LIFECYCLE_FOLLOWING => '活跃',
TrafficPoolCompany::LIFECYCLE_CONVERTED => '已成交',
TrafficPoolCompany::LIFECYCLE_SILENT => '沉默',
TrafficPoolCompany::LIFECYCLE_LOST => '流失',
];
// 价值映射
$intentionMap = [
TrafficPoolCompany::INTENTION_HIGH => '高',
TrafficPoolCompany::INTENTION_MEDIUM => '中',
TrafficPoolCompany::INTENTION_LOW => '低',
TrafficPoolCompany::INTENTION_UNKNOWN => '低',
];
$result[] = [
'id' => intval($item['id']),
'poolCompanyId' => intval($item['id']),
'name' => $item['realName'] ?? $item['nickname'] ?? '未知',
'nickname' => $item['nickname'] ?? '',
'wechatId' => $item['wechatAlias'] ?? $item['wechatId'] ?? '',
'avatar' => $item['avatar'] ?? '',
'phone' => $item['phone'] ?? $item['mobile'] ?? '',
'email' => $item['email'] ?? '',
'status' => $lifecycleMap[$item['lifecycle'] ?? TrafficPoolCompany::LIFECYCLE_NEW] ?? '潜在',
'value' => $intentionMap[$item['intentionLevel'] ?? TrafficPoolCompany::INTENTION_UNKNOWN] ?? '低',
'tags' => $tags ?: [],
'lastContact' => $lastContact,
'nextFollow' => !empty($item['nextFollowTime']) && is_numeric($item['nextFollowTime'])
? date('Y-m-d', intval($item['nextFollowTime']))
: '',
'notes' => $item['remark'] ?? '',
'addedDate' => !empty($item['createTime']) && is_numeric($item['createTime'])
? date('Y-m-d', intval($item['createTime']))
: '',
'valuation' => $valuation,
];
}
return json([
'code' => 200,
'msg' => '获取成功',
'data' => [
'list' => $result,
'total' => $total,
'page' => $page,
'limit' => $limit
]
]);
} catch (\Exception $e) {
Log::error('获取客户列表失败: ' . $e->getMessage());
return json(['code' => 500, 'msg' => '获取失败:' . $e->getMessage()]);
}
}
/**
* 获取客户详情
* GET /v2/store/customers/:id
*
* @return \think\response\Json
*/
public function detail()
{
try {
$userId = $this->userInfo['id'] ?? 0;
$companyId = $this->userInfo['companyId'] ?? 0;
if (empty($userId) || empty($companyId)) {
return json(['code' => 401, 'msg' => '请先登录']);
}
// 获取设备信息
$device = $this->device;
if (empty($device) || empty($device['wechatId'])) {
return json(['code' => 404, 'msg' => '设备未绑定微信']);
}
$wechatId = $device['wechatId'];
// 获取微信账号ID
$wechatAccount = Db::table('s2_wechat_account')
->where('wechatId', $wechatId)
->field('id')
->find();
if (empty($wechatAccount)) {
return json(['code' => 404, 'msg' => '微信账号不存在']);
}
$accountId = $wechatAccount['id'];
// 获取客户ID
$customerId = intval($this->request->param('id', 0));
if (empty($customerId)) {
return json(['code' => 400, 'msg' => '客户ID不能为空']);
}
// 查询客户详情
// 注意s2_wechat_friend 表没有 ck_ 前缀,使用数组形式 join 可以避免自动添加前缀
$customer = Db::name('traffic_pool_company')
->alias('tpc')
->join('traffic_pool tp', 'tp.id = tpc.poolId', 'left')
->join(['s2_wechat_friend' => 'wf'], 'wf.wechatId = tp.wechatId AND wf.ownerWechatId = \'' . $wechatId . '\'', 'left')
->where([
['tpc.id', '=', $customerId],
['tpc.companyId', '=', $companyId],
['tpc.ownerAccountId', '=', $accountId],
])
->field('tpc.*,tp.*,wf.id as friendId,wf.alias as friendAlias,wf.nickname as friendNickname')
->find();
if (empty($customer)) {
return json(['code' => 404, 'msg' => '客户不存在']);
}
// 获取标签
$tags = Db::name('traffic_pool_tag')
->where([
['poolCompanyId', '=', $customerId],
['isDel', '=', 0]
])
->column('tagName');
// 获取流量池标签(系统标签或微信标签)
// 注意从表结构看isSystem字段在tagDefineId关联的标签定义表中
// 这里先获取所有标签后续可以根据tagType区分
$allTags = Db::name('traffic_pool_tag')
->alias('tpt')
->join('traffic_pool_tag_define tptd', 'tpt.tagDefineId = tptd.id', 'left')
->where([
['tpt.poolCompanyId', '=', $customerId],
['tpt.isDel', '=', 0]
])
->field('tpt.tagName,tptd.isSystem')
->select();
$trafficPoolTags = [];
foreach ($allTags as $tag) {
// 系统标签或微信标签tagType=1作为流量池标签
if (!empty($tag['isSystem']) || (!empty($tag['tagType']) && $tag['tagType'] == 1)) {
$trafficPoolTags[] = $tag['tagName'];
}
}
// 获取来源信息
$sources = Db::name('traffic_pool_source')
->where('poolCompanyId', $customerId)
->order('createTime desc')
->select();
$sourceChannel = '未知';
$addTime = '';
if (!empty($sources)) {
$firstSource = $sources[0];
$sourceChannel = $firstSource['sourceName'] ?? '未知';
$addTime = !empty($firstSource['createTime']) && is_numeric($firstSource['createTime'])
? date('Y-m-d', intval($firstSource['createTime']))
: '';
}
// 获取互动统计
$interactionStats = $this->getInteractionStats($customerId);
// 获取价值评估
$valueEvaluation = $this->getValueEvaluation($customerId);
// 获取用户旅程(最近记录)
$journey = $this->getCustomerJourney($customerId, 10);
// 获取消费偏好(从行为记录分析)
$preferences = $this->getCustomerPreferences($customerId);
// 状态映射
$lifecycleMap = [
TrafficPoolCompany::LIFECYCLE_NEW => '潜在',
TrafficPoolCompany::LIFECYCLE_FOLLOWING => '活跃',
TrafficPoolCompany::LIFECYCLE_CONVERTED => '已成交',
TrafficPoolCompany::LIFECYCLE_SILENT => '沉默',
TrafficPoolCompany::LIFECYCLE_LOST => '流失',
];
$conversionStatus = $lifecycleMap[$customer['lifecycle'] ?? TrafficPoolCompany::LIFECYCLE_NEW] ?? '潜在';
// 生成首字母
$name = $customer['realName'] ?? $customer['nickname'] ?? '未知';
$initials = mb_substr($name, 0, 1, 'UTF-8');
return json([
'code' => 200,
'msg' => '获取成功',
'data' => [
// 基础信息
'id' => intval($customer['id']),
'poolCompanyId' => intval($customer['id']),
'initials' => $initials,
// 好友概览
'nickname' => $customer['nickname'] ?? '',
'remarkName' => $customer['realName'] ?? '',
'wechatId' => $customer['wechatAlias'] ?? $customer['wechatId'] ?? '',
'wechatPhone' => $customer['mobile'] ?? '',
'wechatLocation' => $customer['region'] ?? '',
'avatar' => $customer['avatar'] ?? '',
'conversionStatus' => $conversionStatus,
'sourceChannel' => $sourceChannel,
'addTime' => $addTime,
// 基础信息
'realName' => $customer['realName'] ?? '',
'sex' => $this->getGenderText($customer['gender'] ?? 0),
'age' => $this->calculateAge($customer['birthday'] ?? ''),
'personalPhone' => $customer['phone'] ?? '',
'email' => $customer['email'] ?? '',
'idNumber' => $this->maskIdNumber($customer['idCard'] ?? ''),
'address' => $customer['address'] ?? '',
// 标签
'tags' => $tags ?: [],
'trafficPoolTags' => $trafficPoolTags ?: [],
// 互动统计
'interactionStats' => $interactionStats,
// 价值评估
'valueEvaluation' => $valueEvaluation,
'valuationRank' => 'TOP 8%', // 需要计算
'valuationTrend' => '+12%', // 需要计算
// 用户旅程
'journey' => $journey,
// 消费偏好
'preferences' => $preferences,
// AI预测需要实现
'aiProfile' => [
'summary' => '该用户为典型的高净值客户,消费频率高且偏好高端产品。',
'predictions' => [
'预计未来7天内有85%概率下单',
'流失风险极低5%),建议通过会员活动维持粘性',
'最佳触达时间工作日12:00-14:00或周末下午'
]
],
]
]);
} catch (\Exception $e) {
Log::error('获取客户详情失败: ' . $e->getMessage());
return json(['code' => 500, 'msg' => '获取失败:' . $e->getMessage()]);
}
}
/**
* 更新客户信息
* PUT /v2/store/customers/:id
*
* @return \think\response\Json
*/
public function update()
{
try {
$userId = $this->userInfo['id'] ?? 0;
$companyId = $this->userInfo['companyId'] ?? 0;
if (empty($userId) || empty($companyId)) {
return json(['code' => 401, 'msg' => '请先登录']);
}
// 获取设备信息
$device = $this->device;
if (empty($device) || empty($device['wechatId'])) {
return json(['code' => 404, 'msg' => '设备未绑定微信']);
}
$wechatId = $device['wechatId'];
// 获取微信账号ID
$wechatAccount = Db::table('s2_wechat_account')
->where('wechatId', $wechatId)
->field('id')
->find();
if (empty($wechatAccount)) {
return json(['code' => 404, 'msg' => '微信账号不存在']);
}
$accountId = $wechatAccount['id'];
// 获取客户ID
$customerId = intval($this->request->param('id', 0));
if (empty($customerId)) {
return json(['code' => 400, 'msg' => '客户ID不能为空']);
}
// 验证客户是否存在且归属当前账号
$customer = Db::name('traffic_pool_company')
->where([
['id', '=', $customerId],
['companyId', '=', $companyId],
['ownerAccountId', '=', $accountId],
])
->find();
if (empty($customer)) {
return json(['code' => 404, 'msg' => '客户不存在']);
}
// 获取更新参数
$updateType = $this->request->param('updateType', ''); // wechat, personal, tags
$updateData = [];
$updateFields = [];
// 更新微信资料
if ($updateType === 'wechat' || $this->request->has('remarkName')) {
$remarkName = $this->request->param('remarkName', '');
if ($remarkName !== '') {
$updateData['realName'] = $remarkName; // 备注名存储在realName字段
$updateFields[] = '备注名';
}
}
// 更新基础信息
if ($updateType === 'personal') {
$realName = $this->request->param('realName', '');
$sex = $this->request->param('sex', '');
$age = $this->request->param('age', '');
$phone = $this->request->param('phone', '');
$email = $this->request->param('email', '');
$idNumber = $this->request->param('idNumber', '');
$address = $this->request->param('address', '');
if ($realName !== '') {
$updateData['realName'] = $realName;
$updateFields[] = '姓名';
}
if ($sex !== '') {
$updateData['gender'] = $sex === '男' ? 1 : ($sex === '女' ? 2 : 0);
$updateFields[] = '性别';
}
if ($age !== '') {
// 根据年龄计算生日(简化处理)
$birthYear = date('Y') - intval($age);
$updateData['birthday'] = $birthYear . '-01-01';
$updateFields[] = '年龄';
}
if ($phone !== '') {
$updateData['phone'] = $phone;
$updateFields[] = '手机号';
}
if ($email !== '') {
$updateData['email'] = $email;
$updateFields[] = '邮箱';
}
if ($idNumber !== '') {
$updateData['idCard'] = $idNumber;
$updateFields[] = '身份证号';
}
if ($address !== '') {
$updateData['address'] = $address;
$updateFields[] = '住址';
}
}
// 更新标签
if ($updateType === 'tags') {
$tags = $this->request->param('tags', []);
if (is_array($tags)) {
// 获取客户信息用于获取identifier和companyId
$customerInfo = Db::name('traffic_pool_company')
->where('id', $customerId)
->field('identifier,companyId')
->find();
if (!empty($customerInfo)) {
// 软删除旧标签(只删除站内标签,保留微信标签和系统标签)
// 通过关联标签定义表判断是否为站内标签
Db::name('traffic_pool_tag')
->alias('tpt')
->join('traffic_pool_tag_define tptd', 'tpt.tagDefineId = tptd.id', 'left')
->where([
['tpt.poolCompanyId', '=', $customerId],
['tptd.tagType', '=', 2], // 站内标签
['tpt.isDel', '=', 0]
])
->update([
'tpt.isDel' => 1,
'tpt.deleteTime' => time()
]);
// 添加新标签(站内标签)
foreach ($tags as $tag) {
if (!empty($tag)) {
// 查找或创建标签定义
$tagDefine = Db::name('traffic_pool_tag_define')
->where([
['companyId', 'in', [$companyId, 0]],
['tagName', '=', $tag],
['tagType', '=', 2], // 站内标签
['isDel', '=', 0]
])
->order('companyId desc') // 优先使用公司自定义标签
->find();
if (empty($tagDefine)) {
// 创建标签定义
$tagDefineId = Db::name('traffic_pool_tag_define')->insertGetId([
'companyId' => $companyId,
'tagType' => 2, // 站内标签
'tagCode' => 'custom_' . time() . '_' . rand(1000, 9999),
'tagName' => $tag,
'isSystem' => 0,
'status' => 1,
'createTime' => time(),
]);
} else {
$tagDefineId = $tagDefine['id'];
}
// 检查标签是否已存在
$existTag = Db::name('traffic_pool_tag')
->where([
['poolCompanyId', '=', $customerId],
['tagDefineId', '=', $tagDefineId],
['isDel', '=', 0]
])
->find();
if (empty($existTag)) {
Db::name('traffic_pool_tag')->insert([
'poolCompanyId' => $customerId,
'identifier' => $customerInfo['identifier'],
'companyId' => $customerInfo['companyId'],
'tagDefineId' => $tagDefineId,
'tagType' => 2, // 站内标签
'tagName' => $tag,
'source' => 1, // 手动
'operatorId' => $userId,
'createTime' => time(),
]);
}
}
}
}
$updateFields[] = '标签';
}
}
// 更新客户信息
if (!empty($updateData)) {
$updateData['updateTime'] = time();
Db::name('traffic_pool_company')
->where('id', $customerId)
->update($updateData);
}
return json([
'code' => 200,
'msg' => '更新成功',
'data' => [
'updatedFields' => $updateFields
]
]);
} catch (\Exception $e) {
Log::error('更新客户信息失败: ' . $e->getMessage());
return json(['code' => 500, 'msg' => '更新失败:' . $e->getMessage()]);
}
}
/**
* 计算客户估值
*
* @param int $poolCompanyId 客户ID
* @return int
*/
private function calculateCustomerValuation($poolCompanyId)
{
// TODO: 实现真实的估值计算逻辑
// 可以从订单表、行为记录表等计算
return 50000; // 模拟数据
}
/**
* 获取互动统计
*
* @param int $poolCompanyId 客户ID
* @return array
*/
private function getInteractionStats($poolCompanyId)
{
// 统计聊天消息数
$chatCount = Db::name('traffic_pool_behavior')
->where([
['poolCompanyId', '=', $poolCompanyId],
['behaviorType', '=', 1] // 发送消息
])
->count();
// 统计朋友圈互动数
$momentsCount = Db::name('traffic_pool_behavior')
->where([
['poolCompanyId', '=', $poolCompanyId],
['behaviorType', 'in', [9, 10]] // 点赞朋友圈、评论朋友圈
])
->count();
// 统计红包转账总额(从行为记录中获取)
$redPacketTotal = Db::name('traffic_pool_behavior')
->where([
['poolCompanyId', '=', $poolCompanyId],
['behaviorType', '=', 7] // 支付
])
->sum('amount');
$redPacketTotal = round(floatval($redPacketTotal ?? 0), 2);
// 计算活跃度评分(简化计算)
$activeScore = min(100, ($chatCount * 2 + $momentsCount * 3 + $redPacketTotal / 10));
// 获取最后互动时间
$lastBehavior = Db::name('traffic_pool_behavior')
->where('poolCompanyId', $poolCompanyId)
->order('behaviorTime desc')
->find();
$lastInteraction = '从未互动';
if (!empty($lastBehavior) && !empty($lastBehavior['behaviorTime'])) {
$time = intval($lastBehavior['behaviorTime']);
$diff = time() - $time;
if ($diff < 3600) {
$lastInteraction = '刚刚';
} elseif ($diff < 86400) {
$lastInteraction = '今天 ' . date('H:i', $time);
} elseif ($diff < 172800) {
$lastInteraction = '昨天 ' . date('H:i', $time);
} else {
$lastInteraction = date('Y-m-d H:i', $time);
}
}
return [
'lastInteraction' => $lastInteraction,
'chatCount' => intval($chatCount),
'momentsCount' => intval($momentsCount),
'redPacketTotal' => number_format($redPacketTotal, 2),
'activeScore' => intval($activeScore)
];
}
/**
* 获取价值评估
*
* @param int $poolCompanyId 客户ID
* @return array
*/
private function getValueEvaluation($poolCompanyId)
{
// TODO: 实现真实的价值评估计算
// 可以从RFM模型、CLV模型、社交裂变模型等计算
return [
'totalValuation' => 58600,
'models' => [
[
'name' => 'RFM 贡献模型',
'value' => 52000,
'weight' => 0.5,
'score' => 92
],
[
'name' => 'CLV 终身价值模型',
'value' => 78000,
'weight' => 0.3,
'score' => 88
],
[
'name' => '社交/裂变模型',
'value' => 15000,
'weight' => 0.2,
'score' => 75
]
]
];
}
/**
* 获取用户旅程
*
* @param int $poolCompanyId 客户ID
* @param int $limit 限制数量
* @return array
*/
private function getCustomerJourney($poolCompanyId, $limit = 10)
{
// 从行为记录表获取
$behaviors = Db::name('traffic_pool_behavior')
->where('poolCompanyId', $poolCompanyId)
->order('behaviorTime desc')
->limit($limit)
->select();
$journey = [];
$typeMap = [
1 => '发送消息',
2 => '接收消息',
3 => '浏览',
4 => '点击',
5 => '咨询',
6 => '下单',
7 => '支付',
8 => '退款',
9 => '点赞朋友圈',
10 => '评论朋友圈',
];
foreach ($behaviors as $behavior) {
$type = $typeMap[$behavior['behaviorType']] ?? '未知行为';
$content = $behavior['behaviorName'] ?? $type;
if (!empty($behavior['targetName'])) {
$content .= ': ' . $behavior['targetName'];
}
$journey[] = [
'type' => $type,
'content' => $content,
'time' => !empty($behavior['behaviorTime']) && is_numeric($behavior['behaviorTime'])
? date('Y-m-d H:i:s', intval($behavior['behaviorTime']))
: '',
'source' => '存客宝',
'actionType' => $this->getActionType($behavior['behaviorType']),
'amount' => !empty($behavior['amount']) && floatval($behavior['amount']) > 0
? '¥' . number_format(floatval($behavior['amount']), 2)
: '',
];
}
return $journey;
}
/**
* 获取行为类型
*
* @param int $behaviorType 行为类型
* @return string
*/
private function getActionType($behaviorType)
{
if (in_array($behaviorType, [6, 7, 8])) {
return 'transaction'; // 交易
} elseif (in_array($behaviorType, [1, 2, 9, 10])) {
return 'social'; // 社交
} elseif (in_array($behaviorType, [3, 4, 5])) {
return 'footprint'; // 轨迹
} else {
return 'flow'; // 流量
}
}
/**
* 获取消费偏好
*
* @param int $poolCompanyId 客户ID
* @return array
*/
private function getCustomerPreferences($poolCompanyId)
{
// TODO: 从行为记录和订单记录分析消费偏好
return [
'categories' => ['智能数码', '精品咖啡', '商务休闲'],
'recentItems' => ['iPhone 16 Pro', 'iPad Air'],
'coreInterest' => '数码发烧友 & 品质生活追求者'
];
}
/**
* 获取性别文本
*
* @param int $gender 性别代码
* @return string
*/
private function getGenderText($gender)
{
$map = [
0 => '保密',
1 => '男',
2 => '女',
];
return $map[$gender] ?? '未知';
}
/**
* 计算年龄
*
* @param string $birthday 生日
* @return int
*/
private function calculateAge($birthday)
{
if (empty($birthday)) {
return 0;
}
$birthTimestamp = strtotime($birthday);
if ($birthTimestamp === false) {
return 0;
}
$age = date('Y') - date('Y', $birthTimestamp);
if (date('md', $birthTimestamp) > date('md')) {
$age--;
}
return $age;
}
/**
* 脱敏身份证号
*
* @param string $idNumber 身份证号
* @return string
*/
private function maskIdNumber($idNumber)
{
if (empty($idNumber) || strlen($idNumber) < 8) {
return $idNumber;
}
return substr($idNumber, 0, 4) . str_repeat('*', strlen($idNumber) - 8) . substr($idNumber, -4);
}
}