|
# -*- coding: utf-8 -*-
import datetime
from django.db import models
from django.utils.translation import ugettext_lazy as _
from django_models_ext import BaseModelMixin, SexModelMixin
from jsonfield import JSONField
from shortuuidfield import ShortUUIDField
from TimeConvert import TimeConvert as tc
from utils.redis.rqrurl import get_qrcode_url
class IsolationPointFieldPoolInfo(BaseModelMixin):
INPUT = 'input'
SELECT = 'select'
FILE = 'file'
FIELD_TYPE_TUPLE = (
(INPUT, 'input'),
(SELECT, 'select'),
(FILE, 'file'),
)
# {
# "type": "input", # input, select, file
# "name": "",
# "options": ["男", "女"], # type=select
# }
field_type = models.CharField(_('field_type'), max_length=8, choices=FIELD_TYPE_TUPLE, default=INPUT, help_text='字段类型')
field_name = models.CharField(_('field_name'), max_length=32, blank=True, null=True, help_text='字段名称')
field_key = models.CharField(_('field_key'), max_length=32, blank=True, null=True, help_text='字段键值')
field_options = JSONField(_('field_options'), default=[], blank=True, null=True, help_text='字段选择')
class Meta:
verbose_name = _('字段池信息')
verbose_name_plural = _('字段池信息')
def __unicode__(self):
return self.pk
@property
def data(self):
return {
'type': self.field_type,
'key': self.field_key,
'name': self.field_name,
'options': self.field_options,
}
class IsolationPointInfo(BaseModelMixin):
CONTINUOUS = 0
SINGLE = 1
TEMPERATURE_MEASURE_TYPE_TUPLE = (
(CONTINUOUS, '连续型'),
(SINGLE, '单次')
)
point_id = ShortUUIDField(_('point_id'), max_length=32, blank=True, null=True, help_text='隔离点唯一标识', db_index=True, unique=True)
point_name = models.CharField(_('point_name'), max_length=255, blank=True, null=True, help_text='隔离点名称')
# {
# "type": "input", # input, select, file
# "name": "",
# "options": ["男", "女"], # type=select
# }
point_fields = JSONField(_('point_fields'), default=[], blank=True, null=True, help_text='隔离点字段列表')
# [
# {
# 'start': '',
# 'end': '',
# }, {
# 'start': '',
# 'end': '',
# }
# ]
point_upload_period = JSONField(_('point_upload_period'), default=[], blank=True, null=True, help_text='隔离点上传时段')
temperature_measure_type = models.IntegerField(_('temperature_measure_type'), choices=TEMPERATURE_MEASURE_TYPE_TUPLE, default=SINGLE, help_text='测温类型')
limit_scene_qrcode_url = models.CharField(_('limit_scene_qrcode_url'), max_length=255, blank=True, null=True, help_text='字段二维码')
class Meta:
verbose_name = _('隔离点信息')
verbose_name_plural = _('隔离点信息')
def __unicode__(self):
return self.pk
@property
def match_upload_period(self):
for period in self.point_upload_period:
local_date_string = tc.local_date_string()
start_dt = tc.string_to_datetime(f'{local_date_string} {period["start"]}', format='%Y-%m-%d %H:%M')
end_dt = tc.string_to_datetime(f'{local_date_string} {period["end"]}', format='%Y-%m-%d %H:%M')
current_at = tc.make_naive(tc.local_datetime())
if start_dt < current_at < end_dt:
return start_dt, end_dt
return False
@property
def data(self):
qrcode_url = get_qrcode_url(self.point_id)
return {
'point_id': self.point_id,
'point_name': self.point_name,
'point_fields': self.point_fields,
'point_upload_period': self.point_upload_period,
'qrcode_url': qrcode_url,
}
class FamilyMemberInfo(BaseModelMixin):
RELATION_TUPLE = (
('parent', '父母'),
('child', '子女'),
('spouse', '配偶'),
)
member_id = ShortUUIDField(_('member_id'), max_length=32, blank=True, null=True, help_text='家庭成员唯一标识', db_index=True, unique=True)
user_id = models.CharField(_('user_id'), max_length=32, blank=True, null=True, help_text='用户唯一标识', db_index=True)
identity_card_number = models.CharField(_(u'identity_card_number'), max_length=32, blank=True, null=True, help_text=u'身份证号')
identity_card_name = models.CharField(_(u'identity_card_name'), max_length=32, blank=True, null=True, help_text=u'身份证姓名')
relation = models.CharField(_('relative'), choices=RELATION_TUPLE, default='child', max_length=32, help_text='家庭关系', db_index=True)
class Meta:
verbose_name = _('家庭成员信息')
verbose_name_plural = _('家庭成员信息')
def __unicode__(self):
return '%d' % self.pk
@property
def data(self):
try:
user = IsolationPointUserInfo.objects.get(user_id=self.user_id, member_id=self.member_id, status=True).userdata
except IsolationPointUserInfo.DoesNotExist:
user = {}
return {
'member_id': self.member_id,
'user_id': self.user_id,
'identity_card_number': self.identity_card_number,
'identity_card_name': self.identity_card_name,
'relation': self.relation,
'created_at': tc.local_string(utc_dt=self.created_at, format='%Y-%m-%d %H:%M'),
'point_info': user
}
class IsolationPointUserInfo(BaseModelMixin):
HAS_NOT_UPLOAD = '未上报'
HAS_NOT_CONNECTED = '未联网'
HAS_NOT_WORN = '未佩戴'
HAS_SHUTDOWN = '关机'
HAS_YET_UPLOAD = '已上报'
CHG_STA_CHARGING = '充电中'
NEGATIVE = 0
POSITIVE = 1
UNKNOWN = 2
ANTIGEN_RESULT_TYPE = (
(NEGATIVE, '阴性'),
(POSITIVE, '阳性'),
(UNKNOWN, '无效结果'),
)
point_id = models.CharField(_('point_id'), max_length=32, blank=True, null=True, help_text='隔离点唯一标识', db_index=True)
unionid = models.CharField(_('unionid'), max_length=32, blank=True, null=True, help_text='微信 Unionid')
user_id = models.CharField(_('user_id'), max_length=32, blank=True, null=True, help_text='用户唯一标识', db_index=True)
member_id = models.CharField(_('member_id'), max_length=32, blank=True, null=True, help_text='家庭成员唯一标识', db_index=True)
# 身份证上信息,以及电话
name = models.CharField(_('name'), max_length=32, blank=True, null=True, help_text='身份证姓名', db_index=True)
age = models.CharField(_('age'), max_length=32, blank=True, null=True, help_text='身份证年龄', db_index=True)
sex = models.IntegerField(_('sex'), choices=SexModelMixin.SEX_TUPLE, default=SexModelMixin.UNKNOWN, help_text='身份证性别')
phone = models.CharField(_('phone'), max_length=32, blank=True, null=True, help_text='手机号', db_index=True)
fields = JSONField(_('fields'), default=[], blank=True, null=True, help_text='字段信息')
observed_ymds = JSONField(_('observed_ymds'), default=[], blank=True, null=True, help_text='已测温日期')
observed_days = models.IntegerField(_('observed_days'), default=0, help_text='已测温天数')
chg_sta = models.BooleanField(_(u'chg_sta'), default=False, help_text='充电状态,true 充电,false 未充电')
temperature = models.FloatField(_('temperature'), default=0, help_text='用户体温')
last_submit_at = models.DateTimeField(_('last_submit_at'), blank=True, null=True, help_text='上一次上报时间')
leave_at = models.DateTimeField(_('leave_at'), blank=True, null=True, help_text='离开时间')
remark = models.CharField(_('remark'), max_length=255, blank=True, null=True, help_text='备注')
remarks = JSONField(_('remarks'), default=[], blank=True, null=True, help_text='备注')
eqpts = JSONField(_('eqpts'), default=[], blank=True, null=True, help_text='使用设备记录')
antigen_result = models.IntegerField(_('antigen_result'), choices=ANTIGEN_RESULT_TYPE, default=UNKNOWN, help_text='抗原检测结果')
detect_at = models.DateTimeField(_('detect_at'), blank=True, null=True, help_text='检测时间')
antigen_observed_ymds = JSONField(_('antigen_observed_ymds'), default=[], blank=True, null=True, help_text='已测抗原日期')
antigen_observed_days = models.IntegerField(_('observed_days'), default=0, help_text='已测抗原天数')
# 身体状态
dry_cough_status = models.BooleanField(_(u'dry_cough_status'), default=False, help_text='是否干咳')
weak_status = models.BooleanField(_(u'weak_status'), default=False, help_text='是否乏力')
sore_throat_status = models.BooleanField(_(u'sore_throat_status'), default=False, help_text='是否咽痛')
smell_taste_loss_status = models.BooleanField(_(u'smell_taste_loss_status'), default=False, help_text='是否嗅(味)觉减退')
diarrhea_status = models.BooleanField(_(u'diarrhea_status'), default=False, help_text='是否腹泻')
blood_oxygen_saturation = models.IntegerField(_('blood_oxygen_saturation'), default=100, help_text='血氧饱和度')
is_filled = models.BooleanField(_(u'is_filled'), default=False, help_text='是否填写身体状态')
class Meta:
verbose_name = _('隔离点用户录入信息')
verbose_name_plural = _('隔离点用户录入信息')
unique_together = (
('point_id', 'user_id'),
)
def __unicode__(self):
return self.pk
@property
def temperature_has_upload(self):
if self.chg_sta:
return IsolationPointUserInfo.CHG_STA_CHARGING
if self.last_submit_at and self.last_submit_at > tc.utc_datetime(hours=-1):
return IsolationPointUserInfo.HAS_YET_UPLOAD
return IsolationPointUserInfo.HAS_NOT_UPLOAD
@property
def user_status(self):
has_upload = self.last_submit_at and self.last_submit_at > tc.utc_datetime(hours=-1)
if has_upload and self.chg_sta:
return IsolationPointUserInfo.CHG_STA_CHARGING
if has_upload and self.temperature >= 35:
return IsolationPointUserInfo.HAS_YET_UPLOAD
if has_upload and self.temperature < 35:
return IsolationPointUserInfo.HAS_NOT_WORN
if not has_upload and (self.chg_sta or self.temperature > 0):
return IsolationPointUserInfo.HAS_SHUTDOWN
return IsolationPointUserInfo.HAS_NOT_CONNECTED
@property
def get_antigen_result(self):
today = datetime.date.today()
if not self.detect_at:
return u'今日未检测'
if today.day == self.detect_at.day and today.month == self.detect_at.month and today.year == self.detect_at.year:
return self.get_antigen_result_display()
else:
return u'今日未检测'
@property
def data(self):
return {
'pk': self.pk,
'point_id': self.point_id,
'user_id': self.user_id,
'fields': self.fields,
'observed_days': self.observed_days,
'temperature_has_upload': self.temperature_has_upload,
'user_status': self.user_status,
'temperature': self.temperature,
'dry_cough_status': self.dry_cough_status,
'weak_status': self.weak_status,
'sore_throat_status': self.sore_throat_status,
'smell_taste_loss_status': self.smell_taste_loss_status,
'diarrhea_status': self.diarrhea_status,
'blood_oxygen_saturation': self.blood_oxygen_saturation,
'is_filled': self.is_filled,
'last_submit_at': tc.local_string(utc_dt=self.last_submit_at, format='%Y-%m-%d %H:%M:%S') if self.last_submit_at else '',
'last_report_time': tc.local_string(utc_dt=self.last_submit_at, format='%m-%d %H:%M') if self.last_submit_at else '',
'remark': self.remark or '',
'antigen_result': self.get_antigen_result,
'detect_at': tc.local_string(utc_dt=self.detect_at, format='%m-%d %H:%M') if self.detect_at else '',
}
@property
def screen_data(self):
return {
'pk': self.pk,
'point_id': self.point_id,
'user_id': self.user_id,
'fields': self.fields,
'observed_days': self.observed_days,
'temperature_has_upload': self.temperature_has_upload,
'user_status': self.user_status,
'temperature': self.temperature,
'dry_cough_status': self.dry_cough_status,
'weak_status': self.weak_status,
'sore_throat_status': self.sore_throat_status,
'smell_taste_loss_status': self.smell_taste_loss_status,
'diarrhea_status': self.diarrhea_status,
'blood_oxygen_saturation': self.blood_oxygen_saturation,
'is_filled': self.is_filled,
'last_submit_at': self.last_submit_at,
'last_report_time': tc.local_string(utc_dt=self.last_submit_at, format='%m-%d %H:%M') if self.last_submit_at else '',
'remark': self.remark or '',
'antigen_result': self.get_antigen_result,
'detect_at': tc.local_string(utc_dt=self.detect_at, format='%m-%d %H:%M') if self.detect_at else '',
}
@property
def antigen_screen_data(self):
return {
'point_id': self.point_id,
'user_id': self.user_id,
'observed_days': self.antigen_observed_days,
'last_report_time': tc.local_string(utc_dt=self.detect_at, format='%m-%d %H:%M') if self.detect_at else '',
'remark': self.remark or '',
'name': self.name,
'phone': self.phone,
'antigen_result': self.get_antigen_result,
}
@property
def userdata(self):
try:
point = IsolationPointInfo.objects.get(point_id=self.point_id)
except IsolationPointInfo.DoesNotExist:
point = {}
return {
'point_id': self.point_id,
'point_name': point.point_name if point else '',
'user_id': self.user_id,
**{field.get('key', ''): field.get('value', '') for field in self.fields}
}
class ThermometerEquipmentInfo(BaseModelMixin):
ONLINE = 1
OFFLINE = 0
ACTIVE_STATUE_TUPLE = (
(ONLINE, '已激活'),
(OFFLINE, '已离线'),
)
eqpt_id = ShortUUIDField(_('eqpt_id'), max_length=32, blank=True, null=True, help_text='设备唯一标识', db_index=True, unique=True)
point_id = models.CharField(_('point_id'), max_length=32, blank=True, null=True, help_text='隔离点唯一标识', db_index=True)
macid = models.CharField(_('macid'), max_length=32, blank=True, null=True, help_text='设备号')
sn = models.CharField(_('sn'), max_length=32, blank=True, null=True, help_text='序列号')
active_status = models.IntegerField(_('active_status'), choices=ACTIVE_STATUE_TUPLE, default=OFFLINE, help_text='激活状态')
active_at = models.DateTimeField(_('active_at'), blank=True, null=True, help_text='激活时间')
# 用户基本信息
ipui_pk = models.IntegerField(_('ipui_pk'), default=0, help_text='隔离点用户录入PK')
# 历史用户信息
ipui_pks = JSONField(_('ipui_pks'), default=[], blank=True, null=True, help_text='隔离点用户使用记录')
class Meta:
verbose_name = _('测温设备信息')
verbose_name_plural = _('测温设备信息')
def __unicode__(self):
return self.pk
@property
def data(self):
return {
'eqpt_id': self.eqpt_id,
'point_id': self.point_id,
'macid': self.macid,
'sn': self.sn,
'active_status': self.active_status,
'active_status_str': dict(self.ACTIVE_STATUE_TUPLE).get(self.active_status, ''),
'active_at': tc.local_string(utc_dt=self.active_at),
'ipui_pk': self.ipui_pk,
'created_at': tc.local_string(utc_dt=self.created_at),
}
@property
def screen_data(self):
return {
'point_id': self.point_id,
'macid': self.macid,
}
class ThermometerMeasureLogInfo(BaseModelMixin):
CALLBACK = 1
MQTT = 2
MP = 3
TEMPERATURE_SRC_TUPLE = (
(CALLBACK, '接口回调'),
(MQTT, 'MQTT'),
(MP, '小程序'),
)
point_id = models.CharField(_('point_id'), max_length=32, blank=True, null=True, help_text='隔离点唯一标识', db_index=True)
user_id = models.CharField(_('user_id'), max_length=32, blank=True, null=True, help_text='用户唯一标识')
member_id = models.CharField(_('member_id'), max_length=32, blank=True, null=True, help_text='用户唯一标识')
macid = models.CharField(_('macid'), max_length=32, blank=True, null=True, help_text='设备号')
sn = models.CharField(_('sn'), max_length=32, blank=True, null=True, help_text='序列号')
start_stamp = models.BigIntegerField(_('start_stamp'), default=0, help_text='测温开始时间戳')
end_stamp = models.BigIntegerField(_('end_stamp'), default=0, help_text='测温结束时间戳')
temperature_src = models.IntegerField(_('temperature_src'), choices=TEMPERATURE_SRC_TUPLE, default=CALLBACK, help_text='用户体温来源')
temperature = models.FloatField(_('temperature'), default=0, help_text='用户体温')
chg_sta = models.BooleanField(_(u'chg_sta'), default=False, help_text='充电状态,true 充电,false 未充电')
ignore_temperature = models.BooleanField(_(u'ignore_temperature'), default=False, help_text='是否忽略温度')
ignore_fever_temperature = models.BooleanField(_(u'ignore_fever_temperature'), default=False, help_text='是否忽略高度')
upload_temperature_info = models.TextField(_('upload_temperature_info'), blank=True, null=True, help_text='测温结果上传信息')
# 身体状态
dry_cough_status = models.BooleanField(_(u'dry_cough_status'), default=False, help_text='是否干咳')
weak_status = models.BooleanField(_(u'weak_status'), default=False, help_text='是否乏力')
sore_throat_status = models.BooleanField(_(u'sore_throat_status'), default=False, help_text='是否咽痛')
smell_taste_loss_status = models.BooleanField(_(u'smell_taste_loss_status'), default=False, help_text='是否嗅(味)觉减退')
diarrhea_status = models.BooleanField(_(u'diarrhea_status'), default=False, help_text='是否腹泻')
blood_oxygen_saturation = models.IntegerField(_('blood_oxygen_saturation'), default=100, help_text='血氧饱和度')
is_filled = models.BooleanField(_(u'is_filled'), default=False, help_text='是否填写身体状态')
class Meta:
verbose_name = _('测温记录信息')
verbose_name_plural = _('测温记录信息')
def __unicode__(self):
return self.pk
@property
def data(self):
return {
'point_id': self.point_id,
'macid': self.macid,
'sn': self.sn,
'user_id': self.user_id,
'temperature': self.temperature,
'dry_cough_status': self.dry_cough_status,
'weak_status': self.weak_status,
'sore_throat_status': self.sore_throat_status,
'smell_taste_loss_status': self.smell_taste_loss_status,
'diarrhea_status': self.diarrhea_status,
'blood_oxygen_saturation': self.blood_oxygen_saturation,
'is_filled': self.is_filled,
'created_at': tc.local_string(utc_dt=self.created_at, format='%Y-%m-%d'),
}
@property
def userdata(self):
return {
'macid': self.macid,
'sn': self.sn,
'temperature': self.temperature,
'dry_cough_status': self.dry_cough_status,
'weak_status': self.weak_status,
'sore_throat_status': self.sore_throat_status,
'smell_taste_loss_status': self.smell_taste_loss_status,
'diarrhea_status': self.diarrhea_status,
'blood_oxygen_saturation': self.blood_oxygen_saturation,
'is_filled': self.is_filled,
'created_at': tc.local_string(utc_dt=self.created_at, format='%Y-%m-%d %H:%M'),
}
class AepThermometerMeasureLogInfo(BaseModelMixin):
# {
# "upPacketSN": -1,
# "upDataSN": -1,
# "topic": "v1/up/ad",
# "timestamp": 1636096959410,
# "tenantId": "2000051017",
# "serviceId": "",
# "protocol": "lwm2m",
# "productId": "15091846",
# "payload": {
# "APPdata": "MjIyMzk0"
# },
# "messageType": "dataReport",
# "deviceType": "",
# "deviceId": "6b34c9d2d06b4965b4fe505e6d6c342c",
# "assocAssetId": "",
# "IMSI": "460113179251578",
# "IMEI": "355558100904547"
# }
CALLBACK = 1
MQTT = 2
TEMPERATURE_SRC_TUPLE = (
(CALLBACK, '接口回调'),
(MQTT, 'MQTT'),
)
imei = models.CharField(_('imei'), max_length=32, blank=True, null=True, help_text='IMEI', db_index=True)
temperature_src = models.IntegerField(_('temperature_src'), choices=TEMPERATURE_SRC_TUPLE, default=CALLBACK, help_text='用户体温来源')
upload_temperature_info = JSONField(_('upload_temperature_info'), blank=True, null=True, help_text='测温结果上传信息')
temperature_info = JSONField(_('temperature_info'), blank=True, null=True, help_text='温度信息')
battery_info = JSONField(_('battery_info'), blank=True, null=True, help_text='电量信息')
temperature = models.FloatField(_('temperature'), default=0, help_text='用户体温')
battery = models.FloatField(_('battery'), default=0, help_text='用户电量')
class Meta:
verbose_name = _('AEP测温记录信息')
verbose_name_plural = _('AEP测温记录信息')
def __unicode__(self):
return self.pk
class AntigenMeasureLogInfo(BaseModelMixin):
NEGATIVE = 0
POSITIVE = 1
UNKNOWN = 2
ANTIGEN_RESULT_TYPE = (
(NEGATIVE, '阴性'),
(POSITIVE, '阳性'),
(UNKNOWN, '未知'),
)
point_id = models.CharField(_('point_id'), max_length=32, blank=True, null=True, help_text='隔离点唯一标识', db_index=True)
user_id = models.CharField(_('user_id'), max_length=32, blank=True, null=True, help_text='用户唯一标识')
unionid = models.CharField(_('user_id'), max_length=32, blank=True, null=True, help_text='微信 Unionid')
macid = models.CharField(_('macid'), max_length=32, blank=True, null=True, help_text='设备号')
phone = models.CharField(_('phone'), max_length=11, blank=True, null=True, help_text='用户手机号')
user_name = models.CharField(_('user_name'), max_length=255, blank=True, null=True, help_text='用户姓名')
result = models.IntegerField(_('result'), choices=ANTIGEN_RESULT_TYPE, default=UNKNOWN, help_text='抗原检测结果')
detect_at = models.DateTimeField(_('detect_at'), blank=True, null=True, help_text='检测时间')
class Meta:
verbose_name = _('抗原检测记录信息')
verbose_name_plural = _('抗原检测记录信息')
def __unicode__(self):
return self.pk
|