180
peizhi/xieyi_views.py
Normal file
180
peizhi/xieyi_views.py
Normal file
@@ -0,0 +1,180 @@
|
||||
"""小程序协议 — 查询与签署"""
|
||||
import logging
|
||||
import time
|
||||
import uuid
|
||||
|
||||
from django.db import transaction
|
||||
from rest_framework import permissions
|
||||
from rest_framework.parsers import FormParser, JSONParser, MultiPartParser
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.views import APIView
|
||||
|
||||
from peizhi.models import XcxXieyi, XcxXieyiImage, XcxXieyiQianshu
|
||||
from utils.oss_utils import upload_to_oss, validate_image
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
VALID_SHENFEN = frozenset({'dashou', 'guanshi', 'zuzhang', 'shangjia', 'normal'})
|
||||
|
||||
|
||||
def _client_ip(request):
|
||||
xff = request.META.get('HTTP_X_FORWARDED_FOR')
|
||||
if xff:
|
||||
ip = xff.split(',')[0].strip()
|
||||
if ip:
|
||||
return ip
|
||||
return request.META.get('REMOTE_ADDR', '') or ''
|
||||
|
||||
|
||||
def _serialize_xieyi(item, yonghuid=None, include_images=False):
|
||||
signed = False
|
||||
if yonghuid:
|
||||
signed = XcxXieyiQianshu.objects.filter(
|
||||
yonghuid=yonghuid, xieyi_id=item.id, xieyi_version=item.version,
|
||||
).exists()
|
||||
data = {
|
||||
'id': item.id,
|
||||
'title': item.title,
|
||||
'shenfen': item.shenfen,
|
||||
'shenfen_label': item.get_shenfen_display(),
|
||||
'mode': item.mode,
|
||||
'content_title': item.content_title or '',
|
||||
'content_text': item.content_text or '',
|
||||
'version': item.version,
|
||||
'is_active': item.is_active,
|
||||
'sort_order': item.sort_order,
|
||||
'signed': signed,
|
||||
}
|
||||
if include_images:
|
||||
data['images'] = [
|
||||
{'id': img.id, 'image_path': img.image_path, 'sort_order': img.sort_order}
|
||||
for img in item.images.all().order_by('sort_order', 'id')
|
||||
]
|
||||
return data
|
||||
|
||||
|
||||
class XieyiListView(APIView):
|
||||
"""POST /peizhi/xieyihq — 按身份获取启用协议列表"""
|
||||
|
||||
permission_classes = [permissions.IsAuthenticated]
|
||||
parser_classes = [JSONParser]
|
||||
|
||||
def post(self, request):
|
||||
shenfen = (request.data.get('shenfen') or '').strip()
|
||||
if shenfen not in VALID_SHENFEN:
|
||||
return Response({'code': 400, 'msg': '无效的身份参数', 'data': {'list': []}})
|
||||
yonghuid = request.user.yonghuid
|
||||
qs = XcxXieyi.objects.filter(shenfen=shenfen, is_active=True).order_by('sort_order', 'id')
|
||||
items = [_serialize_xieyi(x, yonghuid) for x in qs]
|
||||
return Response({'code': 0, 'msg': 'success', 'data': {'list': items}})
|
||||
|
||||
|
||||
class XieyiDetailView(APIView):
|
||||
"""POST /peizhi/xieyixq — 协议详情"""
|
||||
|
||||
permission_classes = [permissions.IsAuthenticated]
|
||||
parser_classes = [JSONParser]
|
||||
|
||||
def post(self, request):
|
||||
xieyi_id = request.data.get('id') or request.data.get('xieyi_id')
|
||||
if not xieyi_id:
|
||||
return Response({'code': 400, 'msg': '缺少协议 id', 'data': None})
|
||||
try:
|
||||
item = XcxXieyi.objects.prefetch_related('images').get(id=xieyi_id, is_active=True)
|
||||
except XcxXieyi.DoesNotExist:
|
||||
return Response({'code': 404, 'msg': '协议不存在或已下线', 'data': None})
|
||||
yonghuid = request.user.yonghuid
|
||||
return Response({
|
||||
'code': 0,
|
||||
'msg': 'success',
|
||||
'data': _serialize_xieyi(item, yonghuid, include_images=True),
|
||||
})
|
||||
|
||||
|
||||
class XieyiSignStatusView(APIView):
|
||||
"""POST /peizhi/xieyizt — 是否已签署当前版本"""
|
||||
|
||||
permission_classes = [permissions.IsAuthenticated]
|
||||
parser_classes = [JSONParser]
|
||||
|
||||
def post(self, request):
|
||||
xieyi_id = request.data.get('id') or request.data.get('xieyi_id')
|
||||
if not xieyi_id:
|
||||
return Response({'code': 400, 'msg': '缺少协议 id', 'data': None})
|
||||
try:
|
||||
item = XcxXieyi.objects.get(id=xieyi_id, is_active=True)
|
||||
except XcxXieyi.DoesNotExist:
|
||||
return Response({'code': 404, 'msg': '协议不存在', 'data': None})
|
||||
yonghuid = request.user.yonghuid
|
||||
record = XcxXieyiQianshu.objects.filter(
|
||||
yonghuid=yonghuid, xieyi_id=item.id, xieyi_version=item.version,
|
||||
).order_by('-signed_at').first()
|
||||
return Response({
|
||||
'code': 0,
|
||||
'msg': 'success',
|
||||
'data': {
|
||||
'signed': record is not None,
|
||||
'version': item.version,
|
||||
'signed_at': record.signed_at.strftime('%Y-%m-%d %H:%M:%S') if record else '',
|
||||
'signature_path': record.signature_path if record else '',
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
class XieyiSignView(APIView):
|
||||
"""POST /peizhi/xieyiqm — 上传手写签名并完成签署"""
|
||||
|
||||
permission_classes = [permissions.IsAuthenticated]
|
||||
parser_classes = (MultiPartParser, FormParser)
|
||||
|
||||
def post(self, request):
|
||||
xieyi_id = request.data.get('xieyi_id') or request.data.get('id')
|
||||
shenfen = (request.data.get('shenfen') or '').strip()
|
||||
image_file = request.FILES.get('image') or request.FILES.get('file')
|
||||
if not xieyi_id:
|
||||
return Response({'code': 1, 'msg': '缺少 xieyi_id', 'data': None})
|
||||
if not image_file:
|
||||
return Response({'code': 2, 'msg': '请上传签名图片', 'data': None})
|
||||
if shenfen and shenfen not in VALID_SHENFEN:
|
||||
return Response({'code': 3, 'msg': '无效身份', 'data': None})
|
||||
|
||||
is_valid, error_msg = validate_image(image_file)
|
||||
if not is_valid:
|
||||
return Response({'code': 4, 'msg': error_msg, 'data': None})
|
||||
|
||||
try:
|
||||
item = XcxXieyi.objects.get(id=xieyi_id, is_active=True)
|
||||
except XcxXieyi.DoesNotExist:
|
||||
return Response({'code': 404, 'msg': '协议不存在或已下线', 'data': None})
|
||||
|
||||
yonghuid = request.user.yonghuid
|
||||
if XcxXieyiQianshu.objects.filter(
|
||||
yonghuid=yonghuid, xieyi_id=item.id, xieyi_version=item.version,
|
||||
).exists():
|
||||
return Response({'code': 5, 'msg': '您已签署过当前版本协议', 'data': None})
|
||||
|
||||
oss_path = f'qianming/xieyi/{yonghuid}/{item.id}_{int(time.time())}_{uuid.uuid4().hex[:8]}.png'
|
||||
image_file.seek(0)
|
||||
full_url = upload_to_oss(image_file, oss_path)
|
||||
if not full_url:
|
||||
return Response({'code': 6, 'msg': '签名上传失败', 'data': None})
|
||||
|
||||
sign_shenfen = shenfen or item.shenfen
|
||||
with transaction.atomic():
|
||||
record = XcxXieyiQianshu.objects.create(
|
||||
yonghuid=yonghuid,
|
||||
xieyi=item,
|
||||
xieyi_version=item.version,
|
||||
shenfen=sign_shenfen,
|
||||
signature_path=oss_path,
|
||||
client_ip=_client_ip(request),
|
||||
)
|
||||
return Response({
|
||||
'code': 0,
|
||||
'msg': '签署成功',
|
||||
'data': {
|
||||
'id': record.id,
|
||||
'signature_path': oss_path,
|
||||
'signed_at': record.signed_at.strftime('%Y-%m-%d %H:%M:%S'),
|
||||
},
|
||||
})
|
||||
Reference in New Issue
Block a user