Files
along_django/houtai/xieyi_views.py

263 lines
10 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""后台 — 小程序协议管理"""
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
from .utils import verify_kefu_permission
logger = logging.getLogger(__name__)
REQUIRED_PERMISSION = '8080a'
def _check_perm(request):
username = request.data.get('username')
kefu, perms_or_resp = verify_kefu_permission(request, username)
if kefu is None:
return None, perms_or_resp
if REQUIRED_PERMISSION not in perms_or_resp:
return None, Response({'code': 403, 'msg': '您没有权限访问协议管理(需 8080a'})
return kefu, None
def _serialize_admin(item):
return {
'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,
'must_sign': item.must_sign,
'sort_order': item.sort_order,
'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')
],
'created_at': item.created_at.strftime('%Y-%m-%d %H:%M:%S') if item.created_at else '',
'updated_at': item.updated_at.strftime('%Y-%m-%d %H:%M:%S') if item.updated_at else '',
}
class XieyiListAPIView(APIView):
"""POST /houtai/hthqxy — 协议列表"""
permission_classes = [permissions.IsAuthenticated]
parser_classes = [JSONParser]
def post(self, request):
kefu, err = _check_perm(request)
if kefu is None:
return err
shenfen = request.data.get('shenfen')
qs = XcxXieyi.objects.prefetch_related('images').all().order_by('sort_order', 'id')
if shenfen:
qs = qs.filter(shenfen=shenfen)
items = [_serialize_admin(x) for x in qs]
scenes = [{'key': c[0], 'label': c[1]} for c in XcxXieyi.SHENFEN_CHOICES]
modes = [{'key': c[0], 'label': c[1]} for c in XcxXieyi.MODE_CHOICES]
return Response({'code': 0, 'data': {'items': items, 'shenfen_choices': scenes, 'mode_choices': modes}})
class XieyiModifyAPIView(APIView):
"""POST /houtai/htxgxy — 协议增删改"""
permission_classes = [permissions.IsAuthenticated]
parser_classes = [JSONParser]
def post(self, request):
kefu, err = _check_perm(request)
if kefu is None:
return err
action = request.data.get('action')
if action == 'create':
return self._create(request)
if action == 'update':
return self._update(request)
if action == 'delete':
return self._delete(request)
return Response({'code': 400, 'msg': '未知 action'})
def _create(self, request):
title = (request.data.get('title') or '').strip()
shenfen = (request.data.get('shenfen') or '').strip()
mode = int(request.data.get('mode') or XcxXieyi.MODE_TEXT)
if not title or not shenfen:
return Response({'code': 400, 'msg': 'title、shenfen 必填'})
valid_shenfen = {c[0] for c in XcxXieyi.SHENFEN_CHOICES}
if shenfen not in valid_shenfen:
return Response({'code': 400, 'msg': '无效身份'})
item = XcxXieyi.objects.create(
title=title,
shenfen=shenfen,
mode=mode,
content_title=request.data.get('content_title', ''),
content_text=request.data.get('content_text', ''),
is_active=bool(request.data.get('is_active', True)),
must_sign=bool(request.data.get('must_sign', True)),
sort_order=int(request.data.get('sort_order', 0)),
)
return Response({'code': 0, 'msg': '创建成功', 'data': _serialize_admin(item)})
def _update(self, request):
item_id = request.data.get('id')
if not item_id:
return Response({'code': 400, 'msg': '缺少 id'})
try:
item = XcxXieyi.objects.prefetch_related('images').get(id=item_id)
except XcxXieyi.DoesNotExist:
return Response({'code': 404, 'msg': '记录不存在'})
content_changed = False
if 'title' in request.data:
item.title = request.data.get('title', '')
if 'shenfen' in request.data:
shenfen = request.data.get('shenfen')
valid_shenfen = {c[0] for c in XcxXieyi.SHENFEN_CHOICES}
if shenfen not in valid_shenfen:
return Response({'code': 400, 'msg': '无效身份'})
item.shenfen = shenfen
if 'mode' in request.data:
item.mode = int(request.data.get('mode'))
content_changed = True
if 'content_title' in request.data:
item.content_title = request.data.get('content_title', '')
content_changed = True
if 'content_text' in request.data:
item.content_text = request.data.get('content_text', '')
content_changed = True
if 'is_active' in request.data:
item.is_active = bool(request.data.get('is_active'))
if 'must_sign' in request.data:
item.must_sign = bool(request.data.get('must_sign'))
if 'sort_order' in request.data:
item.sort_order = int(request.data.get('sort_order', 0))
if 'bump_version' in request.data and request.data.get('bump_version'):
content_changed = True
if content_changed:
item.version = (item.version or 1) + 1
item.save()
return Response({'code': 0, 'msg': '更新成功', 'data': _serialize_admin(item)})
def _delete(self, request):
item_id = request.data.get('id')
if not item_id:
return Response({'code': 400, 'msg': '缺少 id'})
deleted, _ = XcxXieyi.objects.filter(id=item_id).delete()
if not deleted:
return Response({'code': 404, 'msg': '记录不存在'})
return Response({'code': 0, 'msg': '删除成功'})
class XieyiImageUploadAPIView(APIView):
"""POST /houtai/htxgytp — 上传协议图片"""
permission_classes = [permissions.IsAuthenticated]
parser_classes = (MultiPartParser, FormParser)
def post(self, request):
kefu, err = _check_perm(request)
if kefu is None:
return err
xieyi_id = request.data.get('xieyi_id') or request.data.get('id')
image_file = request.FILES.get('image')
if not xieyi_id or not image_file:
return Response({'code': 400, 'msg': 'xieyi_id 与 image 必填'})
is_valid, error_msg = validate_image(image_file)
if not is_valid:
return Response({'code': 400, 'msg': error_msg})
try:
item = XcxXieyi.objects.get(id=xieyi_id)
except XcxXieyi.DoesNotExist:
return Response({'code': 404, 'msg': '协议不存在'})
oss_path = f'a_long/xieyi/{item.id}/{int(time.time())}_{uuid.uuid4().hex[:8]}.jpg'
image_file.seek(0)
full_url = upload_to_oss(image_file, oss_path)
if not full_url:
return Response({'code': 500, 'msg': '上传失败'})
with transaction.atomic():
img = XcxXieyiImage.objects.create(
xieyi=item,
image_path=oss_path,
sort_order=int(request.data.get('sort_order', 0)),
)
item.version = (item.version or 1) + 1
item.save(update_fields=['version', 'updated_at'])
return Response({
'code': 0,
'msg': '上传成功',
'data': {'id': img.id, 'image_path': oss_path, 'version': item.version},
})
class XieyiImageDeleteAPIView(APIView):
"""POST /houtai/htscxytp — 删除协议图片"""
permission_classes = [permissions.IsAuthenticated]
parser_classes = [JSONParser]
def post(self, request):
kefu, err = _check_perm(request)
if kefu is None:
return err
img_id = request.data.get('image_id')
if not img_id:
return Response({'code': 400, 'msg': '缺少 image_id'})
try:
img = XcxXieyiImage.objects.select_related('xieyi').get(id=img_id)
except XcxXieyiImage.DoesNotExist:
return Response({'code': 404, 'msg': '图片不存在'})
xieyi = img.xieyi
img.delete()
xieyi.version = (xieyi.version or 1) + 1
xieyi.save(update_fields=['version', 'updated_at'])
return Response({'code': 0, 'msg': '删除成功'})
class XieyiSignRecordAPIView(APIView):
"""POST /houtai/hthqxyqs — 查询签署记录"""
permission_classes = [permissions.IsAuthenticated]
parser_classes = [JSONParser]
def post(self, request):
kefu, err = _check_perm(request)
if kefu is None:
return err
yonghuid = (request.data.get('yonghuid') or '').strip()
xieyi_id = request.data.get('xieyi_id')
qs = XcxXieyiQianshu.objects.select_related('xieyi').order_by('-signed_at')
if yonghuid:
qs = qs.filter(yonghuid=yonghuid)
if xieyi_id:
qs = qs.filter(xieyi_id=xieyi_id)
items = []
for r in qs[:200]:
items.append({
'id': r.id,
'yonghuid': r.yonghuid,
'xieyi_id': r.xieyi_id,
'xieyi_title': r.xieyi.title,
'xieyi_version': r.xieyi_version,
'shenfen': r.shenfen,
'signature_path': r.signature_path,
'signed_at': r.signed_at.strftime('%Y-%m-%d %H:%M:%S'),
'client_ip': r.client_ip,
})
return Response({'code': 0, 'data': {'items': items}})