diff --git a/api/dashboard/stats.php b/api/dashboard/stats.php index 0d20d02..0b179dc 100644 --- a/api/dashboard/stats.php +++ b/api/dashboard/stats.php @@ -19,7 +19,7 @@ $sqlMetrics = [ 'company_new' => "SELECT COUNT(*) AS c FROM companies WHERE is_active = 1 AND DATE(created_at) = CURDATE() - INTERVAL 1 DAY", 'person_new' => "SELECT COUNT(*) AS c FROM persons WHERE is_active = 1 AND DATE(created_at) = CURDATE() - INTERVAL 1 DAY", 'preliminary' => "SELECT - (SELECT COUNT(*) FROM preliminary_data WHERE is_active = 1 AND status NOT IN ('已转换','已废弃')) + (SELECT COUNT(*) FROM preliminary_data WHERE is_active = 1 AND converted_id IS NULL) + (SELECT COUNT(*) FROM companies WHERE is_incomplete = 1) + (SELECT COUNT(*) FROM persons WHERE is_incomplete = 1) + (SELECT COUNT(*) FROM social_accounts WHERE is_incomplete = 1) diff --git a/api/fragment/hard_add.php b/api/fragment/hard_add.php index 295343f..bf50e8a 100644 --- a/api/fragment/hard_add.php +++ b/api/fragment/hard_add.php @@ -4,7 +4,7 @@ * 入参:source_type(company|person|product|need|mixed,必填)/ * company_name / person_name / contact_phone / contact_email / * target_product_category / description / source_channel - * 写入 preliminary_data,status=待处理,recorded_by=当前登录用户 + * 写入 preliminary_data,recorded_by=当前登录用户(v1.0.50 起无 status 字段) */ require_once __DIR__ . '/../common/db.php'; require_once __DIR__ . '/../common/response.php'; @@ -85,8 +85,8 @@ $pdo->prepare( "INSERT INTO preliminary_data (source_type, company_name, industry, registration_number, business_role, country, address, person_name, contact_phone, contact_email, work_location, id_number, platform, account_id, profile_url, - source_channel, recorded_by, status) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, '待处理')" + source_channel, recorded_by) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" )->execute([ $sourceType, $companyName !== '' ? $companyName : null, diff --git a/api/fragment/hard_convert.php b/api/fragment/hard_convert.php index 0eef8f9..e9b67e7 100644 --- a/api/fragment/hard_convert.php +++ b/api/fragment/hard_convert.php @@ -31,8 +31,8 @@ $frag = $stmt->fetch(); if (!$frag) { Response::error('碎片不存在'); } -if (in_array($frag['status'], ['已转换', '已废弃'], true)) { - Response::error('该碎片已处理(' . $frag['status'] . ')'); +if ($frag['converted_id']) { + Response::error('该碎片已处理(已转换)'); } $companyName = trim($_POST['company_name'] ?? ($frag['company_name'] ?? '')); @@ -65,31 +65,31 @@ if ($profileUrl !== '' && !preg_match('/^https?:\/\//i', $profileUrl)) { switch ($targetType) { case 'company': if ($companyName === '') { - Response::error('企业类型转软碎片:企业名称为必填项,请先「继续补全」', 400); + Response::error('企业类型转软碎片:企业名称为必填项,请先「手动补全」', 400); } if ($industry === '') { - Response::error('企业类型转软碎片:行业为必填项,请先「继续补全」填写行业', 400); + Response::error('企业类型转软碎片:行业为必填项,请先「手动补全」填写行业', 400); } if ($registrationNum === '') { - Response::error('企业类型转软碎片:注册号为必填项,请先「继续补全」填写注册号', 400); + Response::error('企业类型转软碎片:注册号为必填项,请先「手动补全」填写注册号', 400); } break; case 'person': if ($personName === '') { - Response::error('人员类型转软碎片:姓名为必填项,请先「继续补全」', 400); + Response::error('人员类型转软碎片:姓名为必填项,请先「手动补全」', 400); } if ($phone === '' && $email === '') { - Response::error('人员类型转软碎片:手机号码、邮箱至少填写一项,请先「继续补全」', 400); + Response::error('人员类型转软碎片:手机号码、邮箱至少填写一项,请先「手动补全」', 400); } break; case 'product': if ($companyName === '') { - Response::error('产品类型转软碎片:公司名称为必填项,请先「继续补全」', 400); + Response::error('产品类型转软碎片:公司名称为必填项,请先「手动补全」', 400); } break; case 'need': if ($companyName === '') { - Response::error('需求类型转软碎片:公司名称为必填项,请先「继续补全」', 400); + Response::error('需求类型转软碎片:公司名称为必填项,请先「手动补全」', 400); } break; } @@ -215,9 +215,9 @@ switch ($targetType) { break; } -// 标记碎片已转换 +// 标记碎片已转换(v1.0.50 起不再写 status 字段,以 converted_id 非空标识已转换) $pdo->prepare( - "UPDATE preliminary_data SET status = '已转换', converted_type = ?, converted_id = ?, processed_at = NOW() WHERE id = ?" + "UPDATE preliminary_data SET converted_type = ?, converted_id = ?, processed_at = NOW() WHERE id = ?" )->execute([$targetType, $convertedId, $id]); logCurrent('convert', 'fragment', 'preliminary_data', $id, [ diff --git a/api/fragment/hard_discard.php b/api/fragment/hard_discard.php index 974e9aa..f7dd251 100644 --- a/api/fragment/hard_discard.php +++ b/api/fragment/hard_discard.php @@ -2,6 +2,7 @@ /** * 硬碎片废弃接口 POST /api/fragment/hard_discard.php * 入参:id + * v1.0.50:废弃改为从 preliminary_data 彻底硬删除(不再保留记录) */ require_once __DIR__ . '/../common/db.php'; require_once __DIR__ . '/../common/response.php'; @@ -17,17 +18,18 @@ if ($id <= 0) { } $pdo = DB::getInstance()->getPdo(); -$stmt = $pdo->prepare("SELECT id, status FROM preliminary_data WHERE id = ? AND is_active = 1"); +$stmt = $pdo->prepare("SELECT id, converted_id FROM preliminary_data WHERE id = ? AND is_active = 1"); $stmt->execute([$id]); $frag = $stmt->fetch(); if (!$frag) { Response::error('碎片不存在'); } -if (in_array($frag['status'], ['已转换', '已废弃'], true)) { - Response::error('该碎片已处理(' . $frag['status'] . ')'); +if ($frag['converted_id']) { + Response::error('该碎片已转换,不可废弃'); } -$pdo->prepare("UPDATE preliminary_data SET status = '已废弃', processed_at = NOW() WHERE id = ?")->execute([$id]); +// 彻底硬删除(v1.0.50 起废弃不再保留记录) +$pdo->prepare("DELETE FROM preliminary_data WHERE id = ?")->execute([$id]); -logCurrent('discard', 'fragment', 'preliminary_data', $id, ['status' => '已废弃']); +logCurrent('discard', 'fragment', 'preliminary_data', $id, ['action' => 'hard_delete']); Response::success(null, '已废弃'); diff --git a/api/fragment/hard_list.php b/api/fragment/hard_list.php index 802badd..cd4d4df 100644 --- a/api/fragment/hard_list.php +++ b/api/fragment/hard_list.php @@ -1,8 +1,9 @@ prepare( "SELECT id, source_type, company_name, industry, registration_number, business_role, country, address, person_name, contact_phone, contact_email, work_location, id_number, platform, account_id, profile_url, - status, source_channel, recorded_by, + source_channel, recorded_by, follow_person, converted_type, converted_id, created_at, updated_at FROM preliminary_data WHERE $whereSql diff --git a/api/fragment/hard_update.php b/api/fragment/hard_update.php index f2e69ed..e2ab7ef 100644 --- a/api/fragment/hard_update.php +++ b/api/fragment/hard_update.php @@ -26,8 +26,8 @@ $frag = $stmt->fetch(); if (!$frag) { Response::error('碎片不存在'); } -if (in_array($frag['status'], ['已转换', '已废弃'], true)) { - Response::error('该碎片已处理(' . $frag['status'] . ')'); +if ($frag['converted_id']) { + Response::error('该碎片已处理(已转换)'); } $sourceType = trim($_POST['source_type'] ?? ($frag['source_type'] ?? '')); diff --git a/api/fragment/stats_overview.php b/api/fragment/stats_overview.php index 989ef0c..b64c251 100644 --- a/api/fragment/stats_overview.php +++ b/api/fragment/stats_overview.php @@ -2,12 +2,13 @@ /** * 碎片处理中心 - 顶部概览接口 GET /api/fragment/stats_overview.php * 指标: - * - hard_total 硬碎片待处理数(preliminary_data 未终结) + * - hard_total 硬碎片待处理数(preliminary_data 未转换) * - soft_total 软碎片待处理数(四主表 is_incomplete=1) * - month_new 本月新增(硬碎片本月新增 + 软碎片本月新增) * - month_processed 本月处理(本月已转换硬碎片 + 本月已补全软碎片) * - cumulative 累计处理(历史已转换硬碎片 + 历史已补全软碎片) * - pending 待处理碎片(硬待处理 + 软待处理) + * 说明:v1.0.50 起 preliminary_data 无 status 字段,已转换以 converted_id 非空标识 */ require_once __DIR__ . '/../common/db.php'; require_once __DIR__ . '/../common/response.php'; @@ -18,9 +19,9 @@ checkPermission('preliminary'); $pdo = DB::getInstance()->getPdo(); $monthStart = "DATE_FORMAT(CURDATE(), '%Y-%m-01')"; -// 硬碎片待处理数 +// 硬碎片待处理数(未转换) $hardTotal = (int)$pdo->query( - "SELECT COUNT(*) FROM preliminary_data WHERE is_active = 1 AND status NOT IN ('已转换','已废弃')" + "SELECT COUNT(*) FROM preliminary_data WHERE is_active = 1 AND converted_id IS NULL" )->fetchColumn(); // 软碎片待处理数(四主表 is_incomplete=1 之和) @@ -50,7 +51,7 @@ $softMonthNew += (int)$pdo->query( // 本月已转换硬碎片 $hardConvertedMonth = (int)$pdo->query( "SELECT COUNT(*) FROM preliminary_data - WHERE is_active = 1 AND status = '已转换' AND processed_at >= $monthStart" + WHERE is_active = 1 AND converted_id IS NOT NULL AND processed_at >= $monthStart" )->fetchColumn(); // 本月已补全软碎片(fragment 模块 complete 日志) @@ -60,7 +61,7 @@ $softCompletedMonth = (int)$pdo->query( // 历史累计已转换硬碎片 $hardConvertedTotal = (int)$pdo->query( - "SELECT COUNT(*) FROM preliminary_data WHERE is_active = 1 AND status = '已转换'" + "SELECT COUNT(*) FROM preliminary_data WHERE is_active = 1 AND converted_id IS NOT NULL" )->fetchColumn(); // 历史累计已补全软碎片 diff --git a/api/person/import.php b/api/person/import.php index d6d11f7..aec5aab 100644 --- a/api/person/import.php +++ b/api/person/import.php @@ -61,7 +61,7 @@ while (($row = fgetcsv($handle)) !== false) { continue; } $insPerson->execute([ - $unionId, $rec['full_name'], $rec['gender'] ?? '保密', $rec['nationality'] ?? null, + $unionId, $rec['full_name'], $rec['gender'] ?? '未知', $rec['nationality'] ?? null, $rec['id_type'] ?? null, $rec['id_number'] ?? null, $rec['education'] ?? null, $rec['graduated_from'] ?? null, $rec['hometown'] ?? null, $rec['work_location'] ?? null, $rec['source_channel'] ?? null, $rec['source_detail'] ?? null, diff --git a/api/preliminary/list.php b/api/preliminary/list.php index 5adc139..972ae5f 100644 --- a/api/preliminary/list.php +++ b/api/preliminary/list.php @@ -1,7 +1,7 @@ = ?'; $params[] = $startDate; } if ($endDate !== '') { $where[] = 'DATE(created_at) <= ?'; $params[] = $endDate; } @@ -38,7 +36,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, + source_channel, recorded_by, follow_person, converted_type, converted_id, created_at, updated_at FROM preliminary_data WHERE $whereSql diff --git a/api/preliminary/stats.php b/api/preliminary/stats.php index b67b04d..6a54756 100644 --- a/api/preliminary/stats.php +++ b/api/preliminary/stats.php @@ -1,7 +1,7 @@ getPdo(); $total = (int)$pdo->query("SELECT COUNT(*) FROM preliminary_data WHERE is_active = 1")->fetchColumn(); $today = (int)$pdo->query("SELECT COUNT(*) FROM preliminary_data WHERE is_active = 1 AND DATE(created_at) = CURDATE()")->fetchColumn(); -$statusRows = $pdo->query( - "SELECT status, COUNT(*) AS cnt FROM preliminary_data WHERE is_active = 1 GROUP BY status" -)->fetchAll(); -$statusMap = []; -foreach ($statusRows as $r) { - $statusMap[$r['status']] = (int)$r['cnt']; -} - Response::success([ 'total' => $total, 'today' => $today, - 'status' => $statusMap, - 'statuses' => ['待处理', '待分配', '处理中', '已转换', '已废弃', '已拒收'], ]); diff --git a/sql/migration_v1.0.50.sql b/sql/migration_v1.0.50.sql new file mode 100644 index 0000000..033939d --- /dev/null +++ b/sql/migration_v1.0.50.sql @@ -0,0 +1,20 @@ +-- ============================================================ +-- SuperLink Web - v1.0.50 数据库结构变更 +-- 1) preliminary_data 删除 status 字段(硬数据板块不再有「状态」: +-- 查看弹窗不展示、数据表不存储;已转换以 converted_id 非空标识, +-- 废弃改为彻底硬删除,不再需要已废弃状态) +-- 2) persons.gender 枚举收敛为 男/女/未知(原 其他/保密 不再允许) +-- ============================================================ +SET NAMES utf8mb4; + +-- 1) 硬碎片数据表去掉 status 列(相关索引 idx_status 随列删除) +ALTER TABLE `preliminary_data` DROP COLUMN `status`; + +-- 2) 人员性别:先扩枚举加入「未知」→ 归并旧值 → 再收紧枚举 +ALTER TABLE `persons` + MODIFY COLUMN `gender` enum('男','女','未知','其他','保密') COLLATE utf8mb4_unicode_ci DEFAULT '未知' COMMENT '性别'; + +UPDATE `persons` SET `gender` = '未知' WHERE `gender` IN ('其他', '保密'); + +ALTER TABLE `persons` + MODIFY COLUMN `gender` enum('男','女','未知') COLLATE utf8mb4_unicode_ci DEFAULT '未知' COMMENT '性别'; diff --git a/static/js/config.js b/static/js/config.js index 440fcf5..715db34 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.49'; +var APP_VERSION = 'v1.0.50'; /** 页脚版权/备案信息(在 config.js 中修改) */ var FOOTER_TEXT = '© 2026 SuperLink 管理系统 版权所有 | 备案号:请替换为真实备案号'; diff --git a/static/js/fragment.js b/static/js/fragment.js index 7592b58..5d27d27 100644 --- a/static/js/fragment.js +++ b/static/js/fragment.js @@ -1,7 +1,7 @@ /** - * fragment.js - 碎片处理中心(v1.0.27) + * fragment.js - 碎片处理中心(v1.0.50) * 布局:顶部指标卡 + 【硬碎片】独立区块 + 【软碎片】独立区块(不用 Tab) - * 硬碎片:preliminary_data 中未终结记录(完整度/类型/内容摘要/来源/录入人/时间/状态/操作) + * 硬碎片:preliminary_data 中未转换记录(完整度/类型/内容摘要/来源/录入人/时间/操作;废弃即硬删除,无状态字段) * 软碎片:四张主表 is_incomplete=1 记录(完整度/缺失层级标签/名称/缺失字段/所属表/时间/操作) */ $(function () { @@ -42,8 +42,8 @@ $(function () { // ================= 硬碎片 ================= '