从零搭建招投标管理平台:技术路线、实战经验与优化思考
从零搭建招投标管理平台:技术路线、实战经验与优化思考
作者:Eddygit
日期:2026-10-14
标签:Flask、SQLite、全栈开发、招投标系统、CodeArts
一、为什么选择这个项目
招投标管理是政企信息化中的常见需求。市面上的招投标系统往往体量庞大、部署复杂,对于中小型采购场景来说"杀鸡用牛刀"。本项目旨在打造一个轻量级、零部署成本、开箱即用的招投标管理小工具,覆盖项目发布、投标管理、评审打分、统计分析的核心闭环。
设计目标
| 目标 | 策略 |
|---|---|
| 轻量级 | Flask + SQLite,单文件数据库,无需额外服务 |
| 零配置 | 内置种子数据,启动即用 |
| 无前端框架 | 原生 HTML/CSS/JS,降低维护复杂度 |
| 响应式 | CSS Grid + Flex 布局,适配移动端 |
二、技术路线选型
2.1 后端:Flask 而非 Django
选择 Flask 而非 Django,核心考量是项目规模与框架重量的匹配度:
- 本项目路由约 10 个,模型 4 张表,Django 的 ORM/Admin/Middleware 体系属于过度设计
- Flask 的
before_request/teardown_request钩子足以管理数据库连接生命周期 - Jinja2 模板引擎 Flask 内置,无需额外配置
代价:没有 Django Admin 后台,CRUD 需手写。但对于"小工具"定位,这是可接受的取舍。
2.2 数据库:SQLite 而非 MySQL/PostgreSQL
| 维度 | SQLite | MySQL |
|---|---|---|
| 部署 | 零配置,单文件 | 需安装服务+配置 |
| 并发 | 写锁全库(适合读多写少) | 行级锁 |
| 运维 | 无 | 需备份/监控 |
招投标场景读远多于写(查看项目列表 vs 创建项目),SQLite 的写锁不构成瓶颈。若未来扩展到高并发写场景,可平滑迁移至 PostgreSQL(SQL 语法兼容性好)。
2.3 前端:原生三件套而非 Vue/React
这是一个有争议的选择。理由如下:
- 项目交互复杂度低 — 主要是表格展示 + 表单提交 + 模态框,无复杂状态管理需求
- 减少构建链 — 无需 webpack/vite,无需 node_modules,
python app.py即可运行 - 维护门槛低 — 后端开发者可直接维护前端,无需前端工程化知识
代价:如果后续需要增加复杂交互(如拖拽排序、实时图表),原生 JS 的开发效率会显著低于框架。这是一个有意识的技术债,需要在需求演进时重新评估。
三、实战经验
3.1 数据库连接管理
Flask 中管理 SQLite 连接的最佳实践是请求级连接:
@app.before_request
def before_request():
g.db = get_db()
@app.teardown_request
def teardown_request(exc):
db = getattr(g, 'db', None)
if db is not None:
db.close()
踩坑记录:最初用全局单例连接,并发请求下出现 SQLite objects created in a thread can only be used in that same thread 错误。改为请求级连接后问题消失。
3.2 Jinja2 全局函数注册
模板中需要将状态码转为中文显示(open → 招标中)。最初用 @app.template_filter 注册过滤器,但模板中用函数调用语法 {{ status_text(p.status) }} 而非管道语法 {{ p.status | status_text }},导致 UndefinedError。
解决方案:直接注册到 app.jinja_env.globals 字典:
app.jinja_env.globals['status_text'] = status_text
这是 Flask 文档中不太显眼但很实用的 API。
3.3 评审加权计算
招投标评审通常采用综合评分法,权重分配是业务核心:
total = technical_score * 0.4 + price_score * 0.3 + business_score * 0.3
设计决策:权重硬编码在代码中而非数据库配置。理由是权重变更频率极低(通常由招标文件确定),放数据库反而增加查询开销和一致性维护成本。若未来需要灵活配置,可引入 settings 表。
3.4 种子数据策略
首次启动时自动插入示例数据,让用户立即看到系统效果而非空页面:
existing = c.execute('SELECT COUNT(*) as cnt FROM projects').fetchone()['cnt']
if existing == 0:
seed_data(c)
这是"小工具"定位的重要体验设计 — 降低首次使用的认知成本。
四、存在问题与优化空间
4.1 安全性不足
| 问题 | 风险 | 优化方向 |
|---|---|---|
| 无用户认证 | 任何人可访问所有功能 | 加入 Flask-Login + 角色权限 |
| SQLite 文件权限 | 数据库文件可直接下载 | 移至 web root 外或加密 |
| 无 CSRF 防护 | 表单可被跨站伪造 | 集成 Flask-WTF |
| debug=True | 生产环境暴露调试器 | 环境变量控制 |
4.2 功能扩展空间
- 文件附件 — 招标文件下载、投标文件上传(当前仅文本)
- 流程审批 — 多级审批流(提交→初审→终审→定标)
- 消息通知 — 截止日期提醒、评审结果通知
- 数据导出 — Excel/PDF 报表导出
- 图表可视化 — 用 ECharts 替代纯表格统计
4.3 性能优化
- 数据库索引 —
projects.status、bids.project_id等高频查询字段加索引 - 分页查询 — 项目列表当前全量返回,大数据量时需分页
- 查询优化 —
project_detail中 N+1 查询问题(每个 bid 查一次 evaluation),可改为 JOIN - 前端缓存 — 静态资源加 Cache-Control 头
4.4 代码质量
- 类型标注 — Python 3.12 支持 type hints,可引入 mypy 静态检查
- 单元测试 — 当前无测试覆盖,应补充 pytest 测试用例
- API 文档 — 可集成 Flask-RESTful + Swagger 自动生成 API 文档
- 日志体系 — 当前依赖 Flask 默认日志,应结构化日志 + 分级输出
五、CodeArts 开发体验
本项目在华为云 CodeArts 环境中开发,几点体验:
- 沙箱环境 — CodeArts 提供隔离的沙箱,Python/Node 环境预装,
pip install即可用 - 预览能力 — 通过端口转发可直接预览运行中的应用,无需额外配置
- GitCode 集成 — API v5 建仓 + token 嵌入 URL push,流程顺畅
- Skill 体系 — 发布作品 skill 封装了完整的发布流程,降低操作门槛
不足:沙箱中 hcloud CLI 未预装,发布到高校运营平台需要额外配置 IAM 凭证。
六、总结
这个招投标管理平台小工具验证了"合适的技术 > 先进的技术"这一原则。Flask + SQLite + 原生前端的组合,在"小工具"这个场景下:
- 开发效率高(半天完成全部功能)
- 部署成本低(
pip install + python app.py) - 维护门槛低(无框架版本升级负担)
当然,如果项目演进到企业级规模(多租户、高并发、复杂流程),技术栈需要重新选型。技术选型不是一锤子买卖,而是随需求演进不断校准的过程。
本文为原创技术博客,转载请注明出处:GitCode - Eddygit/bidding-management-platform
- 点赞
- 收藏
- 关注作者
评论(0)