# 工单系统 (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/ # 上传文件目录 │ └── / # 每个工单独立的附件目录 ├── 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