feat: initial commit - lightweight ticket system with Flask+SQLite

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
This commit is contained in:
AI Agent
2026-07-02 15:31:27 +08:00
commit 26940c4574
14 changed files with 2497 additions and 0 deletions
+236
View File
@@ -0,0 +1,236 @@
# 工单系统 (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