diff --git a/api/fragment/hard_add.php b/api/fragment/hard_add.php index 30b337b..af45bbe 100644 --- a/api/fragment/hard_add.php +++ b/api/fragment/hard_add.php @@ -29,13 +29,20 @@ $idNumber = trim($_POST['id_number'] ?? ''); $platform = trim($_POST['platform'] ?? ''); $accountId = trim($_POST['account_id'] ?? ''); $profileUrl = trim($_POST['profile_url'] ?? ''); -$category = trim($_POST['target_product_category'] ?? ''); -$description = trim($_POST['description'] ?? ''); $sourceChannel = trim($_POST['source_channel'] ?? ''); if ($sourceChannel === '') { $sourceChannel = '手动录入'; } +// 硬数据标准校验: +// 企业/产品/需求 → 企业名称必填;人员 → 手机、邮箱至少填一个;混合 → 至少有一项内容 +if (in_array($sourceType, ['company', 'product', 'need'], true) && $companyName === '') { + Response::error('企业类型硬数据:企业名称为必填项', 400); +} +if ($sourceType === 'person' && $phone === '' && $email === '') { + Response::error('人员类型硬数据:手机号码、邮箱至少填写一项', 400); +} + // 格式校验:手机 / 邮箱 / 身份证 / 主页链接 checkFieldFormat('phone', $phone); checkFieldFormat('email', $email); @@ -74,23 +81,21 @@ if ($accountId !== '') $extra['account_id'] = $accountId; if ($profileUrl !== '') $extra['profile_url'] = $profileUrl; // 至少有一项内容才能录为碎片 -if ($companyName === '' && $personName === '' && $phone === '' && $email === '' && $category === '' && $description === '' && !$extra) { +if ($companyName === '' && $personName === '' && $phone === '' && $email === '' && !$extra) { Response::error('请至少填写一项内容', 400); } $pdo->prepare( "INSERT INTO preliminary_data (source_type, company_name, person_name, contact_phone, contact_email, - target_product_category, description, source_channel, recorded_by, status, extra_info) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, '待处理', ?)" + source_channel, recorded_by, status, extra_info) + VALUES (?, ?, ?, ?, ?, ?, ?, '待处理', ?)" )->execute([ $sourceType, $companyName !== '' ? $companyName : null, $personName !== '' ? $personName : null, $phone !== '' ? $phone : null, $email !== '' ? $email : null, - $category !== '' ? $category : null, - $description !== '' ? $description : null, $sourceChannel, $_SESSION['username'] ?? null, $extra ? json_encode($extra, JSON_UNESCAPED_UNICODE) : null, diff --git a/api/fragment/hard_common.php b/api/fragment/hard_common.php index 78e29f3..aaf62b6 100644 --- a/api/fragment/hard_common.php +++ b/api/fragment/hard_common.php @@ -4,11 +4,11 @@ * 被 hard_list.php 与 hard_detail.php 共用 */ -/** 硬碎片可统计字段(公司名/联系人/电话/邮箱/品类/描述) */ -const HARD_FIELDS = ['company_name', 'person_name', 'contact_phone', 'contact_email', 'target_product_category', 'description']; +/** 硬碎片可统计字段(核心+重要:企业名/联系人/手机/邮箱;品类与描述已从表中移除) */ +const HARD_FIELDS = ['company_name', 'person_name', 'contact_phone', 'contact_email']; const HARD_LABELS = [ 'company_name' => '公司名称', 'person_name' => '联系人', 'contact_phone' => '电话', - 'contact_email' => '邮箱', 'target_product_category' => '产品品类', 'description' => '描述', + 'contact_email' => '邮箱', ]; /** 计算硬碎片完整度:已填字段数 ÷ 总可填字段数 × 100% */ @@ -36,7 +36,5 @@ function hardSummary($row) if (!empty($row['person_name'])) $parts[] = '联系人:' . $row['person_name']; if (!empty($row['contact_phone'])) $parts[] = '手机:' . $row['contact_phone']; if (!empty($row['contact_email'])) $parts[] = '邮箱:' . $row['contact_email']; - if (!empty($row['target_product_category'])) $parts[] = '品类:' . $row['target_product_category']; - if (empty($parts) && !empty($row['description'])) $parts[] = '描述:' . mb_substr($row['description'], 0, 20); return implode(' ', $parts); } diff --git a/api/fragment/hard_convert.php b/api/fragment/hard_convert.php index 83db34c..dc7aec1 100644 --- a/api/fragment/hard_convert.php +++ b/api/fragment/hard_convert.php @@ -39,8 +39,8 @@ $companyName = trim($_POST['company_name'] ?? ($frag['company_name'] ?? '')); $personName = trim($_POST['person_name'] ?? ($frag['person_name'] ?? '')); $phone = trim($_POST['contact_phone'] ?? ($frag['contact_phone'] ?? '')); $email = trim($_POST['contact_email'] ?? ($frag['contact_email'] ?? '')); -$category = trim($_POST['target_product_category'] ?? ($frag['target_product_category'] ?? '')); -$description = trim($_POST['description'] ?? ($frag['description'] ?? '')); +$category = trim($_POST['target_product_category'] ?? ''); // 仅补全录入表单提供(表中已无该字段) +$description = trim($_POST['description'] ?? ''); // 仅补全录入表单提供 $industry = trim($_POST['industry'] ?? ''); $sourceChannel = $frag['source_channel'] ?? null; @@ -105,7 +105,7 @@ switch ($targetType) { $industry !== '' ? $industry : null, $description !== '' ? $description : null, $sourceChannel, - $frag['description'] ?? null, + $description !== '' ? $description : null, ]); $convertedId = (int)$pdo->lastInsertId(); $saveContacts('company', $convertedId); @@ -120,7 +120,7 @@ switch ($targetType) { $unionId = 'P' . date('YmdHis') . substr(uniqid(), -6); $pdo->prepare( "INSERT INTO persons (union_id, full_name, source_channel, source_detail) VALUES (?, ?, ?, ?)" - )->execute([$unionId, $personName, $sourceChannel, $frag['description'] ?? null]); + )->execute([$unionId, $personName, $sourceChannel, $description !== '' ? $description : null]); $convertedId = (int)$pdo->lastInsertId(); $saveContacts('person', $convertedId); updateIncomplete($pdo, 'persons', $convertedId); diff --git a/api/fragment/hard_list.php b/api/fragment/hard_list.php index 4d5c2d2..6c6c081 100644 --- a/api/fragment/hard_list.php +++ b/api/fragment/hard_list.php @@ -38,7 +38,7 @@ $total = (int)$stmt->fetchColumn(); $offset = ($page - 1) * $limit; $stmt = $pdo->prepare( "SELECT id, source_type, company_name, person_name, contact_phone, contact_email, - target_product_category, description, status, source_channel, recorded_by, + status, source_channel, recorded_by, follow_person, converted_type, converted_id, created_at, updated_at FROM preliminary_data WHERE $whereSql diff --git a/sql/migration_v1.0.41.sql b/sql/migration_v1.0.41.sql new file mode 100644 index 0000000..5390e4d --- /dev/null +++ b/sql/migration_v1.0.41.sql @@ -0,0 +1,14 @@ +-- ============================================================ +-- SuperLink Web - v1.0.41 数据库结构变更 +-- preliminary_data 瘦身:只保留核心/重要字段,删除非必要字段 +-- 保留:company_name(核心) / contact_phone(核心) / contact_email(核心) / person_name(重要) +-- 删除:target_product_category(非必要) / description(非必要) +-- 说明:删除前先备份整表到 preliminary_data_bak_20260810 +-- ============================================================ +SET NAMES utf8mb4; + +CREATE TABLE `preliminary_data_bak_20260810` AS SELECT * FROM `preliminary_data`; + +ALTER TABLE `preliminary_data` + DROP COLUMN `target_product_category`, + DROP COLUMN `description`; diff --git a/static/js/config.js b/static/js/config.js index d4f49b3..fdfe127 100644 --- a/static/js/config.js +++ b/static/js/config.js @@ -5,7 +5,7 @@ var BASE_URL = '/api/'; var PAGE_SIZE = 20; /** 系统版本号(logo旁展示):修改代码后运行 tools/bump_version.php 自动递增 */ -var APP_VERSION = 'v1.0.40'; +var APP_VERSION = 'v1.0.41'; /** 页脚版权/备案信息(在 config.js 中修改) */ var FOOTER_TEXT = '© 2026 SuperLink 管理系统 版权所有 | 备案号:请替换为真实备案号'; diff --git a/static/js/fragment.js b/static/js/fragment.js index 833a9ff..cbd85d7 100644 --- a/static/js/fragment.js +++ b/static/js/fragment.js @@ -42,7 +42,7 @@ $(function () { // ================= 硬碎片 ================= '
' + '
' + - ' 【硬数据新增与处理】' + + ' 硬数据新增与处理' + ' 关键字段缺失、未入主表的原始线索(不含已转换/已废弃)' + '
' + '
' + @@ -68,7 +68,7 @@ $(function () { // ================= 软碎片 ================= '
' + '
' + - ' 【软数据碎片处理】' + + ' 软数据碎片处理' + ' 已入主表但完整度低于阈值的记录(is_incomplete=1)' + '
' + '
' + @@ -212,7 +212,6 @@ $(function () { '
' + '
' + '
' + - '
' + '
' + '