php crm客户属性字段变更记录:业务合规与数据可信的核心保障

一、变更记录的核心价值

  1. 明确责任,避免扯皮
  • 客户等级、成交概率、联系方式、归属销售等变更都能追溯。
  • 出现问题时,能快速定位:谁操作、何时操作、改前改后
  • 有效防止恶意修改、抢单、数据乱改等行为。
  1. 保证数据可信,支撑决策
  • 报表、业绩、客户分层等核心业务依赖字段数据。
  • 有变更记录,数据可审计、可回溯、可纠错
  • 管理层可放心使用CRM数据进行业务决策。
  1. 合规与风控(尤其对公/金融/政企场景)
  • 满足内控、审计、监管等合规要求。
  • 重要信息(如客户资质、联系人、等级)必须留痕可查
  • 纠纷、投诉、风控事件时,变更记录是关键证据。
  1. 还原客户生命周期,提升服务体验
  • 全程记录客户状态变化(潜在→跟进→成交)。
  • 需求、行业、预算、负责人等变更轨迹一目了然。
  • 便于交接、复盘、复购和客情维护。

二、标准变更记录应包含的信息

  • 客户 ID
  • 字段名(如客户等级、手机号、销售负责人等)
  • 旧值 / 新值
  • 操作人
  • 操作时间
  • 备注 / 修改原因(可选但强烈建议)

三、未做变更记录的风险

  • 数据随意修改,报表不可信
  • 销售扯皮、抢单、甩锅无法查证
  • 审计无法通过,存在合规风险
  • 客户交接混乱,历史信息断档
  • 出现问题只能"凭记忆",无法定位原因

一句话总结:客户属性字段变更记录 = CRM的数据黑匣子 + 业务责任链 + 合规底线。


四、操作记录日志表设计

sql 复制代码
CREATE TABLE `fa_customer_log` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `customer_id` int(10) unsigned DEFAULT NULL COMMENT '客户ID',
  `type` smallint(6) DEFAULT NULL COMMENT '类型',
  `batch_no` varchar(64) DEFAULT '' COMMENT '批量操作的唯一编号',
  `admin_id` int(10) unsigned DEFAULT NULL COMMENT '创建记录人',
  `memo` varchar(255) DEFAULT '' COMMENT '备注',
  `extra` text COMMENT '扩展参数',
  `ip` varchar(50) DEFAULT '' COMMENT 'ip地址',
  `source_id` int(10) unsigned DEFAULT NULL COMMENT '源ID',
  `create_date` datetime DEFAULT NULL COMMENT '创建时间',
  `update_date` datetime DEFAULT NULL COMMENT '更新时间',
  PRIMARY KEY (`id`),
  KEY `idx_customerId` (`customer_id`),
  KEY `idx_createId` (`admin_id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8mb4 COMMENT='客户变更记录';
  • batch_no:操作批次号,方便后续操作还原。

五、客户属性变更日志表设计

sql 复制代码
CREATE TABLE `fa_customer_profile_logs` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `customer_id` int(10) unsigned DEFAULT NULL COMMENT '客户ID',
  `field_name` varchar(100) DEFAULT '' COMMENT '字段值',
  `field_name_text` varchar(255) DEFAULT '' COMMENT '字段值名称',
  `before_field_value` varchar(1000) DEFAULT '' COMMENT '变更前值',
  `before_field_value_text` varchar(1000) DEFAULT '' COMMENT '变更前',
  `after_field_value` varchar(1000) DEFAULT '' COMMENT '变更后值',
  `after_field_value_text` varchar(1000) DEFAULT '' COMMENT '变更后',
  `source_id` int(10) DEFAULT NULL COMMENT '源ID',
  `create_date` datetime DEFAULT NULL COMMENT '创建时间',
  `admin_id` int(10) DEFAULT NULL COMMENT '创建人',
  PRIMARY KEY (`id`),
  KEY `idx_customerId` (`customer_id`),
  KEY `idx_field_name` (`field_name`),
  KEY `idx_source_id` (`source_id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8mb4 COMMENT='客户属性变更记录';

六、客户模型中的变更记录实现(PHP示例)

1. 字段比较方法

php 复制代码
public function compareField($params = [])
{
    if (!$params) {
        $params = $this->getChangedData();
    }

    $originData = $this->origin;

    return $this->buildCompareData($params, $originData);
}

2. 构建比较数据

php 复制代码
public function buildCompareData($params, $originData)
{
    $table = $this->getTable();
    $fields = Db::query("SHOW FULL COLUMNS FROM {$table}");
    $compareFields = array_column($fields, 'Field');
    $fieldNames = array_column($fields, 'Comment', 'Field');

    $data = [];
    foreach ($params as $field => $value) {
        if (!\in_array($field, $compareFields)) {
            continue;
        }
        $oldOriginValue = $originData[$field] ?? '';
        $newOriginValue = $value;

        switch ($field) {
            case 'admin_id':
                $admin_user_list = Admin::whereIn('id', [$oldOriginValue, $newOriginValue])->column('username', 'id');
                $oldFieldText = $admin_user_list[$oldOriginValue] ?? '';
                $newFieldText = $admin_user_list[$newOriginValue] ?? '';
                break;
            case 'type':
                $type_list = CustomerEnum::typeList();
                $oldFieldText = $type_list[$oldOriginValue] ?? '';
                $newFieldText = $type_list[$newOriginValue] ?? '';
                break;
            default:
                $oldFieldText = $oldOriginValue;
                $newFieldText = $newOriginValue;
                break;
        }

        if ($oldOriginValue != $newOriginValue) {
            $data[$field] = [
                'field_name' => $field,
                'field_name_text' => $fieldNames[$field] ?? '',
                'before_field_value' => $oldOriginValue,
                'after_field_value' => $newOriginValue,
                'before_field_value_text' => $oldFieldText,
                'after_field_value_text' => $newFieldText,
            ];
        }
    }
    return $data;
}

3. 操作日志记录方法

php 复制代码
public static function logsRecord($type, $customerId, $memo, $compareData = [], $extra = [])
{
    $batch_no = $extra['batch_no'] ?? '';
    $source_id = $extra['source_id'] ?? null;
    unset($extra['batch_no'], $extra['source_id']);

    if (!$batch_no) {
        $batch_no = get_order_sn();
    }

    $customerLog = CustomerLog::create([
        'type' => $type,
        'customer_id' => $customerId,
        'memo' => $memo,
        'ip' => request()->ip(),
        'extra' => $extra,
        'batch_no' => $batch_no,
        'source_id' => $source_id,
        'admin_id' => session('admin.id'),
    ]);

    // 客户属性变更日志
    if ($compareData) {
        foreach ($compareData as $key => $item) {
            $item['source_id'] = $customerLog->id;
            $item['customer_id'] = $customerId;
            $item['admin_id'] = session('admin.id');
            $item['create_date'] = date('Y-m-d H:i:s');
            $compareData[$key] = $item;
        }
        CustomerProfileLog::insertAll($compareData);
    }
}

七、批量操作示例:从公海获取客户

php 复制代码
 $batch_no = get_order_sn();

foreach ($list as $item) {
    $data['admin_id'] = session('admin.id');
    $compareData = $item->compareField($data);

    $data['last_receive_date'] = date('Y-m-d H:i:s');
    $item->save($data);

    \app\admin\model\customer\Customer::logsRecord(
        CustomerLogEnum::TYPE_RECEIVE,
        $item->id,
        '从公海捞取',
        $compareData,
        [
            'batch_no' => $batch_no,
        ]
    );
}

相关推荐
木子02042 小时前
sql 计算年龄
数据库·sql
CreasyChan3 小时前
phpstorm php windows 配置调试环境
windows·php·phpstorm
zorro_z3 小时前
实战SimpleBlog(一):项目初始化与用户系统搭建
php
SQL必知必会14 小时前
SQL 删除重复行完全指南
数据库·sql
工业甲酰苯胺14 小时前
spring-事务管理
数据库·sql·spring
云游云记14 小时前
php 随机红包数生成
开发语言·php·随机红包
Amarantine、沐风倩✨15 小时前
列表接口严禁嵌套 LISTAGG + REGEXP:一次 mission_label 性能事故复盘
java·数据库·sql
德育处主任Pro21 小时前
『n8n』不用写SQL,了解一下内置的Datatable
数据库·sql
NineData21 小时前
NineData 社区版 V4.9.0 发布!支持应用切换能力以降低迁移风险,慢查询新增外部采集来源
数据库·sql·ninedata·社区版·v4.9.0·sql开发工具·navicat平替