<?php
require_once dirname(__DIR__,2).'/core/lib/data_import.php';require_once dirname(__DIR__,2).'/core/lib/article_review.php';
$allowedTypes=[];foreach(['article','product'] as$t)if(cmsAdminCan((array)$adminAccess,$t,'manage'))$allowedTypes[]=$t;$type=trim((string)($_REQUEST['type']??($allowedTypes[0]??'')));if(!in_array($type,$allowedTypes,true))$type=$allowedTypes[0]??'';
if($type==='' ){echo '<div class="page-container"><div class="content-card" style="padding:50px;text-align:center">当前角色没有文章或产品管理权限，不能使用数据导入。</div></div>';return;}
if(isset($_GET['template'])){$format=$_GET['template']==='xlsx'?'xlsx':'csv';while(ob_get_level()>0)ob_end_clean();$name=$type.'-import-template.'.$format;if($format==='csv'){header('Content-Type: text/csv; charset=UTF-8');header('Content-Disposition: attachment; filename="'.$name.'"');echo "\xEF\xBB\xBF";$out=fopen('php://output','w');foreach(cmsImportTemplateRows($type)as$row)fputcsv($out,$row);fclose($out);}else{$tmp=tempnam(sys_get_temp_dir(),'cms-xlsx-');if(!cmsCreateImportTemplateXlsx($type,$tmp)){http_response_code(500);echo'模板生成失败';exit;}header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');header('Content-Disposition: attachment; filename="'.$name.'"');header('Content-Length: '.filesize($tmp));readfile($tmp);@unlink($tmp);}exit;}
$stage='upload';$token=trim((string)($_POST['token']??$_GET['token']??''));if(!preg_match('/^[a-f0-9]{32}$/',$token))$token='';$sessionKey=$token!==''?'cms_import_'.$token:'';$stored=$sessionKey&&isset($_SESSION[$sessionKey])&&is_array($_SESSION[$sessionKey])?$_SESSION[$sessionKey]:null;if($stored&&intval($stored['created_at']??0)<time()-3600){unset($_SESSION[$sessionKey]);$stored=null;}if($stored&&in_array($stored['type'],$allowedTypes,true))$type=$stored['type'];$message='';
if($_SERVER['REQUEST_METHOD']==='POST'){requireAdminCsrfToken();$importAction=trim((string)($_POST['import_action']??''));
if($importAction==='parse'){$file=$_FILES['import_file']??null;$ext=strtolower(pathinfo((string)($file['name']??''),PATHINFO_EXTENSION));if(!$file||intval($file['error']??1)!==UPLOAD_ERR_OK)$message='请选择有效文件';elseif(intval($file['size'])>5*1024*1024)$message='文件不能超过 5MB';elseif(!in_array($ext,['csv','xlsx'],true))$message='仅支持 CSV 或 XLSX 文件';else{$parsed=cmsImportReadFile($file['tmp_name'],$ext,1000);if(!$parsed['success'])$message=$parsed['message'];else{$token=bin2hex(random_bytes(16));$sessionKey='cms_import_'.$token;$stored=['type'=>$type,'headers'=>$parsed['headers'],'rows'=>$parsed['rows'],'mapping'=>cmsImportAutoMapping($parsed['headers'],$type),'created_at'=>time()];$_SESSION[$sessionKey]=$stored;$stage='mapping';}}}
elseif($importAction==='preview'&&$stored){$mapping=array_map('strval',(array)($_POST['mapping']??[]));$stored['mapping']=$mapping;$canPublish=$type==='article'?cmsCanPublishArticles((array)$adminAccess):cmsAdminCan((array)$adminAccess,'product','manage');$stored['preview']=cmsImportPreview($db,$type,$stored['headers'],$stored['rows'],$mapping,$canPublish);$_SESSION[$sessionKey]=$stored;$stage='preview';}
elseif($importAction==='confirm'&&$stored){$canPublish=$type==='article'?cmsCanPublishArticles((array)$adminAccess):cmsAdminCan((array)$adminAccess,'product','manage');$preview=cmsImportPreview($db,$type,$stored['headers'],$stored['rows'],$stored['mapping'],$canPublish);$result=cmsExecuteImport($db,$type,$preview,intval($_SESSION['admin_id']));if($result['success']){unset($_SESSION[$sessionKey]);addLog('导入','数据导入','批量导入'.($type==='article'?'文章 ':'产品 ').$result['count'].' 条');$message=$result['message'];$stage='done';}else{$message=$result['message'];$stored['preview']=$preview;$stage='preview';}}
}
if($stored&&$stage==='upload')$stage=isset($stored['preview'])?'preview':'mapping';$definitions=cmsImportFieldDefinitions($type);$preview=$stored['preview']??null;
?>
<div class="page-container fade-in import-page"><div class="page-header"><div class="page-title"><div class="page-icon"><i class="fa fa-table"></i></div><div><h1>数据导入</h1><p>文章与产品 CSV / Excel 预检导入</p></div></div><div class="page-actions"><a class="btn btn-secondary" href="?act=data_import&type=<?php echo$type; ?>&template=csv">CSV 模板</a><a class="btn btn-secondary" href="?act=data_import&type=<?php echo$type; ?>&template=xlsx">Excel 模板</a></div></div>
<?php if($message!==''): ?><div class="import-message <?php echo$stage==='done'?'is-success':'is-warning'; ?>"><?php echo htmlspecialchars($message); ?></div><?php endif; ?>
<div class="import-steps"><span class="<?php echo$stage==='upload'?'active':''; ?>">1 选择文件</span><span class="<?php echo$stage==='mapping'?'active':''; ?>">2 字段映射</span><span class="<?php echo$stage==='preview'?'active':''; ?>">3 导入预检</span><span class="<?php echo$stage==='done'?'active':''; ?>">4 完成</span></div>
<?php if($stage==='upload'||$stage==='done'): ?><section class="import-card"><form method="post" enctype="multipart/form-data"><input type="hidden" name="csrf_token" value="<?php echo htmlspecialchars(getAdminCsrfToken()); ?>"><input type="hidden" name="import_action" value="parse"><div class="import-type"><label><input type="radio" name="type" value="article" <?php echo$type==='article'?'checked':''; ?> <?php echo!in_array('article',$allowedTypes,true)?'disabled':''; ?>> 文章</label><label><input type="radio" name="type" value="product" <?php echo$type==='product'?'checked':''; ?> <?php echo!in_array('product',$allowedTypes,true)?'disabled':''; ?>> 产品</label></div><label class="import-drop"><i class="fa fa-cloud-upload"></i><strong>选择 CSV 或 XLSX 文件</strong><span>最大 5MB，最多 1000 行，仅读取 Excel 第一个工作表</span><input type="file" name="import_file" accept=".csv,.xlsx" required></label><button class="btn btn-primary btn-lg">上传并读取字段</button></form></section><?php endif; ?>
<?php if($stage==='mapping'&&$stored): ?><section class="import-card"><div class="import-card-head"><div><small>FIELD MAPPING</small><h2>字段映射</h2></div><span><?php echo count($stored['rows']); ?> 行数据</span></div><form method="post"><input type="hidden" name="csrf_token" value="<?php echo htmlspecialchars(getAdminCsrfToken()); ?>"><input type="hidden" name="import_action" value="preview"><input type="hidden" name="token" value="<?php echo htmlspecialchars($token); ?>"><input type="hidden" name="type" value="<?php echo$type; ?>"><div class="mapping-grid"><?php foreach($stored['headers']as$index=>$header): ?><label><span><?php echo htmlspecialchars($header?:'第 '.($index+1).' 列'); ?></span><select name="mapping[<?php echo$index; ?>]"><option value="">忽略此列</option><?php foreach($definitions as$field=>$def): ?><option value="<?php echo$field; ?>" <?php echo($stored['mapping'][$index]??'')===$field?'selected':''; ?>><?php echo htmlspecialchars($def['label']); ?><?php echo$def['required']?' *':''; ?></option><?php endforeach; ?></select></label><?php endforeach; ?></div><div class="form-actions"><button class="btn btn-primary btn-lg">执行预检</button><a class="btn btn-secondary btn-lg" href="?act=data_import&type=<?php echo$type; ?>">重新上传</a></div></form></section><?php endif; ?>
<?php if($stage==='preview'&&$preview): ?><section class="import-card"><div class="import-card-head"><div><small>VALIDATION</small><h2>预检结果</h2></div><div class="import-counts"><span>总计 <?php echo$preview['total']; ?></span><span class="is-error">错误 <?php echo$preview['error_count']; ?></span><span class="is-warning">提醒 <?php echo$preview['warning_count']; ?></span></div></div><?php foreach($preview['global_errors']as$error): ?><div class="import-global-error"><?php echo htmlspecialchars($error); ?></div><?php endforeach; ?><div class="import-table-wrap"><table class="data-table"><thead><tr><th>行</th><th>标题</th><th>栏目ID</th><th>状态</th><th>检查结果</th></tr></thead><tbody><?php foreach($preview['rows']as$row): ?><tr><td><?php echo$row['line']; ?></td><td><?php echo htmlspecialchars($row['data']['title']??'-'); ?></td><td><?php echo intval($row['data']['channel_id']??0); ?></td><td><?php echo($row['data']['status']??'draft')==='publish'?'发布':'草稿'; ?></td><td><?php if(!$row['errors']&&!$row['warnings']): ?><span class="import-ok">通过</span><?php endif; ?><?php foreach($row['errors']as$error): ?><span class="import-error"><?php echo htmlspecialchars($error); ?></span><?php endforeach; ?><?php foreach($row['warnings']as$warning): ?><span class="import-warning"><?php echo htmlspecialchars($warning); ?></span><?php endforeach; ?></td></tr><?php endforeach; ?></tbody></table></div><div class="form-actions"><form method="post"><input type="hidden" name="csrf_token" value="<?php echo htmlspecialchars(getAdminCsrfToken()); ?>"><input type="hidden" name="import_action" value="confirm"><input type="hidden" name="token" value="<?php echo htmlspecialchars($token); ?>"><input type="hidden" name="type" value="<?php echo$type; ?>"><button class="btn btn-success btn-lg" <?php echo!$preview['success']?'disabled':''; ?> onclick="return confirm('确认导入预检通过的数据？导入过程发生错误会整体回滚。')">确认导入</button></form><a class="btn btn-secondary btn-lg" href="?act=data_import&type=<?php echo$type; ?>">取消并重新上传</a></div></section><?php endif; ?></div>
<style>.import-page{max-width:1250px}.import-message{margin-bottom:14px;padding:12px 15px;border-radius:11px;background:#fffbeb;color:#92400e}.import-message.is-success{background:#ecfdf5;color:#047857}.import-steps{display:grid;grid-template-columns:repeat(4,1fr);gap:8px;margin-bottom:16px}.import-steps span{padding:10px;text-align:center;border-radius:10px;background:#e9eef5;color:#94a3b8;font-size:11px;font-weight:800}.import-steps span.active{background:#2563eb;color:#fff}.import-card{padding:22px;border:1px solid #dfe6ef;border-radius:16px;background:#fff}.import-card-head{display:flex;justify-content:space-between;align-items:center;margin-bottom:18px}.import-card-head small{color:#94a3b8;letter-spacing:.12em}.import-card-head h2{margin:3px 0 0;color:#1e293b}.import-card-head>span{color:#64748b}.import-type{display:flex;gap:20px;margin-bottom:16px}.import-type label{font-weight:700}.import-drop{display:flex;flex-direction:column;align-items:center;margin-bottom:18px;padding:45px 20px;border:2px dashed #cbd5e1;border-radius:15px;background:#f8fafc;cursor:pointer}.import-drop i{font-size:36px;color:#2563eb}.import-drop strong{margin-top:12px;color:#334155}.import-drop span{margin-top:5px;color:#94a3b8;font-size:11px}.import-drop input{margin-top:16px}.mapping-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:12px}.mapping-grid label{display:grid;grid-template-columns:minmax(130px,1fr) 1.3fr;gap:10px;align-items:center;padding:11px;border:1px solid #edf2f7;border-radius:10px}.mapping-grid span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:#475569}.mapping-grid select{height:36px;border:1px solid #dbe3ee;border-radius:8px}.import-counts{display:flex;gap:10px}.import-counts span{padding:6px 9px;border-radius:8px;background:#f1f5f9;color:#64748b;font-size:11px}.import-counts .is-error{background:#fef2f2;color:#b91c1c}.import-counts .is-warning{background:#fffbeb;color:#b45309}.import-global-error{padding:10px;background:#fef2f2;color:#b91c1c}.import-table-wrap{overflow:auto}.import-table-wrap table{min-width:780px}.import-ok,.import-error,.import-warning{display:block;margin:2px 0;font-size:11px}.import-ok{color:#047857}.import-error{color:#b91c1c}.import-warning{color:#b45309}.form-actions{display:flex;gap:10px;margin-top:20px}@media(max-width:700px){.import-steps,.mapping-grid{grid-template-columns:1fr}.mapping-grid label{grid-template-columns:1fr}}</style>
