更新前端配置、文档和脚本
This commit is contained in:
parent
69b1b481b2
commit
b982cd5368
267
docs/user-guide.md
Normal file
267
docs/user-guide.md
Normal file
@ -0,0 +1,267 @@
|
|||||||
|
# 用户使用文档
|
||||||
|
|
||||||
|
## 欢迎使用基本面分析系统
|
||||||
|
|
||||||
|
基本面分析系统是一个专业的股票分析平台,帮助投资者通过多维度的基本面分析,做出更明智的投资决策。
|
||||||
|
|
||||||
|
## 目录
|
||||||
|
|
||||||
|
- [快速开始](#快速开始)
|
||||||
|
- [主要功能](#主要功能)
|
||||||
|
- [使用指南](#使用指南)
|
||||||
|
- [常见问题](#常见问题)
|
||||||
|
- [系统配置](#系统配置)
|
||||||
|
|
||||||
|
## 快速开始
|
||||||
|
|
||||||
|
### 1. 生成分析报告
|
||||||
|
|
||||||
|
1. **访问首页**:在浏览器中打开系统首页
|
||||||
|
2. **输入股票代码**:在输入框中输入股票代码,例如:
|
||||||
|
- 中国股票:`600519`(会自动识别为 600519.SH)或 `600519.SH`
|
||||||
|
- 美国股票:`AAPL`
|
||||||
|
- 香港股票:`00700.HK`
|
||||||
|
3. **选择交易市场**:从下拉菜单中选择对应的交易市场(中国、香港、美国、日本)
|
||||||
|
4. **生成报告**:点击"生成报告"按钮,系统将自动获取财务数据并生成分析报告
|
||||||
|
|
||||||
|
### 2. 查看报告
|
||||||
|
|
||||||
|
报告生成后,您将看到包含以下内容的综合报告:
|
||||||
|
|
||||||
|
- **股价图表**:来自 TradingView 的实时股价图表
|
||||||
|
- **财务数据**:多年财务指标对比,包括:
|
||||||
|
- 主要指标:ROE、ROA、ROIC、毛利率、净利润率等
|
||||||
|
- 费用指标:销售费用率、管理费用率、研发费用率等
|
||||||
|
- 资产占比:现金占比、库存占比、应收款占比等
|
||||||
|
- 周转能力:存货周转天数、应收款周转天数等
|
||||||
|
- 人均效率:人均创收、人均创利、人均工资等
|
||||||
|
- 市场表现:股价、市值、PE、PB、股东户数等
|
||||||
|
- **AI 分析模块**:基于财务数据的智能分析,包括:
|
||||||
|
- 公司简介
|
||||||
|
- 业务分析
|
||||||
|
- 财务健康度评估
|
||||||
|
- 投资建议等
|
||||||
|
|
||||||
|
### 3. 报告操作
|
||||||
|
|
||||||
|
- **开始分析**:点击"开始分析"按钮,系统将按顺序生成各个分析模块
|
||||||
|
- **停止**:在分析过程中,可以随时点击"停止"按钮中断分析
|
||||||
|
- **继续**:停止后可以点击"继续"按钮恢复分析
|
||||||
|
- **重新生成分析**:对任意分析模块,可以点击"重新生成分析"按钮重新生成
|
||||||
|
|
||||||
|
## 主要功能
|
||||||
|
|
||||||
|
### 1. 股票分析报告
|
||||||
|
|
||||||
|
系统提供全面的股票基本面分析,包括:
|
||||||
|
|
||||||
|
- **财务数据展示**:自动从 Tushare 等数据源获取最新的财务数据
|
||||||
|
- **多维度分析**:涵盖盈利能力、运营效率、财务健康度等多个维度
|
||||||
|
- **历史对比**:展示多年的财务指标变化趋势
|
||||||
|
- **实时图表**:集成 TradingView 高级图表组件,提供专业的股价图表
|
||||||
|
|
||||||
|
### 2. 智能分析模块
|
||||||
|
|
||||||
|
系统使用 AI 模型(如 Google Gemini)对财务数据进行深度分析:
|
||||||
|
|
||||||
|
- **自动生成**:根据财务数据自动生成业务分析和投资建议
|
||||||
|
- **模块化设计**:不同分析模块相互独立,可按需生成
|
||||||
|
- **依赖关系**:支持分析模块之间的依赖关系,确保分析的准确性
|
||||||
|
- **实时进度**:显示每个分析模块的生成进度和状态
|
||||||
|
|
||||||
|
### 3. 系统配置管理
|
||||||
|
|
||||||
|
系统提供完善的配置管理功能:
|
||||||
|
|
||||||
|
- **数据库配置**:配置 PostgreSQL 数据库连接
|
||||||
|
- **AI 服务配置**:配置 AI 模型的 API 密钥和端点
|
||||||
|
- **数据源配置**:配置 Tushare、Finnhub 等数据源的 API 密钥
|
||||||
|
- **分析模块配置**:自定义分析模块的名称、模型和提示词模板
|
||||||
|
- **配置测试**:支持测试各项配置的有效性
|
||||||
|
- **配置导入/导出**:支持配置的备份和恢复
|
||||||
|
|
||||||
|
### 4. 历史报告查询
|
||||||
|
|
||||||
|
系统支持查询历史生成的报告:
|
||||||
|
|
||||||
|
- **按市场和企业ID查询**:根据交易市场和企业ID查询历史报告
|
||||||
|
- **报告列表**:查看所有历史报告及其状态
|
||||||
|
- **报告详情**:查看完整的报告内容
|
||||||
|
|
||||||
|
## 使用指南
|
||||||
|
|
||||||
|
### 股票代码格式
|
||||||
|
|
||||||
|
不同市场的股票代码格式:
|
||||||
|
|
||||||
|
- **中国市场**:
|
||||||
|
- 上交所:6 位数字,如 `600519`(系统会自动添加 `.SH` 后缀)
|
||||||
|
- 深交所:6 位数字,如 `000001`(系统会自动添加 `.SZ` 后缀)
|
||||||
|
- 完整格式:`600519.SH` 或 `000001.SZ`
|
||||||
|
- **美国市场**:直接输入股票代码,如 `AAPL`、`MSFT`
|
||||||
|
- **香港市场**:股票代码,如 `00700`
|
||||||
|
- **日本市场**:股票代码,如 `7203`
|
||||||
|
|
||||||
|
### 财务数据解读
|
||||||
|
|
||||||
|
系统展示的财务数据按以下方式组织:
|
||||||
|
|
||||||
|
1. **主要指标**:核心财务指标
|
||||||
|
- ROE(净资产收益率):衡量股东权益的盈利能力,>12% 为优秀
|
||||||
|
- ROA(总资产收益率):衡量资产利用效率
|
||||||
|
- ROIC(投入资本回报率):衡量资本使用效率,>12% 为优秀
|
||||||
|
- 毛利率:反映产品或服务的盈利能力
|
||||||
|
- 净利润率:反映整体盈利能力
|
||||||
|
|
||||||
|
2. **费用指标**:各项费用占收入的比例
|
||||||
|
- 销售费用率、管理费用率、研发费用率等
|
||||||
|
- 其他费用率:通过毛利率减去各项费用率计算得出
|
||||||
|
|
||||||
|
3. **资产占比**:各项资产占总资产的比例
|
||||||
|
- 现金占比:反映资金充裕程度
|
||||||
|
- 库存占比:反映库存管理水平
|
||||||
|
- 应收款占比:反映应收账款风险
|
||||||
|
- 商誉占比:反映并购活动的影响
|
||||||
|
|
||||||
|
4. **周转能力**:反映资产周转效率
|
||||||
|
- 存货周转天数:存货变现的速度
|
||||||
|
- 应收款周转天数:应收账款回收速度(>90天需注意)
|
||||||
|
- 应付款周转天数:应付账款支付周期
|
||||||
|
|
||||||
|
5. **人均效率**:反映人力资源效率
|
||||||
|
- 人均创收、人均创利:衡量员工贡献
|
||||||
|
- 人均工资:反映员工待遇水平
|
||||||
|
|
||||||
|
6. **市场表现**:股票市场的表现指标
|
||||||
|
- PE(市盈率)、PB(市净率):估值指标
|
||||||
|
- 股东户数:反映股东结构变化
|
||||||
|
|
||||||
|
### 分析模块说明
|
||||||
|
|
||||||
|
每个分析模块都有其特定的作用:
|
||||||
|
|
||||||
|
- **公司简介**:自动生成公司的基本介绍和业务概况
|
||||||
|
- **业务分析**:深度分析公司的业务模式和竞争优势
|
||||||
|
- **财务分析**:评估公司的财务健康状况
|
||||||
|
- **风险评估**:识别潜在的投资风险
|
||||||
|
- **投资建议**:提供基于分析的投资建议
|
||||||
|
|
||||||
|
分析模块会按依赖关系顺序执行,确保每个模块都能获得所需的前置分析结果。
|
||||||
|
|
||||||
|
### 执行详情
|
||||||
|
|
||||||
|
在报告页面的"执行详情"标签页,您可以查看:
|
||||||
|
|
||||||
|
- **执行概况**:财务数据获取的耗时、API 调用次数等
|
||||||
|
- **分析任务**:每个分析模块的执行状态、耗时、Token 消耗等
|
||||||
|
- **总体统计**:总耗时、完成的任务数量、总 Token 消耗等
|
||||||
|
|
||||||
|
这些信息有助于了解报告的生成过程和数据来源。
|
||||||
|
|
||||||
|
## 常见问题
|
||||||
|
|
||||||
|
### Q1: 为什么有些财务数据显示为 "-"?
|
||||||
|
|
||||||
|
A: 可能是以下原因:
|
||||||
|
- 该股票在对应年份没有数据
|
||||||
|
- 数据源暂时不可用
|
||||||
|
- 该指标不适用于该股票类型
|
||||||
|
|
||||||
|
### Q2: 分析模块生成失败怎么办?
|
||||||
|
|
||||||
|
A: 您可以:
|
||||||
|
- 点击"重新生成分析"按钮重试
|
||||||
|
- 检查系统配置中的 AI 服务配置是否正确
|
||||||
|
- 查看"执行详情"中的错误信息
|
||||||
|
|
||||||
|
### Q3: 如何查看历史报告?
|
||||||
|
|
||||||
|
A:
|
||||||
|
1. 访问"查询"页面(如果已启用)
|
||||||
|
2. 选择交易市场和企业ID
|
||||||
|
3. 点击"查询"按钮查看历史报告列表
|
||||||
|
|
||||||
|
### Q4: 股票代码输入错误怎么办?
|
||||||
|
|
||||||
|
A: 系统会自动识别一些常见的代码格式,但如果识别失败,请:
|
||||||
|
- 中国市场:使用完整格式,如 `600519.SH` 或 `000001.SZ`
|
||||||
|
- 其他市场:按照该市场的标准格式输入
|
||||||
|
|
||||||
|
### Q5: 如何配置系统?
|
||||||
|
|
||||||
|
A:
|
||||||
|
1. 访问"配置"页面
|
||||||
|
2. 在对应的标签页中配置各项设置
|
||||||
|
3. 使用"测试"按钮验证配置是否正确
|
||||||
|
4. 点击"保存所有配置"保存设置
|
||||||
|
|
||||||
|
### Q6: 分析报告生成需要多长时间?
|
||||||
|
|
||||||
|
A: 生成时间取决于:
|
||||||
|
- 财务数据的获取速度(通常几秒钟)
|
||||||
|
- AI 分析模块的数量和复杂度
|
||||||
|
- AI 服务的响应速度
|
||||||
|
|
||||||
|
完整的报告生成通常需要 1-5 分钟。
|
||||||
|
|
||||||
|
### Q7: 可以同时分析多只股票吗?
|
||||||
|
|
||||||
|
A: 目前系统每次只能分析一只股票。如需分析多只股票,请分别提交请求。
|
||||||
|
|
||||||
|
### Q8: 报告数据是实时的吗?
|
||||||
|
|
||||||
|
A:
|
||||||
|
- 财务数据:来自 Tushare 等数据源,更新频率取决于数据源
|
||||||
|
- 股价图表:TradingView 提供实时股价数据
|
||||||
|
- AI 分析:基于当前获取的财务数据实时生成
|
||||||
|
|
||||||
|
## 系统配置
|
||||||
|
|
||||||
|
### 首次使用配置
|
||||||
|
|
||||||
|
首次使用系统时,需要配置以下内容:
|
||||||
|
|
||||||
|
1. **数据库配置**(如使用)
|
||||||
|
- 数据库连接 URL:`postgresql+asyncpg://user:password@host:port/database`
|
||||||
|
- 使用"测试连接"按钮验证连接
|
||||||
|
|
||||||
|
2. **AI 服务配置**
|
||||||
|
- API Key:输入您的 AI 服务 API 密钥
|
||||||
|
- Base URL:输入 API 端点地址(如使用自建服务)
|
||||||
|
|
||||||
|
3. **数据源配置**
|
||||||
|
- **Tushare**:输入 Tushare API Key(中国市场必需)
|
||||||
|
- **Finnhub**:输入 Finnhub API Key(全球市场可选)
|
||||||
|
|
||||||
|
### 配置注意事项
|
||||||
|
|
||||||
|
- **敏感信息保护**:API 密钥等敏感信息在输入框中不会显示,留空表示保持当前值
|
||||||
|
- **配置验证**:保存前建议使用"测试"按钮验证各项配置
|
||||||
|
- **配置备份**:建议定期使用"导出配置"功能备份配置
|
||||||
|
- **配置恢复**:可使用"导入配置"功能恢复之前的配置
|
||||||
|
|
||||||
|
### 分析模块配置
|
||||||
|
|
||||||
|
在"配置"页面的"分析配置"标签页,您可以:
|
||||||
|
|
||||||
|
- **自定义模块名称**:修改分析模块的显示名称
|
||||||
|
- **选择 AI 模型**:为每个模块指定使用的 AI 模型
|
||||||
|
- **编辑提示词模板**:自定义每个模块的分析提示词
|
||||||
|
- **设置模块依赖**:配置分析模块之间的依赖关系
|
||||||
|
|
||||||
|
配置修改后,点击"保存分析配置"即可生效。
|
||||||
|
|
||||||
|
## 技术支持
|
||||||
|
|
||||||
|
如果您在使用过程中遇到问题,可以:
|
||||||
|
|
||||||
|
1. 查看"执行详情"中的错误信息
|
||||||
|
2. 检查系统配置是否正确
|
||||||
|
3. 查看系统日志(如果已启用)
|
||||||
|
4. 联系系统管理员获取支持
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**最后更新**:2025年1月
|
||||||
|
|
||||||
|
|
||||||
13
frontend/package-lock.json
generated
13
frontend/package-lock.json
generated
@ -15,6 +15,7 @@
|
|||||||
"@radix-ui/react-tabs": "^1.1.13",
|
"@radix-ui/react-tabs": "^1.1.13",
|
||||||
"class-variance-authority": "^0.7.1",
|
"class-variance-authority": "^0.7.1",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
|
"github-markdown-css": "^5.8.1",
|
||||||
"lucide-react": "^0.545.0",
|
"lucide-react": "^0.545.0",
|
||||||
"next": "15.5.5",
|
"next": "15.5.5",
|
||||||
"react": "19.1.0",
|
"react": "19.1.0",
|
||||||
@ -4587,6 +4588,18 @@
|
|||||||
"url": "https://github.com/privatenumber/get-tsconfig?sponsor=1"
|
"url": "https://github.com/privatenumber/get-tsconfig?sponsor=1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/github-markdown-css": {
|
||||||
|
"version": "5.8.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/github-markdown-css/-/github-markdown-css-5.8.1.tgz",
|
||||||
|
"integrity": "sha512-8G+PFvqigBQSWLQjyzgpa2ThD9bo7+kDsriUIidGcRhXgmcaAWUIpCZf8DavJgc+xifjbCG+GvMyWr0XMXmc7g==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/glob-parent": {
|
"node_modules/glob-parent": {
|
||||||
"version": "6.0.2",
|
"version": "6.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
|
||||||
|
|||||||
@ -4,7 +4,7 @@
|
|||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next dev --turbopack",
|
"dev": "next dev --turbopack",
|
||||||
"build": "next build --turbopack",
|
"build": "next build",
|
||||||
"start": "next start",
|
"start": "next start",
|
||||||
"lint": "eslint"
|
"lint": "eslint"
|
||||||
},
|
},
|
||||||
@ -16,6 +16,7 @@
|
|||||||
"@radix-ui/react-tabs": "^1.1.13",
|
"@radix-ui/react-tabs": "^1.1.13",
|
||||||
"class-variance-authority": "^0.7.1",
|
"class-variance-authority": "^0.7.1",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
|
"github-markdown-css": "^5.8.1",
|
||||||
"lucide-react": "^0.545.0",
|
"lucide-react": "^0.545.0",
|
||||||
"next": "15.5.5",
|
"next": "15.5.5",
|
||||||
"react": "19.1.0",
|
"react": "19.1.0",
|
||||||
|
|||||||
@ -6,13 +6,13 @@ import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
|||||||
|
|
||||||
async function getMarkdownContent() {
|
async function getMarkdownContent() {
|
||||||
// process.cwd() is the root of the Next.js project (the 'frontend' directory)
|
// process.cwd() is the root of the Next.js project (the 'frontend' directory)
|
||||||
const mdPath = path.join(process.cwd(), '..', 'docs', 'design.md');
|
const mdPath = path.join(process.cwd(), '..', 'docs', 'user-guide.md');
|
||||||
try {
|
try {
|
||||||
const content = await fs.readFile(mdPath, 'utf8');
|
const content = await fs.readFile(mdPath, 'utf8');
|
||||||
return content;
|
return content;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Failed to read design.md:", error);
|
console.error("Failed to read user-guide.md:", error);
|
||||||
return "# 文档加载失败\n\n无法读取 `docs/design.md` 文件。请检查文件是否存在以及服务器权限。";
|
return "# 文档加载失败\n\n无法读取 `docs/user-guide.md` 文件。请检查文件是否存在以及服务器权限。";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -22,42 +22,22 @@ export default async function DocsPage() {
|
|||||||
return (
|
return (
|
||||||
<div className="container mx-auto py-6 space-y-6">
|
<div className="container mx-auto py-6 space-y-6">
|
||||||
<header className="space-y-2">
|
<header className="space-y-2">
|
||||||
<h1 className="text-3xl font-bold">系统设计文档</h1>
|
<h1 className="text-3xl font-bold">用户使用文档</h1>
|
||||||
<p className="text-muted-foreground">
|
<p className="text-muted-foreground">
|
||||||
这是系统核心功能与架构的技术设计文档,随功能迭代而更新。
|
欢迎使用基本面分析系统。本文档将帮助您快速上手并充分利用系统的各项功能。
|
||||||
</p>
|
</p>
|
||||||
</header>
|
</header>
|
||||||
<Card>
|
<Card>
|
||||||
<CardContent className="p-6">
|
<CardContent className="p-6">
|
||||||
<article className="prose prose-zinc max-w-none dark:prose-invert">
|
<article className="markdown-body" style={{
|
||||||
|
boxSizing: 'border-box',
|
||||||
|
minWidth: '200px',
|
||||||
|
maxWidth: '980px',
|
||||||
|
margin: '0 auto',
|
||||||
|
padding: '0'
|
||||||
|
}}>
|
||||||
<ReactMarkdown
|
<ReactMarkdown
|
||||||
remarkPlugins={[remarkGfm]}
|
remarkPlugins={[remarkGfm]}
|
||||||
components={{
|
|
||||||
h1: ({node, ...props}) => <h1 className="text-3xl font-bold mb-4 mt-8 border-b pb-2" {...props} />,
|
|
||||||
h2: ({node, ...props}) => <h2 className="text-2xl font-bold mb-3 mt-6 border-b pb-2" {...props} />,
|
|
||||||
h3: ({node, ...props}) => <h3 className="text-xl font-semibold mb-2 mt-4" {...props} />,
|
|
||||||
p: ({node, ...props}) => <p className="mb-4 leading-7" {...props} />,
|
|
||||||
ul: ({node, ...props}) => <ul className="list-disc list-inside mb-4 space-y-2" {...props} />,
|
|
||||||
ol: ({node, ...props}) => <ol className="list-decimal list-inside mb-4 space-y-2" {...props} />,
|
|
||||||
li: ({node, ...props}) => <li className="ml-4" {...props} />,
|
|
||||||
code: ({node, inline, className, children, ...props}: any) => {
|
|
||||||
const match = /language-(\w+)/.exec(className || '');
|
|
||||||
return !inline ? (
|
|
||||||
<code className={className} {...props}>
|
|
||||||
{children}
|
|
||||||
</code>
|
|
||||||
) : (
|
|
||||||
<code className="bg-muted px-1.5 py-1 rounded text-sm font-mono" {...props}>
|
|
||||||
{children}
|
|
||||||
</code>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
pre: ({children}) => <pre className="bg-muted p-4 rounded my-4 overflow-x-auto">{children}</pre>,
|
|
||||||
table: ({node, ...props}) => <div className="overflow-x-auto my-4"><table className="border-collapse border border-border w-full" {...props} /></div>,
|
|
||||||
th: ({node, ...props}) => <th className="border border-border px-4 py-2 bg-muted font-semibold text-left" {...props} />,
|
|
||||||
td: ({node, ...props}) => <td className="border border-border px-4 py-2" {...props} />,
|
|
||||||
a: ({node, ...props}) => <a className="text-primary underline hover:text-primary/80" {...props} />,
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
{content}
|
{content}
|
||||||
</ReactMarkdown>
|
</ReactMarkdown>
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
@import "tailwindcss";
|
@import "tailwindcss";
|
||||||
@import "tw-animate-css";
|
@import "tw-animate-css";
|
||||||
|
@import "github-markdown-css/github-markdown.css";
|
||||||
|
|
||||||
@custom-variant dark (&:is(.dark *));
|
@custom-variant dark (&:is(.dark *));
|
||||||
|
|
||||||
|
|||||||
@ -1491,19 +1491,7 @@ export default function ReportPage() {
|
|||||||
: '待开始'}
|
: '待开始'}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/* 失败时的“重新分析”按钮(兼容原逻辑) */}
|
{/* 始终可见的"重新生成分析"按钮 */}
|
||||||
{state.error && !state.loading && (
|
|
||||||
<Button
|
|
||||||
variant="outline"
|
|
||||||
size="sm"
|
|
||||||
onClick={() => retryAnalysis(analysisType)}
|
|
||||||
disabled={currentAnalysisTask !== null}
|
|
||||||
>
|
|
||||||
<RotateCw className="size-4" />
|
|
||||||
重新分析
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
{/* 新增:始终可见的“重新生成分析”按钮 */}
|
|
||||||
{!state.loading && (
|
{!state.loading && (
|
||||||
<Button
|
<Button
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
@ -1524,31 +1512,15 @@ export default function ReportPage() {
|
|||||||
{(state.loading || state.content) && (
|
{(state.loading || state.content) && (
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
<div className="border rounded-lg p-6 bg-card">
|
<div className="border rounded-lg p-6 bg-card">
|
||||||
<div className="leading-relaxed">
|
<article className="markdown-body" style={{
|
||||||
|
boxSizing: 'border-box',
|
||||||
|
minWidth: '200px',
|
||||||
|
maxWidth: '980px',
|
||||||
|
margin: '0 auto',
|
||||||
|
padding: '0'
|
||||||
|
}}>
|
||||||
<ReactMarkdown
|
<ReactMarkdown
|
||||||
remarkPlugins={[remarkGfm]}
|
remarkPlugins={[remarkGfm]}
|
||||||
components={{
|
|
||||||
h1: ({node, ...props}) => <h1 className="text-2xl font-bold mb-4 mt-6 first:mt-0" {...props} />,
|
|
||||||
h2: ({node, ...props}) => <h2 className="text-xl font-bold mb-3 mt-5 first:mt-0" {...props} />,
|
|
||||||
h3: ({node, ...props}) => <h3 className="text-lg font-semibold mb-2 mt-4 first:mt-0" {...props} />,
|
|
||||||
p: ({node, ...props}) => <p className="mb-2 leading-7" {...props} />,
|
|
||||||
ul: ({node, ...props}) => <ul className="list-disc list-inside mb-2 space-y-1 ml-4" {...props} />,
|
|
||||||
ol: ({node, ...props}) => <ol className="list-decimal list-inside mb-2 space-y-1 ml-4" {...props} />,
|
|
||||||
li: ({node, ...props}) => <li className="ml-2" {...props} />,
|
|
||||||
strong: ({node, ...props}) => <strong className="font-semibold" {...props} />,
|
|
||||||
em: ({node, ...props}) => <em className="italic text-muted-foreground" {...props} />,
|
|
||||||
blockquote: ({node, ...props}) => <blockquote className="border-l-4 border-muted pl-4 italic my-2" {...props} />,
|
|
||||||
code: ({node, inline, ...props}: any) =>
|
|
||||||
inline
|
|
||||||
? <code className="bg-muted px-1.5 py-0.5 rounded text-sm font-mono" {...props} />
|
|
||||||
: <code className="block bg-muted p-4 rounded my-2 overflow-x-auto font-mono text-sm" {...props} />,
|
|
||||||
pre: ({node, ...props}) => <pre className="bg-muted p-4 rounded my-2 overflow-x-auto" {...props} />,
|
|
||||||
table: ({node, ...props}) => <div className="overflow-x-auto my-2"><table className="border-collapse border border-border w-full" {...props} /></div>,
|
|
||||||
th: ({node, ...props}) => <th className="border border-border px-3 py-2 bg-muted font-semibold text-left" {...props} />,
|
|
||||||
td: ({node, ...props}) => <td className="border border-border px-3 py-2" {...props} />,
|
|
||||||
a: ({node, ...props}) => <a className="text-primary underline hover:text-primary/80" {...props} />,
|
|
||||||
hr: ({node, ...props}) => <hr className="my-4 border-border" {...props} />,
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
{normalizedContent}
|
{normalizedContent}
|
||||||
</ReactMarkdown>
|
</ReactMarkdown>
|
||||||
@ -1558,7 +1530,7 @@ export default function ReportPage() {
|
|||||||
<span className="text-sm">正在生成中...</span>
|
<span className="text-sm">正在生成中...</span>
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
</div>
|
</article>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
BIN
portwardenc-amd64
Executable file
BIN
portwardenc-amd64
Executable file
Binary file not shown.
@ -34,9 +34,23 @@ ensure_backend() {
|
|||||||
echo -e "${YELLOW}[SETUP]${RESET} Creating Python venv and installing backend requirements..."
|
echo -e "${YELLOW}[SETUP]${RESET} Creating Python venv and installing backend requirements..."
|
||||||
python3 -m venv .venv
|
python3 -m venv .venv
|
||||||
source .venv/bin/activate
|
source .venv/bin/activate
|
||||||
pip install -r requirements.txt
|
# Upgrade pip first
|
||||||
|
pip install --upgrade pip --timeout 100 -i https://pypi.tuna.tsinghua.edu.cn/simple || \
|
||||||
|
pip install --upgrade pip --timeout 100
|
||||||
|
# Install requirements with timeout and mirror
|
||||||
|
pip install -r requirements.txt --timeout 300 -i https://pypi.tuna.tsinghua.edu.cn/simple || \
|
||||||
|
pip install -r requirements.txt --timeout 300
|
||||||
else
|
else
|
||||||
source .venv/bin/activate
|
source .venv/bin/activate
|
||||||
|
# Upgrade pip if needed
|
||||||
|
pip install --upgrade pip --timeout 100 -i https://pypi.tuna.tsinghua.edu.cn/simple 2>/dev/null || \
|
||||||
|
pip install --upgrade pip --timeout 100 2>/dev/null || true
|
||||||
|
# Check if key dependencies are installed
|
||||||
|
if ! python -c "import uvicorn" 2>/dev/null; then
|
||||||
|
echo -e "${YELLOW}[SETUP]${RESET} Installing missing backend requirements..."
|
||||||
|
pip install -r requirements.txt --timeout 300 -i https://pypi.tuna.tsinghua.edu.cn/simple || \
|
||||||
|
pip install -r requirements.txt --timeout 300
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Export TUSHARE_TOKEN from config if available (prefer jq, fallback to node)
|
# Export TUSHARE_TOKEN from config if available (prefer jq, fallback to node)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user