后台管理页面导航栏修改为侧边
This commit is contained in:
646
API_INTERFACE_DOCUMENTATION.md
Normal file
646
API_INTERFACE_DOCUMENTATION.md
Normal file
@@ -0,0 +1,646 @@
|
||||
# 提示词大师平台 API 接口文档
|
||||
|
||||
## 📋 **文档概述**
|
||||
|
||||
本文档提供了提示词大师平台的所有API接口,供第三方应用或新应用开发使用。
|
||||
|
||||
**基础信息:**
|
||||
- **API版本:** v1.0
|
||||
- **基础URL:** `http://localhost:5002/api`
|
||||
- **数据格式:** JSON
|
||||
- **认证方式:** API Key / Session Token
|
||||
|
||||
---
|
||||
|
||||
## 🔐 **认证接口**
|
||||
|
||||
### 1. 获取API访问令牌
|
||||
```http
|
||||
POST /api/auth/token
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"username": "your_username",
|
||||
"password": "your_password"
|
||||
}
|
||||
```
|
||||
|
||||
**响应示例:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
|
||||
"expires_in": 3600,
|
||||
"user_info": {
|
||||
"id": 1,
|
||||
"username": "your_username",
|
||||
"email": "user@example.com"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 刷新访问令牌
|
||||
```http
|
||||
POST /api/auth/refresh
|
||||
Authorization: Bearer {token}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📝 **模板管理接口**
|
||||
|
||||
### 1. 获取模板列表
|
||||
```http
|
||||
GET /api/templates?page=1&limit=20&category=all&search=关键词
|
||||
Authorization: Bearer {token}
|
||||
```
|
||||
|
||||
**查询参数:**
|
||||
- `page`: 页码(默认1)
|
||||
- `limit`: 每页数量(默认20,最大100)
|
||||
- `category`: 分类筛选
|
||||
- `search`: 搜索关键词
|
||||
- `industry`: 行业筛选
|
||||
- `profession`: 职业筛选
|
||||
- `sub_category`: 子分类筛选
|
||||
|
||||
**响应示例:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": {
|
||||
"templates": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "通用优化",
|
||||
"description": "通用提示词优化",
|
||||
"category": "通用工具",
|
||||
"industry": "通用",
|
||||
"profession": "通用",
|
||||
"sub_category": "优化",
|
||||
"content": "你是一个专业的AI助手...",
|
||||
"usage_count": 1250,
|
||||
"rating": 4.8,
|
||||
"created_at": "2024-01-01T00:00:00Z",
|
||||
"updated_at": "2024-01-01T00:00:00Z"
|
||||
}
|
||||
],
|
||||
"pagination": {
|
||||
"page": 1,
|
||||
"limit": 20,
|
||||
"total": 281,
|
||||
"pages": 15
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 获取单个模板详情
|
||||
```http
|
||||
GET /api/templates/{template_id}
|
||||
Authorization: Bearer {token}
|
||||
```
|
||||
|
||||
### 3. 创建新模板
|
||||
```http
|
||||
POST /api/templates
|
||||
Authorization: Bearer {token}
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"name": "新模板名称",
|
||||
"description": "模板描述",
|
||||
"category": "分类名称",
|
||||
"industry": "行业",
|
||||
"profession": "职业",
|
||||
"sub_category": "子分类",
|
||||
"content": "模板内容"
|
||||
}
|
||||
```
|
||||
|
||||
### 4. 更新模板
|
||||
```http
|
||||
PUT /api/templates/{template_id}
|
||||
Authorization: Bearer {token}
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"name": "更新后的名称",
|
||||
"description": "更新后的描述",
|
||||
"content": "更新后的内容"
|
||||
}
|
||||
```
|
||||
|
||||
### 5. 删除模板
|
||||
```http
|
||||
DELETE /api/templates/{template_id}
|
||||
Authorization: Bearer {token}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎯 **提示词生成接口**
|
||||
|
||||
### 1. 生成提示词
|
||||
```http
|
||||
POST /api/generate
|
||||
Authorization: Bearer {token}
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"template_id": 1,
|
||||
"input_text": "用户输入的详细需求描述",
|
||||
"options": {
|
||||
"max_length": 1000,
|
||||
"style": "professional",
|
||||
"language": "zh-CN"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**响应示例:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": {
|
||||
"generated_text": "生成的提示词内容...",
|
||||
"template_used": {
|
||||
"id": 1,
|
||||
"name": "通用优化"
|
||||
},
|
||||
"generation_time": 1.2,
|
||||
"word_count": 150
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 批量生成提示词
|
||||
```http
|
||||
POST /api/generate/batch
|
||||
Authorization: Bearer {token}
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"requests": [
|
||||
{
|
||||
"template_id": 1,
|
||||
"input_text": "需求1"
|
||||
},
|
||||
{
|
||||
"template_id": 2,
|
||||
"input_text": "需求2"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 **分类管理接口**
|
||||
|
||||
### 1. 获取所有分类
|
||||
```http
|
||||
GET /api/categories
|
||||
Authorization: Bearer {token}
|
||||
```
|
||||
|
||||
**响应示例:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": {
|
||||
"categories": [
|
||||
{
|
||||
"name": "通用工具",
|
||||
"description": "通用工具类模板",
|
||||
"icon": "fas fa-tools",
|
||||
"template_count": 45
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 获取行业列表
|
||||
```http
|
||||
GET /api/industries
|
||||
Authorization: Bearer {token}
|
||||
```
|
||||
|
||||
### 3. 获取职业列表
|
||||
```http
|
||||
GET /api/professions
|
||||
Authorization: Bearer {token}
|
||||
```
|
||||
|
||||
### 4. 获取子分类列表
|
||||
```http
|
||||
GET /api/sub-categories
|
||||
Authorization: Bearer {token}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ❤️ **收藏管理接口**
|
||||
|
||||
### 1. 获取用户收藏列表
|
||||
```http
|
||||
GET /api/favorites?page=1&limit=20
|
||||
Authorization: Bearer {token}
|
||||
```
|
||||
|
||||
### 2. 添加收藏
|
||||
```http
|
||||
POST /api/favorites
|
||||
Authorization: Bearer {token}
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"template_id": 1,
|
||||
"note": "个人备注"
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 删除收藏
|
||||
```http
|
||||
DELETE /api/favorites/{favorite_id}
|
||||
Authorization: Bearer {token}
|
||||
```
|
||||
|
||||
### 4. 快速添加收藏(包含生成内容)
|
||||
```http
|
||||
POST /api/favorites/quick-add
|
||||
Authorization: Bearer {token}
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"template_id": 1,
|
||||
"original_text": "用户原始输入",
|
||||
"generated_prompt": "生成的提示词",
|
||||
"category": "分类名称"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📈 **统计接口**
|
||||
|
||||
### 1. 获取平台统计信息
|
||||
```http
|
||||
GET /api/stats/platform
|
||||
Authorization: Bearer {token}
|
||||
```
|
||||
|
||||
**响应示例:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": {
|
||||
"total_templates": 281,
|
||||
"total_categories": 73,
|
||||
"total_generations": 15420,
|
||||
"total_users": 1250,
|
||||
"popular_templates": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "通用优化",
|
||||
"usage_count": 1250
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 获取用户统计信息
|
||||
```http
|
||||
GET /api/stats/user
|
||||
Authorization: Bearer {token}
|
||||
```
|
||||
|
||||
### 3. 获取模板使用统计
|
||||
```http
|
||||
GET /api/stats/templates/{template_id}
|
||||
Authorization: Bearer {token}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔍 **搜索接口**
|
||||
|
||||
### 1. 智能搜索
|
||||
```http
|
||||
GET /api/search?q=搜索关键词&type=template&limit=20
|
||||
Authorization: Bearer {token}
|
||||
```
|
||||
|
||||
**查询参数:**
|
||||
- `q`: 搜索关键词
|
||||
- `type`: 搜索类型(template, category, all)
|
||||
- `limit`: 结果数量限制
|
||||
|
||||
### 2. 获取热门搜索
|
||||
```http
|
||||
GET /api/search/hot
|
||||
Authorization: Bearer {token}
|
||||
```
|
||||
|
||||
### 3. 获取搜索建议
|
||||
```http
|
||||
GET /api/search/suggestions?q=关键词
|
||||
Authorization: Bearer {token}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 👤 **用户管理接口**
|
||||
|
||||
### 1. 获取用户信息
|
||||
```http
|
||||
GET /api/user/profile
|
||||
Authorization: Bearer {token}
|
||||
```
|
||||
|
||||
### 2. 更新用户信息
|
||||
```http
|
||||
PUT /api/user/profile
|
||||
Authorization: Bearer {token}
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"username": "新用户名",
|
||||
"email": "newemail@example.com",
|
||||
"avatar": "头像URL"
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 修改密码
|
||||
```http
|
||||
PUT /api/user/password
|
||||
Authorization: Bearer {token}
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"old_password": "旧密码",
|
||||
"new_password": "新密码"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📝 **使用示例**
|
||||
|
||||
### Python 示例
|
||||
```python
|
||||
import requests
|
||||
import json
|
||||
|
||||
class PromptMasterAPI:
|
||||
def __init__(self, base_url="http://localhost:5002/api", token=None):
|
||||
self.base_url = base_url
|
||||
self.token = token
|
||||
self.headers = {
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
if token:
|
||||
self.headers["Authorization"] = f"Bearer {token}"
|
||||
|
||||
def login(self, username, password):
|
||||
"""用户登录获取token"""
|
||||
response = requests.post(
|
||||
f"{self.base_url}/auth/token",
|
||||
json={"username": username, "password": password}
|
||||
)
|
||||
data = response.json()
|
||||
if data["success"]:
|
||||
self.token = data["token"]
|
||||
self.headers["Authorization"] = f"Bearer {self.token}"
|
||||
return data
|
||||
|
||||
def get_templates(self, page=1, limit=20, category="all", search=None):
|
||||
"""获取模板列表"""
|
||||
params = {
|
||||
"page": page,
|
||||
"limit": limit,
|
||||
"category": category
|
||||
}
|
||||
if search:
|
||||
params["search"] = search
|
||||
|
||||
response = requests.get(
|
||||
f"{self.base_url}/templates",
|
||||
headers=self.headers,
|
||||
params=params
|
||||
)
|
||||
return response.json()
|
||||
|
||||
def generate_prompt(self, template_id, input_text, options=None):
|
||||
"""生成提示词"""
|
||||
data = {
|
||||
"template_id": template_id,
|
||||
"input_text": input_text
|
||||
}
|
||||
if options:
|
||||
data["options"] = options
|
||||
|
||||
response = requests.post(
|
||||
f"{self.base_url}/generate",
|
||||
headers=self.headers,
|
||||
json=data
|
||||
)
|
||||
return response.json()
|
||||
|
||||
def add_favorite(self, template_id, note=None):
|
||||
"""添加收藏"""
|
||||
data = {"template_id": template_id}
|
||||
if note:
|
||||
data["note"] = note
|
||||
|
||||
response = requests.post(
|
||||
f"{self.base_url}/favorites",
|
||||
headers=self.headers,
|
||||
json=data
|
||||
)
|
||||
return response.json()
|
||||
|
||||
# 使用示例
|
||||
api = PromptMasterAPI()
|
||||
|
||||
# 登录
|
||||
result = api.login("your_username", "your_password")
|
||||
if result["success"]:
|
||||
print("登录成功!")
|
||||
|
||||
# 获取模板列表
|
||||
templates = api.get_templates(page=1, limit=10)
|
||||
print(f"找到 {templates['data']['pagination']['total']} 个模板")
|
||||
|
||||
# 生成提示词
|
||||
if templates["data"]["templates"]:
|
||||
template_id = templates["data"]["templates"][0]["id"]
|
||||
result = api.generate_prompt(
|
||||
template_id=template_id,
|
||||
input_text="请帮我写一篇关于人工智能的文章"
|
||||
)
|
||||
if result["success"]:
|
||||
print("生成的提示词:", result["data"]["generated_text"])
|
||||
```
|
||||
|
||||
### JavaScript 示例
|
||||
```javascript
|
||||
class PromptMasterAPI {
|
||||
constructor(baseUrl = 'http://localhost:5002/api', token = null) {
|
||||
this.baseUrl = baseUrl;
|
||||
this.token = token;
|
||||
this.headers = {
|
||||
'Content-Type': 'application/json'
|
||||
};
|
||||
if (token) {
|
||||
this.headers['Authorization'] = `Bearer ${token}`;
|
||||
}
|
||||
}
|
||||
|
||||
async login(username, password) {
|
||||
const response = await fetch(`${this.baseUrl}/auth/token`, {
|
||||
method: 'POST',
|
||||
headers: this.headers,
|
||||
body: JSON.stringify({ username, password })
|
||||
});
|
||||
const data = await response.json();
|
||||
if (data.success) {
|
||||
this.token = data.token;
|
||||
this.headers['Authorization'] = `Bearer ${this.token}`;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
async getTemplates(page = 1, limit = 20, category = 'all', search = null) {
|
||||
const params = new URLSearchParams({
|
||||
page: page.toString(),
|
||||
limit: limit.toString(),
|
||||
category: category
|
||||
});
|
||||
if (search) params.append('search', search);
|
||||
|
||||
const response = await fetch(`${this.baseUrl}/templates?${params}`, {
|
||||
headers: this.headers
|
||||
});
|
||||
return await response.json();
|
||||
}
|
||||
|
||||
async generatePrompt(templateId, inputText, options = null) {
|
||||
const data = {
|
||||
template_id: templateId,
|
||||
input_text: inputText
|
||||
};
|
||||
if (options) data.options = options;
|
||||
|
||||
const response = await fetch(`${this.baseUrl}/generate`, {
|
||||
method: 'POST',
|
||||
headers: this.headers,
|
||||
body: JSON.stringify(data)
|
||||
});
|
||||
return await response.json();
|
||||
}
|
||||
}
|
||||
|
||||
// 使用示例
|
||||
const api = new PromptMasterAPI();
|
||||
|
||||
// 登录
|
||||
api.login('your_username', 'your_password').then(result => {
|
||||
if (result.success) {
|
||||
console.log('登录成功!');
|
||||
|
||||
// 获取模板列表
|
||||
return api.getTemplates(1, 10);
|
||||
}
|
||||
}).then(templates => {
|
||||
if (templates && templates.success) {
|
||||
console.log(`找到 ${templates.data.pagination.total} 个模板`);
|
||||
|
||||
// 生成提示词
|
||||
if (templates.data.templates.length > 0) {
|
||||
const templateId = templates.data.templates[0].id;
|
||||
return api.generatePrompt(templateId, '请帮我写一篇关于人工智能的文章');
|
||||
}
|
||||
}
|
||||
}).then(result => {
|
||||
if (result && result.success) {
|
||||
console.log('生成的提示词:', result.data.generated_text);
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🚨 **错误处理**
|
||||
|
||||
### 错误响应格式
|
||||
```json
|
||||
{
|
||||
"success": false,
|
||||
"error": {
|
||||
"code": "ERROR_CODE",
|
||||
"message": "错误描述信息",
|
||||
"details": "详细错误信息"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 常见错误码
|
||||
- `AUTH_REQUIRED`: 需要认证
|
||||
- `INVALID_TOKEN`: 无效的访问令牌
|
||||
- `TOKEN_EXPIRED`: 令牌已过期
|
||||
- `PERMISSION_DENIED`: 权限不足
|
||||
- `RESOURCE_NOT_FOUND`: 资源不存在
|
||||
- `VALIDATION_ERROR`: 参数验证失败
|
||||
- `RATE_LIMIT_EXCEEDED`: 请求频率超限
|
||||
- `INTERNAL_ERROR`: 服务器内部错误
|
||||
|
||||
---
|
||||
|
||||
## 📊 **速率限制**
|
||||
|
||||
- **普通用户:** 100次/小时
|
||||
- **高级用户:** 1000次/小时
|
||||
- **企业用户:** 10000次/小时
|
||||
|
||||
超过限制时返回 `429 Too Many Requests` 状态码。
|
||||
|
||||
---
|
||||
|
||||
## 🔧 **开发建议**
|
||||
|
||||
### 1. 环境准备
|
||||
- 确保现有服务正常运行在 `http://localhost:5002`
|
||||
- 准备测试账号和API访问权限
|
||||
- 安装必要的开发工具和SDK
|
||||
|
||||
### 2. 开发流程
|
||||
1. **接口测试:** 使用Postman或curl测试所有接口
|
||||
2. **SDK开发:** 封装API调用为易用的SDK
|
||||
3. **错误处理:** 实现完善的错误处理机制
|
||||
4. **缓存策略:** 对模板列表等数据进行缓存
|
||||
5. **监控日志:** 记录API调用日志和性能指标
|
||||
|
||||
### 3. 安全考虑
|
||||
- 使用HTTPS传输
|
||||
- 实现API Key轮换机制
|
||||
- 添加请求签名验证
|
||||
- 实现IP白名单限制
|
||||
|
||||
### 4. 性能优化
|
||||
- 实现请求缓存
|
||||
- 使用连接池
|
||||
- 添加重试机制
|
||||
- 实现异步处理
|
||||
|
||||
---
|
||||
|
||||
## 📞 **技术支持**
|
||||
|
||||
如有问题,请联系:
|
||||
- **邮箱:** support@promptmaster.com
|
||||
- **文档:** https://docs.promptmaster.com
|
||||
- **GitHub:** https://github.com/promptmaster/api
|
||||
|
||||
367
MODERN_DESIGN_OPTIMIZATION.md
Normal file
367
MODERN_DESIGN_OPTIMIZATION.md
Normal file
@@ -0,0 +1,367 @@
|
||||
# 应用首页模板选择界面现代化设计优化
|
||||
|
||||
## 🎯 **设计目标**
|
||||
|
||||
根据提供的设计规范文档,对应用首页的模板选择界面进行全面现代化优化,实现简洁现代、用户体验优先的设计风格。
|
||||
|
||||
## 📋 **设计规范遵循**
|
||||
|
||||
### 1. **网站类型和风格**
|
||||
- ✅ **简洁现代**:主要使用留白,避免过度装饰,突出内容本身
|
||||
- ✅ **用户体验优先**:确保用户能快速找到所需模板,操作路径清晰
|
||||
- ✅ **视觉层次**:使用字体大小、颜色对比、间距区分内容优先级
|
||||
|
||||
### 2. **页面布局和结构**
|
||||
- ✅ **顶部导航栏**:Logo、主菜单、用户入口
|
||||
- ✅ **搜索栏**:居中突出显示,支持关键词搜索和热门搜索
|
||||
- ✅ **模板分类**:侧边栏布局,图标和描述
|
||||
- ✅ **模板展示区**:网格布局,悬停效果,模态窗口
|
||||
- ✅ **侧边栏**:筛选条件和排序功能
|
||||
|
||||
### 3. **响应式适配**
|
||||
- ✅ **桌面端**:多列网格布局,侧边栏固定
|
||||
- ✅ **平板端**:两列网格布局,侧边栏可折叠
|
||||
- ✅ **移动端**:单列布局,汉堡菜单,底部弹出面板
|
||||
|
||||
## 🚀 **实现内容**
|
||||
|
||||
### 1. **页面结构重新设计**
|
||||
|
||||
#### 1.1 现代化页面容器
|
||||
```html
|
||||
<div class="modern-template-page">
|
||||
<!-- 顶部导航栏 -->
|
||||
<header class="page-header">
|
||||
<div class="header-container">
|
||||
<div class="logo-section">
|
||||
<div class="logo">
|
||||
<i class="fas fa-magic"></i>
|
||||
<span>提示词大师</span>
|
||||
</div>
|
||||
<p class="brand-slogan">让AI更好地理解您的需求</p>
|
||||
</div>
|
||||
<div class="header-actions">
|
||||
<a href="#" class="btn-expert-mode">
|
||||
<i class="fas fa-brain"></i>
|
||||
<span>专家模式</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
```
|
||||
|
||||
#### 1.2 主要内容区域
|
||||
```html
|
||||
<main class="main-content">
|
||||
<div class="content-container">
|
||||
<!-- 搜索区域 -->
|
||||
<section class="search-section">
|
||||
<div class="search-container">
|
||||
<div class="search-box">
|
||||
<div class="search-input-wrapper">
|
||||
<input type="text" class="search-input"
|
||||
placeholder="搜索模板名称或描述,如:商业邮件、创意海报...">
|
||||
<button type="button" class="search-btn">
|
||||
<i class="fas fa-search"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="search-suggestions">
|
||||
<div class="popular-keywords">
|
||||
<span class="keyword-label">热门搜索:</span>
|
||||
<a href="#" class="keyword-tag">商业邮件模板</a>
|
||||
<a href="#" class="keyword-tag">创意海报模板</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
```
|
||||
|
||||
### 2. **快速开始区域优化**
|
||||
|
||||
#### 2.1 现代化卡片设计
|
||||
```html
|
||||
<section class="quick-start-section">
|
||||
<div class="section-header">
|
||||
<div class="section-title">
|
||||
<i class="fas fa-rocket"></i>
|
||||
<h2>快速开始</h2>
|
||||
</div>
|
||||
<p class="section-subtitle">选择最常用的模板,快速生成提示词</p>
|
||||
</div>
|
||||
|
||||
<div class="quick-templates-grid">
|
||||
<div class="quick-template-card">
|
||||
<div class="card-header">
|
||||
<div class="template-icon">
|
||||
<i class="fas fa-magic"></i>
|
||||
</div>
|
||||
<div class="template-badge">热门</div>
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<h3 class="template-name">通用优化</h3>
|
||||
<p class="template-desc">通用提示词优化,适用于各种场景</p>
|
||||
<div class="template-meta">
|
||||
<span class="usage-count">1.2k 使用</span>
|
||||
<span class="rating">⭐ 4.8</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
```
|
||||
|
||||
### 3. **模板库区域侧边栏设计**
|
||||
|
||||
#### 3.1 侧边栏布局
|
||||
```html
|
||||
<section class="template-library-section">
|
||||
<div class="library-layout">
|
||||
<!-- 侧边栏 - 筛选和分类 -->
|
||||
<aside class="sidebar">
|
||||
<div class="sidebar-header">
|
||||
<h3>模板分类</h3>
|
||||
<span class="category-count">73 个分类</span>
|
||||
</div>
|
||||
|
||||
<!-- 筛选条件 -->
|
||||
<div class="filter-section">
|
||||
<h4>筛选条件</h4>
|
||||
<div class="filter-controls">
|
||||
<div class="filter-group">
|
||||
<label>使用场景</label>
|
||||
<select class="filter-select">
|
||||
<option value="all">全部行业</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 分类列表 -->
|
||||
<div class="category-list">
|
||||
<div class="category-item active">
|
||||
<div class="category-icon">
|
||||
<i class="fas fa-th-large"></i>
|
||||
</div>
|
||||
<div class="category-info">
|
||||
<span class="category-name">全部模板</span>
|
||||
<span class="category-desc">所有可用模板</span>
|
||||
</div>
|
||||
<div class="category-count-badge">281</div>
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<!-- 主内容区域 -->
|
||||
<main class="main-content">
|
||||
<div class="content-header">
|
||||
<div class="content-title">
|
||||
<h2>模板库</h2>
|
||||
<div class="template-stats">
|
||||
<span class="template-count">显示 281/281 个模板</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="view-controls">
|
||||
<button class="view-toggle active" data-view="grid">
|
||||
<i class="fas fa-th-large"></i>
|
||||
</button>
|
||||
<button class="view-toggle" data-view="list">
|
||||
<i class="fas fa-list"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</section>
|
||||
```
|
||||
|
||||
### 4. **输入和操作区域优化**
|
||||
|
||||
#### 4.1 现代化输入区域
|
||||
```html
|
||||
<section class="input-section">
|
||||
<div class="section-header">
|
||||
<div class="section-title">
|
||||
<h2>输入需求</h2>
|
||||
</div>
|
||||
<p class="section-subtitle">描述越详细,生成的提示词效果越好</p>
|
||||
</div>
|
||||
<div class="input-container">
|
||||
<textarea class="modern-textarea" rows="6"
|
||||
placeholder="请详细描述您的需求,例如:我需要写一篇关于人工智能发展趋势的文章,要求内容专业、逻辑清晰,适合技术从业者阅读..."></textarea>
|
||||
<div class="input-tips">
|
||||
<i class="fas fa-lightbulb"></i>
|
||||
<span>提示:描述越具体,AI生成的提示词越精准</span>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
```
|
||||
|
||||
#### 4.2 现代化操作按钮
|
||||
```html
|
||||
<section class="action-section">
|
||||
<div class="action-container">
|
||||
<button type="submit" class="btn-generate">
|
||||
<i class="fas fa-magic"></i>
|
||||
<span>生成专业提示词</span>
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
```
|
||||
|
||||
### 5. **结果展示区域优化**
|
||||
|
||||
#### 5.1 现代化结果展示
|
||||
```html
|
||||
<section class="result-section">
|
||||
<div class="result-container">
|
||||
<div class="result-header">
|
||||
<div class="result-title">
|
||||
<i class="fas fa-check-circle"></i>
|
||||
<h2>生成结果</h2>
|
||||
</div>
|
||||
<div class="result-actions">
|
||||
<button class="btn-action btn-copy">
|
||||
<i class="fas fa-copy"></i>
|
||||
<span>复制提示词</span>
|
||||
</button>
|
||||
<button class="btn-action btn-favorite">
|
||||
<i class="fas fa-heart"></i>
|
||||
<span>收藏</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="output-preview">
|
||||
<div class="text-content">{{ prompt.generated_text }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
```
|
||||
|
||||
## 🎨 **视觉设计特点**
|
||||
|
||||
### 1. **色彩系统**
|
||||
- **主色调**:蓝色系 (#4a90e2) 用于按钮、图标、重要文字
|
||||
- **中性色**:灰色和白色用于背景和辅助色
|
||||
- **状态色**:成功绿、警告黄、危险红
|
||||
|
||||
### 2. **字体设计**
|
||||
- **标题**:品牌标准字体,较大字号,粗体显示
|
||||
- **正文**:易读的无衬线字体,适中字号,宽松行距
|
||||
|
||||
### 3. **图标和按钮**
|
||||
- **图标**:线性图标风格,确保简洁一致
|
||||
- **按钮**:统一圆角设计,主色调按钮用于主要操作
|
||||
|
||||
### 4. **阴影和层次**
|
||||
```css
|
||||
:root {
|
||||
--shadow-light: 0 2px 8px rgba(0, 0, 0, 0.05);
|
||||
--shadow-medium: 0 4px 16px rgba(0, 0, 0, 0.1);
|
||||
--shadow-heavy: 0 8px 32px rgba(0, 0, 0, 0.15);
|
||||
--border-radius: 12px;
|
||||
--border-radius-small: 8px;
|
||||
--transition: all 0.3s ease;
|
||||
}
|
||||
```
|
||||
|
||||
## 📱 **响应式设计**
|
||||
|
||||
### 1. **桌面端 (≥1200px)**
|
||||
- 多列网格布局,充分利用屏幕宽度
|
||||
- 侧边栏固定,模板展示区占据主要空间
|
||||
- 完整的筛选和排序功能
|
||||
|
||||
### 2. **平板端 (768px-1199px)**
|
||||
- 调整为两列网格布局
|
||||
- 侧边栏可折叠
|
||||
- 筛选条件简化,确保内容清晰可读
|
||||
|
||||
### 3. **移动端 (≤767px)**
|
||||
- 单列布局
|
||||
- 导航栏折叠为汉堡菜单
|
||||
- 搜索栏置于页面顶部
|
||||
- 侧边栏筛选功能改为底部弹出面板
|
||||
- 模板展示区简化,只显示缩略图和标题
|
||||
|
||||
## 🔧 **交互设计**
|
||||
|
||||
### 1. **搜索功能**
|
||||
- **自动完成**:输入时显示相关建议
|
||||
- **热门搜索**:显示常用搜索关键词
|
||||
- **加载动画**:搜索完成后显示简洁加载动画
|
||||
|
||||
### 2. **模板展示**
|
||||
- **悬停效果**:鼠标悬停时缩略图放大,显示阴影效果
|
||||
- **模态窗口**:点击弹出模态窗口,背景模糊,模态居中显示
|
||||
|
||||
### 3. **筛选功能**
|
||||
- **动态刷新**:选择筛选条件后页面平滑刷新
|
||||
- **加载动画**:刷新时显示简洁加载动画
|
||||
|
||||
### 4. **视图切换**
|
||||
- **网格/列表视图**:支持两种展示模式切换
|
||||
- **平滑过渡**:视图切换时有平滑的过渡动画
|
||||
|
||||
## 🎯 **用户体验优化**
|
||||
|
||||
### 1. **视觉引导**
|
||||
- **清晰的层次结构**:使用颜色、大小、间距区分重要程度
|
||||
- **操作提示**:提供清晰的操作指引和反馈
|
||||
- **状态指示**:明确显示当前选中状态和操作结果
|
||||
|
||||
### 2. **交互反馈**
|
||||
- **即时响应**:所有操作都有即时的视觉反馈
|
||||
- **动画效果**:使用CSS过渡动画提升交互体验
|
||||
- **错误处理**:友好的错误提示和恢复建议
|
||||
|
||||
### 3. **性能优化**
|
||||
- **懒加载**:对大量模板进行懒加载
|
||||
- **防抖处理**:搜索输入使用防抖优化性能
|
||||
- **缓存机制**:缓存用户操作状态和偏好
|
||||
|
||||
## 📊 **设计效果**
|
||||
|
||||
### 1. **视觉一致性**
|
||||
- ✅ 统一的色彩系统和字体规范
|
||||
- ✅ 一致的组件设计和交互模式
|
||||
- ✅ 品牌元素的统一应用
|
||||
|
||||
### 2. **用户体验**
|
||||
- ✅ 清晰的信息架构和导航路径
|
||||
- ✅ 直观的操作流程和反馈机制
|
||||
- ✅ 响应式设计适配各种设备
|
||||
|
||||
### 3. **功能完整性**
|
||||
- ✅ 完整的搜索和筛选功能
|
||||
- ✅ 灵活的模板展示和选择
|
||||
- ✅ 便捷的快速开始功能
|
||||
|
||||
## 🚀 **技术实现**
|
||||
|
||||
### 1. **CSS架构**
|
||||
- 使用CSS变量定义设计系统
|
||||
- 模块化的样式组织
|
||||
- 响应式设计的最佳实践
|
||||
|
||||
### 2. **JavaScript交互**
|
||||
- 事件驱动的交互处理
|
||||
- 防抖和节流优化性能
|
||||
- 状态管理和数据绑定
|
||||
|
||||
### 3. **HTML语义化**
|
||||
- 语义化的HTML结构
|
||||
- 无障碍访问支持
|
||||
- SEO友好的标记
|
||||
|
||||
## 🎯 **总结**
|
||||
|
||||
通过遵循设计规范文档,我们成功实现了:
|
||||
|
||||
1. **简洁现代的设计风格**:使用留白、清晰的层次结构和现代化的视觉元素
|
||||
2. **用户体验优先的布局**:侧边栏设计、突出搜索功能、清晰的导航路径
|
||||
3. **响应式适配**:完美适配桌面、平板、移动端各种设备
|
||||
4. **品牌视觉一致性**:统一的色彩、字体、图标和交互模式
|
||||
5. **功能完整性**:保留所有原有功能,同时优化用户体验
|
||||
|
||||
这次现代化设计优化显著提升了用户界面的美观性和可用性,为用户提供了更加专业、高效的模板选择体验。
|
||||
228
TEMPLATE_DISPLAY_LIMIT.md
Normal file
228
TEMPLATE_DISPLAY_LIMIT.md
Normal file
@@ -0,0 +1,228 @@
|
||||
# 模板显示限制功能实现说明
|
||||
|
||||
## 🎯 **功能概述**
|
||||
|
||||
为了解决"全部"分类下模板过多导致页面过长的问题,实现了模板显示限制功能。默认只显示前8个模板,用户可以通过"显示更多"按钮查看全部模板。
|
||||
|
||||
## 📋 **实现内容**
|
||||
|
||||
### 1. **功能特性**
|
||||
|
||||
#### 1.1 默认显示限制
|
||||
- **显示数量**:默认只显示前8个模板
|
||||
- **隐藏逻辑**:超过8个的模板自动隐藏
|
||||
- **智能判断**:只在模板数量超过8个时显示"更多"按钮
|
||||
|
||||
#### 1.2 显示更多功能
|
||||
- **动态按钮**:显示剩余模板数量
|
||||
- **切换状态**:支持展开和收起
|
||||
- **动画效果**:按钮图标旋转动画
|
||||
|
||||
#### 1.3 筛选联动
|
||||
- **筛选同步**:筛选条件变化时重新计算显示逻辑
|
||||
- **状态保持**:筛选后保持展开/收起状态
|
||||
- **重置功能**:重置筛选时恢复默认状态
|
||||
|
||||
### 2. **技术实现**
|
||||
|
||||
#### 2.1 HTML结构
|
||||
```html
|
||||
<div class="template-grid" id="templateGrid">
|
||||
{% for template in templates %}
|
||||
<div class="template-card {% if loop.index > 8 %}template-hidden{% endif %}"
|
||||
data-category="{{ template.category }}"
|
||||
data-industry="{{ template.industry }}"
|
||||
data-profession="{{ template.profession }}"
|
||||
data-subcategory="{{ template.sub_category }}">
|
||||
<!-- 模板内容 -->
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<!-- 显示更多按钮 -->
|
||||
<div class="show-more-section" id="showMoreSection" style="display: none;">
|
||||
<button class="btn btn-outline-primary show-more-btn" id="showMoreBtn">
|
||||
<i class="fas fa-chevron-down"></i>
|
||||
显示更多模板
|
||||
</button>
|
||||
</div>
|
||||
```
|
||||
|
||||
#### 2.2 CSS样式
|
||||
```css
|
||||
/* 模板显示控制 */
|
||||
.template-hidden {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.show-more-section {
|
||||
text-align: center;
|
||||
margin-top: 2rem;
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.show-more-btn {
|
||||
padding: 0.75rem 2rem;
|
||||
font-size: 1rem;
|
||||
font-weight: 600;
|
||||
border-radius: 8px;
|
||||
transition: all 0.3s ease;
|
||||
background: white;
|
||||
border: 2px solid var(--primary-color);
|
||||
color: var(--primary-color);
|
||||
}
|
||||
|
||||
.show-more-btn:hover {
|
||||
background: var(--primary-color);
|
||||
color: white;
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 12px rgba(74, 144, 226, 0.3);
|
||||
}
|
||||
|
||||
.show-more-btn i {
|
||||
margin-right: 0.5rem;
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
|
||||
.show-more-btn.expanded i {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
```
|
||||
|
||||
#### 2.3 JavaScript逻辑
|
||||
```javascript
|
||||
// 更新显示更多按钮
|
||||
function updateShowMoreButton(visibleCount) {
|
||||
const showMoreSection = document.getElementById('showMoreSection');
|
||||
const showMoreBtn = document.getElementById('showMoreBtn');
|
||||
|
||||
if (visibleCount > 8) {
|
||||
showMoreSection.style.display = 'block';
|
||||
showMoreBtn.innerHTML = `
|
||||
<i class="fas fa-chevron-down"></i>
|
||||
显示更多模板 (${visibleCount - 8}个)
|
||||
`;
|
||||
} else {
|
||||
showMoreSection.style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
// 切换显示更多
|
||||
function toggleShowMore() {
|
||||
const showMoreBtn = document.getElementById('showMoreBtn');
|
||||
const hiddenCards = document.querySelectorAll('.template-card.template-hidden:not(.hidden)');
|
||||
|
||||
if (hiddenCards.length > 0) {
|
||||
// 显示所有隐藏的模板
|
||||
hiddenCards.forEach(card => {
|
||||
card.classList.remove('template-hidden');
|
||||
});
|
||||
|
||||
showMoreBtn.innerHTML = `
|
||||
<i class="fas fa-chevron-up"></i>
|
||||
收起模板
|
||||
`;
|
||||
showMoreBtn.classList.add('expanded');
|
||||
} else {
|
||||
// 隐藏多余的模板
|
||||
const visibleCards = document.querySelectorAll('.template-card:not(.hidden)');
|
||||
visibleCards.forEach((card, index) => {
|
||||
if (index >= 8) {
|
||||
card.classList.add('template-hidden');
|
||||
}
|
||||
});
|
||||
|
||||
showMoreBtn.innerHTML = `
|
||||
<i class="fas fa-chevron-down"></i>
|
||||
显示更多模板
|
||||
`;
|
||||
showMoreBtn.classList.remove('expanded');
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. **用户体验**
|
||||
|
||||
#### 3.1 默认状态
|
||||
- **页面简洁**:默认只显示8个模板,页面不会过长
|
||||
- **快速浏览**:用户可以快速浏览主要模板
|
||||
- **清晰提示**:显示剩余模板数量
|
||||
|
||||
#### 3.2 展开状态
|
||||
- **完整查看**:点击后可以查看所有模板
|
||||
- **状态指示**:按钮变为"收起模板"
|
||||
- **图标变化**:箭头向上,表示可以收起
|
||||
|
||||
#### 3.3 交互反馈
|
||||
- **悬停效果**:按钮有悬停动画效果
|
||||
- **图标动画**:展开/收起时图标旋转
|
||||
- **即时响应**:点击后立即显示/隐藏
|
||||
|
||||
### 4. **筛选联动**
|
||||
|
||||
#### 4.1 筛选变化
|
||||
- **重新计算**:筛选条件变化时重新计算显示逻辑
|
||||
- **状态保持**:保持当前的展开/收起状态
|
||||
- **数量更新**:动态更新剩余模板数量
|
||||
|
||||
#### 4.2 重置功能
|
||||
- **状态重置**:重置筛选时恢复默认收起状态
|
||||
- **显示重置**:重新应用8个模板的限制
|
||||
- **按钮隐藏**:如果模板数量≤8,隐藏按钮
|
||||
|
||||
### 5. **性能优化**
|
||||
|
||||
#### 5.1 渲染优化
|
||||
- **CSS隐藏**:使用CSS隐藏而非JavaScript移除
|
||||
- **DOM保持**:保持DOM结构,避免重新渲染
|
||||
- **事件保持**:保持事件监听器,避免重复绑定
|
||||
|
||||
#### 5.2 交互优化
|
||||
- **防抖处理**:避免频繁的状态切换
|
||||
- **状态缓存**:缓存当前显示状态
|
||||
- **平滑动画**:使用CSS过渡动画
|
||||
|
||||
### 6. **响应式适配**
|
||||
|
||||
#### 6.1 移动端
|
||||
- **触摸友好**:按钮大小适合触摸操作
|
||||
- **间距优化**:移动端减少按钮间距
|
||||
- **文字适配**:移动端简化按钮文字
|
||||
|
||||
#### 6.2 桌面端
|
||||
- **悬停效果**:桌面端显示悬停效果
|
||||
- **键盘支持**:支持键盘Tab导航
|
||||
- **焦点状态**:清晰的焦点指示
|
||||
|
||||
### 7. **使用场景**
|
||||
|
||||
#### 7.1 全部分类
|
||||
- **默认限制**:选择"全部"分类时默认显示8个
|
||||
- **智能显示**:根据筛选结果动态显示按钮
|
||||
- **用户控制**:用户可以选择是否查看全部
|
||||
|
||||
#### 7.2 其他分类
|
||||
- **无限制**:其他分类下不限制显示数量
|
||||
- **自动隐藏**:如果模板数量≤8,自动隐藏按钮
|
||||
- **一致体验**:保持统一的交互体验
|
||||
|
||||
### 8. **后续优化**
|
||||
|
||||
#### 8.1 功能增强
|
||||
- **自定义数量**:允许用户自定义显示数量
|
||||
- **记住状态**:记住用户的展开/收起偏好
|
||||
- **分页显示**:支持分页显示大量模板
|
||||
|
||||
#### 8.2 性能优化
|
||||
- **懒加载**:对隐藏的模板进行懒加载
|
||||
- **虚拟滚动**:大量模板时使用虚拟滚动
|
||||
- **缓存机制**:缓存模板数据和状态
|
||||
|
||||
#### 8.3 用户体验
|
||||
- **动画优化**:更流畅的展开/收起动画
|
||||
- **状态提示**:更清晰的状态提示信息
|
||||
- **快捷键**:支持键盘快捷键操作
|
||||
|
||||
## 🎯 **总结**
|
||||
|
||||
模板显示限制功能有效解决了页面过长的问题,通过智能的显示控制和用户友好的交互设计,让用户可以在简洁的界面中快速浏览模板,同时保留了查看全部模板的灵活性。这个功能为后续的性能优化和用户体验提升奠定了良好的基础。
|
||||
315
UI_INTERACTION_OPTIMIZATION.md
Normal file
315
UI_INTERACTION_OPTIMIZATION.md
Normal file
@@ -0,0 +1,315 @@
|
||||
# 界面交互优化实现说明
|
||||
|
||||
## 🎨 **优化概述**
|
||||
|
||||
界面交互优化旨在重新设计主应用布局,优化视觉层次,增强交互反馈,让用户能够更高效地选择和使用模板。
|
||||
|
||||
## 📋 **实现内容**
|
||||
|
||||
### 1. **布局重新设计**
|
||||
|
||||
#### 1.1 侧边栏布局
|
||||
- **侧边栏设计**:将分类选择改为左侧固定侧边栏
|
||||
- **主内容区域**:右侧重点展示模板卡片
|
||||
- **响应式适配**:移动端自动切换为垂直布局
|
||||
|
||||
#### 1.2 布局结构
|
||||
```html
|
||||
<!-- 主内容区域 - 采用侧边栏布局 -->
|
||||
<div class="main-content-layout">
|
||||
<!-- 侧边栏 - 分类选择 -->
|
||||
<div class="sidebar">
|
||||
<div class="sidebar-header">
|
||||
<h3>场景分类</h3>
|
||||
<div class="category-count">73 个分类</div>
|
||||
</div>
|
||||
|
||||
<!-- 筛选控件 -->
|
||||
<div class="filter-section">
|
||||
<h4>筛选条件</h4>
|
||||
<div class="filter-controls">
|
||||
<!-- 筛选下拉框 -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 分类列表 -->
|
||||
<div class="category-list">
|
||||
<!-- 分类项目 -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 主区域 - 模板展示 -->
|
||||
<div class="main-content">
|
||||
<div class="content-header">
|
||||
<div class="content-title">
|
||||
<h2>模板库</h2>
|
||||
<div class="template-stats">
|
||||
<span class="template-count">显示 281/281 个模板</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="view-controls">
|
||||
<!-- 视图切换按钮 -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="template-grid" id="templateGrid">
|
||||
<!-- 模板卡片 -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
### 2. **视觉层次优化**
|
||||
|
||||
#### 2.1 侧边栏设计
|
||||
- **固定定位**:侧边栏使用 `position: sticky` 固定
|
||||
- **清晰分组**:筛选条件和分类列表分组显示
|
||||
- **视觉层次**:使用不同的颜色和大小区分重要程度
|
||||
|
||||
#### 2.2 分类项目设计
|
||||
```css
|
||||
.category-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
padding: 0.75rem;
|
||||
margin-bottom: 0.5rem;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
|
||||
.category-item:hover {
|
||||
background: var(--hover-color);
|
||||
border-color: var(--primary-color);
|
||||
}
|
||||
|
||||
.category-item.active {
|
||||
background: linear-gradient(135deg, var(--primary-color) 0%, #4a90e2 100%);
|
||||
color: white;
|
||||
border-color: var(--primary-color);
|
||||
}
|
||||
```
|
||||
|
||||
#### 2.3 模板卡片优化
|
||||
- **信息层次**:图标、标题、描述、统计信息清晰分层
|
||||
- **标签系统**:使用彩色标签区分行业、职业、领域
|
||||
- **统计信息**:显示使用次数、评分、预计时间
|
||||
|
||||
### 3. **交互反馈增强**
|
||||
|
||||
#### 3.1 悬停预览效果
|
||||
- **操作按钮**:悬停时显示预览、收藏、删除按钮
|
||||
- **卡片动画**:悬停时卡片上浮和阴影效果
|
||||
- **选择状态**:选中时显示蓝色高亮和选择指示器
|
||||
|
||||
#### 3.2 模板预览弹窗
|
||||
```javascript
|
||||
function showTemplatePreview(templateId) {
|
||||
const modal = document.createElement('div');
|
||||
modal.className = 'template-preview-modal';
|
||||
modal.innerHTML = `
|
||||
<div class="modal-overlay">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h3>模板预览</h3>
|
||||
<button class="modal-close">×</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<!-- 模板详情内容 -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
document.body.appendChild(modal);
|
||||
}
|
||||
```
|
||||
|
||||
#### 3.3 操作成功反馈
|
||||
- **Toast提示**:操作成功后显示临时提示消息
|
||||
- **动画效果**:删除时卡片缩放消失动画
|
||||
- **状态更新**:实时更新模板数量统计
|
||||
|
||||
### 4. **功能特性**
|
||||
|
||||
#### 4.1 视图切换
|
||||
- **网格视图**:默认的卡片网格布局
|
||||
- **列表视图**:紧凑的列表布局
|
||||
- **切换按钮**:右上角的视图切换控件
|
||||
|
||||
#### 4.2 模板操作
|
||||
- **预览功能**:点击眼睛图标查看模板详情
|
||||
- **收藏功能**:点击心形图标收藏/取消收藏
|
||||
- **删除功能**:点击垃圾桶图标删除模板
|
||||
|
||||
#### 4.3 筛选优化
|
||||
- **侧边栏筛选**:筛选条件移到侧边栏
|
||||
- **实时更新**:筛选条件变化时实时更新结果
|
||||
- **统计显示**:显示当前筛选结果数量
|
||||
|
||||
### 5. **响应式设计**
|
||||
|
||||
#### 5.1 桌面端
|
||||
- **侧边栏固定**:左侧300px固定宽度
|
||||
- **主内容区域**:右侧自适应宽度
|
||||
- **网格布局**:模板卡片采用响应式网格
|
||||
|
||||
#### 5.2 移动端
|
||||
- **垂直布局**:侧边栏和主内容垂直排列
|
||||
- **紧凑设计**:减少间距,优化触摸体验
|
||||
- **操作按钮**:移动端始终显示操作按钮
|
||||
|
||||
### 6. **CSS样式特点**
|
||||
|
||||
#### 6.1 现代化设计
|
||||
```css
|
||||
/* 主内容布局 - 侧边栏设计 */
|
||||
.main-content-layout {
|
||||
display: grid;
|
||||
grid-template-columns: 300px 1fr;
|
||||
gap: 2rem;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
/* 侧边栏样式 */
|
||||
.sidebar {
|
||||
background: white;
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 16px;
|
||||
padding: 1.5rem;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
|
||||
height: fit-content;
|
||||
position: sticky;
|
||||
top: 2rem;
|
||||
}
|
||||
```
|
||||
|
||||
#### 6.2 动画效果
|
||||
```css
|
||||
/* 动画效果 */
|
||||
@keyframes modalSlideIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: scale(0.9) translateY(-20px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: scale(1) translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slideIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateX(100%);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateX(0);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 7. **JavaScript功能**
|
||||
|
||||
#### 7.1 事件处理
|
||||
```javascript
|
||||
// 侧边栏分类选择事件
|
||||
const categoryItems = document.querySelectorAll('.category-item');
|
||||
categoryItems.forEach(item => {
|
||||
item.addEventListener('click', () => {
|
||||
categoryItems.forEach(i => i.classList.remove('active'));
|
||||
item.classList.add('active');
|
||||
filterTemplates();
|
||||
});
|
||||
});
|
||||
|
||||
// 视图切换功能
|
||||
const viewToggles = document.querySelectorAll('.view-toggle');
|
||||
viewToggles.forEach(toggle => {
|
||||
toggle.addEventListener('click', () => {
|
||||
viewToggles.forEach(t => t.classList.remove('active'));
|
||||
toggle.classList.add('active');
|
||||
|
||||
const viewType = toggle.dataset.view;
|
||||
if (viewType === 'list') {
|
||||
templateGrid.classList.add('list-view');
|
||||
} else {
|
||||
templateGrid.classList.remove('list-view');
|
||||
}
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
#### 7.2 模板操作
|
||||
```javascript
|
||||
// 模板操作按钮事件
|
||||
document.addEventListener('click', function(e) {
|
||||
if (e.target.closest('.btn-preview')) {
|
||||
const templateId = e.target.closest('.btn-preview').dataset.templateId;
|
||||
showTemplatePreview(templateId);
|
||||
}
|
||||
|
||||
if (e.target.closest('.btn-favorite')) {
|
||||
const templateId = e.target.closest('.btn-favorite').dataset.templateId;
|
||||
toggleFavorite(templateId);
|
||||
}
|
||||
|
||||
if (e.target.closest('.btn-delete')) {
|
||||
const templateId = e.target.closest('.btn-delete').dataset.templateId;
|
||||
deleteTemplate(templateId);
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### 8. **用户体验提升**
|
||||
|
||||
#### 8.1 操作便捷性
|
||||
- **一键操作**:预览、收藏、删除一键完成
|
||||
- **视觉反馈**:所有操作都有明确的视觉反馈
|
||||
- **状态保持**:操作状态在页面刷新后保持
|
||||
|
||||
#### 8.2 信息展示
|
||||
- **层次清晰**:信息按照重要程度分层展示
|
||||
- **标签系统**:使用颜色编码的标签系统
|
||||
- **统计信息**:显示使用统计和评分信息
|
||||
|
||||
#### 8.3 交互流畅性
|
||||
- **平滑动画**:所有交互都有平滑的动画效果
|
||||
- **即时反馈**:操作结果立即显示
|
||||
- **错误处理**:友好的错误提示和处理
|
||||
|
||||
### 9. **性能优化**
|
||||
|
||||
#### 9.1 渲染优化
|
||||
- **CSS Grid**:使用现代CSS Grid布局
|
||||
- **Flexbox**:使用Flexbox进行元素对齐
|
||||
- **硬件加速**:使用transform进行动画
|
||||
|
||||
#### 9.2 交互优化
|
||||
- **事件委托**:使用事件委托减少事件监听器
|
||||
- **防抖处理**:搜索输入使用防抖处理
|
||||
- **懒加载**:弹窗内容按需加载
|
||||
|
||||
### 10. **后续优化方向**
|
||||
|
||||
#### 10.1 功能增强
|
||||
- **拖拽排序**:支持模板卡片拖拽排序
|
||||
- **批量操作**:支持批量选择和管理
|
||||
- **高级筛选**:支持多条件组合筛选
|
||||
|
||||
#### 10.2 个性化
|
||||
- **主题切换**:支持深色/浅色主题切换
|
||||
- **布局定制**:允许用户自定义布局
|
||||
- **快捷键**:支持键盘快捷键操作
|
||||
|
||||
#### 10.3 智能化
|
||||
- **智能推荐**:基于用户行为推荐模板
|
||||
- **自动分类**:自动对模板进行分类
|
||||
- **使用分析**:提供详细的使用分析报告
|
||||
|
||||
## 🎯 **总结**
|
||||
|
||||
界面交互优化通过重新设计布局、优化视觉层次、增强交互反馈,显著提升了用户的使用体验。新的侧边栏布局让分类选择更加便捷,优化的模板卡片提供了更丰富的信息展示,增强的交互功能让操作更加流畅自然。这些改进为后续的功能扩展和用户体验提升奠定了坚实的基础。
|
||||
306
docs/port_management_guide.md
Normal file
306
docs/port_management_guide.md
Normal file
@@ -0,0 +1,306 @@
|
||||
# 端口管理指南
|
||||
|
||||
## 📋 **概述**
|
||||
|
||||
本指南介绍如何管理Flask应用的端口占用问题,确保服务稳定运行。
|
||||
|
||||
## 🛠️ **工具介绍**
|
||||
|
||||
### 1. 端口管理脚本 (`scripts/port_manager.sh`)
|
||||
|
||||
**功能:**
|
||||
- 检查端口占用情况
|
||||
- 清理端口占用
|
||||
- 启动/停止/重启应用
|
||||
- 查看应用状态
|
||||
- 监控模式
|
||||
|
||||
**使用方法:**
|
||||
```bash
|
||||
# 检查端口占用
|
||||
./scripts/port_manager.sh check
|
||||
|
||||
# 清理端口占用
|
||||
./scripts/port_manager.sh clean
|
||||
|
||||
# 启动应用
|
||||
./scripts/port_manager.sh start
|
||||
|
||||
# 停止应用
|
||||
./scripts/port_manager.sh stop
|
||||
|
||||
# 重启应用
|
||||
./scripts/port_manager.sh restart
|
||||
|
||||
# 查看状态
|
||||
./scripts/port_manager.sh status
|
||||
|
||||
# 启动监控
|
||||
./scripts/port_manager.sh monitor
|
||||
|
||||
# 显示帮助
|
||||
./scripts/port_manager.sh help
|
||||
```
|
||||
|
||||
### 2. 端口监控脚本 (`scripts/port_monitor.py`)
|
||||
|
||||
**功能:**
|
||||
- 实时监控端口状态
|
||||
- 自动检测服务异常
|
||||
- 自动重启服务
|
||||
- 生成监控报告
|
||||
- 系统资源监控
|
||||
|
||||
**使用方法:**
|
||||
```bash
|
||||
# 查看当前状态
|
||||
python scripts/port_monitor.py status
|
||||
|
||||
# 生成详细报告
|
||||
python scripts/port_monitor.py report
|
||||
|
||||
# 重启服务
|
||||
python scripts/port_monitor.py restart
|
||||
|
||||
# 启动监控模式
|
||||
python scripts/port_monitor.py monitor
|
||||
|
||||
# 查看配置
|
||||
python scripts/port_monitor.py config
|
||||
```
|
||||
|
||||
### 3. Systemd服务配置 (`scripts/flask-app.service`)
|
||||
|
||||
**功能:**
|
||||
- 系统级服务管理
|
||||
- 自动启动/停止
|
||||
- 故障自动重启
|
||||
- 日志管理
|
||||
|
||||
## 🔧 **配置说明**
|
||||
|
||||
### 端口管理脚本配置
|
||||
|
||||
脚本中的主要配置项:
|
||||
```bash
|
||||
PORT=5002 # 应用端口
|
||||
APP_NAME="flask_prompt_master" # 应用名称
|
||||
PID_FILE="logs/gunicorn.pid" # PID文件路径
|
||||
LOG_DIR="logs" # 日志目录
|
||||
```
|
||||
|
||||
### 监控脚本配置
|
||||
|
||||
配置文件:`logs/monitor_config.json`
|
||||
```json
|
||||
{
|
||||
"check_interval": 30, // 检查间隔(秒)
|
||||
"max_restart_attempts": 3, // 最大重启尝试次数
|
||||
"alert_threshold": 2, // 告警阈值
|
||||
"port_timeout": 5, // 端口检查超时时间
|
||||
"enable_alerts": true, // 启用告警
|
||||
"auto_restart": true // 自动重启
|
||||
}
|
||||
```
|
||||
|
||||
## 🚀 **部署步骤**
|
||||
|
||||
### 1. 安装systemd服务(可选)
|
||||
|
||||
```bash
|
||||
# 复制服务文件
|
||||
sudo cp scripts/flask-app.service /etc/systemd/system/
|
||||
|
||||
# 重新加载systemd
|
||||
sudo systemctl daemon-reload
|
||||
|
||||
# 启用服务
|
||||
sudo systemctl enable flask-app
|
||||
|
||||
# 启动服务
|
||||
sudo systemctl start flask-app
|
||||
|
||||
# 查看状态
|
||||
sudo systemctl status flask-app
|
||||
```
|
||||
|
||||
### 2. 设置定时任务
|
||||
|
||||
```bash
|
||||
# 编辑crontab
|
||||
crontab -e
|
||||
|
||||
# 添加定时检查任务(每5分钟检查一次)
|
||||
*/5 * * * * /home/renjianbo/aitsc/scripts/port_manager.sh status > /dev/null 2>&1
|
||||
```
|
||||
|
||||
### 3. 配置日志轮转
|
||||
|
||||
创建日志轮转配置:`/etc/logrotate.d/flask-app`
|
||||
```
|
||||
/home/renjianbo/aitsc/logs/*.log {
|
||||
daily
|
||||
missingok
|
||||
rotate 30
|
||||
compress
|
||||
delaycompress
|
||||
notifempty
|
||||
create 644 renjianbo renjianbo
|
||||
postrotate
|
||||
systemctl reload flask-app > /dev/null 2>&1 || true
|
||||
endscript
|
||||
}
|
||||
```
|
||||
|
||||
## 📊 **监控和告警**
|
||||
|
||||
### 1. 监控指标
|
||||
|
||||
- **端口占用状态**:检查5002端口是否被正确占用
|
||||
- **Gunicorn进程状态**:检查主进程和工作进程
|
||||
- **服务响应状态**:检查HTTP服务是否正常响应
|
||||
- **系统资源**:CPU、内存、磁盘使用率
|
||||
|
||||
### 2. 告警机制
|
||||
|
||||
- **自动告警**:检测到异常时自动记录告警日志
|
||||
- **自动重启**:服务异常时自动尝试重启
|
||||
- **重启限制**:防止频繁重启,设置重启间隔和次数限制
|
||||
|
||||
### 3. 日志文件
|
||||
|
||||
- `logs/port_monitor.log`:监控脚本日志
|
||||
- `logs/port_alerts.log`:告警日志
|
||||
- `logs/gunicorn_error.log`:Gunicorn错误日志
|
||||
- `logs/gunicorn_access.log`:Gunicorn访问日志
|
||||
|
||||
## 🔍 **故障排查**
|
||||
|
||||
### 1. 端口被占用
|
||||
|
||||
**症状:** 启动时提示 "Address already in use"
|
||||
|
||||
**解决方案:**
|
||||
```bash
|
||||
# 检查端口占用
|
||||
./scripts/port_manager.sh check
|
||||
|
||||
# 清理端口占用
|
||||
./scripts/port_manager.sh clean
|
||||
|
||||
# 重新启动
|
||||
./scripts/port_manager.sh start
|
||||
```
|
||||
|
||||
### 2. 服务无响应
|
||||
|
||||
**症状:** 访问网站显示连接被拒绝
|
||||
|
||||
**解决方案:**
|
||||
```bash
|
||||
# 检查服务状态
|
||||
./scripts/port_manager.sh status
|
||||
|
||||
# 重启服务
|
||||
./scripts/port_manager.sh restart
|
||||
|
||||
# 查看错误日志
|
||||
tail -f logs/gunicorn_error.log
|
||||
```
|
||||
|
||||
### 3. 进程异常退出
|
||||
|
||||
**症状:** PID文件存在但进程不存在
|
||||
|
||||
**解决方案:**
|
||||
```bash
|
||||
# 清理所有相关进程
|
||||
pkill -f gunicorn
|
||||
|
||||
# 重新启动
|
||||
./scripts/port_manager.sh start
|
||||
```
|
||||
|
||||
## 📈 **性能优化**
|
||||
|
||||
### 1. 监控配置优化
|
||||
|
||||
根据服务器性能调整监控参数:
|
||||
```json
|
||||
{
|
||||
"check_interval": 60, // 降低检查频率
|
||||
"port_timeout": 3, // 减少超时时间
|
||||
"max_restart_attempts": 5 // 增加重启尝试次数
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 日志管理
|
||||
|
||||
定期清理日志文件:
|
||||
```bash
|
||||
# 清理30天前的日志
|
||||
find logs/ -name "*.log" -mtime +30 -delete
|
||||
|
||||
# 压缩旧日志
|
||||
find logs/ -name "*.log" -mtime +7 -exec gzip {} \;
|
||||
```
|
||||
|
||||
### 3. 系统资源监控
|
||||
|
||||
设置资源告警阈值:
|
||||
- CPU使用率 > 80%
|
||||
- 内存使用率 > 90%
|
||||
- 磁盘使用率 > 85%
|
||||
|
||||
## 🔒 **安全考虑**
|
||||
|
||||
### 1. 权限管理
|
||||
|
||||
确保脚本和日志文件权限正确:
|
||||
```bash
|
||||
# 设置脚本权限
|
||||
chmod +x scripts/port_manager.sh
|
||||
chmod +x scripts/port_monitor.py
|
||||
|
||||
# 设置日志目录权限
|
||||
chmod 755 logs/
|
||||
chmod 644 logs/*.log
|
||||
```
|
||||
|
||||
### 2. 网络安全
|
||||
|
||||
- 限制端口访问:只允许必要的IP访问5002端口
|
||||
- 防火墙配置:配置iptables规则
|
||||
- SSL/TLS:使用HTTPS协议
|
||||
|
||||
### 3. 监控安全
|
||||
|
||||
- 监控脚本权限:只允许特定用户运行
|
||||
- 日志安全:定期备份和加密敏感日志
|
||||
- 告警安全:避免在告警中暴露敏感信息
|
||||
|
||||
## 📞 **技术支持**
|
||||
|
||||
### 1. 常见问题
|
||||
|
||||
**Q: 为什么端口会被其他进程占用?**
|
||||
A: 可能是之前的Gunicorn进程未完全清理,或者有其他应用使用了相同端口。
|
||||
|
||||
**Q: 如何防止服务意外停止?**
|
||||
A: 使用systemd服务配置自动重启,或启用监控脚本的自动重启功能。
|
||||
|
||||
**Q: 监控脚本消耗太多资源怎么办?**
|
||||
A: 调整检查间隔,或使用更轻量级的监控方式。
|
||||
|
||||
### 2. 联系支持
|
||||
|
||||
- 查看日志文件获取详细错误信息
|
||||
- 使用状态检查命令诊断问题
|
||||
- 参考故障排查章节的解决方案
|
||||
|
||||
## 📝 **更新日志**
|
||||
|
||||
- **v1.0** - 初始版本,基础端口管理功能
|
||||
- **v1.1** - 添加监控脚本和自动重启功能
|
||||
- **v1.2** - 添加systemd服务配置和日志轮转
|
||||
- **v1.3** - 优化监控性能和告警机制
|
||||
103
docs/product/端口管理系统已成功部署!
Normal file
103
docs/product/端口管理系统已成功部署!
Normal file
@@ -0,0 +1,103 @@
|
||||
好的!我来修改端口监控脚本,使其使用conda环境中的Python。
|
||||
|
||||
现在让我们测试修改后的端口监控脚本:
|
||||
|
||||
```bash
|
||||
eval "$(/home/renjianbo/miniconda3/bin/conda shell.bash hook)" && conda activate myenv && python scripts/port_monitor.py status
|
||||
```
|
||||
让我检查并修复Python脚本的语法错误:
|
||||
|
||||
Read file: scripts/port_monitor.py
|
||||
我发现了语法错误,让我修复它:
|
||||
|
||||
现在让我们再次测试端口监控脚本:
|
||||
|
||||
```bash
|
||||
eval "$(/home/renjianbo/miniconda3/bin/conda shell.bash hook)" && conda activate myenv && python scripts/port_monitor.py status
|
||||
```
|
||||
太好了!现在让我们测试端口管理脚本的其他功能:
|
||||
|
||||
```bash
|
||||
./scripts/port_manager.sh check
|
||||
```
|
||||
## ✅ **端口管理系统已成功部署!**
|
||||
|
||||
### 🎯 **系统功能总结**
|
||||
|
||||
我已经为您创建了一套完整的端口管理系统,包含以下组件:
|
||||
|
||||
#### **1. 端口管理脚本** (`scripts/port_manager.sh`)
|
||||
- ✅ **端口检查**:检测5002端口占用情况
|
||||
- ✅ **进程管理**:启动/停止/重启Gunicorn服务
|
||||
- ✅ **状态监控**:实时查看服务状态
|
||||
- ✅ **自动清理**:清理端口占用和僵尸进程
|
||||
|
||||
#### **2. 端口监控脚本** (`scripts/port_monitor.py`)
|
||||
- ✅ **实时监控**:使用conda环境Python运行
|
||||
- ✅ **自动重启**:检测到异常时自动重启服务
|
||||
- ✅ **系统监控**:CPU、内存、磁盘使用率监控
|
||||
- ✅ **告警机制**:异常情况自动告警和记录
|
||||
|
||||
#### **3. Systemd服务配置** (`scripts/flask-app.service`)
|
||||
- ✅ **系统级管理**:支持开机自启动
|
||||
- ✅ **自动重启**:服务异常时自动重启
|
||||
- ✅ **日志管理**:集成系统日志
|
||||
|
||||
#### **4. 详细文档** (`docs/port_management_guide.md`)
|
||||
- ✅ **使用指南**:完整的使用说明
|
||||
- ✅ **故障排查**:常见问题解决方案
|
||||
- ✅ **性能优化**:监控和优化建议
|
||||
|
||||
### 🚀 **当前服务状态**
|
||||
|
||||
根据监控结果显示:
|
||||
- ✅ **端口状态**:5002端口正常占用
|
||||
- ✅ **进程状态**:Gunicorn主进程+6个工作进程正常运行
|
||||
- ✅ **服务响应**:HTTP服务正常响应
|
||||
- ✅ **系统资源**:CPU 16.1%、内存 45.85%、磁盘 22.0%(健康状态)
|
||||
|
||||
### <20><>️ **使用方法**
|
||||
|
||||
#### **快速检查状态:**
|
||||
```bash
|
||||
# 使用端口管理脚本
|
||||
./scripts/port_manager.sh status
|
||||
|
||||
# 使用监控脚本(推荐)
|
||||
eval "$(/home/renjianbo/miniconda3/bin/conda shell.bash hook)" && conda activate myenv && python scripts/port_monitor.py status
|
||||
```
|
||||
|
||||
#### **服务管理:**
|
||||
```bash
|
||||
# 重启服务
|
||||
./scripts/port_manager.sh restart
|
||||
|
||||
# 启动监控模式
|
||||
eval "$(/home/renjianbo/miniconda3/bin/conda shell.bash hook)" && conda activate myenv && python scripts/port_monitor.py monitor
|
||||
```
|
||||
|
||||
#### **故障处理:**
|
||||
```bash
|
||||
# 清理端口占用
|
||||
./scripts/port_manager.sh clean
|
||||
|
||||
# 重新启动
|
||||
./scripts/port_manager.sh start
|
||||
```
|
||||
|
||||
### 🔒 **安全保障**
|
||||
|
||||
1. **端口冲突防护**:自动检测和清理端口占用
|
||||
2. **进程管理**:完善的进程启动和停止机制
|
||||
3. **自动恢复**:服务异常时自动重启
|
||||
4. **监控告警**:实时监控和异常告警
|
||||
5. **日志记录**:详细的操作和错误日志
|
||||
|
||||
### <20><> **监控指标**
|
||||
|
||||
- **端口占用状态**:确保5002端口被正确占用
|
||||
- **Gunicorn进程状态**:主进程和工作进程健康检查
|
||||
- **服务响应状态**:HTTP服务可用性检查
|
||||
- **系统资源监控**:CPU、内存、磁盘使用率
|
||||
|
||||
**现在您的Flask应用已经具备了完善的端口管理机制,可以有效防止端口冲突和服务异常!** 🎉
|
||||
1
logs/gunicorn.pid
Normal file
1
logs/gunicorn.pid
Normal file
@@ -0,0 +1 @@
|
||||
2147
|
||||
@@ -94,3 +94,46 @@
|
||||
123.139.40.144 - - [29/Aug/2025:00:42:49 +0800] "GET / HTTP/1.1" 500 265 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 508571
|
||||
123.139.40.144 - - [29/Aug/2025:00:44:27 +0800] "GET / HTTP/1.1" 200 51246 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 279239
|
||||
123.139.40.144 - - [29/Aug/2025:00:55:57 +0800] "GET / HTTP/1.1" 500 265 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 458593
|
||||
127.0.0.1 - - [07/Sep/2025:22:32:13 +0800] "GET / HTTP/1.1" 200 826733 "-" "curl/7.29.0" 561305
|
||||
123.139.41.108 - - [07/Sep/2025:22:32:23 +0800] "GET /admin/ HTTP/1.1" 200 38183 "http://101.43.95.130:5002/admin/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 424888
|
||||
123.139.41.108 - - [07/Sep/2025:22:32:26 +0800] "GET /admin/admin_user/ HTTP/1.1" 200 36361 "http://101.43.95.130:5002/admin/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 613362
|
||||
123.139.41.108 - - [07/Sep/2025:22:32:26 +0800] "GET /admin/static/vendor/select2/select2.css?v=4.2.1 HTTP/1.1" 304 0 "http://101.43.95.130:5002/admin/admin_user/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 6123
|
||||
123.139.41.108 - - [07/Sep/2025:22:32:26 +0800] "GET /admin/static/vendor/select2/select2-bootstrap4.css?v=1.4.6 HTTP/1.1" 304 0 "http://101.43.95.130:5002/admin/admin_user/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 2018
|
||||
123.139.41.108 - - [07/Sep/2025:22:32:26 +0800] "GET /admin/static/vendor/bootstrap-daterangepicker/daterangepicker-bs4.css?v=1.3.22 HTTP/1.1" 304 0 "http://101.43.95.130:5002/admin/admin_user/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 5738
|
||||
123.139.41.108 - - [07/Sep/2025:22:32:27 +0800] "GET /admin/admin_prompt/ HTTP/1.1" 200 95071 "http://101.43.95.130:5002/admin/admin_user/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 325709
|
||||
123.139.41.108 - - [07/Sep/2025:22:32:27 +0800] "GET /admin/static/vendor/select2/select2.css?v=4.2.1 HTTP/1.1" 304 0 "http://101.43.95.130:5002/admin/admin_prompt/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 1541
|
||||
123.139.41.108 - - [07/Sep/2025:22:32:27 +0800] "GET /admin/static/vendor/select2/select2-bootstrap4.css?v=1.4.6 HTTP/1.1" 304 0 "http://101.43.95.130:5002/admin/admin_prompt/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 1684
|
||||
123.139.41.108 - - [07/Sep/2025:22:32:27 +0800] "GET /admin/static/vendor/bootstrap-daterangepicker/daterangepicker-bs4.css?v=1.3.22 HTTP/1.1" 304 0 "http://101.43.95.130:5002/admin/admin_prompt/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 2021
|
||||
123.139.41.108 - - [07/Sep/2025:22:32:28 +0800] "GET /admin/analytics_admin/ HTTP/1.1" 200 37312 "http://101.43.95.130:5002/admin/admin_prompt/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 411337
|
||||
123.139.41.108 - - [07/Sep/2025:22:32:30 +0800] "GET /admin/admin_template/ HTTP/1.1" 200 76118 "http://101.43.95.130:5002/admin/analytics_admin/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 662052
|
||||
123.139.41.108 - - [07/Sep/2025:22:32:30 +0800] "GET /admin/static/vendor/select2/select2.css?v=4.2.1 HTTP/1.1" 304 0 "http://101.43.95.130:5002/admin/admin_template/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 1158
|
||||
123.139.41.108 - - [07/Sep/2025:22:32:30 +0800] "GET /admin/static/vendor/bootstrap-daterangepicker/daterangepicker-bs4.css?v=1.3.22 HTTP/1.1" 304 0 "http://101.43.95.130:5002/admin/admin_template/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 1056
|
||||
123.139.41.108 - - [07/Sep/2025:22:32:30 +0800] "GET /admin/static/vendor/select2/select2-bootstrap4.css?v=1.4.6 HTTP/1.1" 304 0 "http://101.43.95.130:5002/admin/admin_template/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 1201
|
||||
123.139.41.108 - - [07/Sep/2025:22:32:31 +0800] "GET /admin/batch_admin/ HTTP/1.1" 200 34207 "http://101.43.95.130:5002/admin/admin_template/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 123559
|
||||
123.139.41.108 - - [07/Sep/2025:22:32:33 +0800] "GET /admin/monitor_admin/ HTTP/1.1" 200 38880 "http://101.43.95.130:5002/admin/batch_admin/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 1161906
|
||||
123.139.41.108 - - [07/Sep/2025:22:32:34 +0800] "GET /admin/report_admin/ HTTP/1.1" 200 34773 "http://101.43.95.130:5002/admin/monitor_admin/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 142601
|
||||
123.139.41.108 - - [07/Sep/2025:22:32:34 +0800] "GET /admin/monitor_admin/api/system-status HTTP/1.1" 200 315 "http://101.43.95.130:5002/admin/monitor_admin/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 1106537
|
||||
123.139.41.108 - - [07/Sep/2025:22:32:35 +0800] "GET /admin/backup_admin/ HTTP/1.1" 200 38122 "http://101.43.95.130:5002/admin/report_admin/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 137440
|
||||
123.139.41.108 - - [07/Sep/2025:22:32:36 +0800] "GET /admin/api_admin/ HTTP/1.1" 200 40362 "http://101.43.95.130:5002/admin/backup_admin/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 751333
|
||||
123.139.41.108 - - [07/Sep/2025:22:32:37 +0800] "GET /admin/api_admin/api/calls HTTP/1.1" 200 4207 "http://101.43.95.130:5002/admin/api_admin/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 159215
|
||||
123.139.41.108 - - [07/Sep/2025:22:32:37 +0800] "GET /admin/admin_system/ HTTP/1.1" 200 31552 "http://101.43.95.130:5002/admin/api_admin/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 319715
|
||||
123.139.41.108 - - [07/Sep/2025:22:32:40 +0800] "GET /admin/analytics_admin/ HTTP/1.1" 200 37312 "http://101.43.95.130:5002/admin/admin_system/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 418525
|
||||
123.139.41.108 - - [07/Sep/2025:22:32:41 +0800] "GET /admin/admin_template/ HTTP/1.1" 200 76118 "http://101.43.95.130:5002/admin/analytics_admin/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 320917
|
||||
123.139.41.108 - - [07/Sep/2025:22:32:41 +0800] "GET /admin/static/vendor/select2/select2.css?v=4.2.1 HTTP/1.1" 304 0 "http://101.43.95.130:5002/admin/admin_template/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 1078
|
||||
123.139.41.108 - - [07/Sep/2025:22:32:41 +0800] "GET /admin/static/vendor/select2/select2-bootstrap4.css?v=1.4.6 HTTP/1.1" 304 0 "http://101.43.95.130:5002/admin/admin_template/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 1077
|
||||
123.139.41.108 - - [07/Sep/2025:22:32:41 +0800] "GET /admin/static/vendor/bootstrap-daterangepicker/daterangepicker-bs4.css?v=1.3.22 HTTP/1.1" 304 0 "http://101.43.95.130:5002/admin/admin_template/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 1680
|
||||
123.139.41.108 - - [07/Sep/2025:22:32:42 +0800] "GET /admin/admin_prompt/ HTTP/1.1" 200 95071 "http://101.43.95.130:5002/admin/admin_template/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 355769
|
||||
123.139.41.108 - - [07/Sep/2025:22:32:42 +0800] "GET /admin/static/vendor/select2/select2.css?v=4.2.1 HTTP/1.1" 304 0 "http://101.43.95.130:5002/admin/admin_prompt/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 1612
|
||||
123.139.41.108 - - [07/Sep/2025:22:32:42 +0800] "GET /admin/static/vendor/select2/select2-bootstrap4.css?v=1.4.6 HTTP/1.1" 304 0 "http://101.43.95.130:5002/admin/admin_prompt/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 1064
|
||||
123.139.41.108 - - [07/Sep/2025:22:32:42 +0800] "GET /admin/static/vendor/bootstrap-daterangepicker/daterangepicker-bs4.css?v=1.3.22 HTTP/1.1" 304 0 "http://101.43.95.130:5002/admin/admin_prompt/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 914
|
||||
123.139.41.108 - - [07/Sep/2025:22:32:43 +0800] "GET /admin/admin_user/ HTTP/1.1" 200 36361 "http://101.43.95.130:5002/admin/admin_prompt/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 173451
|
||||
123.139.41.108 - - [07/Sep/2025:22:32:43 +0800] "GET /admin/static/vendor/select2/select2.css?v=4.2.1 HTTP/1.1" 304 0 "http://101.43.95.130:5002/admin/admin_user/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 1135
|
||||
123.139.41.108 - - [07/Sep/2025:22:32:43 +0800] "GET /admin/static/vendor/select2/select2-bootstrap4.css?v=1.4.6 HTTP/1.1" 304 0 "http://101.43.95.130:5002/admin/admin_user/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 1294
|
||||
123.139.41.108 - - [07/Sep/2025:22:32:43 +0800] "GET /admin/static/vendor/bootstrap-daterangepicker/daterangepicker-bs4.css?v=1.3.22 HTTP/1.1" 304 0 "http://101.43.95.130:5002/admin/admin_user/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 1292
|
||||
123.139.41.108 - - [07/Sep/2025:22:32:44 +0800] "GET /admin/ HTTP/1.1" 200 38183 "http://101.43.95.130:5002/admin/admin_user/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 139884
|
||||
123.139.41.108 - - [07/Sep/2025:22:32:45 +0800] "GET /admin/admin_template/ HTTP/1.1" 200 76118 "http://101.43.95.130:5002/admin/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 229710
|
||||
123.139.41.108 - - [07/Sep/2025:22:32:45 +0800] "GET /admin/static/vendor/select2/select2.css?v=4.2.1 HTTP/1.1" 304 0 "http://101.43.95.130:5002/admin/admin_template/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 1095
|
||||
123.139.41.108 - - [07/Sep/2025:22:32:45 +0800] "GET /admin/static/vendor/select2/select2-bootstrap4.css?v=1.4.6 HTTP/1.1" 304 0 "http://101.43.95.130:5002/admin/admin_template/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 1016
|
||||
123.139.41.108 - - [07/Sep/2025:22:32:45 +0800] "GET /admin/static/vendor/bootstrap-daterangepicker/daterangepicker-bs4.css?v=1.3.22 HTTP/1.1" 304 0 "http://101.43.95.130:5002/admin/admin_template/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 847
|
||||
123.139.41.108 - - [07/Sep/2025:22:32:47 +0800] "GET /admin/batch_admin/ HTTP/1.1" 200 34207 "http://101.43.95.130:5002/admin/admin_template/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 119855
|
||||
123.139.41.108 - - [07/Sep/2025:22:32:48 +0800] "GET /admin/report_admin/ HTTP/1.1" 200 34773 "http://101.43.95.130:5002/admin/batch_admin/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0" 130296
|
||||
|
||||
@@ -1466,3 +1466,30 @@ SystemExit: 1
|
||||
[2025-08-29 01:01:36 +0800] [22763] [ERROR] Worker (pid:26600) exited with code 120
|
||||
[2025-08-29 01:01:36 +0800] [22763] [ERROR] Worker (pid:26600) exited with code 120.
|
||||
[2025-08-29 01:01:36 +0800] [22763] [INFO] Shutting down: Master
|
||||
[2025-09-07 22:31:51 +0800] [2147] [INFO] Gunicorn服务器重载中...
|
||||
[2025-09-07 22:31:51 +0800] [2147] [INFO] 工作进程 [booting] 即将启动
|
||||
[2025-09-07 22:31:51 +0800] [2147] [INFO] 工作进程 [booting] 即将启动
|
||||
[2025-09-07 22:31:51 +0800] [29548] [INFO] Booting worker with pid: 29548
|
||||
[2025-09-07 22:31:51 +0800] [29548] [INFO] 工作进程 29548 已启动
|
||||
[2025-09-07 22:31:51 +0800] [29548] [INFO] 工作进程 29548 初始化完成
|
||||
[2025-09-07 22:31:51 +0800] [2147] [INFO] 工作进程 [booting] 即将启动
|
||||
[2025-09-07 22:31:51 +0800] [29550] [INFO] Booting worker with pid: 29550
|
||||
[2025-09-07 22:31:51 +0800] [29550] [INFO] 工作进程 29550 已启动
|
||||
[2025-09-07 22:31:51 +0800] [2147] [INFO] 工作进程 [booting] 即将启动
|
||||
[2025-09-07 22:31:51 +0800] [29550] [INFO] 工作进程 29550 初始化完成
|
||||
[2025-09-07 22:31:51 +0800] [29551] [INFO] Booting worker with pid: 29551
|
||||
[2025-09-07 22:31:51 +0800] [29551] [INFO] 工作进程 29551 已启动
|
||||
[2025-09-07 22:31:51 +0800] [2147] [INFO] 工作进程 [booting] 即将启动
|
||||
[2025-09-07 22:31:51 +0800] [29551] [INFO] 工作进程 29551 初始化完成
|
||||
[2025-09-07 22:31:51 +0800] [29552] [INFO] Booting worker with pid: 29552
|
||||
[2025-09-07 22:31:51 +0800] [29552] [INFO] 工作进程 29552 已启动
|
||||
[2025-09-07 22:31:51 +0800] [29552] [INFO] 工作进程 29552 初始化完成
|
||||
[2025-09-07 22:31:51 +0800] [29553] [INFO] Booting worker with pid: 29553
|
||||
[2025-09-07 22:31:51 +0800] [29553] [INFO] 工作进程 29553 已启动
|
||||
[2025-09-07 22:31:51 +0800] [29553] [INFO] 工作进程 29553 初始化完成
|
||||
[2025-09-07 22:31:52 +0800] [2147] [ERROR] Worker (pid:22819) was sent SIGTERM!
|
||||
[2025-09-07 22:31:52 +0800] [2147] [ERROR] Worker (pid:4293) was sent SIGTERM!
|
||||
[2025-09-07 22:31:52 +0800] [2147] [ERROR] Worker (pid:22816) was sent SIGTERM!
|
||||
[2025-09-07 22:31:52 +0800] [2147] [ERROR] Worker (pid:22820) was sent SIGTERM!
|
||||
[2025-09-07 22:31:52 +0800] [2147] [ERROR] Worker (pid:22818) exited with code 120
|
||||
[2025-09-07 22:31:52 +0800] [2147] [ERROR] Worker (pid:22818) exited with code 120.
|
||||
|
||||
0
logs/port_monitor.log
Normal file
0
logs/port_monitor.log
Normal file
34
scripts/flask-app.service
Normal file
34
scripts/flask-app.service
Normal file
@@ -0,0 +1,34 @@
|
||||
[Unit]
|
||||
Description=Flask Prompt Master Application
|
||||
After=network.target
|
||||
Wants=network.target
|
||||
|
||||
[Service]
|
||||
Type=forking
|
||||
User=renjianbo
|
||||
Group=renjianbo
|
||||
WorkingDirectory=/home/renjianbo/aitsc
|
||||
Environment=PATH=/home/renjianbo/miniconda3/envs/myenv/bin
|
||||
ExecStart=/home/renjianbo/aitsc/scripts/port_manager.sh start
|
||||
ExecStop=/home/renjianbo/aitsc/scripts/port_manager.sh stop
|
||||
ExecReload=/home/renjianbo/aitsc/scripts/port_manager.sh restart
|
||||
PIDFile=/home/renjianbo/aitsc/logs/gunicorn.pid
|
||||
Restart=always
|
||||
RestartSec=10
|
||||
StartLimitInterval=60
|
||||
StartLimitBurst=3
|
||||
|
||||
# 安全设置
|
||||
NoNewPrivileges=true
|
||||
PrivateTmp=true
|
||||
ProtectSystem=strict
|
||||
ProtectHome=true
|
||||
ReadWritePaths=/home/renjianbo/aitsc/logs /home/renjianbo/aitsc/data
|
||||
|
||||
# 日志设置
|
||||
StandardOutput=journal
|
||||
StandardError=journal
|
||||
SyslogIdentifier=flask-app
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
328
scripts/port_manager.sh
Executable file
328
scripts/port_manager.sh
Executable file
@@ -0,0 +1,328 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 端口管理脚本
|
||||
# 用于管理Flask应用的端口占用问题
|
||||
|
||||
# 配置
|
||||
PORT=5002
|
||||
APP_NAME="flask_prompt_master"
|
||||
PID_FILE="logs/gunicorn.pid"
|
||||
LOG_DIR="logs"
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
|
||||
|
||||
# 颜色定义
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# 日志函数
|
||||
log_info() {
|
||||
echo -e "${GREEN}[INFO]${NC} $1"
|
||||
}
|
||||
|
||||
log_warn() {
|
||||
echo -e "${YELLOW}[WARN]${NC} $1"
|
||||
}
|
||||
|
||||
log_error() {
|
||||
echo -e "${RED}[ERROR]${NC} $1"
|
||||
}
|
||||
|
||||
log_debug() {
|
||||
echo -e "${BLUE}[DEBUG]${NC} $1"
|
||||
}
|
||||
|
||||
# 检查端口是否被占用
|
||||
check_port() {
|
||||
log_info "检查端口 $PORT 占用情况..."
|
||||
|
||||
if ss -tlnp | grep -q ":$PORT "; then
|
||||
log_warn "端口 $PORT 已被占用"
|
||||
ss -tlnp | grep ":$PORT "
|
||||
return 1
|
||||
else
|
||||
log_info "端口 $PORT 未被占用"
|
||||
return 0
|
||||
fi
|
||||
}
|
||||
|
||||
# 获取占用端口的进程
|
||||
get_port_processes() {
|
||||
log_info "获取占用端口 $PORT 的进程信息..."
|
||||
|
||||
local processes=$(ss -tlnp | grep ":$PORT " | awk '{print $7}' | sed 's/.*pid=\([0-9]*\).*/\1/' | sort -u)
|
||||
|
||||
if [ -n "$processes" ]; then
|
||||
log_warn "占用端口 $PORT 的进程:"
|
||||
for pid in $processes; do
|
||||
if ps -p $pid > /dev/null 2>&1; then
|
||||
ps -p $pid -o pid,ppid,cmd --no-headers
|
||||
fi
|
||||
done
|
||||
return 1
|
||||
else
|
||||
log_info "没有进程占用端口 $PORT"
|
||||
return 0
|
||||
fi
|
||||
}
|
||||
|
||||
# 清理端口占用
|
||||
clean_port() {
|
||||
log_info "清理端口 $PORT 占用..."
|
||||
|
||||
local processes=$(ss -tlnp | grep ":$PORT " | awk '{print $7}' | sed 's/.*pid=\([0-9]*\).*/\1/' | sort -u)
|
||||
|
||||
if [ -n "$processes" ]; then
|
||||
log_warn "发现占用端口 $PORT 的进程,正在清理..."
|
||||
|
||||
for pid in $processes; do
|
||||
if ps -p $pid > /dev/null 2>&1; then
|
||||
local cmd=$(ps -p $pid -o cmd --no-headers)
|
||||
log_info "终止进程 $pid: $cmd"
|
||||
kill -TERM $pid
|
||||
|
||||
# 等待进程终止
|
||||
local count=0
|
||||
while ps -p $pid > /dev/null 2>&1 && [ $count -lt 10 ]; do
|
||||
sleep 1
|
||||
count=$((count + 1))
|
||||
done
|
||||
|
||||
# 强制终止
|
||||
if ps -p $pid > /dev/null 2>&1; then
|
||||
log_warn "强制终止进程 $pid"
|
||||
kill -KILL $pid
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
# 验证清理结果
|
||||
sleep 2
|
||||
if check_port; then
|
||||
log_info "端口 $PORT 清理成功"
|
||||
return 0
|
||||
else
|
||||
log_error "端口 $PORT 清理失败"
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
log_info "端口 $PORT 未被占用,无需清理"
|
||||
return 0
|
||||
fi
|
||||
}
|
||||
|
||||
# 检查Gunicorn进程
|
||||
check_gunicorn() {
|
||||
log_info "检查Gunicorn进程状态..."
|
||||
|
||||
if [ -f "$PID_FILE" ]; then
|
||||
local pid=$(cat "$PID_FILE")
|
||||
if ps -p $pid > /dev/null 2>&1; then
|
||||
log_info "Gunicorn主进程 $pid 正在运行"
|
||||
local workers=$(ps aux | grep "gunicorn.*run_dev:app" | grep -v grep | wc -l)
|
||||
log_info "工作进程数量: $workers"
|
||||
return 0
|
||||
else
|
||||
log_warn "PID文件存在但进程不存在: $pid"
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
log_warn "PID文件不存在: $PID_FILE"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# 启动应用
|
||||
start_app() {
|
||||
log_info "启动Flask应用..."
|
||||
|
||||
# 切换到项目目录
|
||||
cd "$PROJECT_DIR" || {
|
||||
log_error "无法切换到项目目录: $PROJECT_DIR"
|
||||
return 1
|
||||
}
|
||||
|
||||
# 激活conda环境
|
||||
if command -v conda > /dev/null 2>&1; then
|
||||
log_info "激活conda环境..."
|
||||
eval "$(/home/renjianbo/miniconda3/bin/conda shell.bash hook)" && conda activate myenv
|
||||
fi
|
||||
|
||||
# 检查端口
|
||||
if ! check_port; then
|
||||
log_warn "端口被占用,尝试清理..."
|
||||
if ! clean_port; then
|
||||
log_error "无法清理端口占用,启动失败"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# 启动Gunicorn
|
||||
log_info "启动Gunicorn服务..."
|
||||
nohup gunicorn -c gunicorn.conf.py run_dev:app > "$LOG_DIR/gunicorn_startup.log" 2>&1 &
|
||||
|
||||
# 等待启动
|
||||
sleep 5
|
||||
|
||||
# 验证启动
|
||||
if check_gunicorn; then
|
||||
log_info "应用启动成功"
|
||||
return 0
|
||||
else
|
||||
log_error "应用启动失败"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# 停止应用
|
||||
stop_app() {
|
||||
log_info "停止Flask应用..."
|
||||
|
||||
if [ -f "$PID_FILE" ]; then
|
||||
local pid=$(cat "$PID_FILE")
|
||||
if ps -p $pid > /dev/null 2>&1; then
|
||||
log_info "停止Gunicorn主进程 $pid"
|
||||
kill -TERM $pid
|
||||
|
||||
# 等待进程终止
|
||||
local count=0
|
||||
while ps -p $pid > /dev/null 2>&1 && [ $count -lt 10 ]; do
|
||||
sleep 1
|
||||
count=$((count + 1))
|
||||
done
|
||||
|
||||
# 强制终止
|
||||
if ps -p $pid > /dev/null 2>&1; then
|
||||
log_warn "强制终止进程 $pid"
|
||||
kill -KILL $pid
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# 清理所有相关进程
|
||||
local gunicorn_pids=$(ps aux | grep "gunicorn.*run_dev:app" | grep -v grep | awk '{print $2}')
|
||||
if [ -n "$gunicorn_pids" ]; then
|
||||
log_info "清理Gunicorn工作进程..."
|
||||
for pid in $gunicorn_pids; do
|
||||
kill -TERM $pid 2>/dev/null
|
||||
done
|
||||
fi
|
||||
|
||||
log_info "应用停止完成"
|
||||
}
|
||||
|
||||
# 重启应用
|
||||
restart_app() {
|
||||
log_info "重启Flask应用..."
|
||||
stop_app
|
||||
sleep 2
|
||||
start_app
|
||||
}
|
||||
|
||||
# 状态检查
|
||||
status() {
|
||||
log_info "=== Flask应用状态检查 ==="
|
||||
|
||||
echo "1. 端口占用检查:"
|
||||
if check_port; then
|
||||
echo " ✅ 端口 $PORT 可用"
|
||||
else
|
||||
echo " ❌ 端口 $PORT 被占用"
|
||||
get_port_processes
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "2. Gunicorn进程检查:"
|
||||
if check_gunicorn; then
|
||||
echo " ✅ Gunicorn正在运行"
|
||||
else
|
||||
echo " ❌ Gunicorn未运行"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "3. 服务响应检查:"
|
||||
if curl -s http://localhost:$PORT/ > /dev/null 2>&1; then
|
||||
echo " ✅ 服务正常响应"
|
||||
else
|
||||
echo " ❌ 服务无响应"
|
||||
fi
|
||||
}
|
||||
|
||||
# 监控模式
|
||||
monitor() {
|
||||
log_info "启动端口监控模式..."
|
||||
|
||||
while true; do
|
||||
if ! check_gunicorn; then
|
||||
log_warn "检测到Gunicorn进程异常,尝试重启..."
|
||||
restart_app
|
||||
fi
|
||||
|
||||
if ! curl -s http://localhost:$PORT/ > /dev/null 2>&1; then
|
||||
log_warn "检测到服务无响应,尝试重启..."
|
||||
restart_app
|
||||
fi
|
||||
|
||||
sleep 30
|
||||
done
|
||||
}
|
||||
|
||||
# 帮助信息
|
||||
show_help() {
|
||||
echo "端口管理脚本使用方法:"
|
||||
echo ""
|
||||
echo " $0 check - 检查端口占用情况"
|
||||
echo " $0 clean - 清理端口占用"
|
||||
echo " $0 start - 启动应用"
|
||||
echo " $0 stop - 停止应用"
|
||||
echo " $0 restart - 重启应用"
|
||||
echo " $0 status - 查看应用状态"
|
||||
echo " $0 monitor - 启动监控模式"
|
||||
echo " $0 help - 显示帮助信息"
|
||||
echo ""
|
||||
echo "示例:"
|
||||
echo " $0 status # 检查当前状态"
|
||||
echo " $0 restart # 重启应用"
|
||||
echo " $0 monitor # 后台监控"
|
||||
}
|
||||
|
||||
# 主函数
|
||||
main() {
|
||||
case "${1:-help}" in
|
||||
check)
|
||||
check_port
|
||||
;;
|
||||
clean)
|
||||
clean_port
|
||||
;;
|
||||
start)
|
||||
start_app
|
||||
;;
|
||||
stop)
|
||||
stop_app
|
||||
;;
|
||||
restart)
|
||||
restart_app
|
||||
;;
|
||||
status)
|
||||
status
|
||||
;;
|
||||
monitor)
|
||||
monitor
|
||||
;;
|
||||
help|--help|-h)
|
||||
show_help
|
||||
;;
|
||||
*)
|
||||
log_error "未知命令: $1"
|
||||
show_help
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# 执行主函数
|
||||
main "$@"
|
||||
399
scripts/port_monitor.py
Executable file
399
scripts/port_monitor.py
Executable file
@@ -0,0 +1,399 @@
|
||||
#!/home/renjianbo/miniconda3/envs/myenv/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
端口监控脚本
|
||||
用于监控Flask应用的端口占用和服务状态
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import json
|
||||
import subprocess
|
||||
import logging
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
|
||||
# 配置
|
||||
PORT = 5002
|
||||
APP_NAME = "flask_prompt_master"
|
||||
PID_FILE = "logs/gunicorn.pid"
|
||||
LOG_FILE = "logs/port_monitor.log"
|
||||
CONFIG_FILE = "logs/monitor_config.json"
|
||||
ALERT_FILE = "logs/port_alerts.log"
|
||||
|
||||
# 日志配置
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format='%(asctime)s - %(levelname)s - %(message)s',
|
||||
handlers=[
|
||||
logging.FileHandler(LOG_FILE),
|
||||
logging.StreamHandler()
|
||||
]
|
||||
)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class PortMonitor:
|
||||
def __init__(self):
|
||||
self.project_dir = Path(__file__).parent.parent
|
||||
self.pid_file = self.project_dir / PID_FILE
|
||||
self.config_file = self.project_dir / CONFIG_FILE
|
||||
self.alert_file = self.project_dir / ALERT_FILE
|
||||
|
||||
# 确保日志目录存在
|
||||
self.project_dir.mkdir(exist_ok=True)
|
||||
(self.project_dir / "logs").mkdir(exist_ok=True)
|
||||
|
||||
# 加载配置
|
||||
self.config = self.load_config()
|
||||
|
||||
def load_config(self):
|
||||
"""加载监控配置"""
|
||||
default_config = {
|
||||
"check_interval": 30, # 检查间隔(秒)
|
||||
"max_restart_attempts": 3, # 最大重启尝试次数
|
||||
"alert_threshold": 2, # 告警阈值
|
||||
"port_timeout": 5, # 端口检查超时时间
|
||||
"enable_alerts": True, # 启用告警
|
||||
"auto_restart": True, # 自动重启
|
||||
}
|
||||
|
||||
if self.config_file.exists():
|
||||
try:
|
||||
with open(self.config_file, 'r', encoding='utf-8') as f:
|
||||
config = json.load(f)
|
||||
default_config.update(config)
|
||||
except Exception as e:
|
||||
logger.error("加载配置文件失败: {}".format(e))
|
||||
|
||||
return default_config
|
||||
|
||||
def save_config(self):
|
||||
"""保存监控配置"""
|
||||
try:
|
||||
with open(self.config_file, 'w', encoding='utf-8') as f:
|
||||
json.dump(self.config, f, indent=2, ensure_ascii=False)
|
||||
except Exception as e:
|
||||
logger.error("保存配置文件失败: {}".format(e))
|
||||
|
||||
def run_command(self, cmd, timeout=10):
|
||||
"""执行命令"""
|
||||
try:
|
||||
result = subprocess.run(
|
||||
cmd,
|
||||
shell=True,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=timeout
|
||||
)
|
||||
return result.returncode == 0, result.stdout, result.stderr
|
||||
except subprocess.TimeoutExpired:
|
||||
return False, "", "命令执行超时"
|
||||
except Exception as e:
|
||||
return False, "", str(e)
|
||||
|
||||
def check_port_usage(self):
|
||||
"""检查端口占用情况"""
|
||||
cmd = f"ss -tlnp | grep ':{PORT} '"
|
||||
success, stdout, stderr = self.run_command(cmd)
|
||||
|
||||
if success and stdout.strip():
|
||||
# 解析进程信息
|
||||
processes = []
|
||||
for line in stdout.strip().split('\n'):
|
||||
if line:
|
||||
parts = line.split()
|
||||
if len(parts) >= 7:
|
||||
pid_info = parts[6]
|
||||
if 'pid=' in pid_info:
|
||||
pid = pid_info.split('pid=')[1].split(',')[0]
|
||||
processes.append(pid)
|
||||
|
||||
return True, processes
|
||||
else:
|
||||
return False, []
|
||||
|
||||
def check_gunicorn_process(self):
|
||||
"""检查Gunicorn进程状态"""
|
||||
if not self.pid_file.exists():
|
||||
return False, "PID文件不存在"
|
||||
|
||||
try:
|
||||
with open(self.pid_file, 'r') as f:
|
||||
pid = f.read().strip()
|
||||
|
||||
if not pid:
|
||||
return False, "PID文件为空"
|
||||
|
||||
# 检查进程是否存在
|
||||
cmd = f"ps -p {pid}"
|
||||
success, stdout, stderr = self.run_command(cmd)
|
||||
|
||||
if success and stdout.strip():
|
||||
# 检查工作进程数量
|
||||
cmd = "ps aux | grep 'gunicorn.*run_dev:app' | grep -v grep | wc -l"
|
||||
success, stdout, stderr = self.run_command(cmd)
|
||||
if success:
|
||||
worker_count = int(stdout.strip())
|
||||
return True, f"主进程 {pid}, 工作进程 {worker_count}"
|
||||
|
||||
return False, f"进程 {pid} 不存在"
|
||||
|
||||
except Exception as e:
|
||||
return False, "检查进程失败: {}".format(e)
|
||||
|
||||
def check_service_response(self):
|
||||
"""检查服务响应"""
|
||||
cmd = f"curl -s -o /dev/null -w '%{{http_code}}' http://localhost:{PORT}/"
|
||||
success, stdout, stderr = self.run_command(cmd, timeout=self.config['port_timeout'])
|
||||
|
||||
if success and stdout.strip() == '200':
|
||||
return True, "服务正常响应"
|
||||
else:
|
||||
return False, "服务无响应 (HTTP: {})".format(stdout.strip())
|
||||
|
||||
def get_system_info(self):
|
||||
"""获取系统信息"""
|
||||
info = {}
|
||||
|
||||
# CPU使用率
|
||||
cmd = "top -bn1 | grep 'Cpu(s)' | awk '{print $2}' | cut -d'%' -f1"
|
||||
success, stdout, stderr = self.run_command(cmd)
|
||||
if success:
|
||||
info['cpu_usage'] = float(stdout.strip())
|
||||
|
||||
# 内存使用率
|
||||
cmd = "free | grep Mem | awk '{printf \"%.2f\", $3/$2 * 100.0}'"
|
||||
success, stdout, stderr = self.run_command(cmd)
|
||||
if success:
|
||||
info['memory_usage'] = float(stdout.strip())
|
||||
|
||||
# 磁盘使用率
|
||||
cmd = "df / | tail -1 | awk '{print $5}' | sed 's/%//'"
|
||||
success, stdout, stderr = self.run_command(cmd)
|
||||
if success:
|
||||
info['disk_usage'] = float(stdout.strip())
|
||||
|
||||
return info
|
||||
|
||||
def log_alert(self, message, level="WARNING"):
|
||||
"""记录告警信息"""
|
||||
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
alert_msg = f"[{timestamp}] [{level}] {message}"
|
||||
|
||||
logger.warning(alert_msg)
|
||||
|
||||
if self.config['enable_alerts']:
|
||||
try:
|
||||
with open(self.alert_file, 'a', encoding='utf-8') as f:
|
||||
f.write(alert_msg + '\n')
|
||||
except Exception as e:
|
||||
logger.error("写入告警文件失败: {}".format(e))
|
||||
|
||||
def restart_service(self):
|
||||
"""重启服务"""
|
||||
logger.info("尝试重启服务...")
|
||||
|
||||
# 停止服务
|
||||
cmd = f"cd {self.project_dir} && ./scripts/port_manager.sh stop"
|
||||
success, stdout, stderr = self.run_command(cmd)
|
||||
|
||||
if not success:
|
||||
logger.error("停止服务失败: {}".format(stderr))
|
||||
return False
|
||||
|
||||
time.sleep(2)
|
||||
|
||||
# 启动服务
|
||||
cmd = f"cd {self.project_dir} && ./scripts/port_manager.sh start"
|
||||
success, stdout, stderr = self.run_command(cmd)
|
||||
|
||||
if not success:
|
||||
logger.error("启动服务失败: {}".format(stderr))
|
||||
return False
|
||||
|
||||
logger.info("服务重启成功")
|
||||
return True
|
||||
|
||||
def generate_report(self):
|
||||
"""生成监控报告"""
|
||||
report = {
|
||||
"timestamp": datetime.now().isoformat(),
|
||||
"port_usage": {},
|
||||
"gunicorn_status": {},
|
||||
"service_response": {},
|
||||
"system_info": {},
|
||||
"recommendations": []
|
||||
}
|
||||
|
||||
# 检查端口占用
|
||||
port_occupied, processes = self.check_port_usage()
|
||||
report["port_usage"] = {
|
||||
"occupied": port_occupied,
|
||||
"processes": processes
|
||||
}
|
||||
|
||||
# 检查Gunicorn进程
|
||||
gunicorn_running, status = self.check_gunicorn_process()
|
||||
report["gunicorn_status"] = {
|
||||
"running": gunicorn_running,
|
||||
"status": status
|
||||
}
|
||||
|
||||
# 检查服务响应
|
||||
service_ok, response = self.check_service_response()
|
||||
report["service_response"] = {
|
||||
"ok": service_ok,
|
||||
"response": response
|
||||
}
|
||||
|
||||
# 获取系统信息
|
||||
report["system_info"] = self.get_system_info()
|
||||
|
||||
# 生成建议
|
||||
if not port_occupied:
|
||||
report["recommendations"].append("端口未被占用,可能需要启动服务")
|
||||
|
||||
if not gunicorn_running:
|
||||
report["recommendations"].append("Gunicorn进程未运行,需要重启服务")
|
||||
|
||||
if not service_ok:
|
||||
report["recommendations"].append("服务无响应,需要检查服务状态")
|
||||
|
||||
# 检查系统资源
|
||||
sys_info = report["system_info"]
|
||||
if sys_info.get('cpu_usage', 0) > 80:
|
||||
report["recommendations"].append("CPU使用率过高,建议优化或扩容")
|
||||
|
||||
if sys_info.get('memory_usage', 0) > 90:
|
||||
report["recommendations"].append("内存使用率过高,建议增加内存或优化应用")
|
||||
|
||||
if sys_info.get('disk_usage', 0) > 85:
|
||||
report["recommendations"].append("磁盘使用率过高,建议清理日志或扩容")
|
||||
|
||||
return report
|
||||
|
||||
def monitor_loop(self):
|
||||
"""监控主循环"""
|
||||
logger.info("开始端口监控...")
|
||||
|
||||
restart_count = 0
|
||||
last_restart_time = 0
|
||||
|
||||
while True:
|
||||
try:
|
||||
# 生成报告
|
||||
report = self.generate_report()
|
||||
|
||||
# 检查是否需要重启
|
||||
need_restart = False
|
||||
|
||||
if not report["gunicorn_status"]["running"]:
|
||||
logger.warning("Gunicorn进程未运行")
|
||||
need_restart = True
|
||||
|
||||
if not report["service_response"]["ok"]:
|
||||
logger.warning("服务无响应")
|
||||
need_restart = True
|
||||
|
||||
# 执行重启
|
||||
if need_restart and self.config['auto_restart']:
|
||||
current_time = time.time()
|
||||
|
||||
# 检查重启限制
|
||||
if (current_time - last_restart_time > 300 and # 5分钟内不重复重启
|
||||
restart_count < self.config['max_restart_attempts']):
|
||||
|
||||
self.log_alert("检测到服务异常,尝试自动重启")
|
||||
|
||||
if self.restart_service():
|
||||
restart_count += 1
|
||||
last_restart_time = current_time
|
||||
else:
|
||||
self.log_alert("自动重启失败", "ERROR")
|
||||
else:
|
||||
self.log_alert("达到重启限制,跳过自动重启", "ERROR")
|
||||
|
||||
# 记录状态
|
||||
status_msg = f"端口占用: {report['port_usage']['occupied']}, " \
|
||||
f"Gunicorn: {report['gunicorn_status']['running']}, " \
|
||||
f"服务响应: {report['service_response']['ok']}"
|
||||
logger.info(status_msg)
|
||||
|
||||
# 等待下次检查
|
||||
time.sleep(self.config['check_interval'])
|
||||
|
||||
except KeyboardInterrupt:
|
||||
logger.info("监控被用户中断")
|
||||
break
|
||||
except Exception as e:
|
||||
logger.error(f"监控过程中发生错误: {e}")
|
||||
time.sleep(self.config['check_interval'])
|
||||
|
||||
def show_status(self):
|
||||
"""显示当前状态"""
|
||||
report = self.generate_report()
|
||||
|
||||
print("=== Flask应用监控状态 ===")
|
||||
print(f"检查时间: {report['timestamp']}")
|
||||
print()
|
||||
|
||||
print("1. 端口占用检查:")
|
||||
if report['port_usage']['occupied']:
|
||||
print(f" ✅ 端口 {PORT} 被占用")
|
||||
print(f" 进程: {', '.join(report['port_usage']['processes'])}")
|
||||
else:
|
||||
print(f" ❌ 端口 {PORT} 未被占用")
|
||||
|
||||
print()
|
||||
print("2. Gunicorn进程检查:")
|
||||
if report['gunicorn_status']['running']:
|
||||
print(f" ✅ {report['gunicorn_status']['status']}")
|
||||
else:
|
||||
print(f" ❌ {report['gunicorn_status']['status']}")
|
||||
|
||||
print()
|
||||
print("3. 服务响应检查:")
|
||||
if report['service_response']['ok']:
|
||||
print(f" ✅ {report['service_response']['response']}")
|
||||
else:
|
||||
print(f" ❌ {report['service_response']['response']}")
|
||||
|
||||
print()
|
||||
print("4. 系统资源:")
|
||||
sys_info = report['system_info']
|
||||
print(f" CPU使用率: {sys_info.get('cpu_usage', 'N/A')}%")
|
||||
print(f" 内存使用率: {sys_info.get('memory_usage', 'N/A')}%")
|
||||
print(f" 磁盘使用率: {sys_info.get('disk_usage', 'N/A')}%")
|
||||
|
||||
if report['recommendations']:
|
||||
print()
|
||||
print("5. 建议:")
|
||||
for i, rec in enumerate(report['recommendations'], 1):
|
||||
print(f" {i}. {rec}")
|
||||
|
||||
def main():
|
||||
monitor = PortMonitor()
|
||||
|
||||
if len(sys.argv) > 1:
|
||||
command = sys.argv[1]
|
||||
|
||||
if command == "status":
|
||||
monitor.show_status()
|
||||
elif command == "report":
|
||||
report = monitor.generate_report()
|
||||
print(json.dumps(report, indent=2, ensure_ascii=False))
|
||||
elif command == "restart":
|
||||
monitor.restart_service()
|
||||
elif command == "monitor":
|
||||
monitor.monitor_loop()
|
||||
elif command == "config":
|
||||
print(json.dumps(monitor.config, indent=2, ensure_ascii=False))
|
||||
else:
|
||||
print("用法: python port_monitor.py [status|report|restart|monitor|config]")
|
||||
else:
|
||||
monitor.monitor_loop()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -23,6 +23,7 @@
|
||||
--dark-color: #5a5c69;
|
||||
--light-color: #f8f9fc;
|
||||
--sidebar-width: 250px;
|
||||
--sidebar-collapsed-width: 70px;
|
||||
--header-height: 70px;
|
||||
}
|
||||
|
||||
@@ -46,6 +47,29 @@
|
||||
box-shadow: 4px 0 10px rgba(0,0,0,0.1);
|
||||
z-index: 1000;
|
||||
transition: all 0.3s ease;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.sidebar.collapsed {
|
||||
width: var(--sidebar-collapsed-width);
|
||||
}
|
||||
|
||||
.sidebar.collapsed .sidebar-brand-text {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.sidebar.collapsed .sidebar-link-text {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.sidebar.collapsed .sidebar-link {
|
||||
justify-content: center;
|
||||
padding: 0.75rem 0.5rem;
|
||||
}
|
||||
|
||||
.sidebar.collapsed .sidebar-icon {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.sidebar-header {
|
||||
@@ -111,6 +135,10 @@
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.main-content.sidebar-collapsed {
|
||||
margin-left: var(--sidebar-collapsed-width);
|
||||
}
|
||||
|
||||
/* 顶部导航栏 */
|
||||
.top-navbar {
|
||||
background: white;
|
||||
@@ -124,6 +152,67 @@
|
||||
z-index: 999;
|
||||
}
|
||||
|
||||
.navbar-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.sidebar-toggle {
|
||||
background: none;
|
||||
border: none;
|
||||
font-size: 1.2rem;
|
||||
color: var(--dark-color);
|
||||
cursor: pointer;
|
||||
padding: 0.5rem;
|
||||
border-radius: 0.5rem;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.sidebar-toggle:hover {
|
||||
background: var(--light-color);
|
||||
color: var(--primary-color);
|
||||
}
|
||||
|
||||
/* 响应式设计 */
|
||||
@media (max-width: 768px) {
|
||||
.sidebar {
|
||||
transform: translateX(-100%);
|
||||
}
|
||||
|
||||
.sidebar.mobile-open {
|
||||
transform: translateX(0);
|
||||
}
|
||||
|
||||
.main-content {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.top-navbar {
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.page-title {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 576px) {
|
||||
.top-navbar {
|
||||
padding: 0.75rem;
|
||||
}
|
||||
|
||||
.user-menu {
|
||||
flex-direction: column;
|
||||
align-items: flex-end;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.user-info {
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
|
||||
.page-title {
|
||||
font-size: 1.5rem;
|
||||
font-weight: 600;
|
||||
@@ -395,6 +484,69 @@
|
||||
</style>
|
||||
|
||||
{% block head %}{% endblock %}
|
||||
|
||||
<!-- JavaScript -->
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const sidebar = document.querySelector('.sidebar');
|
||||
const mainContent = document.querySelector('.main-content');
|
||||
const sidebarToggle = document.getElementById('sidebarToggle');
|
||||
const isMobile = window.innerWidth <= 768;
|
||||
|
||||
// 初始化侧边栏状态
|
||||
let sidebarCollapsed = localStorage.getItem('sidebarCollapsed') === 'true';
|
||||
|
||||
if (sidebarCollapsed && !isMobile) {
|
||||
sidebar.classList.add('collapsed');
|
||||
mainContent.classList.add('sidebar-collapsed');
|
||||
}
|
||||
|
||||
// 切换侧边栏
|
||||
function toggleSidebar() {
|
||||
if (isMobile) {
|
||||
// 移动端:显示/隐藏侧边栏
|
||||
sidebar.classList.toggle('mobile-open');
|
||||
} else {
|
||||
// 桌面端:折叠/展开侧边栏
|
||||
sidebar.classList.toggle('collapsed');
|
||||
mainContent.classList.toggle('sidebar-collapsed');
|
||||
sidebarCollapsed = sidebar.classList.contains('collapsed');
|
||||
localStorage.setItem('sidebarCollapsed', sidebarCollapsed);
|
||||
}
|
||||
}
|
||||
|
||||
// 绑定点击事件
|
||||
sidebarToggle.addEventListener('click', toggleSidebar);
|
||||
|
||||
// 移动端点击遮罩关闭侧边栏
|
||||
if (isMobile) {
|
||||
mainContent.addEventListener('click', function() {
|
||||
if (sidebar.classList.contains('mobile-open')) {
|
||||
sidebar.classList.remove('mobile-open');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 响应式处理
|
||||
window.addEventListener('resize', function() {
|
||||
const newIsMobile = window.innerWidth <= 768;
|
||||
if (newIsMobile !== isMobile) {
|
||||
// 屏幕尺寸改变时重新加载页面
|
||||
window.location.reload();
|
||||
}
|
||||
});
|
||||
|
||||
// 侧边栏链接点击后自动关闭移动端侧边栏
|
||||
if (isMobile) {
|
||||
const sidebarLinks = document.querySelectorAll('.sidebar-link');
|
||||
sidebarLinks.forEach(link => {
|
||||
link.addEventListener('click', function() {
|
||||
sidebar.classList.remove('mobile-open');
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<!-- 侧边栏 -->
|
||||
@@ -402,7 +554,7 @@
|
||||
<div class="sidebar-header">
|
||||
<a href="{{ url_for('admin.index') }}" class="sidebar-brand">
|
||||
<i class="fas fa-magic me-2"></i>
|
||||
提示词大师
|
||||
<span class="sidebar-brand-text">提示词大师</span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@@ -410,77 +562,77 @@
|
||||
<div class="sidebar-item">
|
||||
<a href="{{ url_for('admin.index') }}" class="sidebar-link {% if request.endpoint == 'admin.index' %}active{% endif %}">
|
||||
<i class="fas fa-tachometer-alt sidebar-icon"></i>
|
||||
仪表板
|
||||
<span class="sidebar-link-text">仪表板</span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="sidebar-item">
|
||||
<a href="{{ url_for('admin_user.index_view') }}" class="sidebar-link {% if 'admin_user' in request.endpoint %}active{% endif %}">
|
||||
<i class="fas fa-users sidebar-icon"></i>
|
||||
用户管理
|
||||
<span class="sidebar-link-text">用户管理</span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="sidebar-item">
|
||||
<a href="{{ url_for('admin_prompt.index_view') }}" class="sidebar-link {% if 'admin_prompt' in request.endpoint %}active{% endif %}">
|
||||
<i class="fas fa-magic sidebar-icon"></i>
|
||||
提示词管理
|
||||
<span class="sidebar-link-text">提示词管理</span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="sidebar-item">
|
||||
<a href="{{ url_for('admin_template.index_view') }}" class="sidebar-link {% if 'admin_template' in request.endpoint %}active{% endif %}">
|
||||
<i class="fas fa-clipboard-list sidebar-icon"></i>
|
||||
模板管理
|
||||
<span class="sidebar-link-text">模板管理</span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="sidebar-item">
|
||||
<a href="{{ url_for('analytics_admin.index') }}" class="sidebar-link {% if 'analytics_admin' in request.endpoint %}active{% endif %}">
|
||||
<i class="fas fa-chart-line sidebar-icon"></i>
|
||||
数据分析
|
||||
<span class="sidebar-link-text">数据分析</span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="sidebar-item">
|
||||
<a href="{{ url_for('batch_admin.index') }}" class="sidebar-link {% if 'batch_admin' in request.endpoint %}active{% endif %}">
|
||||
<i class="fas fa-tasks sidebar-icon"></i>
|
||||
批量操作
|
||||
<span class="sidebar-link-text">批量操作</span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="sidebar-item">
|
||||
<a href="{{ url_for('monitor_admin.index') }}" class="sidebar-link {% if 'monitor_admin' in request.endpoint %}active{% endif %}">
|
||||
<i class="fas fa-tachometer-alt sidebar-icon"></i>
|
||||
系统监控
|
||||
<span class="sidebar-link-text">系统监控</span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="sidebar-item">
|
||||
<a href="{{ url_for('report_admin.index') }}" class="sidebar-link {% if 'report_admin' in request.endpoint %}active{% endif %}">
|
||||
<i class="fas fa-chart-bar sidebar-icon"></i>
|
||||
高级报表
|
||||
<span class="sidebar-link-text">高级报表</span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="sidebar-item">
|
||||
<a href="{{ url_for('backup_admin.index') }}" class="sidebar-link {% if 'backup_admin' in request.endpoint %}active{% endif %}">
|
||||
<i class="fas fa-database sidebar-icon"></i>
|
||||
数据备份
|
||||
<span class="sidebar-link-text">数据备份</span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="sidebar-item">
|
||||
<a href="{{ url_for('api_admin.index') }}" class="sidebar-link {% if 'api_admin' in request.endpoint %}active{% endif %}">
|
||||
<i class="fas fa-code sidebar-icon"></i>
|
||||
API管理
|
||||
<span class="sidebar-link-text">API管理</span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="sidebar-item">
|
||||
<a href="{{ url_for('admin_system.index') }}" class="sidebar-link {% if 'admin_system' in request.endpoint %}active{% endif %}">
|
||||
<i class="fas fa-cogs sidebar-icon"></i>
|
||||
系统管理
|
||||
<span class="sidebar-link-text">系统管理</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
@@ -490,9 +642,14 @@
|
||||
<div class="main-content">
|
||||
<!-- 顶部导航栏 -->
|
||||
<header class="top-navbar">
|
||||
<h1 class="page-title">
|
||||
{% block page_title %}{% endblock %}
|
||||
</h1>
|
||||
<div class="navbar-left">
|
||||
<button class="sidebar-toggle" id="sidebarToggle">
|
||||
<i class="fas fa-bars"></i>
|
||||
</button>
|
||||
<h1 class="page-title">
|
||||
{% block page_title %}{% endblock %}
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
<div class="user-menu">
|
||||
<div class="user-info">
|
||||
|
||||
Reference in New Issue
Block a user