v1.0.29: 碎片处理按dp方案2修订 - 完整度改三层独立判定(核心100%/重要60%/非必要40%,任一不达标即碎片)+字段分层调整(persons email升核心,companies核心扩5字段)+指标卡5张(新增累计处理,本月/累计=硬+软合计)+软碎片列表加各层完整度列+硬碎片完整度改已填/总可填
This commit is contained in:
+82
-49
@@ -1,46 +1,49 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* 完整度计算引擎(碎片处理方案 v1.0.27)
|
* 完整度判定引擎(碎片处理方案 v2,2026-08-09)
|
||||||
* 公式:完整度 = 100 - (缺失核心字段数×20) - (缺失重要字段数×8) - (缺失补充字段数×2),下限 0%
|
* 三层独立判定:任一楼层不达标 → is_incomplete = 1
|
||||||
* 阈值:persons/companies ≥65%,social_accounts ≥60%,media_commercial_attributes ≥55%
|
* - 核心层 必须 100% 达标(不达标 = 缺核心,最高优先级)
|
||||||
|
* - 重要层 必须 ≥ 60% 达标(不达标 = 缺重要)
|
||||||
|
* - 非必要层 必须 ≥ 40% 达标(不达标 = 待补充)
|
||||||
|
* 每层完整度 = 该层已填字段数 ÷ 该层总字段数 × 100%
|
||||||
|
* 整体完整度 = 全部已填字段数 ÷ 全部字段数 × 100%(展示用)
|
||||||
* 说明:persons 的 phone/email 为虚拟字段(来自 social_accounts 关联记录)
|
* 说明:persons 的 phone/email 为虚拟字段(来自 social_accounts 关联记录)
|
||||||
*/
|
*/
|
||||||
require_once __DIR__ . '/db.php';
|
require_once __DIR__ . '/db.php';
|
||||||
|
|
||||||
/** 四表字段分层定义(key => 层级),threshold 为完整度阈值 */
|
/** 四表字段分层定义(key => 所属层;virtual 为关联虚拟字段) */
|
||||||
const COMPLETENESS_LAYERS = [
|
const COMPLETENESS_LAYERS = [
|
||||||
'persons' => [
|
'persons' => [
|
||||||
'core' => ['full_name'],
|
'core' => ['full_name'],
|
||||||
'important' => ['work_location'],
|
'important' => ['work_location'],
|
||||||
'supplementary' => ['gender', 'nationality', 'education', 'graduated_from', 'hometown', 'id_type', 'id_number'],
|
'optional' => ['gender', 'nationality', 'education', 'graduated_from', 'hometown', 'id_type', 'id_number'],
|
||||||
'virtual' => ['phone' => 'core', 'email' => 'important'], // 关联 social_accounts.platform
|
'virtual' => ['phone' => 'core', 'email' => 'core'], // 关联 social_accounts.platform
|
||||||
'threshold' => 65,
|
|
||||||
],
|
],
|
||||||
'companies' => [
|
'companies' => [
|
||||||
'core' => ['display_name', 'industry'],
|
'core' => ['display_name', 'name_zh', 'name_en', 'business_role', 'industry'],
|
||||||
'important' => ['address', 'business_role', 'country'],
|
'important' => ['address', 'country'],
|
||||||
'supplementary' => ['name_zh', 'name_en', 'registration_number', 'legal_form', 'legal_representative',
|
'optional' => ['registration_number', 'legal_form', 'legal_representative', 'business_scope',
|
||||||
'business_scope', 'established_date', 'registered_capital', 'industry_subdivision',
|
'established_date', 'registered_capital', 'industry_subdivision',
|
||||||
'latest_employee_count', 'latest_annual_revenue', 'is_listed', 'stock_code', 'website'],
|
'latest_employee_count', 'latest_annual_revenue', 'is_listed', 'stock_code', 'website'],
|
||||||
'virtual' => [],
|
'virtual' => [],
|
||||||
'threshold' => 65,
|
|
||||||
],
|
],
|
||||||
'social_accounts' => [
|
'social_accounts' => [
|
||||||
'core' => ['platform', 'account_id'],
|
'core' => ['platform', 'account_id'],
|
||||||
'important' => ['is_primary'],
|
'important' => ['is_primary'],
|
||||||
'supplementary' => ['profile_url', 'remark'],
|
'optional' => ['profile_url', 'remark'],
|
||||||
'virtual' => [],
|
'virtual' => [],
|
||||||
'threshold' => 60,
|
|
||||||
],
|
],
|
||||||
'media' => [
|
'media' => [
|
||||||
'core' => ['social_account_id', 'account_level'],
|
'core' => ['social_account_id', 'account_level'],
|
||||||
'important' => ['follower_count', 'content_categories'],
|
'important' => ['follower_count', 'content_categories'],
|
||||||
'supplementary' => ['certification_type', 'avg_read_count', 'special_requirements', 'media_remark'],
|
'optional' => ['avg_read_count', 'certification_type', 'special_requirements', 'media_remark'],
|
||||||
'virtual' => [],
|
'virtual' => [],
|
||||||
'threshold' => 55,
|
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/** 各层达标门槛(%) */
|
||||||
|
const COMPLETENESS_THRESHOLDS = ['core' => 100, 'important' => 60, 'optional' => 40];
|
||||||
|
|
||||||
/** 字段中文名(前端展示缺失字段用) */
|
/** 字段中文名(前端展示缺失字段用) */
|
||||||
const COMPLETENESS_LABELS = [
|
const COMPLETENESS_LABELS = [
|
||||||
'full_name' => '姓名', 'phone' => '手机', 'email' => '邮箱', 'work_location' => '工作所在地',
|
'full_name' => '姓名', 'phone' => '手机', 'email' => '邮箱', 'work_location' => '工作所在地',
|
||||||
@@ -65,53 +68,84 @@ function completenessIsMissing($v)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据分层定义计算完整度
|
* 三层完整度计算
|
||||||
* @param string $table persons|companies|social_accounts|media
|
* @param string $table persons|companies|social_accounts|media
|
||||||
* @param array $row 该表记录(persons 需已注入虚拟字段 phone/email)
|
* @param array $row 该表记录(persons 需已注入虚拟字段 phone/email)
|
||||||
* @return array { score:int, missing_core:[], missing_important:[], missing_supp:[], level:string }
|
* @return array {
|
||||||
|
* layers: { core:{filled,total,rate,passed}, important:{...}, optional:{...} },
|
||||||
|
* overall: float, overall_passed: bool,
|
||||||
|
* missing: { core:[], important:[], optional:[] },
|
||||||
|
* level: core|important|optional|complete
|
||||||
|
* }
|
||||||
*/
|
*/
|
||||||
function completenessCalc($table, $row)
|
function completenessCalc($table, $row)
|
||||||
{
|
{
|
||||||
$layers = COMPLETENESS_LAYERS[$table] ?? null;
|
$layers = COMPLETENESS_LAYERS[$table] ?? null;
|
||||||
|
$default = [
|
||||||
|
'layers' => ['core' => ['filled' => 0, 'total' => 0, 'rate' => 100, 'passed' => true]],
|
||||||
|
'overall' => 100, 'overall_passed' => true,
|
||||||
|
'missing' => ['core' => [], 'important' => [], 'optional' => []],
|
||||||
|
'level' => 'complete',
|
||||||
|
];
|
||||||
if (!$layers) {
|
if (!$layers) {
|
||||||
return ['score' => 100, 'missing_core' => [], 'missing_important' => [], 'missing_supp' => [], 'level' => 'complete'];
|
return $default;
|
||||||
}
|
}
|
||||||
$missing = ['core' => [], 'important' => [], 'supplementary' => []];
|
|
||||||
|
|
||||||
foreach (['core' => 'core', 'important' => 'important', 'supplementary' => 'supplementary'] as $layer => $bucket) {
|
$result = [];
|
||||||
|
$missing = ['core' => [], 'important' => [], 'optional' => []];
|
||||||
|
$totalAll = 0;
|
||||||
|
$filledAll = 0;
|
||||||
|
|
||||||
|
foreach (['core', 'important', 'optional'] as $layer) {
|
||||||
|
$total = count($layers[$layer]);
|
||||||
|
$filled = 0;
|
||||||
foreach ($layers[$layer] as $field) {
|
foreach ($layers[$layer] as $field) {
|
||||||
if (completenessIsMissing($row[$field] ?? null)) {
|
|
||||||
$missing[$bucket][] = $field;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 虚拟字段(如人员 phone/email)按配置的层级计入
|
|
||||||
foreach (($layers['virtual'] ?? []) as $field => $layer) {
|
|
||||||
if (completenessIsMissing($row[$field] ?? null)) {
|
if (completenessIsMissing($row[$field] ?? null)) {
|
||||||
$missing[$layer][] = $field;
|
$missing[$layer][] = $field;
|
||||||
|
} else {
|
||||||
|
$filled++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// 虚拟字段(persons phone/email)按配置层计入
|
||||||
|
foreach (($layers['virtual'] ?? []) as $vf => $vLayer) {
|
||||||
|
if ($vLayer !== $layer) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$total++;
|
||||||
|
if (completenessIsMissing($row[$vf] ?? null)) {
|
||||||
|
$missing[$layer][] = $vf;
|
||||||
|
} else {
|
||||||
|
$filled++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$rate = $total > 0 ? round($filled / $total * 100, 1) : 100;
|
||||||
|
$result[$layer] = [
|
||||||
|
'filled' => $filled,
|
||||||
|
'total' => $total,
|
||||||
|
'rate' => $rate,
|
||||||
|
'passed' => $rate >= COMPLETENESS_THRESHOLDS[$layer],
|
||||||
|
];
|
||||||
|
$totalAll += $total;
|
||||||
|
$filledAll += $filled;
|
||||||
|
}
|
||||||
|
|
||||||
$score = 100
|
$overall = $totalAll > 0 ? round($filledAll / $totalAll * 100, 1) : 100;
|
||||||
- count($missing['core']) * 20
|
$overallPassed = $result['core']['passed'] && $result['important']['passed'] && $result['optional']['passed'];
|
||||||
- count($missing['important']) * 8
|
|
||||||
- count($missing['supplementary']) * 2;
|
|
||||||
$score = max(0, $score);
|
|
||||||
|
|
||||||
$level = 'complete';
|
$level = 'complete';
|
||||||
if (!empty($missing['core'])) {
|
if (!$result['core']['passed']) {
|
||||||
$level = 'core'; // 缺核心(红)
|
$level = 'core'; // 缺核心(红)
|
||||||
} elseif (!empty($missing['important'])) {
|
} elseif (!$result['important']['passed']) {
|
||||||
$level = 'important'; // 缺重要(橙)
|
$level = 'important'; // 缺重要(橙)
|
||||||
} elseif (!empty($missing['supplementary'])) {
|
} elseif (!$result['optional']['passed']) {
|
||||||
$level = 'supplementary'; // 待补充(蓝)
|
$level = 'optional'; // 待补充(蓝)
|
||||||
}
|
}
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'score' => $score,
|
'layers' => $result,
|
||||||
'missing_core' => $missing['core'],
|
'overall' => $overall,
|
||||||
'missing_important' => $missing['important'],
|
'overall_passed' => $overallPassed,
|
||||||
'missing_supp' => $missing['supplementary'],
|
'missing' => $missing,
|
||||||
'level' => $level,
|
'level' => $level,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@@ -138,7 +172,7 @@ function personWithVirtualFields(PDO $pdo, array $row)
|
|||||||
* @param PDO $pdo
|
* @param PDO $pdo
|
||||||
* @param string $table persons|companies|social_accounts|media
|
* @param string $table persons|companies|social_accounts|media
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @return array { row, score, missing_core, missing_important, missing_supp, level, threshold }
|
* @return array|null { row, layers, overall, overall_passed, missing, level, is_complete }
|
||||||
*/
|
*/
|
||||||
function completenessInfo(PDO $pdo, $table, $id)
|
function completenessInfo(PDO $pdo, $table, $id)
|
||||||
{
|
{
|
||||||
@@ -177,18 +211,17 @@ function completenessInfo(PDO $pdo, $table, $id)
|
|||||||
$calc = completenessCalc($table, $row);
|
$calc = completenessCalc($table, $row);
|
||||||
return [
|
return [
|
||||||
'row' => $row,
|
'row' => $row,
|
||||||
'score' => $calc['score'],
|
'layers' => $calc['layers'],
|
||||||
'missing_core' => $calc['missing_core'],
|
'overall' => $calc['overall'],
|
||||||
'missing_important' => $calc['missing_important'],
|
'overall_passed' => $calc['overall_passed'],
|
||||||
'missing_supp' => $calc['missing_supp'],
|
'missing' => $calc['missing'],
|
||||||
'level' => $calc['level'],
|
'level' => $calc['level'],
|
||||||
'threshold' => COMPLETENESS_LAYERS[$table]['threshold'] ?? 65,
|
'is_complete' => $calc['overall_passed'],
|
||||||
'is_complete' => $calc['score'] >= (COMPLETENESS_LAYERS[$table]['threshold'] ?? 65),
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新某条记录的 is_incomplete 标记(完整度低于阈值 → 1)
|
* 更新某条记录的 is_incomplete 标记(任一楼层不达标 → 1)
|
||||||
* @param PDO $pdo
|
* @param PDO $pdo
|
||||||
* @param string $table persons|companies|social_accounts|media
|
* @param string $table persons|companies|social_accounts|media
|
||||||
* @param int $id
|
* @param int $id
|
||||||
|
|||||||
@@ -1,45 +1,31 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* 硬碎片公共逻辑:字段分层 / 完整度计算 / 内容摘要
|
* 硬碎片公共逻辑:完整度计算(按非空字段直接计数)+ 内容摘要
|
||||||
* 被 hard_list.php 与 hard_detail.php 共用
|
* 被 hard_list.php 与 hard_detail.php 共用
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** 硬碎片字段分层(按 source_type) */
|
/** 硬碎片可统计字段(公司名/联系人/电话/邮箱/品类/描述) */
|
||||||
const HARD_LAYERS = [
|
const HARD_FIELDS = ['company_name', 'person_name', 'contact_phone', 'contact_email', 'target_product_category', 'description'];
|
||||||
'company' => ['core' => ['company_name', 'contact_phone'], 'important' => ['contact_email'], 'supplementary' => ['person_name', 'description', 'target_product_category']],
|
|
||||||
'person' => ['core' => ['person_name', 'contact_phone'], 'important' => ['contact_email'], 'supplementary' => ['company_name', 'description', 'target_product_category']],
|
|
||||||
'product' => ['core' => ['company_name', 'target_product_category'], 'important' => ['contact_phone', 'contact_email'], 'supplementary' => ['person_name', 'description']],
|
|
||||||
'need' => ['core' => ['company_name', 'target_product_category'], 'important' => ['contact_phone', 'contact_email'], 'supplementary' => ['person_name', 'description']],
|
|
||||||
'mixed' => ['core' => ['company_name', 'person_name'], 'important' => ['contact_phone', 'contact_email'], 'supplementary' => ['description', 'target_product_category']],
|
|
||||||
];
|
|
||||||
const HARD_LABELS = [
|
const HARD_LABELS = [
|
||||||
'company_name' => '公司名称', 'person_name' => '联系人', 'contact_phone' => '电话',
|
'company_name' => '公司名称', 'person_name' => '联系人', 'contact_phone' => '电话',
|
||||||
'contact_email' => '邮箱', 'target_product_category' => '产品品类', 'description' => '描述',
|
'contact_email' => '邮箱', 'target_product_category' => '产品品类', 'description' => '描述',
|
||||||
];
|
];
|
||||||
|
|
||||||
/** 计算硬碎片完整度与缺失层级 */
|
/** 计算硬碎片完整度:已填字段数 ÷ 总可填字段数 × 100% */
|
||||||
function hardCompleteness($row)
|
function hardCompleteness($row)
|
||||||
{
|
{
|
||||||
$layers = HARD_LAYERS[$row['source_type']] ?? HARD_LAYERS['mixed'];
|
$filled = 0;
|
||||||
$missing = ['core' => [], 'important' => [], 'supplementary' => []];
|
$missing = [];
|
||||||
foreach (['core', 'important', 'supplementary'] as $layer) {
|
foreach (HARD_FIELDS as $field) {
|
||||||
foreach ($layers[$layer] as $field) {
|
if ($row[$field] !== null && trim((string)$row[$field]) !== '') {
|
||||||
if ($row[$field] === null || trim((string)$row[$field]) === '') {
|
$filled++;
|
||||||
$missing[$layer][] = $field;
|
} else {
|
||||||
|
$missing[] = $field;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
$total = count(HARD_FIELDS);
|
||||||
$score = 100 - count($missing['core']) * 20 - count($missing['important']) * 8 - count($missing['supplementary']) * 2;
|
$score = $total > 0 ? (int)round($filled / $total * 100) : 0;
|
||||||
$score = max(0, $score);
|
return ['score' => $score, 'missing' => $missing];
|
||||||
$level = 'complete';
|
|
||||||
if (!empty($missing['core'])) {
|
|
||||||
$level = 'core';
|
|
||||||
} elseif (!empty($missing['important'])) {
|
|
||||||
$level = 'important';
|
|
||||||
} elseif (!empty($missing['supplementary'])) {
|
|
||||||
$level = 'supplementary';
|
|
||||||
}
|
|
||||||
return ['score' => $score, 'level' => $level, 'missing' => $missing];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 内容摘要:拼接已有关键信息 */
|
/** 内容摘要:拼接已有关键信息 */
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ if (!$row) {
|
|||||||
|
|
||||||
$calc = hardCompleteness($row);
|
$calc = hardCompleteness($row);
|
||||||
$row['completeness'] = $calc['score'];
|
$row['completeness'] = $calc['score'];
|
||||||
$row['level'] = $calc['level'];
|
|
||||||
$row['missing'] = $calc['missing'];
|
$row['missing'] = $calc['missing'];
|
||||||
$row['summary'] = hardSummary($row);
|
$row['summary'] = hardSummary($row);
|
||||||
$row['source_type_label'] = ['company' => '企业', 'person' => '人员', 'product' => '产品', 'need' => '需求', 'mixed' => '混合'][$row['source_type']] ?? $row['source_type'];
|
$row['source_type_label'] = ['company' => '企业', 'person' => '人员', 'product' => '产品', 'need' => '需求', 'mixed' => '混合'][$row['source_type']] ?? $row['source_type'];
|
||||||
|
|||||||
@@ -52,7 +52,6 @@ $list = [];
|
|||||||
foreach ($rows as $r) {
|
foreach ($rows as $r) {
|
||||||
$calc = hardCompleteness($r);
|
$calc = hardCompleteness($r);
|
||||||
$r['completeness'] = $calc['score'];
|
$r['completeness'] = $calc['score'];
|
||||||
$r['level'] = $calc['level'];
|
|
||||||
$r['missing'] = $calc['missing'];
|
$r['missing'] = $calc['missing'];
|
||||||
$r['summary'] = hardSummary($r);
|
$r['summary'] = hardSummary($r);
|
||||||
$r['source_type_label'] = ['company' => '企业', 'person' => '人员', 'product' => '产品', 'need' => '需求', 'mixed' => '混合'][$r['source_type']] ?? $r['source_type'];
|
$r['source_type_label'] = ['company' => '企业', 'person' => '人员', 'product' => '产品', 'need' => '需求', 'mixed' => '混合'][$r['source_type']] ?? $r['source_type'];
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* 软碎片详情接口 GET /api/fragment/soft_detail.php?table=persons&id=1
|
* 软碎片详情接口 GET /api/fragment/soft_detail.php?table=persons&id=1
|
||||||
* 返回:{ table, id, name, score, level, missing_core, missing_important, missing_supp, threshold, row }
|
* 返回:{ table, table_label, id, name, overall, level, layers, missing_core, missing_important,
|
||||||
|
* missing_optional, missing_labels, row }
|
||||||
*/
|
*/
|
||||||
require_once __DIR__ . '/../common/db.php';
|
require_once __DIR__ . '/../common/db.php';
|
||||||
require_once __DIR__ . '/../common/response.php';
|
require_once __DIR__ . '/../common/response.php';
|
||||||
@@ -41,16 +42,20 @@ switch ($table) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$label = function ($f) { return ['key' => $f, 'label' => COMPLETENESS_LABELS[$f] ?? $f]; };
|
||||||
|
|
||||||
Response::success([
|
Response::success([
|
||||||
'table' => $table,
|
'table' => $table,
|
||||||
'table_label' => $tableLabels[$table],
|
'table_label' => $tableLabels[$table],
|
||||||
'id' => $id,
|
'id' => $id,
|
||||||
'name' => $name ?: ('#' . $id),
|
'name' => $name ?: ('#' . $id),
|
||||||
'score' => $info['score'],
|
'overall' => $info['overall'],
|
||||||
'level' => $info['level'],
|
'level' => $info['level'],
|
||||||
'threshold' => $info['threshold'],
|
'layers' => $info['layers'],
|
||||||
'missing_core' => array_map(function ($f) { return ['key' => $f, 'label' => COMPLETENESS_LABELS[$f] ?? $f]; }, $info['missing_core']),
|
'missing_core' => array_map($label, $info['missing']['core']),
|
||||||
'missing_important' => array_map(function ($f) { return ['key' => $f, 'label' => COMPLETENESS_LABELS[$f] ?? $f]; }, $info['missing_important']),
|
'missing_important' => array_map($label, $info['missing']['important']),
|
||||||
'missing_supp' => array_map(function ($f) { return ['key' => $f, 'label' => COMPLETENESS_LABELS[$f] ?? $f]; }, $info['missing_supp']),
|
'missing_optional' => array_map($label, $info['missing']['optional']),
|
||||||
|
'missing_labels' => array_map(function ($f) { return COMPLETENESS_LABELS[$f] ?? $f; },
|
||||||
|
array_merge($info['missing']['core'], $info['missing']['important'], $info['missing']['optional'])),
|
||||||
'row' => $info['row'],
|
'row' => $info['row'],
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* 软碎片列表接口 GET /api/fragment/soft_list.php
|
* 软碎片列表接口 GET /api/fragment/soft_list.php
|
||||||
* 参数:page / limit / table(所属表 persons|companies|social_accounts|media)/ level(core|important|supplementary)/ keyword
|
* 参数:page / limit / table(persons|companies|social_accounts|media)/ level(core|important|optional)/ keyword
|
||||||
* 返回:{ list, total, page, limit },每行含 完整度 score、缺失层级标签、名称、缺失字段、所属表、录入时间
|
* 返回:{ list, total, page, limit }
|
||||||
|
* 每行:{ table, table_label, id, name, overall 整体完整度, level 缺失层级,
|
||||||
|
* layer_rates {core,important,optional}, missing_fields 缺失字段(按核心→重要→非必要优先级), created_at }
|
||||||
*/
|
*/
|
||||||
require_once __DIR__ . '/../common/db.php';
|
require_once __DIR__ . '/../common/db.php';
|
||||||
require_once __DIR__ . '/../common/response.php';
|
require_once __DIR__ . '/../common/response.php';
|
||||||
@@ -32,7 +34,7 @@ foreach ($tableMap as $t => $cfg) {
|
|||||||
}
|
}
|
||||||
if ($t === 'media') {
|
if ($t === 'media') {
|
||||||
$rows = $pdo->query(
|
$rows = $pdo->query(
|
||||||
"SELECT m.social_account_id AS id, sa.account_id AS name, m.updated_at AS created_at
|
"SELECT m.social_account_id AS id, sa.account_id AS name, sa.created_at AS created_at
|
||||||
FROM media_commercial_attributes m
|
FROM media_commercial_attributes m
|
||||||
LEFT JOIN social_accounts sa ON sa.id = m.social_account_id
|
LEFT JOIN social_accounts sa ON sa.id = m.social_account_id
|
||||||
WHERE m.is_incomplete = 1"
|
WHERE m.is_incomplete = 1"
|
||||||
@@ -48,24 +50,30 @@ foreach ($tableMap as $t => $cfg) {
|
|||||||
if ($level !== '' && $info['level'] !== $level) {
|
if ($level !== '' && $info['level'] !== $level) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$missingFields = array_merge($info['missing_core'], $info['missing_important'], $info['missing_supp']);
|
// 缺失字段按优先级:核心 → 重要 → 非必要
|
||||||
|
$missingFields = array_merge($info['missing']['core'], $info['missing']['important'], $info['missing']['optional']);
|
||||||
$all[] = [
|
$all[] = [
|
||||||
'table' => $t,
|
'table' => $t,
|
||||||
'table_label' => $cfg['label'],
|
'table_label' => $cfg['label'],
|
||||||
'id' => (int)$r['id'],
|
'id' => (int)$r['id'],
|
||||||
'name' => $r['name'] ?: ('#' . $r['id']),
|
'name' => $r['name'] ?: ('#' . $r['id']),
|
||||||
'score' => $info['score'],
|
'overall' => $info['overall'],
|
||||||
'level' => $info['level'],
|
'level' => $info['level'],
|
||||||
|
'layer_rates' => [
|
||||||
|
'core' => $info['layers']['core']['rate'],
|
||||||
|
'important' => $info['layers']['important']['rate'],
|
||||||
|
'optional' => $info['layers']['optional']['rate'],
|
||||||
|
],
|
||||||
'missing_fields' => array_map(function ($f) { return COMPLETENESS_LABELS[$f] ?? $f; }, $missingFields),
|
'missing_fields' => array_map(function ($f) { return COMPLETENESS_LABELS[$f] ?? $f; }, $missingFields),
|
||||||
'created_at' => $r['created_at'] ?? null,
|
'created_at' => $r['created_at'] ?? null,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 按完整度升序(最残缺的排前面),再按时间倒序
|
// 排序:整体完整度升序(最残缺在前),同分按时间倒序
|
||||||
usort($all, function ($a, $b) {
|
usort($all, function ($a, $b) {
|
||||||
if ($a['score'] !== $b['score']) {
|
if ($a['overall'] !== $b['overall']) {
|
||||||
return $a['score'] <=> $b['score'];
|
return $a['overall'] <=> $b['overall'];
|
||||||
}
|
}
|
||||||
return strcmp($b['created_at'] ?? '', $a['created_at'] ?? '');
|
return strcmp($b['created_at'] ?? '', $a['created_at'] ?? '');
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -135,10 +135,10 @@ if (!$info) {
|
|||||||
Response::error('记录不存在');
|
Response::error('记录不存在');
|
||||||
}
|
}
|
||||||
|
|
||||||
logCurrent('complete', 'fragment', $table, $id, ['fields' => array_keys($fields), 'score' => $info['score']]);
|
logCurrent('complete', 'fragment', $table, $id, ['fields' => array_keys($fields), 'overall' => $info['overall']]);
|
||||||
|
|
||||||
Response::success([
|
Response::success([
|
||||||
'score' => $info['score'],
|
'overall' => $info['overall'],
|
||||||
'level' => $info['level'],
|
'level' => $info['level'],
|
||||||
'is_complete' => $info['is_complete'],
|
'is_complete' => $info['is_complete'],
|
||||||
], $info['is_complete'] ? '补全完成' : '已更新,完整度 ' . $info['score'] . '%');
|
], $info['is_complete'] ? '补全完成' : '已更新,整体完整度 ' . $info['overall'] . '%');
|
||||||
|
|||||||
@@ -1,8 +1,13 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* 碎片处理中心 - 顶部指标卡接口 GET /api/fragment/stats_overview.php
|
* 碎片处理中心 - 顶部概览接口 GET /api/fragment/stats_overview.php
|
||||||
* 返回:{ hard_total 硬碎片总数, soft_total 软碎片总数, month_new 本月新增,
|
* 指标:
|
||||||
* month_processed 本月处理, pending 待处理碎片 }
|
* - hard_total 硬碎片待处理数(preliminary_data 未终结)
|
||||||
|
* - soft_total 软碎片待处理数(四主表 is_incomplete=1)
|
||||||
|
* - month_new 本月新增(硬碎片本月新增 + 软碎片本月新增)
|
||||||
|
* - month_processed 本月处理(本月已转换硬碎片 + 本月已补全软碎片)
|
||||||
|
* - cumulative 累计处理(历史已转换硬碎片 + 历史已补全软碎片)
|
||||||
|
* - pending 待处理碎片(硬待处理 + 软待处理)
|
||||||
*/
|
*/
|
||||||
require_once __DIR__ . '/../common/db.php';
|
require_once __DIR__ . '/../common/db.php';
|
||||||
require_once __DIR__ . '/../common/response.php';
|
require_once __DIR__ . '/../common/response.php';
|
||||||
@@ -11,39 +16,63 @@ require_once __DIR__ . '/../common/auth.php';
|
|||||||
checkPermission('preliminary');
|
checkPermission('preliminary');
|
||||||
|
|
||||||
$pdo = DB::getInstance()->getPdo();
|
$pdo = DB::getInstance()->getPdo();
|
||||||
|
$monthStart = "DATE_FORMAT(CURDATE(), '%Y-%m-01')";
|
||||||
|
|
||||||
// 硬碎片:preliminary_data 中未终结(未转换/未废弃)的记录
|
// 硬碎片待处理数
|
||||||
$hardTotal = (int)$pdo->query(
|
$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 status NOT IN ('已转换','已废弃')"
|
||||||
)->fetchColumn();
|
)->fetchColumn();
|
||||||
|
|
||||||
// 软碎片:四张主表 is_incomplete=1 之和
|
// 软碎片待处理数(四主表 is_incomplete=1 之和)
|
||||||
$softTotal = 0;
|
$softTotal = 0;
|
||||||
foreach (['companies', 'persons', 'social_accounts', 'media_commercial_attributes'] as $t) {
|
foreach (['companies', 'persons', 'social_accounts', 'media_commercial_attributes'] as $t) {
|
||||||
$softTotal += (int)$pdo->query("SELECT COUNT(*) FROM `$t` WHERE is_incomplete = 1")->fetchColumn();
|
$softTotal += (int)$pdo->query("SELECT COUNT(*) FROM `$t` WHERE is_incomplete = 1")->fetchColumn();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 本月新增(硬碎片按 created_at)
|
// 本月新增硬碎片(created_at 在本月)
|
||||||
$monthNew = (int)$pdo->query(
|
$hardMonthNew = (int)$pdo->query(
|
||||||
"SELECT COUNT(*) FROM preliminary_data WHERE is_active = 1 AND created_at >= DATE_FORMAT(CURDATE(), '%Y-%m-01')"
|
"SELECT COUNT(*) FROM preliminary_data WHERE is_active = 1 AND created_at >= $monthStart"
|
||||||
)->fetchColumn();
|
)->fetchColumn();
|
||||||
|
|
||||||
// 本月处理(已转换/已废弃且 processed_at 在本月)
|
// 本月新增软碎片(is_incomplete=1 且本月创建;media 的创建时间取关联 social_accounts)
|
||||||
$monthProcessed = (int)$pdo->query(
|
$softMonthNew = 0;
|
||||||
|
foreach (['companies', 'persons', 'social_accounts'] as $t) {
|
||||||
|
$softMonthNew += (int)$pdo->query(
|
||||||
|
"SELECT COUNT(*) FROM `$t` WHERE is_incomplete = 1 AND created_at >= $monthStart"
|
||||||
|
)->fetchColumn();
|
||||||
|
}
|
||||||
|
$softMonthNew += (int)$pdo->query(
|
||||||
|
"SELECT COUNT(*) FROM media_commercial_attributes m
|
||||||
|
WHERE m.is_incomplete = 1
|
||||||
|
AND EXISTS (SELECT 1 FROM social_accounts sa WHERE sa.id = m.social_account_id AND sa.created_at >= $monthStart)"
|
||||||
|
)->fetchColumn();
|
||||||
|
|
||||||
|
// 本月已转换硬碎片
|
||||||
|
$hardConvertedMonth = (int)$pdo->query(
|
||||||
"SELECT COUNT(*) FROM preliminary_data
|
"SELECT COUNT(*) FROM preliminary_data
|
||||||
WHERE is_active = 1 AND status IN ('已转换','已废弃')
|
WHERE is_active = 1 AND status = '已转换' AND processed_at >= $monthStart"
|
||||||
AND processed_at >= DATE_FORMAT(CURDATE(), '%Y-%m-01')"
|
|
||||||
)->fetchColumn();
|
)->fetchColumn();
|
||||||
|
|
||||||
// 待处理碎片
|
// 本月已补全软碎片(fragment 模块 complete 日志)
|
||||||
$pending = (int)$pdo->query(
|
$softCompletedMonth = (int)$pdo->query(
|
||||||
"SELECT COUNT(*) FROM preliminary_data WHERE is_active = 1 AND status = '待处理'"
|
"SELECT COUNT(*) FROM system_logs WHERE action = 'complete' AND module = 'fragment' AND created_at >= $monthStart"
|
||||||
|
)->fetchColumn();
|
||||||
|
|
||||||
|
// 历史累计已转换硬碎片
|
||||||
|
$hardConvertedTotal = (int)$pdo->query(
|
||||||
|
"SELECT COUNT(*) FROM preliminary_data WHERE is_active = 1 AND status = '已转换'"
|
||||||
|
)->fetchColumn();
|
||||||
|
|
||||||
|
// 历史累计已补全软碎片
|
||||||
|
$softCompletedTotal = (int)$pdo->query(
|
||||||
|
"SELECT COUNT(*) FROM system_logs WHERE action = 'complete' AND module = 'fragment'"
|
||||||
)->fetchColumn();
|
)->fetchColumn();
|
||||||
|
|
||||||
Response::success([
|
Response::success([
|
||||||
'hard_total' => $hardTotal,
|
'hard_total' => $hardTotal,
|
||||||
'soft_total' => $softTotal,
|
'soft_total' => $softTotal,
|
||||||
'month_new' => $monthNew,
|
'month_new' => $hardMonthNew + $softMonthNew,
|
||||||
'month_processed' => $monthProcessed,
|
'month_processed' => $hardConvertedMonth + $softCompletedMonth,
|
||||||
'pending' => $pending,
|
'cumulative' => $hardConvertedTotal + $softCompletedTotal,
|
||||||
|
'pending' => $hardTotal + $softTotal,
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -472,7 +472,7 @@ table.grid .ops a:hover { text-decoration: underline; }
|
|||||||
/* ---------- 指标卡 ---------- */
|
/* ---------- 指标卡 ---------- */
|
||||||
.stat-cards {
|
.stat-cards {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(4, 1fr);
|
grid-template-columns: repeat(5, 1fr);
|
||||||
gap: 14px;
|
gap: 14px;
|
||||||
margin-bottom: 16px;
|
margin-bottom: 16px;
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -5,7 +5,7 @@ var BASE_URL = '/api/';
|
|||||||
var PAGE_SIZE = 20;
|
var PAGE_SIZE = 20;
|
||||||
|
|
||||||
/** 系统版本号(logo旁展示):修改代码后运行 tools/bump_version.php 自动递增 */
|
/** 系统版本号(logo旁展示):修改代码后运行 tools/bump_version.php 自动递增 */
|
||||||
var APP_VERSION = 'v1.0.28';
|
var APP_VERSION = 'v1.0.29';
|
||||||
|
|
||||||
/** 页脚版权/备案信息(在 config.js 中修改) */
|
/** 页脚版权/备案信息(在 config.js 中修改) */
|
||||||
var FOOTER_TEXT = '© 2026 SuperLink 管理系统 版权所有 | 备案号:请替换为真实备案号';
|
var FOOTER_TEXT = '© 2026 SuperLink 管理系统 版权所有 | 备案号:请替换为真实备案号';
|
||||||
|
|||||||
+17
-11
@@ -22,7 +22,7 @@ $(function () {
|
|||||||
function levelTagHtml(level) {
|
function levelTagHtml(level) {
|
||||||
if (level === 'core') return '<span class="tag tag-red">缺核心</span>';
|
if (level === 'core') return '<span class="tag tag-red">缺核心</span>';
|
||||||
if (level === 'important') return '<span class="tag tag-orange">缺重要</span>';
|
if (level === 'important') return '<span class="tag tag-orange">缺重要</span>';
|
||||||
if (level === 'supplementary') return '<span class="tag tag-blue">待补充</span>';
|
if (level === 'optional') return '<span class="tag tag-blue">待补充</span>';
|
||||||
return '<span class="tag tag-green">完整</span>';
|
return '<span class="tag tag-green">完整</span>';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,13 +75,13 @@ $(function () {
|
|||||||
' <option value="social_accounts">联系方式</option><option value="media">媒体</option></select>' +
|
' <option value="social_accounts">联系方式</option><option value="media">媒体</option></select>' +
|
||||||
' <select id="soft-level"><option value="">全部缺失层级</option>' +
|
' <select id="soft-level"><option value="">全部缺失层级</option>' +
|
||||||
' <option value="core">缺核心</option><option value="important">缺重要</option>' +
|
' <option value="core">缺核心</option><option value="important">缺重要</option>' +
|
||||||
' <option value="supplementary">待补充</option></select>' +
|
' <option value="optional">待补充</option></select>' +
|
||||||
' <input type="text" id="soft-keyword" placeholder="名称关键词">' +
|
' <input type="text" id="soft-keyword" placeholder="名称关键词">' +
|
||||||
' <button class="btn btn-primary" id="soft-search">搜索</button>' +
|
' <button class="btn btn-primary" id="soft-search">搜索</button>' +
|
||||||
' <button class="btn" id="soft-reset">重置</button>' +
|
' <button class="btn" id="soft-reset">重置</button>' +
|
||||||
' </div>' +
|
' </div>' +
|
||||||
' <div class="table-wrap"><table class="grid">' +
|
' <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>' +
|
' <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>' +
|
' <tbody id="soft-tbody"></tbody>' +
|
||||||
' </table></div>' +
|
' </table></div>' +
|
||||||
' <div class="pagination" id="soft-pagination"></div>' +
|
' <div class="pagination" id="soft-pagination"></div>' +
|
||||||
@@ -113,13 +113,14 @@ $(function () {
|
|||||||
}).catch(function () {});
|
}).catch(function () {});
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ================= 顶部指标卡 ================= */
|
/* ================= 顶部概览指标卡 ================= */
|
||||||
function loadStats() {
|
function loadStats() {
|
||||||
httpGet('fragment/stats_overview.php').then(function (d) {
|
httpGet('fragment/stats_overview.php').then(function (d) {
|
||||||
$('#stat-cards').html(
|
$('#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-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-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-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>' +
|
||||||
'<div class="stat-card c-red"><div class="num">' + d.pending + '</div><div class="label">待处理碎片</div></div>'
|
'<div class="stat-card c-red"><div class="num">' + d.pending + '</div><div class="label">待处理碎片</div></div>'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@@ -175,17 +176,20 @@ $(function () {
|
|||||||
var html = '';
|
var html = '';
|
||||||
softRows.forEach(function (r) {
|
softRows.forEach(function (r) {
|
||||||
var missing = (r.missing_fields || []).join('、') || '-';
|
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>' +
|
html += '<tr>' +
|
||||||
'<td>' + completenessHtml(r.score) + '</td>' +
|
'<td>' + completenessHtml(r.overall) + '</td>' +
|
||||||
'<td>' + levelTagHtml(r.level) + '</td>' +
|
'<td>' + levelTagHtml(r.level) + '</td>' +
|
||||||
'<td>' + escHtml(r.name) + '</td>' +
|
'<td>' + escHtml(r.name) + '</td>' +
|
||||||
'<td style="max-width:260px;">' + escHtml(missing) + '</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>' + escHtml(r.table_label) + '</td>' +
|
||||||
'<td>' + fmtDate(r.created_at) + '</td>' +
|
'<td>' + fmtDate(r.created_at) + '</td>' +
|
||||||
'<td class="ops"><a onclick="completeSoft(\'' + r.table + '\',' + r.id + ')">补全</a></td></tr>';
|
'<td class="ops"><a onclick="completeSoft(\'' + r.table + '\',' + r.id + ')">补全</a></td></tr>';
|
||||||
});
|
});
|
||||||
if (!softRows.length) {
|
if (!softRows.length) {
|
||||||
html = '<tr><td colspan="7" class="empty-tip" style="padding:30px 0;">暂无软碎片</td></tr>';
|
html = '<tr><td colspan="8" class="empty-tip" style="padding:30px 0;">暂无软碎片</td></tr>';
|
||||||
}
|
}
|
||||||
$('#soft-tbody').html(html);
|
$('#soft-tbody').html(html);
|
||||||
renderPagination($('#soft-pagination'), d, loadSoftList);
|
renderPagination($('#soft-pagination'), d, loadSoftList);
|
||||||
@@ -195,7 +199,6 @@ $(function () {
|
|||||||
/* ================= 硬碎片:查看 ================= */
|
/* ================= 硬碎片:查看 ================= */
|
||||||
window.viewHard = function (id) {
|
window.viewHard = function (id) {
|
||||||
httpGet('fragment/hard_detail.php', { id: id }).then(function (d) {
|
httpGet('fragment/hard_detail.php', { id: id }).then(function (d) {
|
||||||
var missing = [].concat(d.missing.core || [], d.missing.important || [], d.missing.supplementary || []);
|
|
||||||
var rowHtml = '';
|
var rowHtml = '';
|
||||||
var fields = [
|
var fields = [
|
||||||
['类型', d.source_type_label], ['公司名称', d.company_name], ['联系人', d.person_name],
|
['类型', d.source_type_label], ['公司名称', d.company_name], ['联系人', d.person_name],
|
||||||
@@ -301,16 +304,19 @@ $(function () {
|
|||||||
/* ================= 软碎片:补全 ================= */
|
/* ================= 软碎片:补全 ================= */
|
||||||
window.completeSoft = function (table, id) {
|
window.completeSoft = function (table, id) {
|
||||||
httpGet('fragment/soft_detail.php', { table: table, id: id }).then(function (d) {
|
httpGet('fragment/soft_detail.php', { table: table, id: id }).then(function (d) {
|
||||||
var allMissing = [].concat(d.missing_core || [], d.missing_important || [], d.missing_supp || []);
|
var allMissing = [].concat(d.missing_core || [], d.missing_important || [], d.missing_optional || []);
|
||||||
var inputs = '';
|
var inputs = '';
|
||||||
allMissing.forEach(function (m) {
|
allMissing.forEach(function (m) {
|
||||||
var isDate = (m.key === 'established_date');
|
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>' +
|
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>';
|
'<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 =
|
var content =
|
||||||
'<form id="soft-form" style="padding:16px 22px 4px;">' +
|
'<form id="soft-form" style="padding:16px 22px 4px;">' +
|
||||||
'<div style="font-size:12px;color:#8a94a6;margin-bottom:10px;">当前完整度 <b style="color:#d9534f;">' + d.score + '%</b>(阈值 ' + d.threshold + '%),补全后自动重新计算。</div>' +
|
'<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="form-grid">' + inputs + '</div>' +
|
||||||
'<div class="dialog-footer"><button type="button" class="btn" id="soft-cancel">取消</button>' +
|
'<div class="dialog-footer"><button type="button" class="btn" id="soft-cancel">取消</button>' +
|
||||||
'<button type="submit" class="btn btn-primary">保存补全</button></div>' +
|
'<button type="submit" class="btn btn-primary">保存补全</button></div>' +
|
||||||
@@ -332,7 +338,7 @@ $(function () {
|
|||||||
if (name) fd[name] = $(this).val();
|
if (name) fd[name] = $(this).val();
|
||||||
});
|
});
|
||||||
httpPost('fragment/soft_update.php', fd).then(function (res) {
|
httpPost('fragment/soft_update.php', fd).then(function (res) {
|
||||||
Dialog.success(res && res.is_complete ? '补全完成' : '已保存(完整度 ' + (res && res.score) + '%)', function () {
|
Dialog.success(res && res.is_complete ? '补全完成' : '已保存(整体完整度 ' + (res && res.overall) + '%)', function () {
|
||||||
Dialog.close(idx);
|
Dialog.close(idx);
|
||||||
loadStats();
|
loadStats();
|
||||||
loadSoftList(softPage);
|
loadSoftList(softPage);
|
||||||
|
|||||||
Reference in New Issue
Block a user