getPdo(); /** 从 POST 收集需要写入的字段(空串转 null) */ $fields = []; $collect = function ($key) use (&$fields) { if (isset($_POST[$key])) { $v = trim((string)$_POST[$key]); $fields[$key] = $v !== '' ? $v : null; } }; if ($id > 0) { $check = $pdo->prepare("SELECT id, status FROM channel_plans WHERE id = ? AND is_active = 1"); $check->execute([$id]); $cur = $check->fetch(); if (!$cur) { Response::error('计划不存在'); } // 只更新提交的字段 foreach (['channel_type', 'source_detail', 'occurrence_address', 'industry', 'start_date', 'end_date', 'remark', 'status'] as $k) { $collect($k); } if (isset($_POST['cost'])) { $c = trim((string)$_POST['cost']); $fields['cost'] = $c !== '' ? round((float)$c, 2) : null; } // 若只改了状态为「已执行」而原费用为空,前端会单独提交 cost;此处不自动置值 if (!$fields) { Response::error('没有需要更新的字段', 400); } [$sets, $params] = buildUpdate($fields); $params[] = $id; $pdo->prepare("UPDATE channel_plans SET $sets WHERE id = ?")->execute($params); logCurrent('update', 'channel_plan', 'channel_plans', $id, $fields); Response::success(null, '更新成功'); } // 新增:渠道类别必填 $channelType = trim($_POST['channel_type'] ?? ''); if ($channelType === '') { Response::error('渠道类别(channel_type)为必填项', 400); } $fields = [ 'channel_type' => $channelType, 'source_detail' => strOrNull($_POST['source_detail'] ?? null), 'occurrence_address' => strOrNull($_POST['occurrence_address'] ?? null), 'industry' => strOrNull($_POST['industry'] ?? null), 'start_date' => strOrNull($_POST['start_date'] ?? null), 'end_date' => strOrNull($_POST['end_date'] ?? null), 'remark' => strOrNull($_POST['remark'] ?? null), 'status' => $status !== '' ? $status : '待启动', 'cost' => $cost !== '' ? round((float)$cost, 2) : null, ]; [$sql, $params] = buildInsert($fields); $pdo->prepare("INSERT INTO channel_plans $sql")->execute($params); $newId = (int)$pdo->lastInsertId(); logCurrent('add', 'channel_plan', 'channel_plans', $newId, $fields); Response::success(['id' => $newId], '新增成功');