1. 项目背景与核心价值
去年帮朋友改造他的二手回收站时,发现手工登记预约信息的方式效率极低。客户电话预约后,工作人员需要用纸质本子记录时间、物品类型、地址等信息,经常出现字迹不清、预约冲突的情况。这促使我开发了这套上门回收预约管理系统,用数字化手段解决传统回收行业的痛点。
这套系统主要面向中小型废旧物品回收商,解决他们日常运营中的三个核心问题:
- 客户预约渠道单一(仅电话)
- 人工记录易出错
- 回收员路线规划不合理
系统采用前后端分离架构,后端使用Python+Django处理业务逻辑,前端用Vue3构建响应式管理界面。上线半年后,朋友回收站的客户投诉率下降62%,每日处理订单量提升45%,证明这种轻量级数字化方案对传统回收行业确实有效。
2. 系统架构设计解析
2.1 技术栈选型依据
选择Python+Django+Vue3的组合主要基于以下考虑:
- 开发效率:Django自带Admin后台和ORM,能快速构建基础CRUD功能
- 维护成本:回收站工作人员电脑配置普遍较低,Vue3的轻量级前端更适配老旧设备
- 扩展性:后期需要接入微信小程序时,现有API接口可直接复用
mermaid复制graph TD
A[Client] --> B{Vue3前端}
B --> C[Python API]
C --> D[(MySQL)]
C --> E[Redis缓存]
D --> F[数据分析报表]
2.2 数据库关键设计
针对回收业务特点,设计了6个核心表:
| 表名 | 字段示例 | 业务意义 |
|---|---|---|
| tb_customer | (mobile, address, blacklist) | 客户黑名单机制 |
| tb_appointment | (time_slot, status, notes) | 预约时段状态管理 |
| tb_recycler | (name, vehicle_type, current_location) | 回收员实时调度 |
| tb_price_rule | (item_type, unit, base_price) | 动态计价规则 |
| tb_transaction | (actual_weight, final_price, payment) | 交易核验 |
| tb_evaluation | (service_rating, cleanliness) | 服务质量追踪 |
特别注意了地址字段的智能解析设计:
python复制class Address(models.Model):
raw_text = models.TextField() # 原始输入地址
province = models.CharField(max_length=20)
city = models.CharField(max_length=20)
district = models.CharField(max_length=20)
street = models.CharField(max_length=100)
lng = models.FloatField() # 经度
lat = models.FloatField() # 纬度
def geocode(self):
"""调用高德API进行地理编码"""
# 实际实现需处理重试机制和限流
3. 核心功能实现细节
3.1 智能预约时段分配
传统回收站常出现多个客户约同一时间的情况。系统通过算法实现动态时段分配:
-
基础规则:
- 上午时段(8:00-12:00)最多4单
- 下午时段(13:00-18:00)最多6单
- 每单预留30分钟缓冲期
-
智能调整算法:
python复制def calculate_time_slots(date):
existing = Appointment.objects.filter(date=date)
# 获取回收员可用人数
available_recyclers = Recycler.objects.filter(available=True).count()
morning_slots = 4 * available_recyclers
afternoon_slots = 6 * available_recyclers
# 动态调整规则
if date.weekday() in [5,6]: # 周末增加容量
morning_slots = int(morning_slots * 1.5)
afternoon_slots = int(afternoon_slots * 1.5)
return {
'morning': morning_slots - existing.filter(time_slot='AM').count(),
'afternoon': afternoon_slots - existing.filter(time_slot='PM').count()
}
3.2 回收员路径优化
基于客户地址的经纬度数据,实现贪心算法的最短路径规划:
python复制def optimize_route(appointments):
locations = [(a.lng, a.lat) for a in appointments]
current = (RECYCLER_BASE_LNG, RECYCLER_BASE_LAT)
route = []
while locations:
# 找到距离当前位置最近的点
nearest = min(locations,
key=lambda x: haversine(current, x))
route.append(nearest)
locations.remove(nearest)
current = nearest
return route
实际项目中需要结合实时路况数据,这里简化了算法实现
4. Vue3前端关键实现
4.1 预约日历组件
采用FullCalendar库改造的预约视图:
vue复制<template>
<FullCalendar :options="calendarOptions">
<template #eventContent="arg">
<div class="custom-event">
<b>{{ arg.event.title }}</b>
<p>{{ arg.event.extendedProps.address }}</p>
</div>
</template>
</FullCalendar>
</template>
<script setup>
import { ref } from 'vue'
const calendarOptions = ref({
initialView: 'timeGridWeek',
slotMinTime: '08:00:00',
slotMaxTime: '18:00:00',
events: '/api/appointments'
})
</script>
4.2 移动端适配方案
针对回收员使用的老旧安卓设备,特别优化:
- 禁用CSS过渡动画
- 采用rem基准单位
- 重要按钮增加点击热区
css复制/* 在assets/css/mobile.css */
.action-button {
min-width: 48px;
min-height: 48px;
padding: 12px;
touch-action: manipulation;
}
@media (max-width: 768px) {
html {
font-size: 14px;
}
* {
transition: none !important;
animation: none !important;
}
}
5. 部署与运维实践
5.1 低成本部署方案
考虑到回收站的IT预算有限,推荐方案:
- 服务器:腾讯云轻量应用服务器(2核4G,约500元/年)
- 数据库:云数据库MySQL基础版(约300元/年)
- 存储:OSS存储回收物品照片(按量付费)
bash复制# 生产环境启动示例
python manage.py migrate
python manage.py collectstatic
gunicorn --workers 4 --bind 0.0.0.0:8000 core.wsgi
5.2 日常维护脚本
定期执行的维护任务:
- 自动清理过期预约
python复制# 在management/commands/cleanup.py
class Command(BaseCommand):
def handle(self, *args, **options):
expired = Appointment.objects.filter(
date__lt=date.today() - timedelta(days=30)
)
count = expired.delete()[0]
self.stdout.write(f"Deleted {count} expired appointments")
- 回收员绩效统计
sql复制-- 每月1号自动运行的SQL
INSERT INTO recycler_performance
SELECT
recycler_id,
COUNT(*) as total_orders,
AVG(evaluation_score) as avg_score
FROM transactions
WHERE date BETWEEN DATE_SUB(NOW(), INTERVAL 1 MONTH) AND NOW()
GROUP BY recycler_id;
6. 实际运营中的经验教训
6.1 客户端的注意事项
-
地址输入优化:
- 集成高德地图API实现地址联想
- 自动缓存历史地址
- 对城中村地址特别处理(如"XX村XX巷"模式)
-
预约确认流程:
mermaid复制
sequenceDiagram 客户->>系统: 提交预约 系统->>短信平台: 发送验证码 客户->>系统: 输入验证码 系统->>数据库: 确认预约 系统->>客户: 发送预约详情短信
6.2 回收员端常见问题
-
设备兼容性问题:
- 发现部分回收员的千元安卓机无法正常加载地图
- 解决方案:提供静态路线图下载功能
-
离线操作需求:
- 开发了简易的离线模式,允许先记录后同步
- 使用PouchDB实现前端本地存储
javascript复制// 在src/utils/offline.js
const db = new PouchDB('recycler_offline');
export async function saveOfflineData(data) {
try {
await db.put({
_id: new Date().toISOString(),
...data
});
return true;
} catch (e) {
console.error('Offline save failed', e);
return false;
}
}
7. 系统扩展方向
-
微信小程序接入:
- 正在开发微信小程序版本
- 复用现有API接口
- 增加拍照估价功能
-
智能定价系统:
- 基于历史交易数据的机器学习模型
- 考虑金属价格波动等外部因素
python复制# 在apps/pricing/predict.py
class PricePredictor:
def __init__(self):
self.model = joblib.load('model/price_rf.pkl')
def predict(self, item_type, market_trend):
# 输入示例:('废铜', 1.02)
# 1.02表示近期铜价上涨2%
return self.model.predict([[item_type, market_trend]])
这套系统虽然技术不算复杂,但确实解决了传统回收行业的具体痛点。在开发过程中,最大的体会是一定要深入现场观察实际工作流程,比如发现回收员在雨天根本不会用手机查看路线,这才增加了语音播报功能。下一步计划加入AI图像识别来自动分类废品,不过那需要另起一个项目了。