|
|
|
|
@ -16,112 +16,181 @@ from django.views.decorators.csrf import csrf_exempt
|
|
|
|
|
|
|
|
|
|
from .models import OwnTrackLog
|
|
|
|
|
|
|
|
|
|
# 获取logger实例,用于记录日志
|
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 处理OwnTracks位置数据的POST请求,不需要CSRF验证
|
|
|
|
|
@csrf_exempt
|
|
|
|
|
def manage_owntrack_log(request):
|
|
|
|
|
"""
|
|
|
|
|
接收并存储OwnTracks移动端发送的位置数据
|
|
|
|
|
支持格式:JSON格式的位置信息,包含tid(设备ID)、lat(纬度)、lon(经度)
|
|
|
|
|
"""
|
|
|
|
|
try:
|
|
|
|
|
# 解析请求中的JSON数据
|
|
|
|
|
s = json.loads(request.read().decode('utf-8'))
|
|
|
|
|
tid = s['tid']
|
|
|
|
|
lat = s['lat']
|
|
|
|
|
lon = s['lon']
|
|
|
|
|
tid = s['tid'] # 设备标识符
|
|
|
|
|
lat = s['lat'] # 纬度
|
|
|
|
|
lon = s['lon'] # 经度
|
|
|
|
|
|
|
|
|
|
# 记录接收到的位置信息日志
|
|
|
|
|
logger.info(
|
|
|
|
|
'tid:{tid}.lat:{lat}.lon:{lon}'.format(
|
|
|
|
|
tid=tid, lat=lat, lon=lon))
|
|
|
|
|
|
|
|
|
|
# 验证必需字段是否存在
|
|
|
|
|
if tid and lat and lon:
|
|
|
|
|
# 创建新的位置记录对象
|
|
|
|
|
m = OwnTrackLog()
|
|
|
|
|
m.tid = tid
|
|
|
|
|
m.lat = lat
|
|
|
|
|
m.lon = lon
|
|
|
|
|
m.save()
|
|
|
|
|
return HttpResponse('ok')
|
|
|
|
|
m.save() # 保存到数据库
|
|
|
|
|
return HttpResponse('ok') # 返回成功响应
|
|
|
|
|
else:
|
|
|
|
|
return HttpResponse('data error')
|
|
|
|
|
return HttpResponse('data error') # 数据不完整错误
|
|
|
|
|
except Exception as e:
|
|
|
|
|
# 记录异常信息
|
|
|
|
|
logger.error(e)
|
|
|
|
|
return HttpResponse('error')
|
|
|
|
|
return HttpResponse('error') # 返回错误响应
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 显示地图页面,需要用户登录
|
|
|
|
|
@login_required
|
|
|
|
|
def show_maps(request):
|
|
|
|
|
"""
|
|
|
|
|
显示位置轨迹地图页面
|
|
|
|
|
仅超级用户可以访问,支持按日期筛选显示轨迹
|
|
|
|
|
"""
|
|
|
|
|
if request.user.is_superuser:
|
|
|
|
|
# 设置默认日期为当前UTC日期
|
|
|
|
|
defaultdate = str(datetime.datetime.now(timezone.utc).date())
|
|
|
|
|
# 从GET参数获取日期,如未提供则使用默认日期
|
|
|
|
|
date = request.GET.get('date', defaultdate)
|
|
|
|
|
context = {
|
|
|
|
|
'date': date
|
|
|
|
|
}
|
|
|
|
|
# 渲染地图显示页面
|
|
|
|
|
return render(request, 'owntracks/show_maps.html', context)
|
|
|
|
|
else:
|
|
|
|
|
# 非超级用户返回403禁止访问
|
|
|
|
|
from django.http import HttpResponseForbidden
|
|
|
|
|
return HttpResponseForbidden()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 显示有位置记录的日期列表,需要用户登录
|
|
|
|
|
@login_required
|
|
|
|
|
def show_log_dates(request):
|
|
|
|
|
"""
|
|
|
|
|
获取所有有位置记录的日期列表
|
|
|
|
|
用于在地图页面中选择查看特定日期的轨迹
|
|
|
|
|
"""
|
|
|
|
|
# 从数据库获取所有记录的时间戳
|
|
|
|
|
dates = OwnTrackLog.objects.values_list('creation_time', flat=True)
|
|
|
|
|
# 提取日期部分,去重并排序
|
|
|
|
|
results = list(sorted(set(map(lambda x: x.strftime('%Y-%m-%d'), dates))))
|
|
|
|
|
|
|
|
|
|
context = {
|
|
|
|
|
'results': results
|
|
|
|
|
'results': results # 日期列表
|
|
|
|
|
}
|
|
|
|
|
# 渲染日期列表页面
|
|
|
|
|
return render(request, 'owntracks/show_log_dates.html', context)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def convert_to_amap(locations):
|
|
|
|
|
"""
|
|
|
|
|
将GPS坐标批量转换为高德地图坐标
|
|
|
|
|
由于高德API限制,每次最多转换30个坐标点
|
|
|
|
|
|
|
|
|
|
参数:
|
|
|
|
|
locations: OwnTrackLog对象的查询集
|
|
|
|
|
|
|
|
|
|
返回:
|
|
|
|
|
转换后的坐标字符串,格式为"经度,纬度;经度,纬度;..."
|
|
|
|
|
"""
|
|
|
|
|
convert_result = []
|
|
|
|
|
# 创建迭代器用于分批处理
|
|
|
|
|
it = iter(locations)
|
|
|
|
|
|
|
|
|
|
# 每次处理30个坐标点
|
|
|
|
|
item = list(itertools.islice(it, 30))
|
|
|
|
|
while item:
|
|
|
|
|
# 将坐标格式化为高德API要求的格式
|
|
|
|
|
datas = ';'.join(
|
|
|
|
|
set(map(lambda x: str(x.lon) + ',' + str(x.lat), item)))
|
|
|
|
|
|
|
|
|
|
# 高德地图API密钥
|
|
|
|
|
key = '8440a376dfc9743d8924bf0ad141f28e'
|
|
|
|
|
api = 'http://restapi.amap.com/v3/assistant/coordinate/convert'
|
|
|
|
|
query = {
|
|
|
|
|
'key': key,
|
|
|
|
|
'locations': datas,
|
|
|
|
|
'coordsys': 'gps'
|
|
|
|
|
'locations': datas, # 要转换的坐标
|
|
|
|
|
'coordsys': 'gps' # 源坐标系为GPS
|
|
|
|
|
}
|
|
|
|
|
# 调用高德坐标转换API
|
|
|
|
|
rsp = requests.get(url=api, params=query)
|
|
|
|
|
result = json.loads(rsp.text)
|
|
|
|
|
if "locations" in result:
|
|
|
|
|
convert_result.append(result['locations'])
|
|
|
|
|
item = list(itertools.islice(it, 30))
|
|
|
|
|
convert_result.append(result['locations']) # 添加转换结果
|
|
|
|
|
item = list(itertools.islice(it, 30)) # 获取下一批坐标
|
|
|
|
|
|
|
|
|
|
# 合并所有批次的转换结果
|
|
|
|
|
return ";".join(convert_result)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 获取特定日期的位置数据,需要用户登录
|
|
|
|
|
@login_required
|
|
|
|
|
def get_datas(request):
|
|
|
|
|
"""
|
|
|
|
|
根据日期参数获取该日期所有设备的位置轨迹数据
|
|
|
|
|
返回JSON格式,包含每个设备的轨迹路径
|
|
|
|
|
|
|
|
|
|
支持两种坐标格式:
|
|
|
|
|
1. 原始GPS坐标(当前使用)
|
|
|
|
|
2. 高德转换坐标(注释状态)
|
|
|
|
|
"""
|
|
|
|
|
# 设置默认查询时间为当前日期的开始时间(UTC)
|
|
|
|
|
now = django.utils.timezone.now().replace(tzinfo=timezone.utc)
|
|
|
|
|
querydate = django.utils.timezone.datetime(
|
|
|
|
|
now.year, now.month, now.day, 0, 0, 0)
|
|
|
|
|
|
|
|
|
|
# 如果提供了日期参数,解析并设置查询日期
|
|
|
|
|
if request.GET.get('date', None):
|
|
|
|
|
date = list(map(lambda x: int(x), request.GET.get('date').split('-')))
|
|
|
|
|
querydate = django.utils.timezone.datetime(
|
|
|
|
|
date[0], date[1], date[2], 0, 0, 0)
|
|
|
|
|
|
|
|
|
|
# 查询日期范围:从查询日期的00:00到次日00:00
|
|
|
|
|
nextdate = querydate + datetime.timedelta(days=1)
|
|
|
|
|
|
|
|
|
|
# 获取该日期范围内的所有位置记录
|
|
|
|
|
models = OwnTrackLog.objects.filter(
|
|
|
|
|
creation_time__range=(querydate, nextdate))
|
|
|
|
|
|
|
|
|
|
result = list()
|
|
|
|
|
if models and len(models):
|
|
|
|
|
# 按设备ID分组处理
|
|
|
|
|
for tid, item in groupby(
|
|
|
|
|
sorted(models, key=lambda k: k.tid), key=lambda k: k.tid):
|
|
|
|
|
|
|
|
|
|
d = dict()
|
|
|
|
|
d["name"] = tid
|
|
|
|
|
d["name"] = tid # 设备ID作为轨迹名称
|
|
|
|
|
|
|
|
|
|
paths = list()
|
|
|
|
|
# 使用高德转换后的经纬度
|
|
|
|
|
|
|
|
|
|
# 使用高德转换后的经纬度(当前注释掉,使用原始GPS坐标)
|
|
|
|
|
# locations = convert_to_amap(
|
|
|
|
|
# sorted(item, key=lambda x: x.creation_time))
|
|
|
|
|
# for i in locations.split(';'):
|
|
|
|
|
# paths.append(i.split(','))
|
|
|
|
|
# 使用GPS原始经纬度
|
|
|
|
|
|
|
|
|
|
# 使用GPS原始经纬度,按时间排序
|
|
|
|
|
for location in sorted(item, key=lambda x: x.creation_time):
|
|
|
|
|
paths.append([str(location.lon), str(location.lat)])
|
|
|
|
|
d["path"] = paths
|
|
|
|
|
result.append(d)
|
|
|
|
|
return JsonResponse(result, safe=False)
|
|
|
|
|
|
|
|
|
|
d["path"] = paths # 设备的轨迹路径
|
|
|
|
|
result.append(d) # 添加到结果列表
|
|
|
|
|
|
|
|
|
|
# 返回JSON格式的轨迹数据
|
|
|
|
|
return JsonResponse(result, safe=False)
|