feat: 后台考核记录列表统计与退回待审核操作
This commit is contained in:
@@ -14,7 +14,7 @@ from .view import (GetRolePermissionView,
|
||||
FineApplyView, PunishDashouView,
|
||||
FaKuanTongJiView, FaKuanLieBiaoView, FaKuanChuLiView, FaKuanChuangJianView,
|
||||
HqbkxxView,BkxgView,CaiwuView,CwhybkhqView, HybkjtsjView, SzxxView, CwddhqlxView, CwhqjtddsjView,
|
||||
CwqtczhqView, KhpzhqView, ChzsgcView,KhgglView, ShgxgsjView, ZxkfghdsView)
|
||||
CwqtczhqView, KhpzhqView, ChzsgcView,KhgglView, ShgxgsjView, KhjlglView, KhjlczView, ZxkfghdsView)
|
||||
|
||||
urlpatterns = [
|
||||
path('gljshq', GetRolePermissionView.as_view(), name='获取就角色信息'),
|
||||
@@ -103,6 +103,8 @@ urlpatterns = [
|
||||
|
||||
path('khggl', KhgglView.as_view(), name='获取考核管信息'),
|
||||
path('shgxgsj', ShgxgsjView.as_view(), name='修改考核管数据'),
|
||||
path('khjlgl', KhjlglView.as_view(), name='考核记录列表与统计'),
|
||||
path('khjlcz', KhjlczView.as_view(), name='考核记录操作'),
|
||||
|
||||
path('zxkfghds', ZxkfghdsView.as_view(), name='链接换打手或重新下单'),
|
||||
|
||||
|
||||
368
backend/view.py
368
backend/view.py
@@ -97,7 +97,7 @@ from config.models import (
|
||||
## rank
|
||||
from rank.models import (
|
||||
KaoheguanBankuai, Bankuai, Chenghao, KaoheCishuFeiyong,
|
||||
YonghuChenghao
|
||||
YonghuChenghao, ShenheJilu, KaoheJiluFeiyong, KaoheJujueJilu
|
||||
)
|
||||
|
||||
# 序列化器
|
||||
@@ -8836,6 +8836,372 @@ class ZxkfghdsView(APIView):
|
||||
return '游戏订单'
|
||||
|
||||
|
||||
# ==================== 考核记录管理 ====================
|
||||
|
||||
SHENHE_ZHUANGTAI_MAP = {
|
||||
0: '考核中',
|
||||
1: '已通过',
|
||||
2: '未通过',
|
||||
3: '待审核',
|
||||
}
|
||||
|
||||
|
||||
def _batch_user_profile_map(user_uids):
|
||||
"""批量获取用户头像、昵称、手机号"""
|
||||
uids = list({u for u in user_uids if u})
|
||||
if not uids:
|
||||
return {}
|
||||
users = User.query.filter(UserUID__in=uids)
|
||||
dashou_nicks = {
|
||||
d.user.UserUID: d.nicheng
|
||||
for d in UserDashou.query.filter(user__UserUID__in=uids).select_related('user')
|
||||
}
|
||||
result = {}
|
||||
for u in users:
|
||||
result[u.UserUID] = {
|
||||
'yonghuid': u.UserUID,
|
||||
'avatar': u.Avatar or '',
|
||||
'phone': u.Phone or '',
|
||||
'nicheng': dashou_nicks.get(u.UserUID) or u.UserName or u.Phone or u.UserUID,
|
||||
}
|
||||
return result
|
||||
|
||||
|
||||
def _build_shenhe_jilu_filters(request_data):
|
||||
"""构造 ShenheJilu 查询条件(列表与统计共用)"""
|
||||
qs = ShenheJilu.query.select_related('bankuai', 'chenghao')
|
||||
|
||||
jilu_id = (request_data.get('jilu_id') or '').strip()
|
||||
if jilu_id:
|
||||
qs = qs.filter(jilu_id=jilu_id)
|
||||
|
||||
zhuangtai = request_data.get('zhuangtai')
|
||||
if zhuangtai is not None and zhuangtai != '':
|
||||
qs = qs.filter(zhuangtai=int(zhuangtai))
|
||||
|
||||
assessed = request_data.get('assessed')
|
||||
if assessed == 'done':
|
||||
qs = qs.filter(zhuangtai__in=[1, 2])
|
||||
elif assessed == 'undone':
|
||||
qs = qs.filter(zhuangtai__in=[0, 3])
|
||||
|
||||
bankuai_id = request_data.get('bankuai_id')
|
||||
if bankuai_id not in (None, ''):
|
||||
qs = qs.filter(bankuai_id=int(bankuai_id))
|
||||
|
||||
chenghao_id = request_data.get('chenghao_id')
|
||||
if chenghao_id not in (None, ''):
|
||||
qs = qs.filter(chenghao_id=int(chenghao_id))
|
||||
|
||||
cishu = request_data.get('cishu')
|
||||
if cishu not in (None, ''):
|
||||
qs = qs.filter(cishu=int(cishu))
|
||||
|
||||
dashou_kw = (request_data.get('dashou_keyword') or '').strip()
|
||||
if dashou_kw:
|
||||
dashou_uids = list(
|
||||
User.query.filter(
|
||||
Q(UserUID=dashou_kw) |
|
||||
Q(UserName__icontains=dashou_kw) |
|
||||
Q(Phone__icontains=dashou_kw) |
|
||||
Q(DashouProfile__nicheng__icontains=dashou_kw)
|
||||
).values_list('UserUID', flat=True)
|
||||
)
|
||||
if dashou_uids:
|
||||
qs = qs.filter(shenqingren_id__in=dashou_uids)
|
||||
else:
|
||||
qs = qs.none()
|
||||
|
||||
kg_kw = (request_data.get('kaoheguan_keyword') or '').strip()
|
||||
if kg_kw:
|
||||
kg_uids = list(
|
||||
User.query.filter(
|
||||
Q(UserUID=kg_kw) |
|
||||
Q(UserName__icontains=kg_kw) |
|
||||
Q(Phone__icontains=kg_kw) |
|
||||
Q(DashouProfile__nicheng__icontains=kg_kw)
|
||||
).values_list('UserUID', flat=True)
|
||||
)
|
||||
if kg_uids:
|
||||
qs = qs.filter(shenheguan_id__in=kg_uids)
|
||||
else:
|
||||
qs = qs.none()
|
||||
|
||||
start_time = (request_data.get('start_time') or '').strip()
|
||||
end_time = (request_data.get('end_time') or '').strip()
|
||||
if start_time:
|
||||
qs = qs.filter(CreateTime__gte=start_time)
|
||||
if end_time:
|
||||
qs = qs.filter(CreateTime__lte=end_time)
|
||||
|
||||
has_kaoheguan = request_data.get('has_kaoheguan')
|
||||
if has_kaoheguan in (True, 'true', '1', 1):
|
||||
qs = qs.exclude(shenheguan_id__isnull=True).exclude(shenheguan_id='')
|
||||
elif has_kaoheguan in (False, 'false', '0', 0):
|
||||
qs = qs.filter(Q(shenheguan_id__isnull=True) | Q(shenheguan_id=''))
|
||||
|
||||
return qs
|
||||
|
||||
|
||||
def _serialize_shenhe_jilu_row(jl, profile_map, fee_map=None, reject_count_map=None):
|
||||
dashou = profile_map.get(jl.shenqingren_id, {
|
||||
'yonghuid': jl.shenqingren_id,
|
||||
'avatar': '',
|
||||
'phone': '',
|
||||
'nicheng': jl.shenqingren_id,
|
||||
})
|
||||
kaoheguan = None
|
||||
if jl.shenheguan_id:
|
||||
kaoheguan = profile_map.get(jl.shenheguan_id, {
|
||||
'yonghuid': jl.shenheguan_id,
|
||||
'avatar': '',
|
||||
'phone': '',
|
||||
'nicheng': jl.shenheguan_id,
|
||||
})
|
||||
kaoheguan['game_id'] = jl.shenheguan_youxi_id or ''
|
||||
|
||||
current_fee = 0.0
|
||||
if fee_map is not None:
|
||||
current_fee = fee_map.get((jl.jilu_id, jl.cishu), 0.0)
|
||||
else:
|
||||
fd = KaoheJiluFeiyong.query.filter(jilu_id=jl.jilu_id, cishu=jl.cishu).first()
|
||||
if fd:
|
||||
current_fee = float(fd.jine)
|
||||
|
||||
reject_count = 0
|
||||
if reject_count_map is not None:
|
||||
reject_count = reject_count_map.get(jl.jilu_id, 0)
|
||||
|
||||
return {
|
||||
'jilu_id': jl.jilu_id,
|
||||
'zhuangtai': jl.zhuangtai,
|
||||
'zhuangtai_text': SHENHE_ZHUANGTAI_MAP.get(jl.zhuangtai, str(jl.zhuangtai)),
|
||||
'cishu': jl.cishu,
|
||||
'jiaofei_jine': float(jl.jiaofei_jine or 0),
|
||||
'current_fee': current_fee,
|
||||
'bankuai_id': jl.bankuai.bankuai_id if jl.bankuai else None,
|
||||
'bankuai_name': jl.bankuai.mingcheng if jl.bankuai else '',
|
||||
'chenghao_id': jl.chenghao.id if jl.chenghao else None,
|
||||
'chenghao_name': jl.chenghao.mingcheng if jl.chenghao else '',
|
||||
'chenghao_icon': jl.chenghao.tubiao_url if jl.chenghao else '',
|
||||
'guize_neirong': jl.guize_neirong or '',
|
||||
'dashou': {
|
||||
**dashou,
|
||||
'game_id': jl.dashou_youxi_id or '',
|
||||
'beizhu': jl.dashou_beizhu or '',
|
||||
},
|
||||
'kaoheguan': kaoheguan,
|
||||
'reject_count': reject_count,
|
||||
'CreateTime': jl.CreateTime.strftime('%Y-%m-%d %H:%M:%S') if jl.CreateTime else '',
|
||||
'UpdateTime': jl.UpdateTime.strftime('%Y-%m-%d %H:%M:%S') if jl.UpdateTime else '',
|
||||
}
|
||||
|
||||
|
||||
class KhjlglView(APIView):
|
||||
"""
|
||||
考核记录列表 + 统计
|
||||
POST /houtai/khjlgl
|
||||
"""
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
def post(self, request):
|
||||
try:
|
||||
username_from_frontend = request.data.get('phone', None)
|
||||
kefu_obj, permissions = verify_kefu_permission(request, username_from_frontend)
|
||||
if kefu_obj is None:
|
||||
return permissions
|
||||
if 'kaohepeizhi' not in permissions:
|
||||
return Response({'code': 403, 'msg': '无考核管理权限'}, status=403)
|
||||
|
||||
page = int(request.data.get('page', 1))
|
||||
page_size = int(request.data.get('page_size', 20))
|
||||
if page < 1:
|
||||
page = 1
|
||||
if page_size < 1:
|
||||
page_size = 20
|
||||
if page_size > 100:
|
||||
page_size = 100
|
||||
|
||||
qs = _build_shenhe_jilu_filters(request.data)
|
||||
|
||||
stats_qs = qs
|
||||
agg = stats_qs.aggregate(
|
||||
total_fee=Sum('jiaofei_jine'),
|
||||
)
|
||||
tag_rows = stats_qs.values(
|
||||
'chenghao_id', 'chenghao__mingcheng'
|
||||
).annotate(
|
||||
total=Count('jilu_id'),
|
||||
passed=Count('jilu_id', filter=Q(zhuangtai=1)),
|
||||
failed=Count('jilu_id', filter=Q(zhuangtai=2)),
|
||||
in_progress=Count('jilu_id', filter=Q(zhuangtai=0)),
|
||||
pending=Count('jilu_id', filter=Q(zhuangtai=3)),
|
||||
).order_by('-total')
|
||||
|
||||
stats = {
|
||||
'total': stats_qs.count(),
|
||||
'passed': stats_qs.filter(zhuangtai=1).count(),
|
||||
'failed': stats_qs.filter(zhuangtai=2).count(),
|
||||
'in_progress': stats_qs.filter(zhuangtai=0).count(),
|
||||
'pending': stats_qs.filter(zhuangtai=3).count(),
|
||||
'total_fee': float(agg['total_fee'] or 0),
|
||||
'tag_stats': [
|
||||
{
|
||||
'chenghao_id': r['chenghao_id'],
|
||||
'chenghao_name': r['chenghao__mingcheng'] or '未知标签',
|
||||
'total': r['total'],
|
||||
'passed': r['passed'],
|
||||
'failed': r['failed'],
|
||||
'in_progress': r['in_progress'],
|
||||
'pending': r['pending'],
|
||||
}
|
||||
for r in tag_rows if r['chenghao_id']
|
||||
],
|
||||
}
|
||||
|
||||
total = qs.count()
|
||||
start = (page - 1) * page_size
|
||||
rows = qs.order_by('-CreateTime')[start:start + page_size]
|
||||
|
||||
uids = []
|
||||
jilu_ids = []
|
||||
for jl in rows:
|
||||
uids.append(jl.shenqingren_id)
|
||||
if jl.shenheguan_id:
|
||||
uids.append(jl.shenheguan_id)
|
||||
jilu_ids.append(jl.jilu_id)
|
||||
profile_map = _batch_user_profile_map(uids)
|
||||
|
||||
fee_pairs = [(jl.jilu_id, jl.cishu) for jl in rows]
|
||||
fee_map = {}
|
||||
if fee_pairs:
|
||||
jids = [p[0] for p in fee_pairs]
|
||||
for fd in KaoheJiluFeiyong.query.filter(jilu_id__in=jids):
|
||||
fee_map[(fd.jilu_id, fd.cishu)] = float(fd.jine)
|
||||
|
||||
reject_counts = dict(
|
||||
KaoheJujueJilu.query.filter(jilu_id__in=jilu_ids)
|
||||
.values('jilu_id')
|
||||
.annotate(cnt=Count('id'))
|
||||
.values_list('jilu_id', 'cnt')
|
||||
) if jilu_ids else {}
|
||||
|
||||
data_list = [
|
||||
_serialize_shenhe_jilu_row(jl, profile_map, fee_map, reject_counts)
|
||||
for jl in rows
|
||||
]
|
||||
|
||||
all_bankuai = list(Bankuai.query.values('bankuai_id', 'mingcheng'))
|
||||
all_tags = list(
|
||||
Chenghao.query.filter(leixing='dashou')
|
||||
.values('id', 'mingcheng', 'bankuai_id')
|
||||
.order_by('mingcheng')
|
||||
)
|
||||
|
||||
return Response({
|
||||
'code': 0,
|
||||
'msg': 'ok',
|
||||
'data': {
|
||||
'total': total,
|
||||
'page': page,
|
||||
'page_size': page_size,
|
||||
'list': data_list,
|
||||
'stats': stats,
|
||||
'all_bankuai': all_bankuai,
|
||||
'all_tags': all_tags,
|
||||
},
|
||||
})
|
||||
except Exception as e:
|
||||
logger.exception('KhjlglView 接口错误')
|
||||
return Response({'code': 1, 'msg': f'服务器内部错误: {str(e)}'}, status=500)
|
||||
|
||||
|
||||
class KhjlczView(APIView):
|
||||
"""
|
||||
考核记录操作 / 详情
|
||||
POST /houtai/khjlcz
|
||||
action:
|
||||
- get_detail: 获取单条详情(含缴费明细、拒绝历史)
|
||||
- to_pending: 考核中 → 待审核(取消指定考核官,与小程序 transfer 一致)
|
||||
"""
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
def post(self, request):
|
||||
try:
|
||||
username_from_frontend = request.data.get('phone', None)
|
||||
kefu_obj, permissions = verify_kefu_permission(request, username_from_frontend)
|
||||
if kefu_obj is None:
|
||||
return permissions
|
||||
if 'kaohepeizhi' not in permissions:
|
||||
return Response({'code': 403, 'msg': '无考核管理权限'}, status=403)
|
||||
|
||||
action = request.data.get('action')
|
||||
jilu_id = (request.data.get('jilu_id') or '').strip()
|
||||
if not jilu_id:
|
||||
return Response({'code': 1, 'msg': '缺少记录ID'}, status=400)
|
||||
|
||||
if action == 'get_detail':
|
||||
try:
|
||||
jl = ShenheJilu.query.select_related('bankuai', 'chenghao').get(jilu_id=jilu_id)
|
||||
except ShenheJilu.DoesNotExist:
|
||||
return Response({'code': 1, 'msg': '记录不存在'}, status=404)
|
||||
|
||||
uids = [jl.shenqingren_id]
|
||||
if jl.shenheguan_id:
|
||||
uids.append(jl.shenheguan_id)
|
||||
profile_map = _batch_user_profile_map(uids)
|
||||
|
||||
fee_list = [
|
||||
{
|
||||
'cishu': f.cishu,
|
||||
'jine': float(f.jine),
|
||||
}
|
||||
for f in KaoheJiluFeiyong.query.filter(jilu_id=jilu_id).order_by('cishu')
|
||||
]
|
||||
reject_list = []
|
||||
for r in KaoheJujueJilu.query.filter(jilu_id=jilu_id).order_by('-CreateTime'):
|
||||
kg_prof = _batch_user_profile_map([r.shenheguan_id]).get(r.shenheguan_id, {})
|
||||
reject_list.append({
|
||||
'cishu': r.cishu,
|
||||
'shenheguan_id': r.shenheguan_id,
|
||||
'shenheguan_nicheng': kg_prof.get('nicheng', r.shenheguan_id),
|
||||
'yuanyin': r.yuanyin,
|
||||
'CreateTime': r.CreateTime.strftime('%Y-%m-%d %H:%M:%S') if r.CreateTime else '',
|
||||
})
|
||||
|
||||
record = _serialize_shenhe_jilu_row(jl, profile_map)
|
||||
record['fee_list'] = fee_list
|
||||
record['reject_list'] = reject_list
|
||||
return Response({'code': 0, 'msg': 'ok', 'data': record})
|
||||
|
||||
if action == 'to_pending':
|
||||
with transaction.atomic():
|
||||
jl = ShenheJilu.objects.select_for_update().filter(jilu_id=jilu_id).first()
|
||||
if not jl:
|
||||
return Response({'code': 1, 'msg': '记录不存在'}, status=404)
|
||||
if jl.zhuangtai != 0:
|
||||
return Response({'code': 1, 'msg': '仅「考核中」的记录可退回待审核'}, status=400)
|
||||
|
||||
old_kg_id = jl.shenheguan_id
|
||||
jl.shenheguan_id = None
|
||||
jl.shenheguan_youxi_id = None
|
||||
jl.zhuangtai = 3
|
||||
jl.save(update_fields=['shenheguan_id', 'shenheguan_youxi_id', 'zhuangtai', 'UpdateTime'])
|
||||
|
||||
if old_kg_id:
|
||||
UserShenheguan.query.filter(user__UserUID=old_kg_id).update(shenhe_zhuangtai=0)
|
||||
|
||||
return Response({'code': 0, 'msg': '已退回待审核,考核官指定已取消'})
|
||||
|
||||
return Response({'code': 1, 'msg': '无效的操作类型'}, status=400)
|
||||
|
||||
except Exception as e:
|
||||
logger.exception('KhjlczView 接口错误')
|
||||
return Response({'code': 1, 'msg': f'服务器内部错误: {str(e)}'}, status=500)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user