263 lines
10 KiB
Python
263 lines
10 KiB
Python
"""后台 — 小程序协议管理"""
|
||
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}})
|