From 319fbbe34c4eed717f39e31a1cc90745b9778ef1 Mon Sep 17 00:00:00 2001 From: nanguaboss <602995148@qq.com> Date: Mon, 10 Aug 2026 00:53:09 +0800 Subject: [PATCH] =?UTF-8?q?v1.0.48:=20preliminary=5Fdata=E9=87=8D=E6=9E=84?= =?UTF-8?q?=E6=8C=89=E4=B8=89=E5=B1=82=E5=8E=9F=E5=88=99=20-=20=E6=A0=B8?= =?UTF-8?q?=E5=BF=83+=E9=87=8D=E8=A6=81=E5=AD=97=E6=AE=B5=E6=AD=A3?= =?UTF-8?q?=E5=BC=8F=E5=8C=96(business=5Frole/country/address/work=5Flocat?= =?UTF-8?q?ion/id=5Fnumber/platform/account=5Fid/profile=5Furl=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E5=88=97,=E8=BA=AB=E4=BB=BD=E8=AF=81/=E7=A4=BE?= =?UTF-8?q?=E5=AA=92/=E4=B8=BB=E9=A1=B5=E4=BB=8Eextra=5Finfo=E6=8F=90?= =?UTF-8?q?=E4=B8=BA=E6=AD=A3=E5=BC=8F=E5=88=97)+=E5=88=A0=E9=99=A4extra?= =?UTF-8?q?=5Finfo(=E5=93=81=E7=B1=BB/=E9=9C=80=E6=B1=82=E7=B1=BB=E5=88=AB?= =?UTF-8?q?=E7=AD=89=E9=9D=9E=E5=BF=85=E8=A6=81=E4=B8=8D=E5=86=8D=E5=AD=98?= =?UTF-8?q?=E6=94=BE)+=E8=A1=A8=E5=8D=95/=E8=BD=AC=E6=8D=A2/=E5=88=97?= =?UTF-8?q?=E8=A1=A8=E5=85=A8=E9=83=A8=E9=80=82=E9=85=8D(product=E5=93=81?= =?UTF-8?q?=E7=B1=BB=E9=BB=98=E8=AE=A4=E6=9C=AA=E5=88=86=E7=B1=BB)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/fragment/hard_add.php | 49 +++++++++--------- api/fragment/hard_convert.php | 97 ++++++++++++++++++----------------- api/fragment/hard_list.php | 3 +- api/fragment/hard_update.php | 37 ++++++------- sql/migration_v1.0.48.sql | 22 ++++++++ static/js/config.js | 2 +- static/js/fragment.js | 58 +++++++++++---------- 7 files changed, 150 insertions(+), 118 deletions(-) create mode 100644 sql/migration_v1.0.48.sql diff --git a/api/fragment/hard_add.php b/api/fragment/hard_add.php index 1e7c71d..295343f 100644 --- a/api/fragment/hard_add.php +++ b/api/fragment/hard_add.php @@ -22,17 +22,19 @@ if (!in_array($sourceType, ['company', 'person', 'product', 'need', 'mixed'], tr } $companyName = trim($_POST['company_name'] ?? ''); +$industry = trim($_POST['industry'] ?? ''); // 核心-企业 +$registrationNum = trim($_POST['registration_number'] ?? ''); // 核心-企业 +$businessRole = trim($_POST['business_role'] ?? ''); // 重要-企业 +$country = trim($_POST['country'] ?? ''); // 重要-企业 +$address = trim($_POST['address'] ?? ''); // 重要-企业 $personName = trim($_POST['person_name'] ?? ''); $phone = trim($_POST['contact_phone'] ?? ''); $email = trim($_POST['contact_email'] ?? ''); -$idNumber = trim($_POST['id_number'] ?? ''); -$platform = trim($_POST['platform'] ?? ''); -$accountId = trim($_POST['account_id'] ?? ''); -$profileUrl = trim($_POST['profile_url'] ?? ''); -$industry = trim($_POST['industry'] ?? ''); // 企业:行业 -$registrationNum = trim($_POST['registration_number'] ?? ''); // 企业:注册号 -$category = trim($_POST['target_product_category'] ?? ''); // 产品:品类(存 extra) -$needCategory = trim($_POST['need_category'] ?? ''); // 需求:需求类别(存 extra) +$workLocation = trim($_POST['work_location'] ?? ''); // 重要-人员 +$idNumber = trim($_POST['id_number'] ?? ''); // 重要-人员 +$platform = trim($_POST['platform'] ?? ''); // 核心-社媒 +$accountId = trim($_POST['account_id'] ?? ''); // 核心-社媒 +$profileUrl = trim($_POST['profile_url'] ?? ''); // 重要-主页 $sourceChannel = trim($_POST['source_channel'] ?? ''); // 硬数据标准校验: @@ -74,36 +76,35 @@ if ($accountId !== '' && $platform !== '') { } if (!empty($dups)) Response::duplicates($dups); -// 额外信息(身份证/社媒平台/账号ID/主页链接/产品品类/需求类别)存 extra_info -$extra = []; -if ($idNumber !== '') $extra['id_number'] = $idNumber; -if ($platform !== '') $extra['platform'] = $platform; -if ($accountId !== '') $extra['account_id'] = $accountId; -if ($profileUrl !== '') $extra['profile_url'] = $profileUrl; -if ($category !== '') $extra['category'] = $category; -if ($needCategory !== '') $extra['need_category'] = $needCategory; - // 至少有一项内容才能录为碎片 -if ($companyName === '' && $personName === '' && $phone === '' && $email === '' && !$extra) { +if ($companyName === '' && $personName === '' && $phone === '' && $email === '' && $idNumber === '' && $accountId === '') { Response::error('请至少填写一项内容', 400); } $pdo->prepare( "INSERT INTO preliminary_data - (source_type, company_name, industry, registration_number, person_name, contact_phone, contact_email, - source_channel, recorded_by, status, extra_info) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, '待处理', ?)" + (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 (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, '待处理')" )->execute([ $sourceType, $companyName !== '' ? $companyName : null, $industry !== '' ? $industry : null, $registrationNum !== '' ? $registrationNum : null, + $businessRole !== '' ? $businessRole : null, + $country !== '' ? $country : null, + $address !== '' ? $address : null, $personName !== '' ? $personName : null, $phone !== '' ? $phone : null, $email !== '' ? $email : null, + $workLocation !== '' ? $workLocation : null, + $idNumber !== '' ? $idNumber : null, + $platform !== '' ? $platform : null, + $accountId !== '' ? $accountId : null, + $profileUrl !== '' ? $profileUrl : null, $sourceChannel !== '' ? $sourceChannel : null, // 未选择来源保持空白 $_SESSION['username'] ?? null, - $extra ? json_encode($extra, JSON_UNESCAPED_UNICODE) : null, ]); $newId = (int)$pdo->lastInsertId(); @@ -113,7 +114,9 @@ logCurrent('add', 'fragment', 'preliminary_data', $newId, [ 'person_name' => $personName, 'phone' => $phone, 'email' => $email, - 'extra' => $extra, + 'id_number' => $idNumber, + 'platform' => $platform, + 'account_id' => $accountId, ]); Response::success(['id' => $newId], '新增成功'); diff --git a/api/fragment/hard_convert.php b/api/fragment/hard_convert.php index d65ace6..0eef8f9 100644 --- a/api/fragment/hard_convert.php +++ b/api/fragment/hard_convert.php @@ -39,25 +39,27 @@ $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'] ?? ''); // 仅补全录入表单提供(表中已无该字段) -$description = trim($_POST['description'] ?? ''); // 仅补全录入表单提供 -$industry = trim($_POST['industry'] ?? ($frag['industry'] ?? '')); // 企业:行业(转软碎片必填) -$registrationNum = trim($_POST['registration_number'] ?? ($frag['registration_number'] ?? '')); // 企业:注册号(转软碎片必填) +$industry = trim($_POST['industry'] ?? ($frag['industry'] ?? '')); // 核心-企业(转软碎片必填) +$registrationNum = trim($_POST['registration_number'] ?? ($frag['registration_number'] ?? '')); // 核心-企业(转软碎片必填) +$businessRole = trim($_POST['business_role'] ?? ($frag['business_role'] ?? '')); +$country = trim($_POST['country'] ?? ($frag['country'] ?? '')); +$address = trim($_POST['address'] ?? ($frag['address'] ?? '')); +$workLocation = trim($_POST['work_location'] ?? ($frag['work_location'] ?? '')); +$idNumber = trim($_POST['id_number'] ?? ($frag['id_number'] ?? '')); +$platform = trim($_POST['platform'] ?? ($frag['platform'] ?? '')); +$accountId = trim($_POST['account_id'] ?? ($frag['account_id'] ?? '')); +$profileUrl = trim($_POST['profile_url'] ?? ($frag['profile_url'] ?? '')); $sourceChannel = $frag['source_channel'] ?? null; -// 补全表单额外信息(extra_info) -$fragExtra = json_decode($frag['extra_info'] ?? 'null', true); -if (!is_array($fragExtra)) { - $fragExtra = []; -} -if ($category === '') $category = trim((string)($fragExtra['category'] ?? '')); -$needCategory = trim($_POST['need_category'] ?? ($fragExtra['need_category'] ?? '')); - $convertedId = 0; -// 格式校验:手机 / 邮箱 +// 格式校验:手机 / 邮箱 / 身份证 / 主页链接 checkFieldFormat('phone', $phone); checkFieldFormat('email', $email); +checkFieldFormat('id_number', $idNumber); +if ($profileUrl !== '' && !preg_match('/^https?:\/\//i', $profileUrl)) { + Response::error('主页链接格式不正确(应以 http:// 或 https:// 开头)', 400); +} // 各类型转软碎片基本要求 switch ($targetType) { @@ -84,17 +86,11 @@ switch ($targetType) { if ($companyName === '') { Response::error('产品类型转软碎片:公司名称为必填项,请先「继续补全」', 400); } - if ($category === '') { - Response::error('产品类型转软碎片:产品品类为必填项,请先「继续补全」填写品类', 400); - } break; case 'need': if ($companyName === '') { Response::error('需求类型转软碎片:公司名称为必填项,请先「继续补全」', 400); } - if ($needCategory === '') { - Response::error('需求类型转软碎片:需求类别为必填项,请先「继续补全」填写需求类别', 400); - } break; } @@ -126,6 +122,20 @@ $saveContacts = function ($ownerType, $ownerId) use ($pdo, $phone, $email) { } }; +/** 写入社媒账号(platform + account_id,主页链接作备注) */ +function saveSocialAccountIfAny(PDO $pdo, $ownerType, $ownerId, $platform, $accountId, $profileUrl = '') +{ + $platform = trim((string)$platform); + $accountId = trim((string)$accountId); + if ($platform === '' || $accountId === '' || in_array($platform, ['phone', 'email'], true)) { + return; + } + $pdo->prepare( + "INSERT INTO social_accounts (owner_type, owner_id, platform, account_id, profile_url, is_primary, is_defult) + VALUES (?, ?, ?, ?, ?, 0, 0)" + )->execute([$ownerType, $ownerId, $platform, $accountId, trim((string)$profileUrl) !== '' ? $profileUrl : null]); +} + /** 按名称找公司,找不到则自动创建 */ $resolveCompany = function () use ($pdo, $companyName, $sourceChannel, $industry, $registrationNum) { $stmt = $pdo->prepare("SELECT id FROM companies WHERE display_name = ? AND is_active = 1 LIMIT 1"); @@ -143,69 +153,62 @@ $resolveCompany = function () use ($pdo, $companyName, $sourceChannel, $industry switch ($targetType) { case 'company': $pdo->prepare( - "INSERT INTO companies (display_name, name_zh, industry, registration_number, business_scope, source_channel, source_detail) - VALUES (?, ?, ?, ?, ?, ?, ?)" + "INSERT INTO companies (display_name, name_zh, industry, registration_number, business_role, country, address, source_channel) + VALUES (?, ?, ?, ?, ?, ?, ?, ?)" )->execute([ $companyName, $companyName, $industry !== '' ? $industry : null, $registrationNum !== '' ? $registrationNum : null, - $description !== '' ? $description : null, + $businessRole !== '' ? $businessRole : null, + $country !== '' ? $country : null, + $address !== '' ? $address : null, $sourceChannel, - $description !== '' ? $description : null, ]); $convertedId = (int)$pdo->lastInsertId(); $saveContacts('company', $convertedId); + saveSocialAccountIfAny($pdo, 'company', $convertedId, $platform, $accountId, $profileUrl); updateIncomplete($pdo, 'companies', $convertedId); updateAccountsIncomplete($pdo, 'company', $convertedId); break; case 'person': - if ($personName === '') { - Response::error('联系人为必填项', 400); - } $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, $description !== '' ? $description : null]); + "INSERT INTO persons (union_id, full_name, work_location, id_number, source_channel) VALUES (?, ?, ?, ?, ?)" + )->execute([ + $unionId, $personName, + $workLocation !== '' ? $workLocation : null, + $idNumber !== '' ? $idNumber : null, + $sourceChannel, + ]); $convertedId = (int)$pdo->lastInsertId(); $saveContacts('person', $convertedId); + saveSocialAccountIfAny($pdo, 'person', $convertedId, $platform, $accountId, $profileUrl); updateIncomplete($pdo, 'persons', $convertedId); updateAccountsIncomplete($pdo, 'person', $convertedId); break; case 'product': - if ($companyName === '') { - Response::error('公司名称为必填项', 400); - } - if ($category === '') { - Response::error('产品品类为必填项', 400); - } $companyId = $resolveCompany(); + // 品类字段已在 preliminary 移除(非必要/待定),转换时默认「未分类」 $pdo->prepare( - "INSERT INTO company_products (company_id, category_name, category_description) - VALUES (?, ?, ?)" - )->execute([$companyId, $category, $description !== '' ? $description : null]); + "INSERT INTO company_products (company_id, category_name) + VALUES (?, '未分类')" + )->execute([$companyId]); $convertedId = (int)$pdo->lastInsertId(); updateIncomplete($pdo, 'companies', $companyId); break; case 'need': - if ($companyName === '') { - Response::error('公司名称为必填项', 400); - } $companyId = $resolveCompany(); $contactPerson = trim($_POST['contact_person'] ?? ($frag['person_name'] ?? '')); - $scenario = trim($_POST['application_scenario'] ?? ''); $pdo->prepare( - "INSERT INTO company_needs (company_id, contact_person, need_category, target_product_category, application_scenario, description) - VALUES (?, ?, ?, ?, ?, ?)" + "INSERT INTO company_needs (company_id, contact_person, description) + VALUES (?, ?, ?)" )->execute([ $companyId, $contactPerson !== '' ? $contactPerson : null, - $needCategory !== '' ? $needCategory : null, - $category !== '' ? $category : null, - $scenario !== '' ? $scenario : null, - $description !== '' ? $description : null, + null, ]); $convertedId = (int)$pdo->lastInsertId(); updateIncomplete($pdo, 'companies', $companyId); diff --git a/api/fragment/hard_list.php b/api/fragment/hard_list.php index 6c6c081..802badd 100644 --- a/api/fragment/hard_list.php +++ b/api/fragment/hard_list.php @@ -37,7 +37,8 @@ $total = (int)$stmt->fetchColumn(); $offset = ($page - 1) * $limit; $stmt = $pdo->prepare( - "SELECT id, source_type, company_name, person_name, contact_phone, contact_email, + "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, follow_person, converted_type, converted_id, created_at, updated_at FROM preliminary_data diff --git a/api/fragment/hard_update.php b/api/fragment/hard_update.php index e3df8ba..f2e69ed 100644 --- a/api/fragment/hard_update.php +++ b/api/fragment/hard_update.php @@ -32,17 +32,19 @@ if (in_array($frag['status'], ['已转换', '已废弃'], true)) { $sourceType = trim($_POST['source_type'] ?? ($frag['source_type'] ?? '')); $companyName = trim($_POST['company_name'] ?? ''); +$industry = trim($_POST['industry'] ?? ''); +$registrationNum = trim($_POST['registration_number'] ?? ''); +$businessRole = trim($_POST['business_role'] ?? ''); +$country = trim($_POST['country'] ?? ''); +$address = trim($_POST['address'] ?? ''); $personName = trim($_POST['person_name'] ?? ''); $phone = trim($_POST['contact_phone'] ?? ''); $email = trim($_POST['contact_email'] ?? ''); +$workLocation = trim($_POST['work_location'] ?? ''); $idNumber = trim($_POST['id_number'] ?? ''); $platform = trim($_POST['platform'] ?? ''); $accountId = trim($_POST['account_id'] ?? ''); $profileUrl = trim($_POST['profile_url'] ?? ''); -$industry = trim($_POST['industry'] ?? ''); // 企业:行业 -$registrationNum = trim($_POST['registration_number'] ?? ''); // 企业:注册号 -$category = trim($_POST['target_product_category'] ?? ''); // 产品:品类 -$needCategory = trim($_POST['need_category'] ?? ''); // 需求:需求类别 if (!in_array($sourceType, ['company', 'person', 'product', 'need', 'mixed'], true)) { Response::error('碎片类型不合法', 400); } @@ -84,32 +86,27 @@ if ($accountId !== '' && $platform !== '') { } if (!empty($dups)) Response::duplicates($dups); -// extra_info 合并更新(身份证/平台/账号ID/主页链接/品类/需求类别) -$extra = json_decode($frag['extra_info'] ?? 'null', true); -if (!is_array($extra)) { - $extra = []; -} -if ($idNumber !== '') $extra['id_number'] = $idNumber; else unset($extra['id_number']); -if ($platform !== '') $extra['platform'] = $platform; else unset($extra['platform']); -if ($accountId !== '') $extra['account_id'] = $accountId; else unset($extra['account_id']); -if ($profileUrl !== '') $extra['profile_url'] = $profileUrl; else unset($extra['profile_url']); -if ($category !== '') $extra['category'] = $category; else unset($extra['category']); -if ($needCategory !== '') $extra['need_category'] = $needCategory; else unset($extra['need_category']); - $pdo->prepare( "UPDATE preliminary_data - SET source_type = ?, company_name = ?, industry = ?, registration_number = ?, person_name = ?, - contact_phone = ?, contact_email = ?, extra_info = ? + SET 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 = ? WHERE id = ?" )->execute([ $sourceType, $companyName !== '' ? $companyName : null, $industry !== '' ? $industry : null, $registrationNum !== '' ? $registrationNum : null, + $businessRole !== '' ? $businessRole : null, + $country !== '' ? $country : null, + $address !== '' ? $address : null, $personName !== '' ? $personName : null, $phone !== '' ? $phone : null, $email !== '' ? $email : null, - $extra ? json_encode($extra, JSON_UNESCAPED_UNICODE) : null, + $workLocation !== '' ? $workLocation : null, + $idNumber !== '' ? $idNumber : null, + $platform !== '' ? $platform : null, + $accountId !== '' ? $accountId : null, + $profileUrl !== '' ? $profileUrl : null, $id, ]); @@ -119,7 +116,7 @@ logCurrent('update', 'fragment', 'preliminary_data', $id, [ 'person_name' => $personName, 'phone' => $phone, 'email' => $email, - 'extra' => $extra, + 'id_number' => $idNumber, ]); Response::success(null, '已保存,点击「转软碎片」完成转换'); diff --git a/sql/migration_v1.0.48.sql b/sql/migration_v1.0.48.sql new file mode 100644 index 0000000..d0ab0bd --- /dev/null +++ b/sql/migration_v1.0.48.sql @@ -0,0 +1,22 @@ +-- ============================================================ +-- SuperLink Web - v1.0.48 数据库结构变更 +-- preliminary_data 重构:只保留核心+重要字段为正式列,删除非必要字段 +-- 新增(重要字段正式化):business_role / country / address / work_location / +-- id_number / platform / account_id / profile_url +-- 删除:extra_info(原 JSON 容器;其中品类/需求类别为非必要/待定,不再存放) +-- 说明:删除前先备份整表到 preliminary_data_bak_20260810b +-- ============================================================ +SET NAMES utf8mb4; + +CREATE TABLE `preliminary_data_bak_20260810b` AS SELECT * FROM `preliminary_data`; + +ALTER TABLE `preliminary_data` + ADD COLUMN `business_role` varchar(50) DEFAULT NULL COMMENT '业务类型(重要)' AFTER `registration_number`, + ADD COLUMN `country` varchar(100) DEFAULT NULL COMMENT '国家/地区(重要)' AFTER `business_role`, + ADD COLUMN `address` varchar(255) DEFAULT NULL COMMENT '地址(重要)' AFTER `country`, + ADD COLUMN `work_location` varchar(100) DEFAULT NULL COMMENT '工作所在地(重要)' AFTER `contact_email`, + ADD COLUMN `id_number` varchar(100) DEFAULT NULL COMMENT '身份证号码(重要)' AFTER `work_location`, + ADD COLUMN `platform` varchar(50) DEFAULT NULL COMMENT '社媒平台(核心)' AFTER `id_number`, + ADD COLUMN `account_id` varchar(200) DEFAULT NULL COMMENT '社媒账号ID(核心)' AFTER `platform`, + ADD COLUMN `profile_url` varchar(500) DEFAULT NULL COMMENT '主页链接(重要)' AFTER `account_id`, + DROP COLUMN `extra_info`; diff --git a/static/js/config.js b/static/js/config.js index f1b1bed..ca0f687 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.47'; +var APP_VERSION = 'v1.0.48'; /** 页脚版权/备案信息(在 config.js 中修改) */ var FOOTER_TEXT = '© 2026 SuperLink 管理系统 版权所有 | 备案号:请替换为真实备案号'; diff --git a/static/js/fragment.js b/static/js/fragment.js index ead959d..6fb4815 100644 --- a/static/js/fragment.js +++ b/static/js/fragment.js @@ -209,8 +209,10 @@ $(function () { '
' + '
' + '
' + - '
' + - '
' + + '
' + + '
' + + '
' + + '
' + '
' + '
' + '
' + '' + '' + @@ -334,15 +337,17 @@ $(function () { '
' + '
' + '
' + - '
' + - '
' + - '
' + + '
' + + '
' + + '
' + + '
' + + '
' + '
' + - '
' + - '
' + + '
' + + '
' + '
' + '
补全仅保存到硬数据,点击「转软碎片」后才转换为主表数据。
' + '