├── .cursorrules
├── .gitignore
├── LICENSE
├── README-zh.md
├── README.md
├── admin
├── .editorconfig
├── .env
├── .gitattributes
├── .gitignore
├── .prettierrc.json
├── README.md
├── env.d.ts
├── eslint.config.ts
├── index.html
├── package-lock.json
├── package.json
├── public
│ └── favicon.ico
├── src
│ ├── App.vue
│ ├── assets
│ │ ├── base.css
│ │ ├── logo.svg
│ │ └── main.css
│ ├── components
│ │ ├── HelloWorld.vue
│ │ ├── SideBar.vue
│ │ ├── TheWelcome.vue
│ │ ├── WelcomeItem.vue
│ │ └── icons
│ │ │ ├── IconCommunity.vue
│ │ │ ├── IconDocumentation.vue
│ │ │ ├── IconEcosystem.vue
│ │ │ ├── IconSupport.vue
│ │ │ └── IconTooling.vue
│ ├── composables
│ │ └── useCharts.ts
│ ├── layouts
│ │ └── AdminLayout.vue
│ ├── main.ts
│ ├── router
│ │ └── index.ts
│ ├── services
│ │ └── api.ts
│ ├── stores
│ │ └── counter.ts
│ ├── types
│ │ └── index.ts
│ ├── utils
│ │ └── date.ts
│ └── views
│ │ ├── AboutView.vue
│ │ ├── DashboardView.vue
│ │ ├── FeedbackView.vue
│ │ ├── HomeView.vue
│ │ └── StatsView.vue
├── ssl
│ ├── cert.pem
│ └── key.pem
├── start.sh
├── tsconfig.app.json
├── tsconfig.json
├── tsconfig.node.json
└── vite.config.ts
├── certs
├── cert.pem
└── key.pem
├── client
├── .gitignore
├── README.md
├── copy-pdf-worker.js
├── index.html
├── package-lock.json
├── package.json
├── postcss.config.js
├── public
│ ├── ai-logo.svg
│ ├── error-placeholder.svg
│ ├── pdf
│ │ ├── cmaps
│ │ │ ├── 78-EUC-H.bcmap
│ │ │ ├── 78-EUC-V.bcmap
│ │ │ ├── 78-H.bcmap
│ │ │ ├── 78-RKSJ-H.bcmap
│ │ │ ├── 78-RKSJ-V.bcmap
│ │ │ ├── 78-V.bcmap
│ │ │ ├── 78ms-RKSJ-H.bcmap
│ │ │ ├── 78ms-RKSJ-V.bcmap
│ │ │ ├── 83pv-RKSJ-H.bcmap
│ │ │ ├── 90ms-RKSJ-H.bcmap
│ │ │ ├── 90ms-RKSJ-V.bcmap
│ │ │ ├── 90msp-RKSJ-H.bcmap
│ │ │ ├── 90msp-RKSJ-V.bcmap
│ │ │ ├── 90pv-RKSJ-H.bcmap
│ │ │ ├── 90pv-RKSJ-V.bcmap
│ │ │ ├── Add-H.bcmap
│ │ │ ├── Add-RKSJ-H.bcmap
│ │ │ ├── Add-RKSJ-V.bcmap
│ │ │ ├── Add-V.bcmap
│ │ │ ├── Adobe-CNS1-0.bcmap
│ │ │ ├── Adobe-CNS1-1.bcmap
│ │ │ ├── Adobe-CNS1-2.bcmap
│ │ │ ├── Adobe-CNS1-3.bcmap
│ │ │ ├── Adobe-CNS1-4.bcmap
│ │ │ ├── Adobe-CNS1-5.bcmap
│ │ │ ├── Adobe-CNS1-6.bcmap
│ │ │ ├── Adobe-CNS1-UCS2.bcmap
│ │ │ ├── Adobe-GB1-0.bcmap
│ │ │ ├── Adobe-GB1-1.bcmap
│ │ │ ├── Adobe-GB1-2.bcmap
│ │ │ ├── Adobe-GB1-3.bcmap
│ │ │ ├── Adobe-GB1-4.bcmap
│ │ │ ├── Adobe-GB1-5.bcmap
│ │ │ ├── Adobe-GB1-UCS2.bcmap
│ │ │ ├── Adobe-Japan1-0.bcmap
│ │ │ ├── Adobe-Japan1-1.bcmap
│ │ │ ├── Adobe-Japan1-2.bcmap
│ │ │ ├── Adobe-Japan1-3.bcmap
│ │ │ ├── Adobe-Japan1-4.bcmap
│ │ │ ├── Adobe-Japan1-5.bcmap
│ │ │ ├── Adobe-Japan1-6.bcmap
│ │ │ ├── Adobe-Japan1-UCS2.bcmap
│ │ │ ├── Adobe-Korea1-0.bcmap
│ │ │ ├── Adobe-Korea1-1.bcmap
│ │ │ ├── Adobe-Korea1-2.bcmap
│ │ │ ├── Adobe-Korea1-UCS2.bcmap
│ │ │ ├── B5-H.bcmap
│ │ │ ├── B5-V.bcmap
│ │ │ ├── B5pc-H.bcmap
│ │ │ ├── B5pc-V.bcmap
│ │ │ ├── CNS-EUC-H.bcmap
│ │ │ ├── CNS-EUC-V.bcmap
│ │ │ ├── CNS1-H.bcmap
│ │ │ ├── CNS1-V.bcmap
│ │ │ ├── CNS2-H.bcmap
│ │ │ ├── CNS2-V.bcmap
│ │ │ ├── ETHK-B5-H.bcmap
│ │ │ ├── ETHK-B5-V.bcmap
│ │ │ ├── ETen-B5-H.bcmap
│ │ │ ├── ETen-B5-V.bcmap
│ │ │ ├── ETenms-B5-H.bcmap
│ │ │ ├── ETenms-B5-V.bcmap
│ │ │ ├── EUC-H.bcmap
│ │ │ ├── EUC-V.bcmap
│ │ │ ├── Ext-H.bcmap
│ │ │ ├── Ext-RKSJ-H.bcmap
│ │ │ ├── Ext-RKSJ-V.bcmap
│ │ │ ├── Ext-V.bcmap
│ │ │ ├── GB-EUC-H.bcmap
│ │ │ ├── GB-EUC-V.bcmap
│ │ │ ├── GB-H.bcmap
│ │ │ ├── GB-V.bcmap
│ │ │ ├── GBK-EUC-H.bcmap
│ │ │ ├── GBK-EUC-V.bcmap
│ │ │ ├── GBK2K-H.bcmap
│ │ │ ├── GBK2K-V.bcmap
│ │ │ ├── GBKp-EUC-H.bcmap
│ │ │ ├── GBKp-EUC-V.bcmap
│ │ │ ├── GBT-EUC-H.bcmap
│ │ │ ├── GBT-EUC-V.bcmap
│ │ │ ├── GBT-H.bcmap
│ │ │ ├── GBT-V.bcmap
│ │ │ ├── GBTpc-EUC-H.bcmap
│ │ │ ├── GBTpc-EUC-V.bcmap
│ │ │ ├── GBpc-EUC-H.bcmap
│ │ │ ├── GBpc-EUC-V.bcmap
│ │ │ ├── H.bcmap
│ │ │ ├── HKdla-B5-H.bcmap
│ │ │ ├── HKdla-B5-V.bcmap
│ │ │ ├── HKdlb-B5-H.bcmap
│ │ │ ├── HKdlb-B5-V.bcmap
│ │ │ ├── HKgccs-B5-H.bcmap
│ │ │ ├── HKgccs-B5-V.bcmap
│ │ │ ├── HKm314-B5-H.bcmap
│ │ │ ├── HKm314-B5-V.bcmap
│ │ │ ├── HKm471-B5-H.bcmap
│ │ │ ├── HKm471-B5-V.bcmap
│ │ │ ├── HKscs-B5-H.bcmap
│ │ │ ├── HKscs-B5-V.bcmap
│ │ │ ├── Hankaku.bcmap
│ │ │ ├── Hiragana.bcmap
│ │ │ ├── KSC-EUC-H.bcmap
│ │ │ ├── KSC-EUC-V.bcmap
│ │ │ ├── KSC-H.bcmap
│ │ │ ├── KSC-Johab-H.bcmap
│ │ │ ├── KSC-Johab-V.bcmap
│ │ │ ├── KSC-V.bcmap
│ │ │ ├── KSCms-UHC-H.bcmap
│ │ │ ├── KSCms-UHC-HW-H.bcmap
│ │ │ ├── KSCms-UHC-HW-V.bcmap
│ │ │ ├── KSCms-UHC-V.bcmap
│ │ │ ├── KSCpc-EUC-H.bcmap
│ │ │ ├── KSCpc-EUC-V.bcmap
│ │ │ ├── Katakana.bcmap
│ │ │ ├── LICENSE
│ │ │ ├── NWP-H.bcmap
│ │ │ ├── NWP-V.bcmap
│ │ │ ├── RKSJ-H.bcmap
│ │ │ ├── RKSJ-V.bcmap
│ │ │ ├── Roman.bcmap
│ │ │ ├── UniCNS-UCS2-H.bcmap
│ │ │ ├── UniCNS-UCS2-V.bcmap
│ │ │ ├── UniCNS-UTF16-H.bcmap
│ │ │ ├── UniCNS-UTF16-V.bcmap
│ │ │ ├── UniCNS-UTF32-H.bcmap
│ │ │ ├── UniCNS-UTF32-V.bcmap
│ │ │ ├── UniCNS-UTF8-H.bcmap
│ │ │ ├── UniCNS-UTF8-V.bcmap
│ │ │ ├── UniGB-UCS2-H.bcmap
│ │ │ ├── UniGB-UCS2-V.bcmap
│ │ │ ├── UniGB-UTF16-H.bcmap
│ │ │ ├── UniGB-UTF16-V.bcmap
│ │ │ ├── UniGB-UTF32-H.bcmap
│ │ │ ├── UniGB-UTF32-V.bcmap
│ │ │ ├── UniGB-UTF8-H.bcmap
│ │ │ ├── UniGB-UTF8-V.bcmap
│ │ │ ├── UniJIS-UCS2-H.bcmap
│ │ │ ├── UniJIS-UCS2-HW-H.bcmap
│ │ │ ├── UniJIS-UCS2-HW-V.bcmap
│ │ │ ├── UniJIS-UCS2-V.bcmap
│ │ │ ├── UniJIS-UTF16-H.bcmap
│ │ │ ├── UniJIS-UTF16-V.bcmap
│ │ │ ├── UniJIS-UTF32-H.bcmap
│ │ │ ├── UniJIS-UTF32-V.bcmap
│ │ │ ├── UniJIS-UTF8-H.bcmap
│ │ │ ├── UniJIS-UTF8-V.bcmap
│ │ │ ├── UniJIS2004-UTF16-H.bcmap
│ │ │ ├── UniJIS2004-UTF16-V.bcmap
│ │ │ ├── UniJIS2004-UTF32-H.bcmap
│ │ │ ├── UniJIS2004-UTF32-V.bcmap
│ │ │ ├── UniJIS2004-UTF8-H.bcmap
│ │ │ ├── UniJIS2004-UTF8-V.bcmap
│ │ │ ├── UniJISPro-UCS2-HW-V.bcmap
│ │ │ ├── UniJISPro-UCS2-V.bcmap
│ │ │ ├── UniJISPro-UTF8-V.bcmap
│ │ │ ├── UniJISX0213-UTF32-H.bcmap
│ │ │ ├── UniJISX0213-UTF32-V.bcmap
│ │ │ ├── UniJISX02132004-UTF32-H.bcmap
│ │ │ ├── UniJISX02132004-UTF32-V.bcmap
│ │ │ ├── UniKS-UCS2-H.bcmap
│ │ │ ├── UniKS-UCS2-V.bcmap
│ │ │ ├── UniKS-UTF16-H.bcmap
│ │ │ ├── UniKS-UTF16-V.bcmap
│ │ │ ├── UniKS-UTF32-H.bcmap
│ │ │ ├── UniKS-UTF32-V.bcmap
│ │ │ ├── UniKS-UTF8-H.bcmap
│ │ │ ├── UniKS-UTF8-V.bcmap
│ │ │ ├── V.bcmap
│ │ │ └── WP-Symbol.bcmap
│ │ ├── pdf.worker.min.js
│ │ └── pdf.worker.min.mjs
│ ├── pdfium
│ │ ├── pdfium.js
│ │ └── pdfium.wasm
│ └── vite.svg
├── src
│ ├── App.vue
│ ├── assets
│ │ ├── ai-logo.svg
│ │ └── vue.svg
│ ├── components
│ │ ├── DocTree.vue
│ │ ├── DocView.vue
│ │ ├── HelloWorld.vue
│ │ ├── ImmersiveReader.vue
│ │ ├── MarkdownViewer.vue
│ │ ├── MobileNav.vue
│ │ ├── NavBar.vue
│ │ ├── PDFViewer.vue
│ │ ├── ReadingControls.vue
│ │ ├── RecentDocs.vue
│ │ ├── SearchBar.vue
│ │ ├── TreeNode.vue
│ │ ├── announcement
│ │ │ ├── AnnouncementBoard.vue
│ │ │ ├── AnnouncementButton.vue
│ │ │ ├── FeedbackForm.vue
│ │ │ ├── RecommendationsPanel.vue
│ │ │ └── UpdatesPanel.vue
│ │ └── icons
│ │ │ └── index.js
│ ├── composables
│ │ └── useDebounce.ts
│ ├── main.ts
│ ├── router
│ │ └── index.ts
│ ├── services
│ │ └── api.ts
│ ├── stores
│ │ ├── announcement.ts
│ │ ├── doc.ts
│ │ ├── reading.ts
│ │ ├── search.ts
│ │ └── theme.ts
│ ├── style.css
│ ├── styles
│ │ ├── immersive.css
│ │ └── immersive.scss
│ ├── utils
│ │ └── markdown.ts
│ ├── views
│ │ ├── AdminDashboard.vue
│ │ ├── DocView.vue
│ │ ├── HomeView.vue
│ │ └── SearchView.vue
│ └── vite-env.d.ts
├── ssl
│ ├── cert.pem
│ └── key.pem
├── stats.html
├── tailwind.config.js
├── tsconfig.app.json
├── tsconfig.json
├── tsconfig.node.json
├── vite.config.ts
├── yarn.lock
└── 图书网站UI.html
├── dark-mode.png
├── deploy.sh
├── docker-compose.yml
├── env.md
├── home.png
├── install_meilisearch_windows.md
├── meilisearch.md
├── mode.png
├── requirements.txt
├── responsive.png
├── search.png
├── server
├── app
│ ├── __init__.py
│ ├── main.py
│ ├── routers
│ │ ├── __init__.py
│ │ ├── admin.py
│ │ ├── announcements.py
│ │ ├── docs.py
│ │ ├── feedback.py
│ │ └── search.py
│ └── services
│ │ ├── __init__.py
│ │ ├── announcement_service.py
│ │ ├── doc_service.py
│ │ ├── meilisearch_service.py
│ │ ├── search_service.py
│ │ └── stats_service.py
├── build_index.py
├── cert.pem
├── data
│ ├── feedback.json
│ ├── popular_docs.json
│ ├── recommendations.json
│ ├── stats.json
│ ├── updates.json
│ └── visits.json
├── key.pem
├── logs.txt
├── package-lock.json
├── requirements.txt
├── run_h2.py
├── ssl
│ ├── cert.pem
│ └── key.pem
├── start_with_meilisearch.sh
├── static
│ └── stats
│ │ ├── popular_docs.json
│ │ ├── stats.json
│ │ └── visits.json
├── test_meili.py
└── 软链.md
├── start_services.ps1
└── tools
├── categorize_articles.py
├── clean_empty_courses.py
├── detect_duplicates.py
├── fix_image_paths.py
├── llm_api.py
├── search_engine.py
├── smart_categorize.py
├── split_articles.py
└── web_scraper.py
/.gitignore:
--------------------------------------------------------------------------------
1 | # 输出目录
2 | downloaded_content/
3 |
4 | # 日志文件
5 | *.log
6 |
7 | # 爬虫文件
8 | scraper.py
9 |
10 | # Python 相关
11 | __pycache__/
12 | *.py[cod]
13 | *$py.class
14 | *.so
15 | .Python
16 | env/
17 | build/
18 | develop-eggs/
19 | dist/
20 | downloads/
21 | eggs/
22 | .eggs/
23 | lib/
24 | lib64/
25 | parts/
26 | sdist/
27 | var/
28 | wheels/
29 | *.egg-info/
30 | .installed.cfg
31 | *.egg
32 |
33 | # 虚拟环境
34 | venv/
35 | py310/
36 | ENV/
37 |
38 | # IDE 相关
39 | .idea/
40 | .vscode/
41 | *.swp
42 | *.swo
43 | .DS_Store
44 |
45 | # 临时文件
46 | *.tmp
47 | *.bak
48 | *.swp
49 | *~
50 |
51 | # 系统文件
52 | .DS_Store
53 | Thumbs.db
54 |
55 | # Docs 相关
56 | docs/
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2024 AI Library
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/README-zh.md:
--------------------------------------------------------------------------------
1 | # AI Library
2 |
3 | [](README.md)
4 | [](README-zh.md)
5 |
6 | AI Library 是一个由ai开发的现代化的文档管理系统,专注于提供优雅的阅读体验和高效的知识管理。
7 |
8 | ## ✨ 功能展示
9 |
10 |
11 | ### 📱 响应式布局
12 | 
13 | 完美适配桌面端和移动端,提供一致的阅读体验。
14 |
15 | ### 🌓 深色模式
16 | 
17 | 自动跟随系统切换,保护你的眼睛。支持浅色、深色和护眼模式。
18 |
19 | ### 沉浸护眼模式
20 | 
21 | 进入深度阅读模式,排除一切干扰,自动隐藏设置栏,护眼模式低饱和暖色
22 |
23 | ### 🔍 实时搜索
24 | 
25 | 快速定位文档,支持标题和内容搜索。
26 |
27 | ## 功能特点
28 |
29 | ### 阅读体验
30 | - 沉浸式阅读模式
31 | - 智能隐藏非必要UI元素
32 | - 自动调整内容宽度和留白
33 | - 支持键盘快捷操作
34 | - 阅读进度实时显示
35 | - 章节导航保持显示
36 | - 支持自动滚动
37 | - 多主题支持
38 | - 浅色主题
39 | - 深色主题
40 | - 护眼模式
41 | - 阅读设置
42 | - 字体大小调节
43 | - 行高调整
44 | - 段落间距设置
45 | - 页面宽度控制
46 | - 大屏优化
47 | - 支持24-40寸显示器自适应
48 | - 智能分栏布局
49 | - 图片优化显示
50 |
51 | ### 文档管理
52 | - 支持多种文档格式
53 | - Markdown 文档
54 | - PDF 文件
55 | - 树形目录结构
56 | - 文档实时搜索
57 | - 最近访问记录
58 | - 阅读位置记忆
59 | - 阅读时长统计
60 |
61 | ### 用户体验
62 | - 响应式设计
63 | - 多主题支持
64 | - 优雅的动画过渡
65 | - 手势操作支持
66 | - 快捷键支持
67 |
68 | ### 特性
69 | - HTTP/2 支持
70 | - 高性能后端 API
71 | - 实时搜索引擎
72 | - 缓存优化
73 |
74 | ## 技术栈
75 |
76 | ### 前端
77 | - Vue 3 (Composition API)
78 | - TypeScript
79 | - Tailwind CSS
80 | - Vite
81 | - Pinia 状态管理
82 | - Vue Router
83 |
84 | ### 后端
85 | - FastAPI
86 | - Uvicorn (HTTP/2 支持)
87 | - Python 3.10+
88 |
89 | ### 部署
90 | - HTTPS/HTTP2
91 | - Docker 支持
92 | - Cloudflare Tunnel
93 |
94 | ## 环境要求
95 |
96 | ### 开发环境
97 | - Node.js 16+
98 | - Python 3.10+
99 | - pip
100 | - yarn/npm
101 | - Git
102 |
103 | ### 生产环境
104 | - Linux/macOS/Windows
105 | - Docker (可选)
106 |
107 | ## 安装指南
108 |
109 | ### 1. 克隆项目
110 | ```bash
111 | git clone https://github.com/yourusername/ai-library.git
112 | cd ai-library
113 | ```
114 |
115 | ### 2. 后端设置
116 | ```bash
117 | # 创建 Python 虚拟环境
118 | python -m venv py310
119 | source py310/bin/activate # Linux/macOS
120 | # 或
121 | .\py310\Scripts\activate # Windows
122 |
123 | # 安装依赖
124 | pip install -r requirements.txt
125 |
126 | # 生成 SSL 证书(用于开发环境)
127 | openssl req -x509 -newkey rsa:4096 -keyout server/key.pem -out server/cert.pem -days 365 -nodes
128 | ```
129 |
130 | ### 3. 前端设置
131 | ```bash
132 | cd client
133 | yarn install # 或 npm install
134 |
135 | # 开发环境配置
136 | cp .env.example .env.local
137 | ```
138 |
139 | ## 开发指南
140 |
141 | ### 启动开发服务器
142 |
143 | 1. 后端服务器
144 | ```bash
145 | cd server
146 | PYTHONPATH=/path/to/project/server python run.py
147 | ```
148 |
149 | 2. 前端服务器
150 | ```bash
151 | cd client
152 | yarn dev # 或 npm run dev
153 | ```
154 |
155 | ### 开发模式
156 | - 后端服务器运行在 https://localhost:8000
157 | - 前端服务器运行在 https://localhost:5173
158 | - API 文档访问地址:https://localhost:8000/docs
159 |
160 | ## API接口
161 |
162 | ### 文档接口
163 | - `GET /api/docs/tree` - 获取文档目录树
164 | - `GET /api/docs/content/{path}` - 获取文档内容
165 | - `GET /api/docs/metadata/{path}` - 获取文档元数据
166 | - `GET /api/docs/recent` - 获取最近访问的文档
167 | - `GET /api/docs/breadcrumb/{path}` - 获取文档面包屑导航
168 |
169 | ### 搜索接口
170 | - `GET /api/search?q={query}` - 搜索文档
171 | - `POST /api/search/rebuild-index` - 重建搜索索引
172 |
173 | ## 项目结构
174 | ```
175 | .
176 | ├── client/ # 前端代码
177 | │ ├── src/
178 | │ │ ├── components/ # Vue 组件
179 | │ │ ├── stores/ # Pinia 状态管理
180 | │ │ ├── services/ # API 服务
181 | │ │ └── styles/ # 全局样式
182 | │ └── public/ # 静态资源
183 | ├── server/ # 后端代码
184 | │ ├── app/ # FastAPI 应用
185 | │ │ ├── routers/ # API 路由
186 | │ │ ├── services/ # 业务逻辑
187 | │ │ └── models/ # 数据模型
188 | │ ├── static/ # 静态文件
189 | │ │ └── docs/ # 文档存储
190 | │ └── tests/ # 测试用例
191 | └── docs/ # 文档目录
192 | ```
193 |
194 | ## 贡献指南
195 |
196 | 1. Fork 项目
197 | 2. 创建功能分支 (`git checkout -b feature/AmazingFeature`)
198 | 3. 提交更改 (`git commit -m 'Add some AmazingFeature'`)
199 | 4. 推送到分支 (`git push origin feature/AmazingFeature`)
200 | 5. 提交 Pull Request
201 |
202 | ## 许可证
203 |
204 | [MIT License](LICENSE)
205 |
206 | ## 联系方式
207 |
208 | - 项目维护者:[LY-GGBOY](li1980303503@gmail.com)
209 | - 项目主页:[GitHub](https://github.com/Ly-GGboy/ai-library)
--------------------------------------------------------------------------------
/admin/.editorconfig:
--------------------------------------------------------------------------------
1 | [*.{js,jsx,mjs,cjs,ts,tsx,mts,cts,vue}]
2 | charset = utf-8
3 | indent_size = 2
4 | indent_style = space
5 | insert_final_newline = true
6 | trim_trailing_whitespace = true
7 |
8 | end_of_line = lf
9 | max_line_length = 100
10 |
--------------------------------------------------------------------------------
/admin/.env:
--------------------------------------------------------------------------------
1 | VITE_API_BASE_URL=https://localhost:8000
--------------------------------------------------------------------------------
/admin/.gitattributes:
--------------------------------------------------------------------------------
1 | * text=auto eol=lf
2 |
--------------------------------------------------------------------------------
/admin/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | .DS_Store
12 | dist
13 | dist-ssr
14 | coverage
15 | *.local
16 |
17 | /cypress/videos/
18 | /cypress/screenshots/
19 |
20 | # Editor directories and files
21 | .vscode/*
22 | !.vscode/extensions.json
23 | .idea
24 | *.suo
25 | *.ntvs*
26 | *.njsproj
27 | *.sln
28 | *.sw?
29 |
30 | *.tsbuildinfo
31 |
--------------------------------------------------------------------------------
/admin/.prettierrc.json:
--------------------------------------------------------------------------------
1 |
2 | {
3 | "$schema": "https://json.schemastore.org/prettierrc",
4 | "semi": false,
5 | "singleQuote": true,
6 | "printWidth": 100
7 | }
8 |
--------------------------------------------------------------------------------
/admin/README.md:
--------------------------------------------------------------------------------
1 | # AI Library 管理后台
2 |
3 | AI Library 管理后台是一个独立的管理界面,用于管理AI Library的内容、监控用户访问和查看用户反馈。
4 |
5 | ## 功能特性
6 |
7 | - **仪表盘**: 总览网站访问数据、热门文档和用户反馈
8 | - **访问统计**: 查看详细的访问统计和趋势分析
9 | - **用户反馈**: 管理用户提交的反馈和建议
10 |
11 | ## 技术栈
12 |
13 | - **前端框架**: Vue.js 3 + TypeScript
14 | - **UI组件**: 纯CSS自定义组件
15 | - **状态管理**: Vue Composition API
16 | - **HTTP客户端**: Axios
17 | - **构建工具**: Vite
18 |
19 | ## 开发指南
20 |
21 | ### 环境准备
22 |
23 | 确保已安装以下工具:
24 |
25 | - Node.js (v14+)
26 | - npm 或 yarn
27 |
28 | ### 安装依赖
29 |
30 | ```bash
31 | npm install
32 | # 或
33 | yarn
34 | ```
35 |
36 | ### 启动开发服务器
37 |
38 | ```bash
39 | npm run dev
40 | # 或
41 | yarn dev
42 | ```
43 |
44 | 或者使用提供的启动脚本:
45 |
46 | ```bash
47 | chmod +x start.sh
48 | ./start.sh
49 | ```
50 |
51 | ### 构建生产版本
52 |
53 | ```bash
54 | npm run build
55 | # 或
56 | yarn build
57 | ```
58 |
59 | ## API接口
60 |
61 | 管理后台通过以下API与后端通信:
62 |
63 | - `GET /api/admin/dashboard` - 获取仪表盘数据
64 | - `GET /api/admin/stats` - 获取访问统计数据
65 | - `GET /api/admin/popular-documents` - 获取热门文档
66 | - `GET /api/admin/feedback` - 获取用户反馈
67 |
68 | ## 项目结构
69 |
70 | ```
71 | admin/
72 | ├── public/ # 静态资源
73 | ├── src/
74 | │ ├── assets/ # 项目资源文件
75 | │ ├── components/ # 共享组件
76 | │ ├── router/ # 路由配置
77 | │ ├── services/ # API服务
78 | │ ├── views/ # 页面组件
79 | │ ├── App.vue # 根组件
80 | │ └── main.ts # 入口文件
81 | ├── .env # 环境变量
82 | ├── index.html # HTML模板
83 | ├── package.json # 项目依赖
84 | ├── tsconfig.json # TypeScript配置
85 | ├── vite.config.ts # Vite配置
86 | └── README.md # 项目文档
87 | ```
88 |
89 | ## 部署指南
90 |
91 | 1. 构建生产版本:
92 | ```bash
93 | npm run build
94 | ```
95 |
96 | 2. 将 `dist` 目录部署到Web服务器的适当位置
97 |
98 | 3. 确保API服务器正在运行并配置了正确的API基础URL
99 |
100 | ## 许可证
101 |
102 | [MIT License](LICENSE)
103 |
--------------------------------------------------------------------------------
/admin/env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/admin/eslint.config.ts:
--------------------------------------------------------------------------------
1 | import pluginVue from 'eslint-plugin-vue'
2 | import { defineConfigWithVueTs, vueTsConfigs } from '@vue/eslint-config-typescript'
3 | import skipFormatting from '@vue/eslint-config-prettier/skip-formatting'
4 |
5 | // To allow more languages other than `ts` in `.vue` files, uncomment the following lines:
6 | // import { configureVueProject } from '@vue/eslint-config-typescript'
7 | // configureVueProject({ scriptLangs: ['ts', 'tsx'] })
8 | // More info at https://github.com/vuejs/eslint-config-typescript/#advanced-setup
9 |
10 | export default defineConfigWithVueTs(
11 | {
12 | name: 'app/files-to-lint',
13 | files: ['**/*.{ts,mts,tsx,vue}'],
14 | },
15 |
16 | {
17 | name: 'app/files-to-ignore',
18 | ignores: ['**/dist/**', '**/dist-ssr/**', '**/coverage/**'],
19 | },
20 |
21 | pluginVue.configs['flat/essential'],
22 | vueTsConfigs.recommended,
23 | skipFormatting,
24 | )
25 |
--------------------------------------------------------------------------------
/admin/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Vite App
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/admin/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "admin",
3 | "version": "0.0.0",
4 | "private": true,
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "run-p type-check \"build-only {@}\" --",
9 | "preview": "vite preview",
10 | "build-only": "vite build",
11 | "type-check": "vue-tsc --build",
12 | "lint": "eslint . --fix",
13 | "format": "prettier --write src/"
14 | },
15 | "dependencies": {
16 | "@headlessui/vue": "^1.7.23",
17 | "@vicons/fluent": "^0.13.0",
18 | "@vicons/ionicons5": "^0.13.0",
19 | "axios": "^1.8.1",
20 | "chart.js": "^4.4.8",
21 | "echarts": "^5.6.0",
22 | "naive-ui": "^2.41.0",
23 | "pinia": "^3.0.1",
24 | "vue": "^3.5.13",
25 | "vue-chartjs": "^5.3.2",
26 | "vue-router": "^4.5.0"
27 | },
28 | "devDependencies": {
29 | "@tsconfig/node22": "^22.0.0",
30 | "@types/node": "^22.13.4",
31 | "@vitejs/plugin-vue": "^5.2.1",
32 | "@vue/eslint-config-prettier": "^10.2.0",
33 | "@vue/eslint-config-typescript": "^14.4.0",
34 | "@vue/tsconfig": "^0.7.0",
35 | "eslint": "^9.20.1",
36 | "eslint-plugin-vue": "^9.32.0",
37 | "jiti": "^2.4.2",
38 | "npm-run-all2": "^7.0.2",
39 | "prettier": "^3.5.1",
40 | "typescript": "~5.7.3",
41 | "vite": "^6.1.0",
42 | "vite-plugin-vue-devtools": "^7.7.2",
43 | "vue-tsc": "^2.2.2"
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/admin/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Ly-GGboy/AI-Library/2fc1a855fc66b2c1743fe7a154b8a13a03210aff/admin/public/favicon.ico
--------------------------------------------------------------------------------
/admin/src/App.vue:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
23 |
--------------------------------------------------------------------------------
/admin/src/assets/base.css:
--------------------------------------------------------------------------------
1 | /* color palette from */
2 | :root {
3 | --vt-c-white: #ffffff;
4 | --vt-c-white-soft: #f8f8f8;
5 | --vt-c-white-mute: #f2f2f2;
6 |
7 | --vt-c-black: #181818;
8 | --vt-c-black-soft: #222222;
9 | --vt-c-black-mute: #282828;
10 |
11 | --vt-c-indigo: #2c3e50;
12 |
13 | --vt-c-divider-light-1: rgba(60, 60, 60, 0.29);
14 | --vt-c-divider-light-2: rgba(60, 60, 60, 0.12);
15 | --vt-c-divider-dark-1: rgba(84, 84, 84, 0.65);
16 | --vt-c-divider-dark-2: rgba(84, 84, 84, 0.48);
17 |
18 | --vt-c-text-light-1: var(--vt-c-indigo);
19 | --vt-c-text-light-2: rgba(60, 60, 60, 0.66);
20 | --vt-c-text-dark-1: var(--vt-c-white);
21 | --vt-c-text-dark-2: rgba(235, 235, 235, 0.64);
22 | }
23 |
24 | /* semantic color variables for this project */
25 | :root {
26 | --color-background: var(--vt-c-white);
27 | --color-background-soft: var(--vt-c-white-soft);
28 | --color-background-mute: var(--vt-c-white-mute);
29 |
30 | --color-border: var(--vt-c-divider-light-2);
31 | --color-border-hover: var(--vt-c-divider-light-1);
32 |
33 | --color-heading: var(--vt-c-text-light-1);
34 | --color-text: var(--vt-c-text-light-1);
35 |
36 | --section-gap: 160px;
37 | }
38 |
39 | @media (prefers-color-scheme: dark) {
40 | :root {
41 | --color-background: var(--vt-c-black);
42 | --color-background-soft: var(--vt-c-black-soft);
43 | --color-background-mute: var(--vt-c-black-mute);
44 |
45 | --color-border: var(--vt-c-divider-dark-2);
46 | --color-border-hover: var(--vt-c-divider-dark-1);
47 |
48 | --color-heading: var(--vt-c-text-dark-1);
49 | --color-text: var(--vt-c-text-dark-2);
50 | }
51 | }
52 |
53 | *,
54 | *::before,
55 | *::after {
56 | box-sizing: border-box;
57 | margin: 0;
58 | font-weight: normal;
59 | }
60 |
61 | body {
62 | min-height: 100vh;
63 | color: var(--color-text);
64 | background: var(--color-background);
65 | transition:
66 | color 0.5s,
67 | background-color 0.5s;
68 | line-height: 1.6;
69 | font-family:
70 | Inter,
71 | -apple-system,
72 | BlinkMacSystemFont,
73 | 'Segoe UI',
74 | Roboto,
75 | Oxygen,
76 | Ubuntu,
77 | Cantarell,
78 | 'Fira Sans',
79 | 'Droid Sans',
80 | 'Helvetica Neue',
81 | sans-serif;
82 | font-size: 15px;
83 | text-rendering: optimizeLegibility;
84 | -webkit-font-smoothing: antialiased;
85 | -moz-osx-font-smoothing: grayscale;
86 | }
87 |
--------------------------------------------------------------------------------
/admin/src/assets/logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/admin/src/assets/main.css:
--------------------------------------------------------------------------------
1 | @import './base.css';
2 |
3 | /* 重置默认样式 */
4 | * {
5 | margin: 0;
6 | padding: 0;
7 | box-sizing: border-box;
8 | }
9 |
10 | #app {
11 | width: 100%;
12 | height: 100vh;
13 | }
14 |
15 | /* 主题变量 */
16 | :root {
17 | /* 主题色 */
18 | --primary-color: #18a058;
19 | --info-color: #2080f0;
20 | --success-color: #18a058;
21 | --warning-color: #f0a020;
22 | --error-color: #d03050;
23 |
24 | /* 文字颜色 */
25 | --text-color-base: #333639;
26 | --text-color-secondary: #666;
27 | --text-color-disabled: #999;
28 |
29 | /* 背景色 */
30 | --background-color: #f5f7fa;
31 | --background-color-light: #fff;
32 |
33 | /* 边框颜色 */
34 | --border-color: #eee;
35 | --border-radius: 8px;
36 |
37 | /* 阴影 */
38 | --box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
39 | --box-shadow-light: 0 2px 8px 0 rgba(0, 0, 0, 0.06);
40 | }
41 |
42 | /* 全局样式 */
43 | html, body {
44 | margin: 0;
45 | padding: 0;
46 | width: 100%;
47 | height: 100%;
48 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial,
49 | 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol',
50 | 'Noto Color Emoji';
51 | -webkit-font-smoothing: antialiased;
52 | -moz-osx-font-smoothing: grayscale;
53 | background-color: var(--background-color);
54 | color: var(--text-color-base);
55 | }
56 |
57 | /* 滚动条样式 */
58 | ::-webkit-scrollbar {
59 | width: 6px;
60 | height: 6px;
61 | }
62 |
63 | ::-webkit-scrollbar-track {
64 | background: transparent;
65 | }
66 |
67 | ::-webkit-scrollbar-thumb {
68 | background: rgba(0, 0, 0, 0.2);
69 | border-radius: 3px;
70 | }
71 |
72 | ::-webkit-scrollbar-thumb:hover {
73 | background: rgba(0, 0, 0, 0.3);
74 | }
75 |
76 | /* 过渡动画 */
77 | .fade-enter-active,
78 | .fade-leave-active {
79 | transition: opacity 0.3s ease;
80 | }
81 |
82 | .fade-enter-from,
83 | .fade-leave-to {
84 | opacity: 0;
85 | }
86 |
87 | /* 通用布局类 */
88 | .flex-center {
89 | display: flex;
90 | align-items: center;
91 | justify-content: center;
92 | }
93 |
94 | .flex-between {
95 | display: flex;
96 | align-items: center;
97 | justify-content: space-between;
98 | }
99 |
100 | .flex-column {
101 | display: flex;
102 | flex-direction: column;
103 | }
104 |
105 | /* 间距类 */
106 | .mt-1 { margin-top: 4px; }
107 | .mt-2 { margin-top: 8px; }
108 | .mt-3 { margin-top: 12px; }
109 | .mt-4 { margin-top: 16px; }
110 | .mt-5 { margin-top: 20px; }
111 |
112 | .mb-1 { margin-bottom: 4px; }
113 | .mb-2 { margin-bottom: 8px; }
114 | .mb-3 { margin-bottom: 12px; }
115 | .mb-4 { margin-bottom: 16px; }
116 | .mb-5 { margin-bottom: 20px; }
117 |
118 | .mr-1 { margin-right: 4px; }
119 | .mr-2 { margin-right: 8px; }
120 | .mr-3 { margin-right: 12px; }
121 | .mr-4 { margin-right: 16px; }
122 | .mr-5 { margin-right: 20px; }
123 |
124 | .ml-1 { margin-left: 4px; }
125 | .ml-2 { margin-left: 8px; }
126 | .ml-3 { margin-left: 12px; }
127 | .ml-4 { margin-left: 16px; }
128 | .ml-5 { margin-left: 20px; }
129 |
--------------------------------------------------------------------------------
/admin/src/components/HelloWorld.vue:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
9 |
{{ msg }}
10 |
11 | You’ve successfully created a project with
12 | Vite +
13 | Vue 3 . What's next?
14 |
15 |
16 |
17 |
18 |
42 |
--------------------------------------------------------------------------------
/admin/src/components/TheWelcome.vue:
--------------------------------------------------------------------------------
1 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | Documentation
18 |
19 | Vue’s
20 | official documentation
21 | provides you with all information you need to get started.
22 |
23 |
24 |
25 |
26 |
27 |
28 | Tooling
29 |
30 | This project is served and bundled with
31 | Vite . The
32 | recommended IDE setup is
33 | VSCode
34 | +
35 | Volar . If
36 | you need to test your components and web pages, check out
37 | Vitest
38 | and
39 | Cypress
40 | /
41 | Playwright .
42 |
43 |
44 |
45 | More instructions are available in
46 | README.md
.
48 |
49 |
50 |
51 |
52 |
53 |
54 | Ecosystem
55 |
56 | Get official tools and libraries for your project:
57 | Pinia ,
58 | Vue Router ,
59 | Vue Test Utils , and
60 | Vue Dev Tools . If
61 | you need more resources, we suggest paying
62 | Awesome Vue
63 | a visit.
64 |
65 |
66 |
67 |
68 |
69 |
70 | Community
71 |
72 | Got stuck? Ask your question on
73 | Vue Land
74 | (our official Discord server), or
75 | StackOverflow . You should also follow the official
78 | @vuejs.org
79 | Bluesky account or the
80 | @vuejs
81 | X account for latest news in the Vue world.
82 |
83 |
84 |
85 |
86 |
87 |
88 | Support Vue
89 |
90 | As an independent project, Vue relies on community backing for its sustainability. You can help
91 | us by
92 | becoming a sponsor .
93 |
94 |
95 |
--------------------------------------------------------------------------------
/admin/src/components/WelcomeItem.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
88 |
--------------------------------------------------------------------------------
/admin/src/components/icons/IconCommunity.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/admin/src/components/icons/IconDocumentation.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/admin/src/components/icons/IconEcosystem.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/admin/src/components/icons/IconSupport.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/admin/src/components/icons/IconTooling.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
14 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/admin/src/composables/useCharts.ts:
--------------------------------------------------------------------------------
1 | import * as echarts from 'echarts'
2 | import type { ChartData } from '@/types'
3 |
4 | let chart: echarts.ECharts | null = null
5 |
6 | export function useCharts() {
7 | const initChart = (elementId: string) => {
8 | const chartElement = document.getElementById(elementId)
9 | if (!chartElement) return
10 |
11 | chart = echarts.init(chartElement)
12 |
13 | // 监听窗口大小变化
14 | window.addEventListener('resize', () => {
15 | chart?.resize()
16 | })
17 | }
18 |
19 | const updateChart = (data: ChartData) => {
20 | if (!chart) return
21 |
22 | chart.setOption({
23 | tooltip: {
24 | trigger: 'axis',
25 | axisPointer: {
26 | type: 'shadow'
27 | }
28 | },
29 | legend: {
30 | data: ['访问量', '独立访客']
31 | },
32 | grid: {
33 | left: '3%',
34 | right: '4%',
35 | bottom: '3%',
36 | containLabel: true
37 | },
38 | xAxis: {
39 | type: 'category',
40 | data: data.dates,
41 | axisLabel: {
42 | rotate: 45
43 | }
44 | },
45 | yAxis: {
46 | type: 'value'
47 | },
48 | series: [
49 | {
50 | name: '访问量',
51 | type: 'line',
52 | smooth: true,
53 | data: data.visits,
54 | itemStyle: {
55 | color: '#18a058'
56 | },
57 | areaStyle: {
58 | color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
59 | {
60 | offset: 0,
61 | color: 'rgba(24, 160, 88, 0.4)'
62 | },
63 | {
64 | offset: 1,
65 | color: 'rgba(24, 160, 88, 0.1)'
66 | }
67 | ])
68 | }
69 | },
70 | {
71 | name: '独立访客',
72 | type: 'line',
73 | smooth: true,
74 | data: data.visitors,
75 | itemStyle: {
76 | color: '#2080f0'
77 | },
78 | areaStyle: {
79 | color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
80 | {
81 | offset: 0,
82 | color: 'rgba(32, 128, 240, 0.4)'
83 | },
84 | {
85 | offset: 1,
86 | color: 'rgba(32, 128, 240, 0.1)'
87 | }
88 | ])
89 | }
90 | }
91 | ]
92 | })
93 | }
94 |
95 | const destroyChart = () => {
96 | if (chart) {
97 | chart.dispose()
98 | chart = null
99 | }
100 | window.removeEventListener('resize', () => {
101 | chart?.resize()
102 | })
103 | }
104 |
105 | return {
106 | initChart,
107 | updateChart,
108 | destroyChart
109 | }
110 | }
--------------------------------------------------------------------------------
/admin/src/main.ts:
--------------------------------------------------------------------------------
1 | import './assets/main.css'
2 |
3 | import { createApp } from 'vue'
4 | import { createPinia } from 'pinia'
5 | import {
6 | create,
7 | NButton,
8 | NCard,
9 | NSpace,
10 | NLayout,
11 | NLayoutSider,
12 | NLayoutHeader,
13 | NLayoutContent,
14 | NMenu,
15 | NIcon,
16 | NBreadcrumb,
17 | NBreadcrumbItem,
18 | NAvatar,
19 | NGrid,
20 | NGridItem,
21 | NStatistic,
22 | NSelect,
23 | NDatePicker,
24 | NRadioGroup,
25 | NRadioButton,
26 | NDataTable,
27 | NTag,
28 | NH2,
29 | NText
30 | } from 'naive-ui'
31 |
32 | import App from './App.vue'
33 | import router from './router'
34 |
35 | const naive = create({
36 | components: [
37 | NButton,
38 | NCard,
39 | NSpace,
40 | NLayout,
41 | NLayoutSider,
42 | NLayoutHeader,
43 | NLayoutContent,
44 | NMenu,
45 | NIcon,
46 | NBreadcrumb,
47 | NBreadcrumbItem,
48 | NAvatar,
49 | NGrid,
50 | NGridItem,
51 | NStatistic,
52 | NSelect,
53 | NDatePicker,
54 | NRadioGroup,
55 | NRadioButton,
56 | NDataTable,
57 | NTag,
58 | NH2,
59 | NText
60 | ]
61 | })
62 |
63 | const app = createApp(App)
64 |
65 | app.use(createPinia())
66 | app.use(router)
67 | app.use(naive)
68 |
69 | app.mount('#app')
70 |
--------------------------------------------------------------------------------
/admin/src/router/index.ts:
--------------------------------------------------------------------------------
1 | import { createRouter, createWebHistory } from 'vue-router'
2 | import AdminLayout from '@/layouts/AdminLayout.vue'
3 |
4 | const router = createRouter({
5 | history: createWebHistory(import.meta.env.BASE_URL),
6 | routes: [
7 | {
8 | path: '/admin',
9 | component: AdminLayout,
10 | children: [
11 | {
12 | path: '',
13 | name: 'dashboard',
14 | component: () => import('@/views/DashboardView.vue')
15 | },
16 | {
17 | path: 'stats',
18 | name: 'stats',
19 | component: () => import('@/views/StatsView.vue')
20 | },
21 | {
22 | path: 'feedback',
23 | name: 'feedback',
24 | component: () => import('@/views/FeedbackView.vue')
25 | }
26 | ]
27 | }
28 | ]
29 | })
30 |
31 | // 路由守卫,用于设置页面标题
32 | router.beforeEach((to, from, next) => {
33 | // 设置页面标题
34 | document.title = to.meta.title as string || 'AI Library 管理后台'
35 | next()
36 | })
37 |
38 | export default router
39 |
--------------------------------------------------------------------------------
/admin/src/services/api.ts:
--------------------------------------------------------------------------------
1 | import axios from 'axios'
2 |
3 | // 创建API基础配置
4 | const API_BASE_URL = import.meta.env.VITE_API_BASE_URL || 'https://localhost:8000'
5 |
6 | // 创建Axios实例
7 | const apiClient = axios.create({
8 | baseURL: API_BASE_URL,
9 | headers: {
10 | 'Content-Type': 'application/json',
11 | 'Accept': 'application/json'
12 | },
13 | timeout: 10000,
14 | withCredentials: true // 添加这个配置以支持跨域请求携带cookie
15 | })
16 |
17 | // 请求拦截器
18 | apiClient.interceptors.request.use(
19 | config => {
20 | // 可以在这里添加身份验证令牌等
21 | return config
22 | },
23 | error => {
24 | return Promise.reject(error)
25 | }
26 | )
27 |
28 | // 响应拦截器
29 | apiClient.interceptors.response.use(
30 | response => {
31 | return response
32 | },
33 | error => {
34 | console.error('API请求错误:', error.response?.data || error.message)
35 | return Promise.reject(error)
36 | }
37 | )
38 |
39 | // 管理后台API服务
40 | export const adminAPI = {
41 | // 获取仪表盘统计数据
42 | getDashboardData: async () => {
43 | try {
44 | const response = await apiClient.get('/api/admin/dashboard')
45 | return response.data
46 | } catch (error) {
47 | console.error('获取仪表盘数据失败:', error)
48 | throw error
49 | }
50 | },
51 |
52 | // 获取访问统计数据
53 | getStats: async (timeRange = '7d') => {
54 | try {
55 | const response = await apiClient.get('/api/admin/stats', {
56 | params: { range: timeRange }
57 | })
58 | return response.data
59 | } catch (error) {
60 | console.error('获取访问统计数据失败:', error)
61 | throw error
62 | }
63 | },
64 |
65 | // 获取热门文档
66 | getPopularDocuments: async (limit = 10) => {
67 | try {
68 | const response = await apiClient.get('/api/admin/popular-docs', {
69 | params: { limit }
70 | })
71 | return response.data
72 | } catch (error) {
73 | console.error('获取热门文档失败:', error)
74 | throw error
75 | }
76 | },
77 |
78 | // 获取用户反馈
79 | getFeedback: async (params = {}) => {
80 | try {
81 | const response = await apiClient.get('/api/admin/feedback', { params })
82 | return response.data
83 | } catch (error) {
84 | console.error('获取用户反馈失败:', error)
85 | throw error
86 | }
87 | },
88 |
89 | // 回复用户反馈
90 | replyToFeedback: async (feedbackId: string, replyText: string) => {
91 | try {
92 | const response = await apiClient.post(`/api/admin/feedback/${feedbackId}/reply`, {
93 | reply_text: replyText
94 | })
95 | return response.data
96 | } catch (error) {
97 | console.error('回复反馈失败:', error)
98 | throw error
99 | }
100 | }
101 | }
102 |
103 | export default apiClient
--------------------------------------------------------------------------------
/admin/src/stores/counter.ts:
--------------------------------------------------------------------------------
1 | import { ref, computed } from 'vue'
2 | import { defineStore } from 'pinia'
3 |
4 | export const useCounterStore = defineStore('counter', () => {
5 | const count = ref(0)
6 | const doubleCount = computed(() => count.value * 2)
7 | function increment() {
8 | count.value++
9 | }
10 |
11 | return { count, doubleCount, increment }
12 | })
13 |
--------------------------------------------------------------------------------
/admin/src/types/index.ts:
--------------------------------------------------------------------------------
1 | export interface DailyStats {
2 | date: string
3 | total_visits: number
4 | unique_visitors: number
5 | avg_duration: number
6 | bounce_rate: number
7 | }
8 |
9 | export interface VisitStats {
10 | total_visits: number
11 | unique_visitors: number
12 | avg_daily_visits: number
13 | bounce_rate: number
14 | daily_data: DailyStats[]
15 | }
16 |
17 | export interface ChartData {
18 | dates: string[]
19 | visits: number[]
20 | visitors: number[]
21 | }
--------------------------------------------------------------------------------
/admin/src/utils/date.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * 格式化日期字符串为本地时间格式
3 | * @param dateString ISO格式的日期字符串
4 | * @returns 格式化后的日期字符串
5 | */
6 | export function formatDate(dateString: string): string {
7 | if (!dateString) return '未知时间'
8 | const date = new Date(dateString)
9 | return date.toLocaleString('zh-CN', {
10 | year: 'numeric',
11 | month: '2-digit',
12 | day: '2-digit',
13 | hour: '2-digit',
14 | minute: '2-digit'
15 | })
16 | }
--------------------------------------------------------------------------------
/admin/src/views/AboutView.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
This is an about page
4 |
5 |
6 |
7 |
16 |
--------------------------------------------------------------------------------
/admin/src/views/HomeView.vue:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/admin/ssl/cert.pem:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIIFCTCCAvGgAwIBAgIUDobUkiV/hI+pVjFaI6kL4P74YtUwDQYJKoZIhvcNAQEL
3 | BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTI1MDIyNjE1NDMwMloXDTI2MDIy
4 | NjE1NDMwMlowFDESMBAGA1UEAwwJbG9jYWxob3N0MIICIjANBgkqhkiG9w0BAQEF
5 | AAOCAg8AMIICCgKCAgEAtdmBYOviegREW7QRnxckKirSW3XykM8JCnlW6DuMWJVQ
6 | OtEnlE35g/C/ElYxV81WV+zpUiH/B5DMTqvM2Qipk+cPUK+kY2jWofbC6GCa2fk6
7 | jTICTxGmFV5seEAUEwRm/yZ1Eb6aoCv/Z8ah/7IAjoDeZU5qKZTF/AqoVpLOjmbn
8 | jRK/ZtrIqR9l8SkrVeK4NhdYnuoU63TdcBI1UNbRKi/Bz+iFVFb6c5JdVhHNntZz
9 | lcnEeezjWalEU2qp8B9x8SeKyDuDRXSRuMwXMpu583MObq97tWez/UBGpUEM5M8o
10 | 5UBX7q+jRjZVdfGQg+WeOfM/IDeT09zNs8a/ZyvN4SVwlToYpy1ca1SR3SGrGwr3
11 | 8MGudtNa5gYh4wwh1XJTg/hZNJgy+f9oJQ34+V0anMmscYG5IavxJjxYfXcFMpy2
12 | 1GwIHml8C5xn0dbn4nX0J1c9BUE5FkFlWvoy0RvT35oM5CilafhAIZRcz+e0cIad
13 | NnU9u10U+HfZgaoNsgnPoQRoXsrcVpOsVoEb2hICz+bUIX3+bICPoaA7gRGxC+2q
14 | 8JhN+hxalojdfdJfOUD6sKH498kGzVOeTstZrQKJxDmOIF/VXBa/yPJEErLJhjhQ
15 | h6RyIERSm3feJU2qO/2Hzl4H+l1iDhVvELYmX7ULmKnN/WntTzu8PkpR6nFDv+cC
16 | AwEAAaNTMFEwHQYDVR0OBBYEFCQISLSS8QIFcTWN3L5/PcRvFR0sMB8GA1UdIwQY
17 | MBaAFCQISLSS8QIFcTWN3L5/PcRvFR0sMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI
18 | hvcNAQELBQADggIBADc1h66VvZ0LVTVxLwhNHNvhdOhpWmNctFhTuvKdWzQgJWOn
19 | 8gUWO4lxbk3kavfIGAM7gCOial0UV46cuDTKwEHBBMBczaBWLH89HUcbtuVldOZO
20 | 1xV4tYKzguUwHs7RqOvPmTykcciymdOjae7ZlVd478qQcgRPaZfzhf+VKptpAQSN
21 | uj4DGl6+BK0SJ3GAP7sieVVz/LfDq7n5E6EK+aN8Bj5a2PJzaVAp25m/hXyqpmFH
22 | UqsN0bk8cfLE/WU50fqiUfbrDpnlhRh79UKCURlBoOcqLSNj5Rw1KW1SGMRzQ9ou
23 | 1KCszTIo7nVmcPMed1YO5eGJw1xLP/cZlM78Jo8KuReyKgjDRDUnD6OoGkPJhE+b
24 | 7cW+q1e4rSvII+Zz6lRGy5htTfITe2jsh74ORKl0secSko6h9xkfBHRQPQa1dhVo
25 | Drd+3ZSaTFkRitMcZn10sRxpFKpD6UyhE0iHT3wJKl0g4+CLvfBp8IKuMA3dEM89
26 | Rm/C3l8hDtuItnWQqo+WX9VaoC52yMCzO2v6UDED88CNbdTFlaLdzEuZsrZMb8AG
27 | C9oF2dMrhMKcP5bueUKyF+Dp9Uy/u3Y0gg5wvddB2SA5y591GHY5ZGwtyaKmqEB/
28 | rFEUcFP8er7bozX0+CJMgLIaTIPrrI9M/IAK9+yD0rnxXPYYRDmrwXZMiP2J
29 | -----END CERTIFICATE-----
30 |
--------------------------------------------------------------------------------
/admin/ssl/key.pem:
--------------------------------------------------------------------------------
1 | -----BEGIN PRIVATE KEY-----
2 | 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
51 | BsENT9oIAn7MfkgmhGB6PbgAJNnm
52 | -----END PRIVATE KEY-----
53 |
--------------------------------------------------------------------------------
/admin/start.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # AI Library 管理后台启动脚本
3 |
4 | echo "===== 启动 AI Library 管理后台 ====="
5 | echo "确保已安装Node.js和npm..."
6 |
7 | # 检查是否已安装依赖
8 | if [ ! -d "node_modules" ]; then
9 | echo "正在安装依赖..."
10 | npm install
11 | fi
12 |
13 | # 启动开发服务器
14 | echo "启动管理后台开发服务器..."
15 | npm run dev
16 |
17 | # 如果需要构建生产版本
18 | # echo "构建管理后台生产版本..."
19 | # npm run build
--------------------------------------------------------------------------------
/admin/tsconfig.app.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "@vue/tsconfig/tsconfig.dom.json",
3 | "include": ["env.d.ts", "src/**/*", "src/**/*.vue"],
4 | "exclude": ["src/**/__tests__/*"],
5 | "compilerOptions": {
6 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
7 |
8 | "paths": {
9 | "@/*": ["./src/*"]
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/admin/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "files": [],
3 | "references": [
4 | {
5 | "path": "./tsconfig.node.json"
6 | },
7 | {
8 | "path": "./tsconfig.app.json"
9 | }
10 | ]
11 | }
12 |
--------------------------------------------------------------------------------
/admin/tsconfig.node.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "@tsconfig/node22/tsconfig.json",
3 | "include": [
4 | "vite.config.*",
5 | "vitest.config.*",
6 | "cypress.config.*",
7 | "nightwatch.conf.*",
8 | "playwright.config.*",
9 | "eslint.config.*"
10 | ],
11 | "compilerOptions": {
12 | "noEmit": true,
13 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
14 |
15 | "module": "ESNext",
16 | "moduleResolution": "Bundler",
17 | "types": ["node"]
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/admin/vite.config.ts:
--------------------------------------------------------------------------------
1 | import { fileURLToPath, URL } from 'node:url'
2 | import fs from 'node:fs'
3 | import path from 'node:path'
4 |
5 | import { defineConfig } from 'vite'
6 | import vue from '@vitejs/plugin-vue'
7 | import vueDevTools from 'vite-plugin-vue-devtools'
8 |
9 | // https://vite.dev/config/
10 | export default defineConfig({
11 | plugins: [
12 | vue(),
13 | vueDevTools(),
14 | ],
15 | resolve: {
16 | alias: {
17 | '@': fileURLToPath(new URL('./src', import.meta.url))
18 | },
19 | },
20 | server: {
21 | https: {
22 | key: fs.readFileSync(path.resolve(__dirname, 'ssl/key.pem')),
23 | cert: fs.readFileSync(path.resolve(__dirname, 'ssl/cert.pem')),
24 | },
25 | port: 5175,
26 | host: '0.0.0.0',
27 | },
28 | })
29 |
--------------------------------------------------------------------------------
/certs/cert.pem:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | 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
32 | -----END CERTIFICATE-----
33 |
--------------------------------------------------------------------------------
/certs/key.pem:
--------------------------------------------------------------------------------
1 | -----BEGIN PRIVATE KEY-----
2 | MIIJQgIBADANBgkqhkiG9w0BAQEFAASCCSwwggkoAgEAAoICAQCgf1bmH9WMQtC1
3 | 55d198XCUn4YD8NZjHhbpCbVT0UTAwoVw2azIRQdLpprNxu0cABQgR1vRl3KoBFY
4 | b0IaXV7A23xYrNErxdYxsbXOmnFsHnaprim1B6CgjjlP8e+NhJhq322dwqUagKRz
5 | zHebIgG85KSoKUWSRkIyaEP66OCD0PDHRcAc+oIFpqzN55F9/Azz6KdZRqpylyi+
6 | MWOCfjsGLm5+ixtwAwa9dNVWCHOFcZQTesXR8PwOK5a+zCQJaFMR+chZps5zY/RK
7 | Tdscni5Ey0ugWO73UzMWL/Qu89oCFi8Y6ed8ZumeDaqsLnyqFTADkPni6XEejUnK
8 | 9Ls5n/0uyR8FqLqKPsc1Th8iCowV2ILObcsfbCNBRw+IcAVp5ooc9We7D7vU0l9f
9 | 7H79dSdR4kEBLGz9s/QoRzhsNJ7EL/fnbhRQ3/VcOezFIT/nWU0Fji5vCbhnrEJh
10 | TODX3HCyd6GNMrXmiJeyvkvUgNgt/JZASVj7I20mkjbX9wGw5qTn/rCDsRVnJrXr
11 | m+FwYqOemmEke2XX719gTgIBTQZdslyAfXGniahcMKJFlp/ERsUItAtQFmFMgus7
12 | o9aJL1s6oN4JS2yvvmiSEi8nqmkOlg0BlL5ZT9UCLzt+tSx0tIEH2HomRd0Xa6xI
13 | yzCFXKbxt2MSv6JPnh6QHeacQyTgcQIDAQABAoICAARW88aGEhVoWZcaOjEmAtEt
14 | Kexp4bL2SRYA7LgMEYlbmyOpQcnCZquJfu1QTfBtg66pkmjiYXxuTVBuNV6mi2k3
15 | eL0M6DImLRNb03dbhklW010la3UyAyTQOlUSwj15+jqP4cQtdwl4n2m4+7tvD8EN
16 | JXVyuec5fTD6etW/bfxWc2o59OFmYHVkEzb/5czUT7/ZGLb24eU2YzNC/TEyNf5F
17 | 62DXz0/n1GBIoaZBan6PVS0H1EPn1Og9A2bo42kPNXQjxD1wqj36aV4Id/jF6f5G
18 | yRvT8nCEza7yBejZQ69BLQ3ABlgJutOg7uOtX/DOi5qvFPikGKtLhUp78/jcCPcW
19 | bfTZ2a18Eogc0rS8uhZ8jBwuUeKGnPEFOPABhQabjROblXkP9Xef4iYPbN7LBhHz
20 | gVQxPXMWATcCBpfp6jAkc755Dtw/UwGVNWtTjdwbf2Qz0GQXRN6NVxJmSmiPZjnJ
21 | xHiG+fP5ag4ViD1tpg9q706LmFjKh5K/buNUHlsu4z0Uhd3Pu83c64DwukE6233R
22 | iKFUMhdZfWjznTFlRzqaxh22qyJ06YZI0rAD4Li44OGC7MQWJ1cboFfsYoZt77Yf
23 | Pbi+oFjzDSP5/yX2eogG/V4OVQH1nsO8KBFX7mIlSRJCp0lFHN/k6uz7CJsoXrSz
24 | sD28XNmSXi91sEDwq025AoIBAQDcF0AXw7KhsrACkogLRRi1oLor9BclX7GgWGVQ
25 | k/1cxJB3z24tv40KCNt+wsA1S/yrXNC6LdPDf/zzdwiH/bwp36IfJtk7iBKuq8S0
26 | 1lPEwVJkYUgCG7SdacyPWz3veX0dUyl4Kw/lA1wgEASdSFgzBxCxHCQgHLl4c2wf
27 | oACZSNPQSQf+vUAKnOtyk8705LwljL5xW7OhJP44fqaNNrWG+zyeCcqEIkScn4Gq
28 | gw+OYz+F5bLURgmjQ/Kw9+FAXUhW0umvYEdvA2p1SL0YsZKkyZSG0Z2H2dNE7tG5
29 | WW9kelOYFo0YuuJAKXw61nU55vlJ7QtKFNhIZ1UJfdwfYLvJAoIBAQC6rv4uyhHN
30 | p497n1lvwFuRRwQUwczPk/t+33VatKkcz8PPW2w/bsab+jxUUb4Ai9NxXyldDlE4
31 | /IsfIYvb2tDICG0pUXpico/KKBULOdx76ItsaS11neSfKvbdXkemXVxrd16Nt/L3
32 | rbdqdkEbM3aoOK8FnsAMdAPbK/622yWp62r/axazS/k7xF0ZEJNhly3dMiD5M+qE
33 | +rZN5/9x3yr3Dq4zZgoZrGtg5d2JnLsJySlIyPGSZF8XbKYKzey8L45clO8mrjXr
34 | CdL0N8M5FOL8YmnUSqeS1VwuPsJBqLFwCtCVIsMdvTgF6NfNT1zqvBuMUZ3W5fqr
35 | 1adc/yUxYINpAoIBAQCbZ2NfJFSGbkhvmI2s/34CCVpLXM/XGOmwIZpwOf6lOToV
36 | DwdqEB4DXtu1dsgHGf9v9FqBi4hCO6YdNwh0FYp+OqUbv++VZHBkm26KjeeaPzLx
37 | I+uXaX6vw5uoAbIK3MqmISlf63AOsb+j+At6DzIP3cZAeHFdp0qirUVEU1L46P5+
38 | zIJzsad9lu18+rcgHj5neSijnC+K8jb7JxptDZtBkzZrFNjFUfkGam5BOseKL7QT
39 | 1GvgDRATExBTOsP3EabZf5V3utDVpyDNba3vuLql1pwkUfAck4bk3oiBio/n76QE
40 | +K9qLdNBoMlSNkmRt/B/7XuSNIO/JA9cY11BXqlZAoIBABcZQfAuJofIvNMyA1H1
41 | fh76p4Gd/SaOC+dF5PJlOiuLdZH5oOo0XbS9AKv6NUVCB9aWTLrr45bmgJxIfVKl
42 | v4GQsVkUcM0vmaUM0pXCAgr+2gl+9hYAhGJBYaxAVyM5mA7gBT4JzbFhuDkfCq0/
43 | 7+WepeFPJDomPLfouKqNcRqWO3YBHRzwQJVplY9dYq8HkrA03KmZB+KOVvJKy2ue
44 | jmVlVp6beJJ2qA6kQoYdc3Mhhc8wtdtEOhPe6KiblDgwti+0aebiVV+Qpp57K9er
45 | Qu6xiqCu4A8mATLjpwuSwOm5HNfnJjdOy1jH17PapweQYOQ60QnfCOYsGHpEQ6jZ
46 | ZUkCggEAUphrkOPLJaILnkxOUqRFy6vxTWP+IWONrMsw+ca+lXe7ezWqamXx4CLe
47 | bvfb4cPpeisnhJwH1qAHzCA0gQvzZu/niPjUPXx3LHGsnHlyR8bj3FBusguzaren
48 | bGrb7aLdWvYg0tpG/0u0JfeoNUyR4I0/YuhdD/NcLr57fmZ40+1GBr1sI8fQrd6r
49 | 23hoF63GyYhd2q77XQeybBAnte/qgm/SjYdJargcWDBStass3QzzwLi3+0GGWuAA
50 | Sdi+DOQwefeGO60bM6kVrp8OC/ocwoRuitHo1q/2cLGmoeDmW50uJJybG7lOuhX4
51 | B5fnscVWigrrN73w2K1Oh/1eKT0t9Q==
52 | -----END PRIVATE KEY-----
53 |
--------------------------------------------------------------------------------
/client/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/client/README.md:
--------------------------------------------------------------------------------
1 | # Vue 3 + TypeScript + Vite
2 |
3 | This template should help get you started developing with Vue 3 and TypeScript in Vite. The template uses Vue 3 `
67 |
68 |
78 |