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,
        ]
    );
}

相关推荐
两个人的幸福2 天前
Windows 桌面应用自研 PHP 队列(下):完整代码与六大工程化优化
php
zzzzzz3103 天前
9K Star 炸裂开源!这个 C 语言写的代码知识图谱,把 Linux 内核索引压缩到了 3 分钟
linux·服务器·sql
云技纵横5 天前
唯一索引 INSERT 死锁实战:5 秒复现交叉插入的 S 锁循环等待
sql·mysql
BingoGo5 天前
PHP 泛型之殇 泛型 RFC 提案被拒绝
后端·php
JaguarJack5 天前
PHP 泛型之殇 泛型 RFC 提案被拒绝
后端·php
用户3074596982075 天前
PHP 扩展——从入门到理解
php
鹏仔先生6 天前
拷贝漫画APP下载页PHP程序,后台带免费AI写作
php
云水一下6 天前
从零开始学 PHP 系列(一):PHP 的前世今生与开发环境搭建
开发语言·php
xingpanvip6 天前
星盘接口开发文档:本命盘接口指南
android·开发语言·css·php·lua
BD_Marathon6 天前
SQL学习指南——视图
数据库·sql