26940c4574
Features: - User authentication (login/register) - Ticket CRUD with status/priority/category - Rich text description with paste-to-image - File attachment upload (images/documents) - Multi-select CC recipients - Role-based permission control (admin/user) - In-app notifications - Statistics dashboard - Gunicorn production deployment
237 lines
6.5 KiB
Markdown
237 lines
6.5 KiB
Markdown
# 工单系统 (Ticket System)
|
||
|
||
轻量级工单系统,基于 Flask + SQLite,适合个人或小团队使用。
|
||
|
||
## 功能特性
|
||
|
||
### 工单管理
|
||
- 创建、编辑、删除、关闭工单
|
||
- 状态流转:新建 → 进行中 → 待处理 → 已完成 → 已关闭
|
||
- 分类管理:技术故障、功能需求、咨询、事件处理、其他
|
||
- 优先级设置:低、中、高、紧急
|
||
- 自由标签支持
|
||
|
||
### 富文本描述
|
||
- **内容可编辑**:contenteditable 富文本编辑器
|
||
- **图片内联显示**:支持 Ctrl+V 粘贴截图,图片直接嵌入描述中
|
||
- **插入图片按钮**:📎 点击选择图片上传
|
||
- **基础格式**:支持加粗、斜体
|
||
- **粘贴上传**:粘贴的图片会自动上传到服务器
|
||
|
||
### 附件管理
|
||
- 支持多种文件类型:图片、文档、压缩包等
|
||
- 最大文件大小:20 MB
|
||
- 图片预览:支持点击放大查看
|
||
- 附件下载:点击即可下载
|
||
|
||
### 用户系统
|
||
- 用户注册、登录、登出
|
||
- 默认管理员账号:`admin / admin`
|
||
- 密码安全存储(哈希)
|
||
|
||
### 权限控制
|
||
- **管理员**:可查看所有工单
|
||
- **普通用户**:只能查看自己参与(提交人/处理人/抄送人)的工单
|
||
- 无权限访问时返回 403 错误
|
||
|
||
### 抄送功能
|
||
- 支持多选抄送人
|
||
- 自定义下拉选择器
|
||
- 抄送人自动收到通知
|
||
- 抄送人可查看工单和附件
|
||
|
||
### 通知系统
|
||
- 站内通知:工单分配、评论、关闭等操作自动通知相关人员
|
||
- 未读角标:导航栏显示未读通知数量
|
||
- 通知列表:可查看通知详情
|
||
|
||
### 统计看板
|
||
- 工单总数统计
|
||
- 按状态、优先级、分类聚合
|
||
- 最近工单列表
|
||
- 我的工单计数
|
||
|
||
## 技术栈
|
||
|
||
- **后端**:Flask + SQLAlchemy
|
||
- **数据库**:SQLite
|
||
- **前端**:Jinja2 模板 + 原生 JavaScript
|
||
- **部署**:Gunicorn + systemd
|
||
|
||
## 快速开始
|
||
|
||
### 安装依赖
|
||
```bash
|
||
pip install -r requirements.txt --break-system-packages
|
||
```
|
||
|
||
### 启动开发服务器
|
||
```bash
|
||
python app.py
|
||
```
|
||
|
||
### 启动生产服务器
|
||
```bash
|
||
gunicorn --workers 2 --bind 0.0.0.0:5000 wsgi:app
|
||
```
|
||
|
||
### 访问系统
|
||
打开浏览器访问:`http://localhost:5000`
|
||
|
||
默认管理员账号:
|
||
- 用户名:`admin`
|
||
- 密码:`admin`
|
||
|
||
## 项目结构
|
||
|
||
```
|
||
ticket-system/
|
||
├── app.py # Flask 主程序(模型 + 路由)
|
||
├── wsgi.py # Gunicorn WSGI 入口
|
||
├── requirements.txt # 依赖列表
|
||
├── README.md # 项目说明
|
||
├── instance/
|
||
│ └── tickets.db # SQLite 数据库(自动创建)
|
||
├── uploads/ # 上传文件目录
|
||
│ └── <ticket_id>/ # 每个工单独立的附件目录
|
||
├── templates/ # Jinja2 模板
|
||
│ ├── base.html # 基础布局模板
|
||
│ ├── login.html # 登录页
|
||
│ ├── register.html # 注册页
|
||
│ ├── dashboard.html # 统计看板
|
||
│ ├── ticket_list.html # 工单列表
|
||
│ ├── ticket_form.html # 新建/编辑工单
|
||
│ ├── ticket_detail.html # 工单详情
|
||
│ ├── notifications.html # 通知列表
|
||
│ └── error.html # 错误页
|
||
└── static/
|
||
└── style.css # 样式文件
|
||
```
|
||
|
||
## 数据模型
|
||
|
||
### User(用户)
|
||
| 字段 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| id | Integer | 主键 |
|
||
| username | String(80) | 用户名(唯一) |
|
||
| password_hash | String(200) | 密码哈希 |
|
||
| role | String(20) | 角色(admin/user) |
|
||
| created_at | DateTime | 创建时间 |
|
||
|
||
### Ticket(工单)
|
||
| 字段 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| id | Integer | 主键 |
|
||
| title | String(200) | 标题 |
|
||
| description | Text | 描述(支持 HTML) |
|
||
| status | String(20) | 状态 |
|
||
| priority | String(20) | 优先级 |
|
||
| category | String(20) | 分类 |
|
||
| assignee | String(100) | 处理人 |
|
||
| requester | String(100) | 提交人 |
|
||
| cc_users | String(500) | 抄送人(逗号分隔) |
|
||
| tags | String(500) | 标签(逗号分隔) |
|
||
| created_at | DateTime | 创建时间 |
|
||
| updated_at | DateTime | 更新时间 |
|
||
|
||
### Comment(评论)
|
||
| 字段 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| id | Integer | 主键 |
|
||
| ticket_id | Integer | 所属工单 |
|
||
| author | String(100) | 评论人 |
|
||
| content | Text | 评论内容 |
|
||
| created_at | DateTime | 创建时间 |
|
||
|
||
### Attachment(附件)
|
||
| 字段 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| id | Integer | 主键 |
|
||
| ticket_id | Integer | 所属工单 |
|
||
| filename | String(200) | 存储文件名(UUID) |
|
||
| original_name | String(300) | 原始文件名 |
|
||
| content_type | String(100) | MIME 类型 |
|
||
| size | Integer | 文件大小(字节) |
|
||
| is_image | Boolean | 是否为图片 |
|
||
| uploaded_by | String(100) | 上传人 |
|
||
| uploaded_at | DateTime | 上传时间 |
|
||
|
||
### Notification(通知)
|
||
| 字段 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| id | Integer | 主键 |
|
||
| user_id | Integer | 接收用户 |
|
||
| title | String(200) | 通知标题 |
|
||
| content | Text | 通知内容 |
|
||
| ticket_id | Integer | 关联工单 |
|
||
| read | Boolean | 是否已读 |
|
||
| created_at | DateTime | 创建时间 |
|
||
|
||
## 部署说明
|
||
|
||
### systemd 服务部署
|
||
|
||
1. 创建服务文件:`/etc/systemd/system/ticket-system.service`
|
||
|
||
```ini
|
||
[Unit]
|
||
Description=Ticket System
|
||
After=network.target
|
||
|
||
[Service]
|
||
Type=exec
|
||
WorkingDirectory=/path/to/ticket-system
|
||
Environment="PATH=/usr/local/bin:/usr/bin:/bin"
|
||
Environment="PYTHONUNBUFFERED=1"
|
||
ExecStart=/usr/local/bin/gunicorn --workers 2 --bind 0.0.0.0:5000 --access-logfile /var/log/ticket-system/access.log --error-logfile /var/log/ticket-system/error.log wsgi:app
|
||
Restart=on-failure
|
||
RestartSec=5
|
||
|
||
[Install]
|
||
WantedBy=multi-user.target
|
||
```
|
||
|
||
2. 创建日志目录
|
||
```bash
|
||
mkdir -p /var/log/ticket-system
|
||
```
|
||
|
||
3. 启动服务
|
||
```bash
|
||
systemctl daemon-reload
|
||
systemctl enable --now ticket-system
|
||
systemctl status ticket-system
|
||
```
|
||
|
||
### Nginx 反向代理(可选)
|
||
|
||
```nginx
|
||
server {
|
||
listen 80;
|
||
server_name ticket.example.com;
|
||
|
||
location / {
|
||
proxy_pass http://127.0.0.1:5000;
|
||
proxy_set_header Host $host;
|
||
proxy_set_header X-Real-IP $remote_addr;
|
||
}
|
||
|
||
location /uploads/ {
|
||
alias /path/to/ticket-system/uploads/;
|
||
}
|
||
}
|
||
```
|
||
|
||
## 注意事项
|
||
|
||
1. **首次启动**:会自动创建默认管理员账号(admin/admin)
|
||
2. **数据库迁移**:新增字段需要手动添加到 SQLite 数据库
|
||
3. **文件上传**:需要确保 `uploads/` 目录存在且可写
|
||
4. **安全配置**:生产环境请修改 `SECRET_KEY` 和默认管理员密码
|
||
5. **最大上传大小**:默认 20 MB,可在 `app.py` 中修改 `MAX_CONTENT_LENGTH`
|
||
|
||
## 许可证
|
||
|
||
MIT License
|