feat: 全面代码更新 - ECharts 5.4.2 重构、新增量化分析模块、前端库升级
- 升级 ECharts 到 5.4.2,重构 lib/ 目录结构 - 新增 DataTables 2.x 和 FixedColumns 插件 - 新增 quant/ 宏观研究报告模块 - 重构图表页面:stock_trend、hkholdbycode 等采用 JS fetch API.doorcome.cn 模式 - 新增 CLAUDE.md 补充页面文档和新数据流说明 - 更新 inc/config.php TuShare API 配置 - 更新新闻联播分析模块 news/ 和相关研究报告 research/ - 新增 api_document/ 参考文档 - 清理 .gitignore,排除 uploads/xls/.mcp.json/ source maps 等非代码文件 - 所有 PHP 文件通过 php -l 语法检查 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
include_once __DIR__ . "/../inc/config.php";
|
||||
|
||||
$mysqli = get_mysqli_connection();
|
||||
$sql = "SELECT id, report_date, created_at, title, subject_type, subject_code
|
||||
FROM mac_report WHERE is_active = 1 ORDER BY report_date DESC, id DESC";
|
||||
$result = $mysqli->query($sql);
|
||||
$reports = $result ? $result->fetch_all(MYSQLI_ASSOC) : [];
|
||||
$mysqli->close();
|
||||
|
||||
// Group by subject_type for organization
|
||||
$groups = [];
|
||||
foreach ($reports as $r) {
|
||||
$type = $r['subject_type'] ?: '其他';
|
||||
$groups[$type][] = $r;
|
||||
}
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>宏观研究</title>
|
||||
<script src="/lib/js/tailwindcss-3.4.17.js"></script>
|
||||
<style type="text/tailwindcss">
|
||||
@layer utilities {
|
||||
.card-hover { @apply transition-all duration-300 hover:shadow-lg hover:-translate-y-1; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-gray-50 min-h-screen font-sans text-gray-900">
|
||||
<header class="bg-white shadow-sm sticky top-0 z-50 border-b border-gray-200">
|
||||
<div class="max-w-4xl mx-auto px-4 py-4 flex justify-between items-center">
|
||||
<div class="flex items-center space-x-2">
|
||||
<div class="w-8 h-8 bg-indigo-600 rounded-lg flex items-center justify-center">
|
||||
<svg class="w-5 h-5 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z"/>
|
||||
</svg>
|
||||
</div>
|
||||
<h1 class="text-xl font-bold">宏观研究</h1>
|
||||
</div>
|
||||
<a href="/index-2.php" class="text-sm text-gray-500 hover:text-indigo-600 transition-colors">首页</a>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="max-w-4xl mx-auto px-4 py-8">
|
||||
<?php if (empty($reports)): ?>
|
||||
<div class="text-center py-16 text-gray-400">
|
||||
<svg class="w-16 h-16 mx-auto mb-4 opacity-30" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"/>
|
||||
</svg>
|
||||
<p class="text-lg">暂无报告数据</p>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<?php foreach ($groups as $type => $items): ?>
|
||||
<section class="mb-8">
|
||||
<div class="flex items-center space-x-2 mb-4">
|
||||
<span class="px-2.5 py-0.5 rounded text-xs font-medium bg-indigo-100 text-indigo-800 uppercase tracking-wide"><?= htmlspecialchars($type) ?></span>
|
||||
<span class="text-xs text-gray-400"><?= count($items) ?> 篇</span>
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
<?php foreach ($items as $r):
|
||||
$date = $r['report_date'];
|
||||
$created = $r['created_at'] ? date('Y-m-d H:i', strtotime($r['created_at'])) : '';
|
||||
?>
|
||||
<a href="report.php?id=<?= $r['id'] ?>"
|
||||
class="card-hover block bg-white rounded-lg border border-gray-200 p-4 hover:border-indigo-300">
|
||||
<div class="flex justify-between items-start">
|
||||
<div class="flex-1 min-w-0">
|
||||
<h3 class="text-base font-semibold text-gray-900 truncate"><?= htmlspecialchars($r['title']) ?></h3>
|
||||
<?php if ($r['subject_code']): ?>
|
||||
<p class="text-xs text-gray-400 mt-1"><?= htmlspecialchars($r['subject_code']) ?></p>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div class="flex-shrink-0 text-right ml-4">
|
||||
<div class="text-sm text-gray-500"><?= $date ?></div>
|
||||
<?php if ($created): ?>
|
||||
<div class="text-xs text-gray-400 mt-0.5"><?= $created ?></div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</section>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</main>
|
||||
|
||||
<footer class="border-t border-gray-200 py-8 text-center text-sm text-gray-400">
|
||||
<p>宏观研究 © <?= date('Y') ?></p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,138 @@
|
||||
<?php
|
||||
include_once __DIR__ . "/../inc/config.php";
|
||||
|
||||
$id = intval($_GET['id'] ?? 0);
|
||||
if ($id <= 0) {
|
||||
header("Location: index.php");
|
||||
exit();
|
||||
}
|
||||
|
||||
$mysqli = get_mysqli_connection();
|
||||
$stmt = $mysqli->prepare("SELECT * FROM mac_report WHERE id = ? AND is_active = 1");
|
||||
$stmt->bind_param('i', $id);
|
||||
$stmt->execute();
|
||||
$result = $stmt->get_result();
|
||||
$report = $result->fetch_assoc();
|
||||
$stmt->close();
|
||||
$mysqli->close();
|
||||
|
||||
if (!$report) {
|
||||
header("Location: index.php");
|
||||
exit();
|
||||
}
|
||||
|
||||
$date = $report['report_date'];
|
||||
$title = $report['title'];
|
||||
$content = $report['content'];
|
||||
$subject_type = $report['subject_type'];
|
||||
$subject_code = $report['subject_code'];
|
||||
$created_at = $report['created_at'] ? date('Y-m-d H:i', strtotime($report['created_at'])) : '';
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title><?= htmlspecialchars($title) ?> - 宏观研究</title>
|
||||
<script src="/lib/js/tailwindcss-3.4.17.js"></script>
|
||||
<script src="/lib/js/marked-15.0.12.min.js"></script>
|
||||
<style type="text/tailwindcss">
|
||||
@layer utilities {
|
||||
.prose h1 { @apply text-2xl font-bold text-gray-900 mt-8 mb-4 pb-2 border-b border-gray-200; }
|
||||
.prose h2 { @apply text-xl font-semibold text-gray-900 mt-6 mb-3; }
|
||||
.prose h3 { @apply text-lg font-semibold text-gray-800 mt-5 mb-2; }
|
||||
.prose h4 { @apply text-base font-semibold text-gray-800 mt-4 mb-2; }
|
||||
.prose p { @apply text-gray-700 leading-relaxed my-3; }
|
||||
.prose strong { @apply font-semibold text-gray-900; }
|
||||
.prose a { @apply text-indigo-600 hover:text-indigo-800 underline decoration-indigo-300 hover:decoration-indigo-600 transition-colors; }
|
||||
.prose blockquote { @apply border-l-4 border-indigo-300 bg-indigo-50 pl-4 pr-2 py-2 my-4 rounded-r text-gray-700 italic; }
|
||||
.prose ul { @apply list-disc pl-6 my-3 space-y-1; }
|
||||
.prose ol { @apply list-decimal pl-6 my-3 space-y-1; }
|
||||
.prose li { @apply text-gray-700 leading-relaxed; }
|
||||
.prose code { @apply bg-gray-100 text-pink-600 px-1.5 py-0.5 rounded text-sm font-mono; }
|
||||
.prose pre { @apply bg-gray-900 text-gray-100 rounded-lg p-4 my-4 overflow-x-auto; }
|
||||
.prose pre code { @apply bg-transparent text-gray-100 px-0 py-0; }
|
||||
.prose table { @apply w-full border-collapse my-4 text-sm; }
|
||||
.prose thead { @apply bg-gray-50; }
|
||||
.prose th { @apply border border-gray-300 px-3 py-2 text-left font-semibold text-gray-700; }
|
||||
.prose td { @apply border border-gray-300 px-3 py-2 text-gray-600; }
|
||||
.prose tr:hover td { @apply bg-gray-50; }
|
||||
.prose hr { @apply border-0 border-t border-gray-200 my-8; }
|
||||
.prose img { @apply max-w-full rounded-lg my-4; }
|
||||
.prose em { @apply italic; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-gray-50 min-h-screen font-sans text-gray-900 antialiased">
|
||||
<header class="bg-white shadow-sm sticky top-0 z-50 border-b border-gray-200">
|
||||
<div class="max-w-3xl mx-auto px-4 py-4 flex justify-between items-center">
|
||||
<div class="flex items-center space-x-2 min-w-0">
|
||||
<a href="index.php" class="flex items-center space-x-2 hover:opacity-80 transition-opacity">
|
||||
<div class="w-8 h-8 bg-indigo-600 rounded-lg flex items-center justify-center flex-shrink-0">
|
||||
<svg class="w-5 h-5 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z"/>
|
||||
</svg>
|
||||
</div>
|
||||
<span class="text-lg font-bold hidden sm:inline">宏观研究</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="flex items-center space-x-4">
|
||||
<a href="/index-2.php" class="text-sm text-gray-400 hover:text-indigo-600 transition-colors">首页</a>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="max-w-3xl mx-auto px-4 py-8">
|
||||
<article>
|
||||
<!-- Report header -->
|
||||
<div class="mb-8">
|
||||
<div class="flex items-center space-x-3 mb-3">
|
||||
<?php if ($subject_type): ?>
|
||||
<span class="px-2 py-0.5 rounded text-xs font-medium bg-indigo-100 text-indigo-700 uppercase tracking-wide"><?= htmlspecialchars($subject_type) ?></span>
|
||||
<?php endif; ?>
|
||||
<time class="text-sm text-gray-400">报告日期:<?= $date ?></time>
|
||||
<?php if ($created_at): ?>
|
||||
<span class="text-sm text-gray-400">生成时间:<?= $created_at ?></span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<h1 class="text-2xl md:text-3xl font-bold text-gray-900 leading-tight"><?= htmlspecialchars($title) ?></h1>
|
||||
<?php if ($subject_code): ?>
|
||||
<p class="text-sm text-gray-400 mt-2"><?= htmlspecialchars($subject_code) ?></p>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<!-- Divider -->
|
||||
<div class="border-t border-gray-200 my-6"></div>
|
||||
|
||||
<!-- Markdown content rendered by marked.js -->
|
||||
<div id="content" class="prose max-w-none"></div>
|
||||
</article>
|
||||
|
||||
<div class="border-t border-gray-200 mt-10 pt-6 text-center">
|
||||
<a href="index.php" class="inline-flex items-center space-x-1 text-sm text-indigo-600 hover:text-indigo-800 transition-colors">
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7"/>
|
||||
</svg>
|
||||
<span>返回列表</span>
|
||||
</a>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<footer class="border-t border-gray-200 py-8 text-center text-sm text-gray-400">
|
||||
<p>宏观研究 © <?= date('Y') ?></p>
|
||||
</footer>
|
||||
|
||||
<script>
|
||||
var rawContent = <?= json_encode($content) ?>;
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Configure marked
|
||||
marked.setOptions({
|
||||
breaks: true,
|
||||
gfm: true,
|
||||
});
|
||||
var html = marked.parse(rawContent);
|
||||
document.getElementById('content').innerHTML = html;
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
+1512
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user