Files
superlink/static/js/fragment.js
T

525 lines
33 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* fragment.js - 碎片处理中心(v1.0.27)
* 布局:顶部指标卡 + 【硬碎片】独立区块 + 【软碎片】独立区块(不用 Tab)
* 硬碎片:preliminary_data 中未终结记录(完整度/类型/内容摘要/来源/录入人/时间/状态/操作)
* 软碎片:四张主表 is_incomplete=1 记录(完整度/缺失层级标签/名称/缺失字段/所属表/时间/操作)
*/
$(function () {
renderShell('碎片处理中心', '数据管理 / 碎片处理');
renderPage();
initPage('preliminary', function (user) {
if (!checkPagePermission('preliminary')) return;
loadStats();
loadHardList(1);
loadSoftList(1);
loadDicts();
});
var hardPage = 1, softPage = 1;
var hardRows = [], softRows = [];
/** 缺失层级标签样式 */
function levelTagHtml(level) {
if (level === 'core') return '<span class="tag tag-red">缺核心</span>';
if (level === 'important') return '<span class="tag tag-orange">缺重要</span>';
if (level === 'optional') return '<span class="tag tag-blue">待补充</span>';
return '<span class="tag tag-green">完整</span>';
}
/** 完整度进度条 + 百分比 */
function completenessHtml(score) {
var color = score >= 80 ? '#2f8f46' : (score >= 65 ? '#e6a23c' : '#d9534f');
return '<div style="display:flex;align-items:center;gap:6px;min-width:90px;">' +
'<div style="flex:1;height:6px;background:#eef0f4;border-radius:3px;overflow:hidden;">' +
'<div style="height:100%;width:' + score + '%;background:' + color + ';border-radius:3px;"></div></div>' +
'<span style="font-size:12px;color:' + color + ';white-space:nowrap;">' + score + '%</span></div>';
}
/** 渲染页面内容:指标卡 + 硬碎片 + 软碎片 两个独立区块 */
function renderPage() {
$('#page-content').html(
'<div class="stat-cards" id="stat-cards"></div>' +
// ================= 硬碎片 =================
'<div class="card" style="margin-top:14px;">' +
' <div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:10px;">' +
' <b style="font-size:15px;color:#1e2a3a;">硬数据新增与处理</b>' +
' <span style="font-size:12px;color:#8a94a6;">关键字段缺失、未入主表的原始线索(不含已转换/已废弃)</span>' +
' </div>' +
' <div class="toolbar">' +
' <select id="hard-type"><option value="">全部类型</option>' +
' <option value="company">企业</option><option value="person">人员</option>' +
' <option value="product">产品</option><option value="need">需求</option><option value="mixed">混合</option></select>' +
' <select id="hard-source"><option value="">全部来源</option></select>' +
' <input type="text" id="hard-keyword" placeholder="公司/姓名/电话/邮箱关键词">' +
' <button class="btn btn-primary" id="hard-search">搜索</button>' +
' <button class="btn" id="hard-reset">重置</button>' +
' <span class="spacer"></span>' +
' <button class="btn btn-success" id="hard-add">+ 新增碎片</button>' +
' </div>' +
' <div class="table-wrap"><table class="grid">' +
' <thead><tr><th>完整度</th><th>类型</th><th>内容摘要</th><th>来源</th><th>录入人</th><th>最后修改</th><th>操作</th></tr></thead>' +
' <tbody id="hard-tbody"></tbody>' +
' </table></div>' +
' <div class="pagination" id="hard-pagination"></div>' +
'</div>' +
// ================= 软碎片 =================
'<div class="card" style="margin-top:14px;">' +
' <div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:10px;">' +
' <b style="font-size:15px;color:#1e2a3a;">软数据碎片处理</b>' +
' <span style="font-size:12px;color:#8a94a6;">已入主表但完整度低于阈值的记录(is_incomplete=1)</span>' +
' </div>' +
' <div class="toolbar">' +
' <select id="soft-table"><option value="">全部所属表</option>' +
' <option value="persons">人员</option><option value="companies">企业</option>' +
' <option value="social_accounts">联系方式</option><option value="media">媒体</option></select>' +
' <select id="soft-level"><option value="">全部缺失层级</option>' +
' <option value="core">缺核心</option><option value="important">缺重要</option>' +
' <option value="optional">待补充</option></select>' +
' <input type="text" id="soft-keyword" placeholder="名称关键词">' +
' <button class="btn btn-primary" id="soft-search">搜索</button>' +
' <button class="btn" id="soft-reset">重置</button>' +
' </div>' +
' <div class="table-wrap"><table class="grid">' +
' <thead><tr><th>完整度</th><th>缺失层级</th><th>名称</th><th>各层完整度</th><th>缺失字段</th><th>所属表</th><th>最近更新</th><th>操作</th></tr></thead>' +
' <tbody id="soft-tbody"></tbody>' +
' </table></div>' +
' <div class="pagination" id="soft-pagination"></div>' +
'</div>'
);
$('#hard-search').on('click', function () { loadHardList(1); });
$('#hard-keyword').on('keydown', function (e) { if (e.keyCode === 13) loadHardList(1); });
$('#hard-reset').on('click', function () {
$('#hard-type').val(''); $('#hard-source').val(''); $('#hard-keyword').val('');
loadHardList(1);
});
$('#hard-add').on('click', function () { openHardAdd(); });
$('#soft-search').on('click', function () { loadSoftList(1); });
$('#soft-keyword').on('keydown', function (e) { if (e.keyCode === 13) loadSoftList(1); });
$('#soft-reset').on('click', function () {
$('#soft-table').val(''); $('#soft-level').val(''); $('#soft-keyword').val('');
loadSoftList(1);
});
}
/** 来源渠道下拉选项 */
function loadDicts() {
httpGet('common/dicts.php', { type: 'all' }).then(function (d) {
var html = '<option value="">全部来源</option>';
(d.source_channels || []).forEach(function (c) {
html += '<option value="' + escHtml(c.name) + '">' + escHtml(c.name) + '</option>';
});
$('#hard-source').html(html);
}).catch(function () {});
}
/* ================= 顶部概览指标卡 ================= */
function loadStats() {
httpGet('fragment/stats_overview.php').then(function (d) {
$('#stat-cards').html(
'<div class="stat-card c-blue"><div class="num">' + d.hard_total + '/' + d.soft_total + '</div><div class="label">碎片总数(硬/软)</div></div>' +
'<div class="stat-card c-green"><div class="num">' + d.month_new + '</div><div class="label">本月新增</div></div>' +
'<div class="stat-card c-orange"><div class="num">' + d.month_processed + '</div><div class="label">本月处理</div></div>' +
'<div class="stat-card c-teal"><div class="num">' + d.cumulative + '</div><div class="label">累计处理</div></div>'
);
});
}
/* ================= 硬碎片列表 ================= */
function loadHardList(page) {
hardPage = page;
var params = {
page: page,
source_type: $('#hard-type').val(),
source_channel: $('#hard-source').val(),
keyword: $.trim($('#hard-keyword').val())
};
httpGet('fragment/hard_list.php', params).then(function (d) {
hardRows = d.list || [];
var html = '';
hardRows.forEach(function (r) {
html += '<tr>' +
'<td>' + completenessHtml(r.completeness) + '</td>' +
'<td>' + escHtml(r.source_type_label) + '</td>' +
'<td title="' + escHtml(r.summary) + '" style="max-width:280px;">' + escHtml(r.summary || '-') + '</td>' +
'<td>' + escHtml(r.source_channel || '-') + '</td>' +
'<td>' + escHtml(r.recorded_by || '-') + '</td>' +
'<td>' + fmtDate(r.updated_at) + '</td>' +
'<td class="ops">' +
' <a onclick="viewHard(' + r.id + ')">查看</a>' +
' <a onclick="convertHard(' + r.id + ')">继续补全</a>' +
' <a onclick="convertHardQuick(' + r.id + ')">转软碎片</a>' +
' <a onclick="discardHard(' + r.id + ')">废弃</a>' +
'</td></tr>';
});
if (!hardRows.length) {
html = '<tr><td colspan="7" class="empty-tip" style="padding:30px 0;">暂无硬碎片</td></tr>';
}
$('#hard-tbody').html(html);
renderPagination($('#hard-pagination'), d, loadHardList);
});
}
/* ================= 软碎片列表 ================= */
function loadSoftList(page) {
softPage = page;
var params = {
page: page,
table: $('#soft-table').val(),
level: $('#soft-level').val(),
keyword: $.trim($('#soft-keyword').val())
};
httpGet('fragment/soft_list.php', params).then(function (d) {
softRows = d.list || [];
var html = '';
softRows.forEach(function (r) {
var missing = (r.missing_fields || []).join('、') || '-';
var layers = r.layer_rates || {};
var layerHtml = '核心' + (layers.core !== undefined ? layers.core : '-') + '% / 重要' + (layers.important !== undefined ? layers.important : '-') + '% / 非必要' + (layers.optional !== undefined ? layers.optional : '-') + '%';
html += '<tr>' +
'<td>' + completenessHtml(r.overall) + '</td>' +
'<td>' + levelTagHtml(r.level) + '</td>' +
'<td>' + escHtml(r.name) + '</td>' +
'<td style="font-size:12px;color:#5a6472;white-space:nowrap;">' + layerHtml + '</td>' +
'<td style="max-width:240px;">' + escHtml(missing) + '</td>' +
'<td>' + escHtml(r.table_label) + '</td>' +
'<td>' + fmtDate(r.updated_at) + '</td>' +
'<td class="ops"><a onclick="completeSoft(\'' + r.table + '\',' + r.id + ')">补全</a></td></tr>';
});
if (!softRows.length) {
html = '<tr><td colspan="8" class="empty-tip" style="padding:30px 0;">暂无软碎片</td></tr>';
}
$('#soft-tbody').html(html);
renderPagination($('#soft-pagination'), d, loadSoftList);
});
}
/* ================= 硬碎片:新增 ================= */
function openHardAdd() {
var typeSel = '<select id="ha-type">' +
'<option value="company">企业</option><option value="person">人员</option>' +
'<option value="product">产品</option><option value="need">需求</option><option value="mixed">混合</option></select>';
var content =
'<form id="ha-form" style="padding:16px 22px 4px;">' +
'<div class="form-grid">' +
' <div class="form-item"><label>碎片类型<span class="req">*</span></label>' + typeSel + '</div>' +
' <div class="form-item" id="ha-f-company_name"><label>公司名称</label><input type="text" name="company_name" placeholder="如:深圳XX科技"></div>' +
' <div class="form-item" id="ha-f-person_name"><label>姓名</label><input type="text" name="person_name" placeholder="如:张三"></div>' +
' <div class="form-item"><label>联系电话</label><input type="text" name="contact_phone" placeholder="如:13812345678"></div>' +
' <div class="form-item"><label>联系邮箱</label><input type="text" name="contact_email" placeholder="如:a@b.com"></div>' +
' <div class="form-item" id="ha-f-industry"><label>行业</label><input type="text" name="industry" placeholder="转软碎片必填,如:工业机器人"></div>' +
' <div class="form-item" id="ha-f-regnum"><label>注册号</label><input type="text" name="registration_number" placeholder="转软碎片必填"></div>' +
' <div class="form-item" id="ha-f-bizrole"><label>业务类型</label><input type="text" name="business_role" placeholder="如:manufacturer/integrator"></div>' +
' <div class="form-item" id="ha-f-country"><label>国家/地区</label><input type="text" name="country" placeholder="如:中国"></div>' +
' <div class="form-item" id="ha-f-address"><label>地址</label><input type="text" name="address" placeholder="注册地址"></div>' +
' <div class="form-item" id="ha-f-workloc"><label>工作所在地</label><input type="text" name="work_location" placeholder="如:广东深圳"></div>' +
' <div class="form-item" id="ha-f-idnumber"><label>身份证号码</label><input type="text" name="id_number" placeholder="15 或 18 位"></div>' +
' <div class="form-item"><label>来源渠道</label><select name="source_channel" id="ha-source"><option value="">-</option></select></div>' +
' <div class="form-item" id="ha-f-platform"><label>社媒平台</label><select name="platform" id="ha-platform"><option value="">-</option>' +
' <option value="wechat">微信</option><option value="weibo">微博</option><option value="douyin">抖音</option>' +
' <option value="bilibili">B站</option><option value="linkedin">领英</option><option value="xiaohongshu">小红书</option>' +
' <option value="other">其他</option></select></div>' +
' <div class="form-item" id="ha-f-account"><label>账号ID</label><input type="text" name="account_id" placeholder="社媒账号ID"></div>' +
' <div class="form-item" id="ha-f-profile"><label>主页链接</label><input type="text" name="profile_url" placeholder="https://..."></div>' +
'</div>' +
'<div class="dialog-footer"><button type="button" class="btn" id="ha-cancel">取消</button>' +
'<button type="submit" class="btn btn-primary">保存碎片</button></div>' +
'</form>';
var idx = Dialog.open({
title: '新增硬碎片',
area: ['640px', 'auto'],
content: content,
btn: false
});
// 来源渠道选项(与 source_channels 字典保持一致,不额外添加选项)
httpGet('common/dicts.php', { type: 'all' }).then(function (d) {
var html = '<option value="">-</option>';
(d.source_channels || []).forEach(function (c) {
html += '<option value="' + escHtml(c.name) + '">' + escHtml(c.name) + '</option>';
});
$('#ha-source').html(html);
}).catch(function () {});
function syncFields() {
var t = $('#ha-type').val();
// 公司名称:除人员外都显示
$('#ha-f-company_name').toggle(t !== 'person');
// 姓名/联系人:人员与混合显示「姓名」,其它类型显示「联系人」
$('#ha-f-person_name').toggle(true);
$('#ha-f-person_name label').text((t === 'person' || t === 'mixed') ? '姓名' : '联系人');
// 企业专属:行业 / 注册号 / 业务类型 / 国家 / 地址
var isCompany = (t === 'company');
$('#ha-f-industry').toggle(isCompany);
$('#ha-f-regnum').toggle(isCompany);
$('#ha-f-bizrole').toggle(isCompany);
$('#ha-f-country').toggle(isCompany);
$('#ha-f-address').toggle(isCompany);
// 人员专属:工作所在地
$('#ha-f-workloc').toggle(t === 'person');
// 身份证 / 社媒平台 / 账号 / 主页:企业与人员显示
var showIdSocial = (t === 'company' || t === 'person');
$('#ha-f-idnumber').toggle(showIdSocial);
$('#ha-f-platform').toggle(showIdSocial);
$('#ha-f-account').toggle(showIdSocial);
$('#ha-f-profile').toggle(showIdSocial);
}
$('#ha-type').on('change', syncFields);
syncFields();
$('#ha-cancel').on('click', function () { Dialog.close(idx); });
$('#ha-form').on('submit', function (e) {
e.preventDefault();
var fd = {};
$(this).find('input, select, textarea').each(function () {
var name = $(this).attr('name');
if (name) fd[name] = $(this).val();
});
fd.source_type = $('#ha-type').val();
// 硬数据标准校验:企业/产品/需求 → 企业名称必填;人员 → 手机、邮箱至少一项
if (fd.source_type !== 'person' && !$.trim(fd.company_name)) { Dialog.error('企业类型硬数据:企业名称为必填项'); return; }
if (fd.source_type === 'person' && !$.trim(fd.contact_phone) && !$.trim(fd.contact_email)) { Dialog.error('人员类型硬数据:手机号码、邮箱至少填写一项'); return; }
// 格式校验:手机 / 邮箱 / 身份证
if (fd.contact_phone && !validatePhoneCN(fd.contact_phone)) { Dialog.error('手机号码格式不正确(应为国内 11 位手机号,如 13812345678)'); return; }
if (fd.contact_email && !validateEmail(fd.contact_email)) { Dialog.error('邮箱格式不正确'); return; }
if (fd.id_number && !validateIdCard(fd.id_number)) { Dialog.error('身份证号码格式不正确(应为 15 或 18 位)'); return; }
if (fd.profile_url && !/^https?:\/\//.test(fd.profile_url)) { Dialog.error('主页链接格式不正确(应以 http:// 或 https:// 开头)'); return; }
httpPost('fragment/hard_add.php', fd).then(function () {
Dialog.success('新增成功', function () {
Dialog.close(idx);
loadStats();
loadHardList(1);
});
});
});
}
/* ================= 硬碎片:查看 ================= */
window.viewHard = function (id) {
httpGet('fragment/hard_detail.php', { id: id }).then(function (d) {
var rowHtml = '';
var fields = [
['类型', d.source_type_label], ['公司名称', d.company_name], ['联系人', d.person_name],
['联系电话', d.contact_phone], ['联系邮箱', d.contact_email],
['来源渠道', d.source_channel], ['录入人', d.recorded_by], ['状态', d.status],
['录入时间', d.created_at], ['处理时间', d.processed_at]
];
fields.forEach(function (f) {
rowHtml += '<div style="display:flex;margin:6px 0;"><span style="width:80px;color:#8a94a6;">' + f[0] + '</span>' +
'<span>' + escHtml(f[1] || '-') + '</span></div>';
});
Dialog.open({
title: '硬碎片详情(完整度 ' + d.completeness + '%)',
area: ['560px', 'auto'],
content: '<div style="padding:16px 22px;">' + rowHtml + '</div>',
btn: ['关闭']
});
});
};
/* ================= 硬碎片:补全录入(转换) ================= */
window.convertHard = function (id) {
httpGet('fragment/hard_detail.php', { id: id }).then(function (d) {
var typeSel = '<select id="cv-type">' +
'<option value="company"' + (d.source_type === 'company' ? ' selected' : '') + '>企业</option>' +
'<option value="person"' + (d.source_type === 'person' ? ' selected' : '') + '>人员</option>' +
'<option value="product"' + (d.source_type === 'product' ? ' selected' : '') + '>产品</option>' +
'<option value="need"' + (d.source_type === 'need' ? ' selected' : '') + '>需求</option>' +
'<option value="mixed"' + (d.source_type === 'mixed' ? ' selected' : '') + '>混合</option></select>';
var content =
'<form id="cv-form" style="padding:16px 22px 4px;">' +
'<div class="form-grid">' +
' <div class="form-item"><label>碎片类型<span class="req">*</span></label>' + typeSel + '</div>' +
' <div class="form-item" id="cv-f-company_name"><label>公司名称</label><input type="text" name="company_name" value="' + escHtml(d.company_name || '') + '"></div>' +
' <div class="form-item" id="cv-f-person_name"><label>联系人</label><input type="text" name="person_name" value="' + escHtml(d.person_name || '') + '"></div>' +
' <div class="form-item"><label>联系电话</label><input type="text" name="contact_phone" value="' + escHtml(d.contact_phone || '') + '"></div>' +
' <div class="form-item"><label>联系邮箱</label><input type="text" name="contact_email" value="' + escHtml(d.contact_email || '') + '"></div>' +
' <div class="form-item" id="cv-f-industry"><label>行业</label><input type="text" name="industry" value="' + escHtml(d.industry || '') + '" placeholder="转软碎片必填"></div>' +
' <div class="form-item" id="cv-f-regnum"><label>注册号</label><input type="text" name="registration_number" value="' + escHtml(d.registration_number || '') + '" placeholder="转软碎片必填"></div>' +
' <div class="form-item" id="cv-f-bizrole"><label>业务类型</label><input type="text" name="business_role" value="' + escHtml(d.business_role || '') + '"></div>' +
' <div class="form-item" id="cv-f-country"><label>国家/地区</label><input type="text" name="country" value="' + escHtml(d.country || '') + '"></div>' +
' <div class="form-item" id="cv-f-address"><label>地址</label><input type="text" name="address" value="' + escHtml(d.address || '') + '"></div>' +
' <div class="form-item" id="cv-f-workloc"><label>工作所在地</label><input type="text" name="work_location" value="' + escHtml(d.work_location || '') + '"></div>' +
' <div class="form-item" id="cv-f-idnumber"><label>身份证号码</label><input type="text" name="id_number" value="' + escHtml(d.id_number || '') + '" placeholder="15 或 18 位"></div>' +
' <div class="form-item" id="cv-f-platform"><label>社媒平台</label><select name="platform" id="cv-platform"><option value="">-</option>' +
' <option value="wechat">微信</option><option value="weibo">微博</option><option value="douyin">抖音</option>' +
' <option value="bilibili">B站</option><option value="linkedin">领英</option><option value="xiaohongshu">小红书</option>' +
' <option value="other">其他</option></select></div>' +
' <div class="form-item" id="cv-f-account"><label>账号ID</label><input type="text" name="account_id" value="' + escHtml(d.account_id || '') + '" placeholder="社媒账号ID"></div>' +
' <div class="form-item" id="cv-f-profile"><label>主页链接</label><input type="text" name="profile_url" value="' + escHtml(d.profile_url || '') + '" placeholder="https://..."></div>' +
'</div>' +
'<div style="font-size:12px;color:#8a94a6;margin-top:4px;">补全仅保存到硬数据,点击「转软碎片」后才转换为主表数据。</div>' +
'<div class="dialog-footer"><button type="button" class="btn" id="cv-cancel">取消</button>' +
'<button type="submit" class="btn btn-primary">保存补全</button></div>' +
'</form>';
var idx = Dialog.open({
title: '硬数据继续补全',
area: ['640px', 'auto'],
content: content,
btn: false
});
$('#cv-platform').val(d.platform || '');
function syncFields() {
var t = $('#cv-type').val();
$('#cv-f-company_name').toggle(t !== 'person');
$('#cv-f-person_name').toggle(true);
$('#cv-f-person_name label').text((t === 'person' || t === 'mixed') ? '姓名' : '联系人');
var isCompany = (t === 'company');
$('#cv-f-industry').toggle(isCompany);
$('#cv-f-regnum').toggle(isCompany);
$('#cv-f-bizrole').toggle(isCompany);
$('#cv-f-country').toggle(isCompany);
$('#cv-f-address').toggle(isCompany);
$('#cv-f-workloc').toggle(t === 'person');
var showIdSocial = (t === 'company' || t === 'person');
$('#cv-f-idnumber').toggle(showIdSocial);
$('#cv-f-platform').toggle(showIdSocial);
$('#cv-f-account').toggle(showIdSocial);
$('#cv-f-profile').toggle(showIdSocial);
}
$('#cv-type').on('change', syncFields);
syncFields();
function syncFields() {
var t = $('#cv-type').val();
$('#cv-f-company_name').toggle(t !== 'person');
$('#cv-f-person_name').toggle(t === 'person' || t === 'mixed');
}
$('#cv-type').on('change', syncFields);
syncFields();
$('#cv-cancel').on('click', function () { Dialog.close(idx); });
$('#cv-form').on('submit', function (e) {
e.preventDefault();
var fd = {};
$(this).find('input, select').each(function () {
var name = $(this).attr('name');
if (name) fd[name] = $(this).val();
});
fd.id = id;
// 类型标准校验
if (fd.source_type !== 'person' && fd.source_type !== 'mixed' && !$.trim(fd.company_name)) { Dialog.error('企业类型硬数据:企业名称为必填项'); return; }
if (fd.source_type === 'person' && !$.trim(fd.contact_phone) && !$.trim(fd.contact_email)) { Dialog.error('人员类型硬数据:手机号码、邮箱至少填写一项'); return; }
// 格式校验:手机 / 邮箱 / 身份证 / 主页链接
if (fd.contact_phone && !validatePhoneCN(fd.contact_phone)) { Dialog.error('手机号码格式不正确(应为国内 11 位手机号,如 13812345678)'); return; }
if (fd.contact_email && !validateEmail(fd.contact_email)) { Dialog.error('邮箱格式不正确'); return; }
if (fd.id_number && !validateIdCard(fd.id_number)) { Dialog.error('身份证号码格式不正确(应为 15 或 18 位)'); return; }
if (fd.profile_url && !/^https?:\/\//.test(fd.profile_url)) { Dialog.error('主页链接格式不正确(应以 http:// 或 https:// 开头)'); return; }
httpPost('fragment/hard_update.php', fd).then(function () {
Dialog.success('已保存,点击「转软碎片」完成转换', function () {
Dialog.close(idx);
loadHardList(hardPage);
});
});
});
});
};
/* ================= 硬碎片:转软碎片(不弹窗,直接转换) ================= */
window.convertHardQuick = function (id) {
httpGet('fragment/hard_detail.php', { id: id }).then(function (d) {
var target = d.source_type;
if (target === 'mixed') {
target = d.company_name ? 'company' : (d.person_name ? 'person' : '');
}
if (!target) {
Dialog.error('该碎片缺少可转换信息,请使用「继续补全」');
return;
}
// 各类型转软碎片基本要求预检
if (target === 'company' && (!d.industry || !d.registration_number)) {
Dialog.error('企业类型转软碎片:请先「继续补全」填写行业和注册号');
return;
}
if (target === 'person' && !d.person_name) {
Dialog.error('人员类型转软碎片:请先「继续补全」填写姓名');
return;
}
if (target === 'product' && !d.company_name) {
Dialog.error('产品类型转软碎片:请先「继续补全」填写公司名称');
return;
}
if (target === 'need' && !d.company_name) {
Dialog.error('需求类型转软碎片:请先「继续补全」填写公司名称');
return;
}
Dialog.confirm('确定将该硬数据直接转换为软数据碎片吗?', function () {
httpPost('fragment/hard_convert.php', { id: id, target_type: target }).then(function () {
Dialog.success('已转为软碎片', function () {
loadStats();
loadHardList(hardPage);
loadSoftList(1);
});
});
});
});
};
/* ================= 硬碎片:废弃 ================= */
window.discardHard = function (id) {
Dialog.confirm('确定废弃该碎片吗?废弃后不可恢复。', function () {
httpPost('fragment/hard_discard.php', { id: id }).then(function () {
Dialog.success('已废弃', function () {
loadStats();
loadHardList(hardPage);
});
});
});
};
/* ================= 软碎片:补全 ================= */
window.completeSoft = function (table, id) {
httpGet('fragment/soft_detail.php', { table: table, id: id }).then(function (d) {
var allMissing = [].concat(d.missing_core || [], d.missing_important || [], d.missing_optional || []);
var inputs = '';
allMissing.forEach(function (m) {
var isDate = (m.key === 'established_date');
inputs += '<div class="form-item"><label>' + escHtml(m.label) + (m.key === 'full_name' || m.key === 'display_name' ? '<span class="req">*</span>' : '') + '</label>' +
'<input type="' + (isDate ? 'date' : 'text') + '" name="' + m.key + '"></div>';
});
var layers = d.layers || {};
var layerDesc = '核心' + (layers.core ? layers.core.rate : '-') + '% / 重要' + (layers.important ? layers.important.rate : '-') + '% / 非必要' + (layers.optional ? layers.optional.rate : '-') + '%';
var content =
'<form id="soft-form" style="padding:16px 22px 4px;">' +
'<div style="font-size:12px;color:#8a94a6;margin-bottom:4px;">整体完整度 <b style="color:#d9534f;">' + d.overall + '%</b>,各层:' + layerDesc + '</div>' +
'<div style="font-size:12px;color:#8a94a6;margin-bottom:10px;">核心层须 100%、重要层 ≥60%、非必要层 ≥40%,补全后自动重新计算。</div>' +
'<div class="form-grid">' + inputs + '</div>' +
'<div class="dialog-footer"><button type="button" class="btn" id="soft-cancel">取消</button>' +
'<button type="submit" class="btn btn-primary">保存补全</button></div>' +
'</form>';
var idx = Dialog.open({
title: '软碎片补全 - ' + escHtml(d.name) + '(' + d.table_label + ')',
area: ['640px', 'auto'],
content: content,
btn: false
});
$('#soft-cancel').on('click', function () { Dialog.close(idx); });
$('#soft-form').on('submit', function (e) {
e.preventDefault();
var fd = { table: table, id: id };
$(this).find('input').each(function () {
var name = $(this).attr('name');
if (name) fd[name] = $(this).val();
});
// 格式校验:身份证 / 手机 / 邮箱
if (fd.id_number && !validateIdCard(fd.id_number)) { Dialog.error('身份证号码格式不正确(应为 15 或 18 位)'); return; }
if (fd.phone && !validatePhoneCN(fd.phone)) { Dialog.error('手机号码格式不正确(应为国内 11 位手机号,如 13812345678)'); return; }
if (fd.email && !validateEmail(fd.email)) { Dialog.error('邮箱格式不正确'); return; }
httpPost('fragment/soft_update.php', fd).then(function (res) {
Dialog.success(res && res.is_complete ? '补全完成' : '已保存(整体完整度 ' + (res && res.overall) + '%)', function () {
Dialog.close(idx);
loadStats();
loadSoftList(softPage);
loadHardList(hardPage);
});
});
});
});
};
});