|
|
|
|
@ -1,3 +1,4 @@
|
|
|
|
|
#gjl
|
|
|
|
|
# Create your views here.
|
|
|
|
|
import datetime
|
|
|
|
|
import itertools
|
|
|
|
|
@ -27,93 +28,93 @@ logger = logging.getLogger(__name__)
|
|
|
|
|
@csrf_exempt
|
|
|
|
|
def manage_owntrack_log(request):
|
|
|
|
|
try:
|
|
|
|
|
# 读取请求体的原始数据,并解码为 UTF-8 字符串,然后解析为 Python 字典
|
|
|
|
|
# gjl 读取请求体的原始数据,并解码为 UTF-8 字符串,然后解析为 Python 字典
|
|
|
|
|
s = json.loads(request.read().decode('utf-8'))
|
|
|
|
|
# 从解析后的数据中提取 tid(用户/设备标识)、lat(纬度)、lon(经度)
|
|
|
|
|
# gjl 从解析后的数据中提取 tid(用户/设备标识)、lat(纬度)、lon(经度)
|
|
|
|
|
tid = s['tid']
|
|
|
|
|
lat = s['lat']
|
|
|
|
|
lon = s['lon']
|
|
|
|
|
|
|
|
|
|
# 记录一条 INFO 级别的日志,包含接收到的位置信息
|
|
|
|
|
# gjl 记录一条 INFO 级别的日志,包含接收到的位置信息
|
|
|
|
|
logger.info(
|
|
|
|
|
'tid:{tid}.lat:{lat}.lon:{lon}'.format(
|
|
|
|
|
tid=tid, lat=lat, lon=lon))
|
|
|
|
|
|
|
|
|
|
# 验证提取的数据是否都存在(非空)
|
|
|
|
|
if tid and lat and lon:
|
|
|
|
|
# 创建一个新的 OwnTrackLog 模型实例
|
|
|
|
|
# gjl 创建一个新的 OwnTrackLog 模型实例
|
|
|
|
|
m = OwnTrackLog()
|
|
|
|
|
# 将接收到的数据赋值给模型字段
|
|
|
|
|
# gjl 将接收到的数据赋值给模型字段
|
|
|
|
|
m.tid = tid
|
|
|
|
|
m.lat = lat
|
|
|
|
|
m.lon = lon
|
|
|
|
|
# 保存到数据库(creation_time 会自动使用默认值 now)
|
|
|
|
|
# gjl 保存到数据库(creation_time 会自动使用默认值 now)
|
|
|
|
|
m.save()
|
|
|
|
|
# 返回 HTTP 响应 'ok',表示数据接收和保存成功
|
|
|
|
|
# gjl 返回 HTTP 响应 'ok',表示数据接收和保存成功
|
|
|
|
|
return HttpResponse('ok')
|
|
|
|
|
else:
|
|
|
|
|
# 如果数据不完整,返回 'data error'
|
|
|
|
|
# gjl 如果数据不完整,返回 'data error'
|
|
|
|
|
return HttpResponse('data error')
|
|
|
|
|
except Exception as e:
|
|
|
|
|
# 捕获任何异常,记录错误日志,并返回 'error' 响应
|
|
|
|
|
# gjl 捕获任何异常,记录错误日志,并返回 'error' 响应
|
|
|
|
|
logger.error(e)
|
|
|
|
|
return HttpResponse('error')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 视图函数:渲染显示地图的 HTML 页面
|
|
|
|
|
# 使用 @login_required 装饰器,确保只有登录用户才能访问
|
|
|
|
|
# gjl 视图函数:渲染显示地图的 HTML 页面
|
|
|
|
|
# gjl 使用 @login_required 装饰器,确保只有登录用户才能访问
|
|
|
|
|
@login_required
|
|
|
|
|
def show_maps(request):
|
|
|
|
|
# 进一步检查用户是否为超级用户(管理员)
|
|
|
|
|
# gjl 进一步检查用户是否为超级用户(管理员)
|
|
|
|
|
if request.user.is_superuser:
|
|
|
|
|
# 获取当前 UTC 日期,作为默认日期
|
|
|
|
|
# gjl 获取当前 UTC 日期,作为默认日期
|
|
|
|
|
defaultdate = str(datetime.datetime.now(timezone.utc).date())
|
|
|
|
|
# 从 GET 请求参数中获取 'date',如果不存在则使用默认日期
|
|
|
|
|
# gjl 从 GET 请求参数中获取 'date',如果不存在则使用默认日期
|
|
|
|
|
date = request.GET.get('date', defaultdate)
|
|
|
|
|
# 构造模板上下文,将日期传递给前端
|
|
|
|
|
# gjl 构造模板上下文,将日期传递给前端
|
|
|
|
|
context = {
|
|
|
|
|
'date': date
|
|
|
|
|
}
|
|
|
|
|
# 使用指定的 HTML 模板渲染响应
|
|
|
|
|
# gjl 使用指定的 HTML 模板渲染响应
|
|
|
|
|
return render(request, 'owntracks/show_maps.html', context)
|
|
|
|
|
else:
|
|
|
|
|
# 如果不是超级用户,返回 403 禁止访问
|
|
|
|
|
# gjl 如果不是超级用户,返回 403 禁止访问
|
|
|
|
|
from django.http import HttpResponseForbidden
|
|
|
|
|
return HttpResponseForbidden()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 视图函数:渲染显示有轨迹记录的日期列表页面
|
|
|
|
|
# 使用 @login_required 装饰器,确保只有登录用户才能访问
|
|
|
|
|
# gjl 视图函数:渲染显示有轨迹记录的日期列表页面
|
|
|
|
|
# gjl 使用 @login_required 装饰器,确保只有登录用户才能访问
|
|
|
|
|
@login_required
|
|
|
|
|
def show_log_dates(request):
|
|
|
|
|
# 查询所有 OwnTrackLog 记录的 creation_time 字段值
|
|
|
|
|
# gjl 查询所有 OwnTrackLog 记录的 creation_time 字段值
|
|
|
|
|
dates = OwnTrackLog.objects.values_list('creation_time', flat=True)
|
|
|
|
|
# 将 datetime 对象转换为 'YYYY-MM-DD' 格式的字符串,并去重、排序
|
|
|
|
|
# gjl 将 datetime 对象转换为 'YYYY-MM-DD' 格式的字符串,并去重、排序
|
|
|
|
|
results = list(sorted(set(map(lambda x: x.strftime('%Y-%m-%d'), dates))))
|
|
|
|
|
|
|
|
|
|
# 构造模板上下文,将日期列表传递给前端
|
|
|
|
|
# gjl 构造模板上下文,将日期列表传递给前端
|
|
|
|
|
context = {
|
|
|
|
|
'results': results
|
|
|
|
|
}
|
|
|
|
|
# 使用指定的 HTML 模板渲染响应
|
|
|
|
|
# gjl 使用指定的 HTML 模板渲染响应
|
|
|
|
|
return render(request, 'owntracks/show_log_dates.html', context)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 辅助函数:将 GPS 坐标(WGS-84)批量转换为高德地图坐标系(GCJ-02)
|
|
|
|
|
# 由于高德 API 有数量限制,此处每次处理最多 30 个点
|
|
|
|
|
# 注意:此函数在 get_datas 中被注释掉,当前未使用
|
|
|
|
|
# gjl 辅助函数:将 GPS 坐标(WGS-84)批量转换为高德地图坐标系(GCJ-02)
|
|
|
|
|
# gjl 由于高德 API 有数量限制,此处每次处理最多 30 个点
|
|
|
|
|
# gjl 注意:此函数在 get_datas 中被注释掉,当前未使用
|
|
|
|
|
def convert_to_amap(locations):
|
|
|
|
|
convert_result = [] # 存储转换后的坐标结果
|
|
|
|
|
it = iter(locations) # 创建一个迭代器
|
|
|
|
|
|
|
|
|
|
# 每次从迭代器中取出最多 30 个位置点
|
|
|
|
|
# gjl 每次从迭代器中取出最多 30 个位置点
|
|
|
|
|
item = list(itertools.islice(it, 30))
|
|
|
|
|
while item:
|
|
|
|
|
# 将每个点的经度和纬度拼接成 "lon,lat" 字符串,用分号连接成一个列表
|
|
|
|
|
# gjl 将每个点的经度和纬度拼接成 "lon,lat" 字符串,用分号连接成一个列表
|
|
|
|
|
datas = ';'.join(
|
|
|
|
|
set(map(lambda x: str(x.lon) + ',' + str(x.lat), item)))
|
|
|
|
|
|
|
|
|
|
# 高德坐标转换 API 的固定参数
|
|
|
|
|
# gjl 高德坐标转换 API 的固定参数
|
|
|
|
|
key = '8440a376dfc9743d8924bf0ad141f28e'
|
|
|
|
|
api = 'http://restapi.amap.com/v3/assistant/coordinate/convert'
|
|
|
|
|
# 构造请求参数
|
|
|
|
|
@ -136,9 +137,9 @@ def convert_to_amap(locations):
|
|
|
|
|
return ";".join(convert_result)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 视图函数:返回指定日期的位置轨迹数据,供前端地图使用
|
|
|
|
|
# 返回 JSON 格式的数据,通常由 AJAX 调用
|
|
|
|
|
# 使用 @login_required 装饰器,确保只有登录用户才能访问
|
|
|
|
|
# gjl 视图函数:返回指定日期的位置轨迹数据,供前端地图使用
|
|
|
|
|
# gjl 返回 JSON 格式的数据,通常由 AJAX 调用
|
|
|
|
|
# gjl 使用 @login_required 装饰器,确保只有登录用户才能访问
|
|
|
|
|
@login_required
|
|
|
|
|
def get_datas(request):
|
|
|
|
|
# 获取当前 UTC 时间
|
|
|
|
|
@ -154,17 +155,17 @@ def get_datas(request):
|
|
|
|
|
querydate = django.utils.timezone.datetime(
|
|
|
|
|
date[0], date[1], date[2], 0, 0, 0)
|
|
|
|
|
|
|
|
|
|
# 计算查询结束时间(起始时间 + 1 天)
|
|
|
|
|
# gjl 计算查询结束时间(起始时间 + 1 天)
|
|
|
|
|
nextdate = querydate + datetime.timedelta(days=1)
|
|
|
|
|
|
|
|
|
|
# 查询指定日期范围内(当天)的所有位置记录
|
|
|
|
|
# gjl查询指定日期范围内(当天)的所有位置记录
|
|
|
|
|
models = OwnTrackLog.objects.filter(
|
|
|
|
|
creation_time__range=(querydate, nextdate))
|
|
|
|
|
|
|
|
|
|
# 初始化结果列表
|
|
|
|
|
# gjl 初始化结果列表
|
|
|
|
|
result = list()
|
|
|
|
|
|
|
|
|
|
# 如果查询到记录,则按 tid(用户/设备)分组处理
|
|
|
|
|
# glj 如果查询到记录,则按 tid(用户/设备)分组处理
|
|
|
|
|
if models and len(models):
|
|
|
|
|
for tid, item in groupby(
|
|
|
|
|
# 先按 tid 排序,以便 groupby 正确分组
|
|
|
|
|
@ -172,19 +173,19 @@ def get_datas(request):
|
|
|
|
|
# 指定分组依据为 tid
|
|
|
|
|
key=lambda k: k.tid):
|
|
|
|
|
|
|
|
|
|
# 为每个 tid 创建一个数据字典
|
|
|
|
|
# gjl 为每个 tid 创建一个数据字典
|
|
|
|
|
d = dict()
|
|
|
|
|
d["name"] = tid # 记录设备/用户名称
|
|
|
|
|
paths = list() # 存储该设备的轨迹点序列
|
|
|
|
|
|
|
|
|
|
# 方案一(当前启用):直接使用原始 GPS 坐标
|
|
|
|
|
# 遍历该设备当天的所有位置点,按时间排序
|
|
|
|
|
# gjl 方案一(当前启用):直接使用原始 GPS 坐标
|
|
|
|
|
# gjl 遍历该设备当天的所有位置点,按时间排序
|
|
|
|
|
for location in sorted(item, key=lambda x: x.creation_time):
|
|
|
|
|
# 将每个点的经度和纬度作为字符串列表添加到 paths
|
|
|
|
|
# gjl 将每个点的经度和纬度作为字符串列表添加到 paths
|
|
|
|
|
paths.append([str(location.lon), str(location.lat)])
|
|
|
|
|
|
|
|
|
|
# # 方案二(注释中):使用高德转换后的坐标
|
|
|
|
|
# # 先转换坐标,然后解析
|
|
|
|
|
# # gjl 方案二(注释中):使用高德转换后的坐标
|
|
|
|
|
# # gjl 先转换坐标,然后解析
|
|
|
|
|
# locations = convert_to_amap(
|
|
|
|
|
# sorted(item, key=lambda x: x.creation_time))
|
|
|
|
|
# for i in locations.split(';'):
|
|
|
|
|
@ -195,6 +196,6 @@ def get_datas(request):
|
|
|
|
|
# 将该设备的轨迹数据添加到总结果列表
|
|
|
|
|
result.append(d)
|
|
|
|
|
|
|
|
|
|
# 将结果列表序列化为 JSON 并返回
|
|
|
|
|
# safe=False 允许返回非字典类型的对象(如列表)
|
|
|
|
|
# gjl 将结果列表序列化为 JSON 并返回
|
|
|
|
|
# gjl safe=False 允许返回非字典类型的对象(如列表)
|
|
|
|
|
return JsonResponse(result, safe=False)
|