将文件夹命名从拼音改为英文,整理了一些代码,将导入语句迁移到了头部
This commit is contained in:
0
rank/__init__.py
Normal file
0
rank/__init__.py
Normal file
3
rank/admin.py
Normal file
3
rank/admin.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from django.contrib import admin
|
||||
|
||||
# Register your models here.
|
||||
6
rank/apps.py
Normal file
6
rank/apps.py
Normal file
@@ -0,0 +1,6 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class DengjiConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'dengji'
|
||||
111
rank/migrations/0001_initial.py
Normal file
111
rank/migrations/0001_initial.py
Normal file
@@ -0,0 +1,111 @@
|
||||
# Generated by Django 4.2.27 on 2026-05-12 02:17
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
('dingdan', '0026_fadanfenhonglilv_alter_fadan_shenqingren_shenfen_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Bankuai',
|
||||
fields=[
|
||||
('bankuai_id', models.AutoField(primary_key=True, serialize=False, verbose_name='板块ID')),
|
||||
('mingcheng', models.CharField(db_index=True, max_length=50, unique=True, verbose_name='板块名称')),
|
||||
('create_time', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '板块',
|
||||
'verbose_name_plural': '板块',
|
||||
'db_table': 'bankuai',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Chenghao',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('mingcheng', models.CharField(max_length=50, unique=True, verbose_name='称号名称')),
|
||||
('leixing', models.CharField(choices=[('dashou', '打手'), ('boss', '老板'), ('shangjia', '商家'), ('guanshi', '管事'), ('zuzhang', '组长')], max_length=10, verbose_name='称号类型')),
|
||||
('tubiao_url', models.CharField(blank=True, max_length=200, null=True, verbose_name='称号图标相对URL')),
|
||||
('texiao_miaoshu', models.TextField(blank=True, null=True, verbose_name='特效描述(JSON)')),
|
||||
('create_time', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
|
||||
('bankuai', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='dengji.bankuai', verbose_name='所属板块(空=全板块通用)')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '称号',
|
||||
'verbose_name_plural': '称号',
|
||||
'db_table': 'chenghao',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='YonghuChenghao',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('huode_time', models.DateTimeField(auto_now_add=True, verbose_name='获得时间')),
|
||||
('chenghao', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='dengji.chenghao', verbose_name='称号')),
|
||||
('yonghu', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='chenghao_list', to=settings.AUTH_USER_MODEL, verbose_name='用户')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '用户称号关联',
|
||||
'verbose_name_plural': '用户称号关联',
|
||||
'db_table': 'yonghu_chenghao',
|
||||
'indexes': [models.Index(fields=['yonghu', 'chenghao'], name='yonghu_chen_yonghu__cac0a1_idx')],
|
||||
'unique_together': {('yonghu', 'chenghao')},
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='JingyanJilu',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('yonghu_id', models.CharField(db_index=True, max_length=7, verbose_name='用户ID')),
|
||||
('yonghu_leixing', models.CharField(choices=[('dashou', '打手'), ('boss', '老板'), ('shangjia', '商家'), ('guanshi', '管事'), ('zuzhang', '组长')], max_length=10, verbose_name='用户类型')),
|
||||
('sudu_jingyan', models.DecimalField(decimal_places=2, default=0, max_digits=8, verbose_name='上线速度经验')),
|
||||
('shili_jingyan', models.DecimalField(decimal_places=2, default=0, max_digits=8, verbose_name='打手实力经验')),
|
||||
('taidu_jingyan', models.DecimalField(decimal_places=2, default=0, max_digits=8, verbose_name='服务态度经验')),
|
||||
('zonghe_jingyan', models.DecimalField(decimal_places=2, default=0, max_digits=8, verbose_name='综合经验')),
|
||||
('dingdan_id', models.CharField(blank=True, db_index=True, max_length=32, null=True, verbose_name='关联订单ID')),
|
||||
('create_time', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
|
||||
('update_time', models.DateTimeField(auto_now=True, verbose_name='更新时间')),
|
||||
('bankuai', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='dengji.bankuai', verbose_name='所属板块')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '经验变动记录',
|
||||
'verbose_name_plural': '经验变动记录',
|
||||
'db_table': 'jingyan_jilu',
|
||||
'indexes': [models.Index(fields=['yonghu_id', 'bankuai', 'create_time'], name='jingyan_jil_yonghu__786992_idx')],
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='DashouBiaoxian',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('dashou_id', models.CharField(db_index=True, max_length=32, verbose_name='打手ID')),
|
||||
('shangxian_sudu', models.PositiveSmallIntegerField(blank=True, null=True, verbose_name='上线速度评价(1-5)')),
|
||||
('fuwu_taidu', models.PositiveSmallIntegerField(blank=True, null=True, verbose_name='服务态度评价(1-5)')),
|
||||
('fanche_cishu', models.PositiveIntegerField(blank=True, null=True, verbose_name='翻车次数')),
|
||||
('create_time', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
|
||||
('jiedan_time', models.DateTimeField(blank=True, null=True, verbose_name='接单时间')),
|
||||
('tijiao_time', models.DateTimeField(blank=True, null=True, verbose_name='提交时间')),
|
||||
('bankuai', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='dengji.bankuai', verbose_name='所属板块')),
|
||||
('dingdan', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='biaoxian', to='dingdan.dingdan', verbose_name='关联订单')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '打手订单表现',
|
||||
'verbose_name_plural': '打手订单表现',
|
||||
'db_table': 'dashou_biaoxian',
|
||||
'indexes': [models.Index(fields=['dashou_id', 'bankuai', 'create_time'], name='dashou_biao_dashou__36e1c3_idx')],
|
||||
},
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name='chenghao',
|
||||
index=models.Index(fields=['leixing', 'bankuai'], name='chenghao_leixing_8f4371_idx'),
|
||||
),
|
||||
]
|
||||
20
rank/migrations/0002_alter_dashoubiaoxian_dingdan.py
Normal file
20
rank/migrations/0002_alter_dashoubiaoxian_dingdan.py
Normal file
@@ -0,0 +1,20 @@
|
||||
# Generated by Django 4.2.27 on 2026-05-12 02:25
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('dingdan', '0026_fadanfenhonglilv_alter_fadan_shenqingren_shenfen_and_more'),
|
||||
('dengji', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='dashoubiaoxian',
|
||||
name='dingdan',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='biaoxian', to='dingdan.dingdan', to_field='dingdan_id', verbose_name='关联订单'),
|
||||
),
|
||||
]
|
||||
19
rank/migrations/0003_alter_dashoubiaoxian_bankuai.py
Normal file
19
rank/migrations/0003_alter_dashoubiaoxian_bankuai.py
Normal file
@@ -0,0 +1,19 @@
|
||||
# Generated by Django 4.2.27 on 2026-05-12 02:32
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('dengji', '0002_alter_dashoubiaoxian_dingdan'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='dashoubiaoxian',
|
||||
name='bankuai',
|
||||
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, to='dengji.bankuai', verbose_name='所属板块'),
|
||||
),
|
||||
]
|
||||
26
rank/migrations/0004_dingdanbiaoqian.py
Normal file
26
rank/migrations/0004_dingdanbiaoqian.py
Normal file
@@ -0,0 +1,26 @@
|
||||
# dengji/migrations/0004_dingdanbiaoqian.py
|
||||
from django.db import migrations
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('dingdan', '0026_fadanfenhonglilv_alter_fadan_shenqingren_shenfen_and_more'), # 保持你之前的依赖
|
||||
('dengji', '0003_alter_dashoubiaoxian_bankuai'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunSQL(
|
||||
sql="""
|
||||
CREATE TABLE IF NOT EXISTS dingdan_biaoqian (
|
||||
id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||
create_time DATETIME(6) NOT NULL,
|
||||
chenghao_id BIGINT NOT NULL,
|
||||
dingdan_id VARCHAR(32) NOT NULL,
|
||||
CONSTRAINT fk_dingdanbiaoqian_chenghao FOREIGN KEY (chenghao_id) REFERENCES chenghao (id),
|
||||
CONSTRAINT fk_dingdanbiaoqian_dingdan FOREIGN KEY (dingdan_id) REFERENCES dingdan (dingdan_id),
|
||||
UNIQUE KEY uniq_dingdan_chenghao (dingdan_id, chenghao_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
""",
|
||||
reverse_sql="DROP TABLE IF EXISTS dingdan_biaoqian;"
|
||||
),
|
||||
]
|
||||
36
rank/migrations/0005_fix_state.py
Normal file
36
rank/migrations/0005_fix_state.py
Normal file
@@ -0,0 +1,36 @@
|
||||
# dengji/migrations/0005_fix_state.py
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('dingdan', '0026_fadanfenhonglilv_alter_fadan_shenqingren_shenfen_and_more'), # 保持你之前的依赖
|
||||
('dengji', '0004_dingdanbiaoqian'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.SeparateDatabaseAndState(
|
||||
database_operations=[], # 表已存在,不做任何数据库操作
|
||||
state_operations=[
|
||||
migrations.CreateModel(
|
||||
name='DingdanBiaoqian',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('create_time', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
|
||||
('chenghao', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='dengji.chenghao', verbose_name='标签')),
|
||||
('dingdan', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='dingdan.dingdan', to_field='dingdan_id', verbose_name='订单')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '订单需求标签',
|
||||
'verbose_name_plural': '订单需求标签',
|
||||
'db_table': 'dingdan_biaoqian',
|
||||
'unique_together': {('dingdan', 'chenghao')},
|
||||
'indexes': [
|
||||
models.Index(fields=['dingdan'], name='dingdan_bia_dingdan_4d046b_idx'),
|
||||
],
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
]
|
||||
35
rank/migrations/0006_shenhejilu.py
Normal file
35
rank/migrations/0006_shenhejilu.py
Normal file
@@ -0,0 +1,35 @@
|
||||
# Generated by Django 4.2.27 on 2026-05-14 18:42
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('dengji', '0005_fix_state'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='ShenheJilu',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('shenqingren_id', models.CharField(max_length=7, verbose_name='申请人用户ID')),
|
||||
('shenheguan_id', models.CharField(max_length=7, null=True, verbose_name='审核官用户ID')),
|
||||
('zhuangtai', models.IntegerField(choices=[(0, '审核中'), (1, '通过'), (2, '未通过')], default=0, verbose_name='审核状态')),
|
||||
('cishu', models.IntegerField(default=1, verbose_name='第几次审核')),
|
||||
('jiaofei_jine', models.DecimalField(decimal_places=2, default=0.0, max_digits=10, verbose_name='缴纳费用')),
|
||||
('create_time', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
|
||||
('update_time', models.DateTimeField(auto_now=True, verbose_name='更新时间')),
|
||||
('bankuai', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='dengji.bankuai', verbose_name='审核板块')),
|
||||
('chenghao', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='dengji.chenghao', verbose_name='审核标签')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '审核记录',
|
||||
'verbose_name_plural': '审核记录',
|
||||
'db_table': 'shenhe_jilu',
|
||||
'indexes': [models.Index(fields=['shenqingren_id', 'zhuangtai'], name='shenhe_jilu_shenqin_502e9b_idx'), models.Index(fields=['shenheguan_id'], name='shenhe_jilu_shenheg_5c9959_idx')],
|
||||
},
|
||||
),
|
||||
]
|
||||
29
rank/migrations/0007_kaoheguanbankuai.py
Normal file
29
rank/migrations/0007_kaoheguanbankuai.py
Normal file
@@ -0,0 +1,29 @@
|
||||
# Generated by Django 4.2.27 on 2026-05-15 00:31
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('dengji', '0006_shenhejilu'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='KaoheguanBankuai',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('kaoheguan_id', models.CharField(db_index=True, max_length=7, verbose_name='考核官用户ID')),
|
||||
('bankuai', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='dengji.bankuai', verbose_name='所属板块')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '考核官板块关联',
|
||||
'verbose_name_plural': '考核官板块关联',
|
||||
'db_table': 'kaoheguan_bankuai',
|
||||
'indexes': [models.Index(fields=['kaoheguan_id'], name='kaoheguan_b_kaohegu_00f7c5_idx')],
|
||||
'unique_together': {('kaoheguan_id', 'bankuai')},
|
||||
},
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,48 @@
|
||||
# Generated by Django 4.2.27 on 2026-05-15 04:16
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('dengji', '0007_kaoheguanbankuai'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='chenghao',
|
||||
name='kaohe_guize',
|
||||
field=models.TextField(blank=True, null=True, verbose_name='考核规则'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='shenhejilu',
|
||||
name='dashou_beizhu',
|
||||
field=models.TextField(blank=True, null=True, verbose_name='打手备注'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='shenhejilu',
|
||||
name='dashou_youxi_id',
|
||||
field=models.CharField(blank=True, max_length=50, null=True, verbose_name='打手游戏ID'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='shenhejilu',
|
||||
name='guize_neirong',
|
||||
field=models.TextField(blank=True, null=True, verbose_name='规则内容'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='shenhejilu',
|
||||
name='jilu_id',
|
||||
field=models.CharField(db_index=True, max_length=32, null=True, verbose_name='记录ID'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='shenhejilu',
|
||||
name='shenheguan_youxi_id',
|
||||
field=models.CharField(blank=True, max_length=50, null=True, verbose_name='审核官游戏ID'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='shenhejilu',
|
||||
name='zhuangtai',
|
||||
field=models.IntegerField(choices=[(0, '审核中'), (1, '通过'), (2, '未通过'), (3, '待审核')], default=0, verbose_name='审核状态'),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,58 @@
|
||||
# Generated by Django 4.2.27 on 2026-05-15 13:20
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('dengji', '0008_chenghao_kaohe_guize_shenhejilu_dashou_beizhu_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='chenghao',
|
||||
name='kaioi_jinpai',
|
||||
field=models.BooleanField(default=False, verbose_name='是否同时开启金牌'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='shenhejilu',
|
||||
name='jilu_id',
|
||||
field=models.CharField(db_index=True, default='Sh111', max_length=32, unique=True, verbose_name='记录ID'),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='KaoheJujueJilu',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('cishu', models.IntegerField(verbose_name='对应次数')),
|
||||
('shenheguan_id', models.CharField(max_length=7, verbose_name='考核官用户ID')),
|
||||
('yuanyin', models.TextField(verbose_name='拒绝原因')),
|
||||
('create_time', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
|
||||
('jilu', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='dengji.shenhejilu', to_field='jilu_id', verbose_name='审核记录')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '拒绝原因记录',
|
||||
'verbose_name_plural': '拒绝原因记录',
|
||||
'db_table': 'kaohe_jujue_jilu',
|
||||
'indexes': [models.Index(fields=['jilu_id', 'cishu'], name='kaohe_jujue_jilu_id_1f2b29_idx')],
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='KaoheCishuFeiyong',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('cishu', models.IntegerField(verbose_name='第几次考核')),
|
||||
('feiyong', models.DecimalField(decimal_places=2, max_digits=10, verbose_name='需缴纳金额')),
|
||||
('chenghao', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='dengji.chenghao', verbose_name='标签')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '考核次数费用',
|
||||
'verbose_name_plural': '考核次数费用',
|
||||
'db_table': 'kaohe_cishu_feiyong',
|
||||
'indexes': [models.Index(fields=['chenghao', 'cishu'], name='kaohe_cishu_chengha_edc272_idx')],
|
||||
'unique_together': {('chenghao', 'cishu')},
|
||||
},
|
||||
),
|
||||
]
|
||||
29
rank/migrations/0010_kaohejilufeiyong.py
Normal file
29
rank/migrations/0010_kaohejilufeiyong.py
Normal file
@@ -0,0 +1,29 @@
|
||||
# Generated by Django 4.2.27 on 2026-05-15 16:10
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('dengji', '0009_chenghao_kaioi_jinpai_alter_shenhejilu_jilu_id_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='KaoheJiluFeiyong',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('cishu', models.IntegerField(verbose_name='第几次考核')),
|
||||
('jine', models.DecimalField(decimal_places=2, max_digits=10, verbose_name='缴纳金额')),
|
||||
('jilu', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='dengji.shenhejilu', to_field='jilu_id', verbose_name='考核记录')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '考核记录费用',
|
||||
'verbose_name_plural': '考核记录费用',
|
||||
'db_table': 'kaohe_jilu_feiyong',
|
||||
'unique_together': {('jilu', 'cishu')},
|
||||
},
|
||||
),
|
||||
]
|
||||
35
rank/migrations/0011_kaohepaytemp.py
Normal file
35
rank/migrations/0011_kaohepaytemp.py
Normal file
@@ -0,0 +1,35 @@
|
||||
# Generated by Django 4.2.27 on 2026-05-19 13:35
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('dengji', '0010_kaohejilufeiyong'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='KaohePayTemp',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('dingdan_id', models.CharField(db_index=True, max_length=50, unique=True, verbose_name='订单ID')),
|
||||
('yonghuid', models.CharField(db_index=True, max_length=7, verbose_name='用户ID')),
|
||||
('tag_id', models.IntegerField(verbose_name='标签ID')),
|
||||
('game_nick', models.CharField(max_length=100, verbose_name='游戏昵称')),
|
||||
('remark', models.TextField(blank=True, verbose_name='备注')),
|
||||
('reapply', models.BooleanField(default=False, verbose_name='是否再次申请')),
|
||||
('jilu_id', models.CharField(blank=True, max_length=32, null=True, verbose_name='原记录ID(再次申请时)')),
|
||||
('shenheguan_id', models.CharField(blank=True, max_length=7, verbose_name='指定考核官ID')),
|
||||
('cishu', models.IntegerField(verbose_name='本次考核次数(预计算)')),
|
||||
('fee', models.DecimalField(decimal_places=2, max_digits=10, verbose_name='本次费用(分账单位)')),
|
||||
('create_time', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '考核支付临时表',
|
||||
'verbose_name_plural': '考核支付临时表',
|
||||
'db_table': 'kaohe_pay_temp',
|
||||
},
|
||||
),
|
||||
]
|
||||
0
rank/migrations/__init__.py
Normal file
0
rank/migrations/__init__.py
Normal file
224
rank/models.py
Normal file
224
rank/models.py
Normal file
@@ -0,0 +1,224 @@
|
||||
from django.db import models
|
||||
from django.conf import settings
|
||||
from orders.models import Dingdan
|
||||
|
||||
# ==================== 板块表 ====================
|
||||
class Bankuai(models.Model):
|
||||
bankuai_id = models.AutoField(primary_key=True, verbose_name='板块ID')
|
||||
mingcheng = models.CharField(max_length=50, unique=True, db_index=True, verbose_name='板块名称')
|
||||
create_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
|
||||
|
||||
class Meta:
|
||||
db_table = 'bankuai'
|
||||
verbose_name = '板块'
|
||||
verbose_name_plural = verbose_name
|
||||
|
||||
def __str__(self):
|
||||
return self.mingcheng
|
||||
|
||||
|
||||
# ==================== 打手订单表现记录 ====================
|
||||
class DashouBiaoxian(models.Model):
|
||||
dingdan = models.ForeignKey('dingdan.Dingdan', to_field='dingdan_id', on_delete=models.CASCADE, related_name='biaoxian', verbose_name='关联订单', db_index=True)
|
||||
|
||||
dashou_id = models.CharField(max_length=32, db_index=True, verbose_name='打手ID')
|
||||
bankuai = models.ForeignKey(Bankuai, on_delete=models.PROTECT, to_field='bankuai_id', verbose_name='所属板块', db_index=True,null=True)
|
||||
shangxian_sudu = models.PositiveSmallIntegerField(null=True, blank=True, verbose_name='上线速度评价(1-5)')
|
||||
fuwu_taidu = models.PositiveSmallIntegerField(null=True, blank=True, verbose_name='服务态度评价(1-5)')
|
||||
fanche_cishu = models.PositiveIntegerField(null=True, blank=True, verbose_name='翻车次数')
|
||||
create_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
|
||||
jiedan_time = models.DateTimeField(null=True, blank=True, verbose_name='接单时间')
|
||||
tijiao_time = models.DateTimeField(null=True, blank=True, verbose_name='提交时间')
|
||||
|
||||
class Meta:
|
||||
db_table = 'dashou_biaoxian'
|
||||
verbose_name = '打手订单表现'
|
||||
verbose_name_plural = verbose_name
|
||||
indexes = [models.Index(fields=['dashou_id', 'bankuai', 'create_time'])]
|
||||
|
||||
|
||||
# ==================== 经验变动记录 ====================
|
||||
class JingyanJilu(models.Model):
|
||||
yonghu_id = models.CharField(max_length=7, db_index=True, verbose_name='用户ID')
|
||||
yonghu_leixing = models.CharField(max_length=10, choices=[('dashou','打手'),('boss','老板'),('shangjia','商家'),('guanshi','管事'),('zuzhang','组长')], verbose_name='用户类型')
|
||||
bankuai = models.ForeignKey(Bankuai, on_delete=models.PROTECT, to_field='bankuai_id', verbose_name='所属板块', db_index=True)
|
||||
sudu_jingyan = models.DecimalField(max_digits=8, decimal_places=2, default=0, verbose_name='上线速度经验')
|
||||
shili_jingyan = models.DecimalField(max_digits=8, decimal_places=2, default=0, verbose_name='打手实力经验')
|
||||
taidu_jingyan = models.DecimalField(max_digits=8, decimal_places=2, default=0, verbose_name='服务态度经验')
|
||||
zonghe_jingyan = models.DecimalField(max_digits=8, decimal_places=2, default=0, verbose_name='综合经验')
|
||||
dingdan_id = models.CharField(max_length=32, null=True, blank=True, db_index=True, verbose_name='关联订单ID')
|
||||
create_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
|
||||
update_time = models.DateTimeField(auto_now=True, verbose_name='更新时间')
|
||||
|
||||
|
||||
class Meta:
|
||||
db_table = 'jingyan_jilu'
|
||||
verbose_name = '经验变动记录'
|
||||
verbose_name_plural = verbose_name
|
||||
indexes = [models.Index(fields=['yonghu_id', 'bankuai', 'create_time'])]
|
||||
|
||||
|
||||
# ==================== 称号主表 ====================
|
||||
class Chenghao(models.Model):
|
||||
mingcheng = models.CharField(max_length=50, unique=True, verbose_name='称号名称')
|
||||
leixing = models.CharField(max_length=10, choices=[('dashou','打手'),('boss','老板'),('shangjia','商家'),('guanshi','管事'),('zuzhang','组长')], verbose_name='称号类型')
|
||||
bankuai = models.ForeignKey(Bankuai, on_delete=models.PROTECT, to_field='bankuai_id', null=True, blank=True, verbose_name='所属板块(空=全板块通用)')
|
||||
tubiao_url = models.CharField(max_length=200, null=True, blank=True, verbose_name='称号图标相对URL')
|
||||
texiao_miaoshu = models.TextField(null=True, blank=True, verbose_name='特效描述(JSON)')
|
||||
create_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
|
||||
kaohe_guize = models.TextField(null=True, blank=True, verbose_name='考核规则') # 新增
|
||||
kaioi_jinpai = models.BooleanField(default=False, verbose_name='是否同时开启金牌')
|
||||
|
||||
class Meta:
|
||||
db_table = 'chenghao'
|
||||
verbose_name = '称号'
|
||||
verbose_name_plural = verbose_name
|
||||
indexes = [models.Index(fields=['leixing', 'bankuai'])]
|
||||
|
||||
|
||||
# ==================== 用户 - 称号关联 ====================
|
||||
class YonghuChenghao(models.Model):
|
||||
yonghu = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='chenghao_list', verbose_name='用户', db_index=True)
|
||||
chenghao = models.ForeignKey(Chenghao, on_delete=models.CASCADE, verbose_name='称号')
|
||||
huode_time = models.DateTimeField(auto_now_add=True, verbose_name='获得时间')
|
||||
|
||||
class Meta:
|
||||
db_table = 'yonghu_chenghao'
|
||||
verbose_name = '用户称号关联'
|
||||
verbose_name_plural = verbose_name
|
||||
unique_together = ('yonghu', 'chenghao')
|
||||
# 修复:只索引本表字段
|
||||
indexes = [models.Index(fields=['yonghu', 'chenghao'])]
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class DingdanBiaoqian(models.Model):
|
||||
"""订单需求标签关联表"""
|
||||
dingdan = models.ForeignKey(
|
||||
Dingdan,
|
||||
to_field='dingdan_id', # 关联到字符串字段 dingdan_id
|
||||
on_delete=models.CASCADE,
|
||||
verbose_name='订单',
|
||||
db_index=True
|
||||
)
|
||||
chenghao = models.ForeignKey('dengji.Chenghao', on_delete=models.CASCADE, verbose_name='标签')
|
||||
create_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
|
||||
|
||||
class Meta:
|
||||
db_table = 'dingdan_biaoqian'
|
||||
verbose_name = '订单需求标签'
|
||||
verbose_name_plural = verbose_name
|
||||
unique_together = ('dingdan', 'chenghao')
|
||||
indexes = [models.Index(fields=['dingdan'])]
|
||||
|
||||
|
||||
|
||||
|
||||
class ShenheJilu(models.Model):
|
||||
"""审核记录表"""
|
||||
shenqingren_id = models.CharField(max_length=7, verbose_name='申请人用户ID')
|
||||
shenheguan_id = models.CharField(max_length=7, null = True,verbose_name='审核官用户ID')
|
||||
zhuangtai = models.IntegerField(choices=[(0, '审核中'), (1, '通过'), (2, '未通过'), (3, '待审核')], default=0, verbose_name='审核状态')
|
||||
bankuai = models.ForeignKey(Bankuai, on_delete=models.PROTECT, to_field='bankuai_id', null=True, blank=True, verbose_name='审核板块')
|
||||
chenghao = models.ForeignKey(Chenghao, on_delete=models.PROTECT, null=True, blank=True, verbose_name='审核标签')
|
||||
cishu = models.IntegerField(default=1, verbose_name='第几次审核')
|
||||
jiaofei_jine = models.DecimalField(max_digits=10, decimal_places=2, default=0.00, verbose_name='缴纳费用')
|
||||
create_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
|
||||
update_time = models.DateTimeField(auto_now=True, verbose_name='更新时间')
|
||||
jilu_id = models.CharField(max_length=32, unique=True, db_index=True, verbose_name='记录ID') # 新增
|
||||
guize_neirong = models.TextField(null=True, blank=True, verbose_name='规则内容')
|
||||
shenheguan_youxi_id = models.CharField(max_length=50, null=True, blank=True, verbose_name='审核官游戏ID')
|
||||
dashou_youxi_id = models.CharField(max_length=50, null=True, blank=True, verbose_name='打手游戏ID')
|
||||
dashou_beizhu = models.TextField(null=True, blank=True, verbose_name='打手备注')
|
||||
|
||||
class Meta:
|
||||
db_table = 'shenhe_jilu'
|
||||
verbose_name = '审核记录'
|
||||
verbose_name_plural = verbose_name
|
||||
indexes = [
|
||||
models.Index(fields=['shenqingren_id', 'zhuangtai']),
|
||||
models.Index(fields=['shenheguan_id']),
|
||||
]
|
||||
|
||||
|
||||
|
||||
class KaohePayTemp(models.Model):
|
||||
"""考核支付临时上下文(仅用于支付成功后回调取参,不删除数据)"""
|
||||
dingdan_id = models.CharField(max_length=50, unique=True, db_index=True, verbose_name='订单ID')
|
||||
yonghuid = models.CharField(max_length=7, db_index=True, verbose_name='用户ID')
|
||||
tag_id = models.IntegerField(verbose_name='标签ID')
|
||||
game_nick = models.CharField(max_length=100, verbose_name='游戏昵称')
|
||||
remark = models.TextField(blank=True, verbose_name='备注')
|
||||
reapply = models.BooleanField(default=False, verbose_name='是否再次申请')
|
||||
jilu_id = models.CharField(max_length=32, null=True, blank=True, verbose_name='原记录ID(再次申请时)')
|
||||
shenheguan_id = models.CharField(max_length=7, blank=True, verbose_name='指定考核官ID')
|
||||
cishu = models.IntegerField(verbose_name='本次考核次数(预计算)')
|
||||
fee = models.DecimalField(max_digits=10, decimal_places=2, verbose_name='本次费用(分账单位)')
|
||||
create_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
|
||||
|
||||
class Meta:
|
||||
db_table = 'kaohe_pay_temp'
|
||||
verbose_name = '考核支付临时表'
|
||||
verbose_name_plural = verbose_name
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class KaoheCishuFeiyong(models.Model):
|
||||
"""各标签各考核次数所需缴纳金额"""
|
||||
chenghao = models.ForeignKey(Chenghao, on_delete=models.CASCADE, verbose_name='标签')
|
||||
cishu = models.IntegerField(verbose_name='第几次考核')
|
||||
feiyong = models.DecimalField(max_digits=10, decimal_places=2, verbose_name='需缴纳金额')
|
||||
|
||||
class Meta:
|
||||
db_table = 'kaohe_cishu_feiyong'
|
||||
verbose_name = '考核次数费用'
|
||||
verbose_name_plural = verbose_name
|
||||
unique_together = ('chenghao', 'cishu')
|
||||
indexes = [models.Index(fields=['chenghao', 'cishu'])]
|
||||
|
||||
|
||||
class KaoheJujueJilu(models.Model):
|
||||
"""考核拒绝原因记录"""
|
||||
jilu = models.ForeignKey(ShenheJilu, on_delete=models.CASCADE, to_field='jilu_id', verbose_name='审核记录')
|
||||
cishu = models.IntegerField(verbose_name='对应次数')
|
||||
shenheguan_id = models.CharField(max_length=7, verbose_name='考核官用户ID')
|
||||
yuanyin = models.TextField(verbose_name='拒绝原因')
|
||||
create_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
|
||||
|
||||
class Meta:
|
||||
db_table = 'kaohe_jujue_jilu'
|
||||
verbose_name = '拒绝原因记录'
|
||||
verbose_name_plural = verbose_name
|
||||
indexes = [models.Index(fields=['jilu_id', 'cishu'])]
|
||||
|
||||
|
||||
class KaoheJiluFeiyong(models.Model):
|
||||
"""每次考核记录实际缴纳的费用明细"""
|
||||
jilu = models.ForeignKey(ShenheJilu, on_delete=models.CASCADE, to_field='jilu_id', verbose_name='考核记录')
|
||||
cishu = models.IntegerField(verbose_name='第几次考核')
|
||||
jine = models.DecimalField(max_digits=10, decimal_places=2, verbose_name='缴纳金额')
|
||||
|
||||
class Meta:
|
||||
db_table = 'kaohe_jilu_feiyong'
|
||||
verbose_name = '考核记录费用'
|
||||
verbose_name_plural = verbose_name
|
||||
unique_together = ('jilu', 'cishu')
|
||||
|
||||
|
||||
|
||||
class KaoheguanBankuai(models.Model):
|
||||
"""考核官与板块多对多关联表"""
|
||||
kaoheguan_id = models.CharField(max_length=7, db_index=True, verbose_name='考核官用户ID')
|
||||
bankuai = models.ForeignKey(Bankuai, on_delete=models.CASCADE, to_field='bankuai_id', verbose_name='所属板块')
|
||||
|
||||
class Meta:
|
||||
db_table = 'kaoheguan_bankuai'
|
||||
verbose_name = '考核官板块关联'
|
||||
verbose_name_plural = verbose_name
|
||||
unique_together = ('kaoheguan_id', 'bankuai')
|
||||
indexes = [models.Index(fields=['kaoheguan_id'])]
|
||||
87
rank/services.py
Normal file
87
rank/services.py
Normal file
@@ -0,0 +1,87 @@
|
||||
# dengji/services.py
|
||||
import logging
|
||||
from django.db import transaction, IntegrityError
|
||||
from django.utils import timezone
|
||||
from .models import DashouBiaoxian
|
||||
|
||||
logger = logging.getLogger('dengji')
|
||||
|
||||
def record_dashou_biaoxian(dingdan_id, dashou_id, xingwei, **kwargs):
|
||||
"""
|
||||
统一记录打手订单表现
|
||||
:param dingdan_id: 订单ID
|
||||
:param dashou_id: 打手ID
|
||||
:param xingwei: 行为类型 1-抢单 2-提交订单 3-结算
|
||||
:param kwargs: 可选字段(与模型字段同名):
|
||||
jiedan_time, tijiao_time,
|
||||
bankuai, shangxian_sudu, fuwu_taidu, fanche_cishu
|
||||
注意:不管是哪种行为,dingdan_id 和 dashou_id 都是必传的,
|
||||
如果没传时间且业务需要时间,则自动取当前时间。
|
||||
"""
|
||||
try:
|
||||
# ----- 抢单:创建记录 -----
|
||||
if xingwei == 1:
|
||||
jiedan_time = kwargs.get('jiedan_time') or timezone.now()
|
||||
bankuai = kwargs.get('bankuai') # 可为 None
|
||||
|
||||
# 避免重复创建(同一订单只会有一条表现记录)
|
||||
obj, created = DashouBiaoxian.objects.get_or_create(
|
||||
dingdan_id=dingdan_id,
|
||||
dashou_id=dashou_id,
|
||||
defaults={
|
||||
'bankuai': bankuai,
|
||||
'jiedan_time': jiedan_time,
|
||||
}
|
||||
)
|
||||
if not created:
|
||||
logger.info(f"表现记录已存在,跳过创建: dingdan={dingdan_id}, dashou={dashou_id}")
|
||||
else:
|
||||
logger.info(f"创建抢单表现记录: dingdan={dingdan_id}, dashou={dashou_id}")
|
||||
|
||||
# ----- 提交订单:更新提交时间 -----
|
||||
elif xingwei == 2:
|
||||
tijiao_time = kwargs.get('tijiao_time') or timezone.now()
|
||||
# 只更新已存在的记录,找不到就直接跳过
|
||||
updated = DashouBiaoxian.objects.filter(
|
||||
dingdan_id=dingdan_id,
|
||||
dashou_id=dashou_id
|
||||
).update(tijiao_time=tijiao_time)
|
||||
if updated:
|
||||
logger.info(f"更新提交时间: dingdan={dingdan_id}, dashou={dashou_id}")
|
||||
else:
|
||||
logger.info(f"无对应记录,跳过提交时间更新: dingdan={dingdan_id}, dashou={dashou_id}")
|
||||
|
||||
# ----- 结算:更新评价信息 -----
|
||||
elif xingwei == 3:
|
||||
# 构建要更新的字段,只更新 kwargs 中传入的非 None 字段
|
||||
update_fields = {}
|
||||
for field in ['shangxian_sudu', 'fuwu_taidu', 'fanche_cishu']:
|
||||
val = kwargs.get(field)
|
||||
if val is not None:
|
||||
update_fields[field] = val
|
||||
# 如果还传了板块也可以更新
|
||||
bankuai = kwargs.get('bankuai')
|
||||
if bankuai is not None:
|
||||
update_fields['bankuai'] = bankuai
|
||||
|
||||
if update_fields:
|
||||
updated = DashouBiaoxian.objects.filter(
|
||||
dingdan_id=dingdan_id,
|
||||
dashou_id=dashou_id
|
||||
).update(**update_fields)
|
||||
if updated:
|
||||
logger.info(f"更新评价信息: dingdan={dingdan_id}, dashou={dashou_id}, fields={update_fields}")
|
||||
else:
|
||||
logger.info(f"无对应记录,跳过评价更新: dingdan={dingdan_id}, dashou={dashou_id}")
|
||||
else:
|
||||
logger.info(f"结算时未传入任何评价字段,跳过更新")
|
||||
|
||||
else:
|
||||
logger.warning(f"未知的行为类型: {xingwei}")
|
||||
|
||||
except IntegrityError as e:
|
||||
# 唯一约束冲突(get_or_create 理论上已处理,但并发时仍可能撞上)
|
||||
logger.warning(f"表现记录写入冲突,可能并发创建: {e}")
|
||||
except Exception as e:
|
||||
# 无论发生什么错误,都不影响主流程
|
||||
logger.error(f"记录打手表现异常: dingdan={dingdan_id}, dashou={dashou_id}, xingwei={xingwei}, error={e}", exc_info=True)
|
||||
3
rank/tests.py
Normal file
3
rank/tests.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
||||
22
rank/urls.py
Normal file
22
rank/urls.py
Normal file
@@ -0,0 +1,22 @@
|
||||
from django.urls import path
|
||||
from .views import DashouBiaoqianView , BankuaiBiaoqianView, KaoheguanRegisterView, \
|
||||
KaoheguanRefreshView , ShenheDatingModuleView, ShenheDatingDataView, ShenheQiangdanView, ShenheCaozuoView,ShenheXiangqingView, KaoheJinpaiTagsView, KaoheJiluView, KaoheFreeApplyView,\
|
||||
KaoheJiluListView
|
||||
|
||||
urlpatterns = [
|
||||
path('dsbqhq', DashouBiaoqianView.as_view(), name='打手标签获取'),
|
||||
# 其他已有路由保持不变
|
||||
path('bkqhbq', BankuaiBiaoqianView.as_view(), name='抢单页面获取标签'),
|
||||
path('khgzc', KaoheguanRegisterView.as_view(), name='kaoheguan_register'),
|
||||
path('khgsx', KaoheguanRefreshView.as_view(), name='kaoheguan_refresh'),
|
||||
path('shdthqmk', ShenheDatingModuleView.as_view(), name='审核官获取板块'),
|
||||
path('hqshsj', ShenheDatingDataView.as_view(), name='审核官获取待审核列表'),
|
||||
path('shqd', ShenheQiangdanView.as_view(), name='审核官接待审核'),
|
||||
path('hqkhxq', ShenheXiangqingView.as_view(), name='获取审核内容'),
|
||||
path('khgxgkh', ShenheCaozuoView.as_view(), name='修改审核状态'),
|
||||
|
||||
path('dskhhq', KaoheJinpaiTagsView.as_view(), name='考核金牌页面标签'),
|
||||
path('dskhjl', KaoheJiluView.as_view(), name='打手考核记录'),
|
||||
path('dssqkh', KaoheFreeApplyView.as_view(), name='免费考核申请接口'),
|
||||
path('khghqkhjl', KaoheJiluListView.as_view(), name='考核官获取考核记录'),
|
||||
]
|
||||
410
rank/utils.py
Normal file
410
rank/utils.py
Normal file
@@ -0,0 +1,410 @@
|
||||
# 标准库
|
||||
import time
|
||||
import random
|
||||
import logging
|
||||
from decimal import Decimal
|
||||
# Django 内置
|
||||
from django.db import models
|
||||
from django.db.models import Q, F, Max
|
||||
# 项目模型
|
||||
## 当前dengji应用
|
||||
from .models import (
|
||||
Chenghao, KaoheCishuFeiyong, ShenheJilu, KaoheJiluFeiyong,
|
||||
YonghuChenghao, KaoheguanBankuai, DingdanBiaoqian
|
||||
)
|
||||
## users应用
|
||||
from users.models import UserMain, UserShenheguan, UserDashou
|
||||
## orders应用
|
||||
from orders.models import YonghuChenghao
|
||||
# 日志对象
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
|
||||
def check_dashou_biaoqian_required(order_id, dashou_yonghuid):
|
||||
"""
|
||||
检查打手是否满足订单的标签需求。
|
||||
- 如果订单没有需求标签,直接放行。
|
||||
- 如果有,则要求打手至少拥有其中一个标签。
|
||||
返回 (allowed: bool, message: str)
|
||||
"""
|
||||
try:
|
||||
# 1. 获取订单的需求标签ID集合
|
||||
required_ids = set(
|
||||
DingdanBiaoqian.objects.filter(dingdan_id=order_id)
|
||||
.values_list('chenghao_id', flat=True)
|
||||
)
|
||||
if not required_ids:
|
||||
return True, ''
|
||||
|
||||
# 2. 找到打手对应的用户记录
|
||||
try:
|
||||
user = UserMain.objects.get(yonghuid=dashou_yonghuid)
|
||||
except UserMain.DoesNotExist:
|
||||
return False, '用户信息异常'
|
||||
|
||||
# 3. 获取打手已拥有的标签ID集合(只取打手类型)
|
||||
owned_ids = set(
|
||||
YonghuChenghao.objects.filter(
|
||||
yonghu=user,
|
||||
chenghao__leixing='dashou'
|
||||
).values_list('chenghao_id', flat=True)
|
||||
)
|
||||
|
||||
if not owned_ids:
|
||||
return False, '您未拥有任何打手标签,无法抢此订单'
|
||||
|
||||
# 4. 交集判断
|
||||
if required_ids.intersection(owned_ids):
|
||||
return True, ''
|
||||
else:
|
||||
return False, '您的标签不符合此订单要求,无法抢单'
|
||||
|
||||
except Exception as e:
|
||||
# 标签校验失败不影响主流程,记录日志并保守放行(也可保守拒绝,按需求选择)
|
||||
logger.error(f"标签校验异常: {e}", exc_info=True)
|
||||
# 安全起见,如果校验出错,选择拒绝,避免越权
|
||||
return False, '订单标签校验异常,请稍后重试'
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def get_tag_fee(chenghao, cishu):
|
||||
"""
|
||||
获取标签在指定考核次数下的费用。
|
||||
- 若有对应次数的配置,直接返回。
|
||||
- 若没有该次数,取该标签下已有最大次数的费用(作为后续次数的价格)。
|
||||
- 若该标签完全没有费用记录,返回 0.00(免费)。
|
||||
"""
|
||||
fee_obj = KaoheCishuFeiyong.objects.filter(chenghao=chenghao, cishu=cishu).first()
|
||||
if fee_obj:
|
||||
return fee_obj.feiyong
|
||||
|
||||
max_obj = KaoheCishuFeiyong.objects.filter(chenghao=chenghao).order_by('-cishu').first()
|
||||
if max_obj:
|
||||
return max_obj.feiyong
|
||||
|
||||
return Decimal('0.00')
|
||||
|
||||
|
||||
def generate_unique_jilu_id():
|
||||
"""
|
||||
生成唯一的审核记录 ID,格式:SH + 时间戳(10位) + 随机数(4位)
|
||||
循环检查数据库避免重复,最多尝试 10 次。
|
||||
"""
|
||||
for _ in range(10):
|
||||
timestamp = str(int(time.time() * 1000))[-10:]
|
||||
random_part = str(random.randint(1000, 9999))
|
||||
jilu_id = f'SH{timestamp}{random_part}'
|
||||
if not ShenheJilu.objects.filter(jilu_id=jilu_id).exists():
|
||||
return jilu_id
|
||||
raise Exception('无法生成唯一记录ID,请稍后重试')
|
||||
|
||||
|
||||
def validate_shenheguan(shenheguan_id, bankuai, fee, applicant_user):
|
||||
"""
|
||||
校验指定考核官是否合法
|
||||
- 考核官必须存在且未被禁用
|
||||
- 必须属于对应板块
|
||||
- 必须处于空闲状态
|
||||
- 若费用>0,则要求已认证
|
||||
返回 (valid, error_msg)
|
||||
"""
|
||||
if not shenheguan_id:
|
||||
return True, ''
|
||||
try:
|
||||
kg = UserShenheguan.objects.select_related('user').get(
|
||||
user__yonghuid=shenheguan_id,
|
||||
zhuangtai=1
|
||||
)
|
||||
except UserShenheguan.DoesNotExist:
|
||||
return False, '考核官不存在或已被禁用'
|
||||
|
||||
# 板块权限
|
||||
if not KaoheguanBankuai.objects.filter(kaoheguan_id=shenheguan_id, bankuai=bankuai).exists():
|
||||
return False, '该考核官不属于此板块'
|
||||
|
||||
# 空闲状态
|
||||
if kg.shenhe_zhuangtai != 0:
|
||||
return False, '该考核官当前忙碌,无法指定'
|
||||
|
||||
# 费用>0需要认证
|
||||
if float(fee) > 0 and not kg.is_renzheng:
|
||||
return False, '费用大于0时只能指定已认证的考核官'
|
||||
|
||||
return True, ''
|
||||
|
||||
|
||||
def create_shenhe_jilu(user, tag_id, game_nick, remark, reapply, jilu_id=None, shenheguan_id=''):
|
||||
"""
|
||||
创建或更新审核记录。
|
||||
- 首次申请:创建新记录,生成唯一 jilu_id。
|
||||
- 再次申请:基于原记录(必须状态为未通过)更新次数、累加总费用、更新备注和游戏昵称,
|
||||
保留审核官信息,状态重置为待审核。不创建新记录。
|
||||
- 每次申请均创建一条费用明细记录(KaoheJiluFeiyong),记录本次缴费。
|
||||
- 若原记录有考核官,则将其状态改为审核中。
|
||||
- 新增 shenheguan_id 参数:指定考核官ID,仅在原记录无考核官时可传入。
|
||||
返回 (success, message, record)
|
||||
"""
|
||||
try:
|
||||
# 1. 校验标签存在
|
||||
try:
|
||||
chenghao = Chenghao.objects.get(id=tag_id)
|
||||
except Chenghao.DoesNotExist:
|
||||
return False, '标签不存在', None
|
||||
|
||||
# 2. 判断用户是否已拥有该标签
|
||||
if YonghuChenghao.objects.filter(yonghu=user, chenghao=chenghao).exists():
|
||||
return False, '您已拥有该标签,无需重复考核', None
|
||||
|
||||
# 3. 检查是否有进行中的审核记录(待审核、审核中)
|
||||
has_pending = ShenheJilu.objects.filter(
|
||||
shenqingren_id=user.yonghuid,
|
||||
chenghao=chenghao,
|
||||
zhuangtai__in=[0, 3]
|
||||
).exists()
|
||||
if has_pending:
|
||||
return False, '您有未完成的考核申请,请等待结果', None
|
||||
|
||||
last_record = None
|
||||
current_fee = Decimal('0.00')
|
||||
|
||||
# 4. 处理再次申请
|
||||
if reapply and jilu_id:
|
||||
# 查询原记录(未通过状态)
|
||||
last_record = ShenheJilu.objects.filter(
|
||||
jilu_id=jilu_id,
|
||||
shenqingren_id=user.yonghuid,
|
||||
zhuangtai=2
|
||||
).first()
|
||||
if not last_record:
|
||||
return False, '原记录不存在或状态不是未通过', None
|
||||
|
||||
new_cishu = last_record.cishu + 1
|
||||
current_fee = get_tag_fee(chenghao, new_cishu)
|
||||
|
||||
# 确定最终状态:有考核官 = 审核中(0),否则待审核(3)
|
||||
final_kg_id = last_record.shenheguan_id # 保留原来的
|
||||
if shenheguan_id and not last_record.shenheguan_id:
|
||||
final_kg_id = shenheguan_id # 新指定
|
||||
|
||||
final_zhuangtai = 0 if final_kg_id else 3 # 有考核官就是审核中
|
||||
if final_zhuangtai == 3:
|
||||
final_kg_id = None
|
||||
|
||||
# 原子化更新
|
||||
ShenheJilu.objects.filter(pk=last_record.pk).update(
|
||||
cishu=new_cishu,
|
||||
jiaofei_jine=F('jiaofei_jine') + current_fee,
|
||||
dashou_youxi_id=game_nick,
|
||||
dashou_beizhu=remark,
|
||||
guize_neirong=chenghao.kaohe_guize or '',
|
||||
zhuangtai=final_zhuangtai,
|
||||
shenheguan_id=final_kg_id,
|
||||
)
|
||||
last_record.refresh_from_db()
|
||||
record = last_record
|
||||
|
||||
# 如果原考核官被替换或清除,释放旧考核官
|
||||
if last_record.shenheguan_id != final_kg_id:
|
||||
if last_record.shenheguan_id:
|
||||
UserShenheguan.objects.filter(
|
||||
user__yonghuid=last_record.shenheguan_id
|
||||
).update(shenhe_zhuangtai=0)
|
||||
else:
|
||||
# 首次申请
|
||||
max_cishu = ShenheJilu.objects.filter(
|
||||
shenqingren_id=user.yonghuid,
|
||||
chenghao=chenghao,
|
||||
zhuangtai__in=[1, 2]
|
||||
).aggregate(max=Max('cishu'))['max'] or 0
|
||||
new_cishu = max_cishu + 1
|
||||
current_fee = get_tag_fee(chenghao, new_cishu)
|
||||
|
||||
bankuai = chenghao.bankuai
|
||||
rule_text = chenghao.kaohe_guize or ''
|
||||
new_jilu_id = generate_unique_jilu_id()
|
||||
|
||||
initial_zhuangtai = 0 if shenheguan_id else 3 # 指定→审核中,否则待审核
|
||||
record = ShenheJilu.objects.create(
|
||||
jilu_id=new_jilu_id,
|
||||
shenqingren_id=user.yonghuid,
|
||||
zhuangtai=initial_zhuangtai,
|
||||
bankuai=bankuai,
|
||||
chenghao=chenghao,
|
||||
cishu=new_cishu,
|
||||
jiaofei_jine=current_fee,
|
||||
dashou_youxi_id=game_nick,
|
||||
dashou_beizhu=remark,
|
||||
guize_neirong=rule_text,
|
||||
shenheguan_id=shenheguan_id if shenheguan_id else None,
|
||||
)
|
||||
|
||||
# 5. 创建费用明细(防重复)
|
||||
KaoheJiluFeiyong.objects.get_or_create(
|
||||
jilu=record,
|
||||
cishu=record.cishu,
|
||||
defaults={'jine': current_fee}
|
||||
)
|
||||
|
||||
# 6. 更新考核官统计(仅当状态为审核中且有考核官)
|
||||
if record.zhuangtai == 0 and record.shenheguan_id:
|
||||
UserShenheguan.objects.filter(
|
||||
user__yonghuid=record.shenheguan_id
|
||||
).update(
|
||||
shenhe_zongshu=F('shenhe_zongshu') + 1,
|
||||
shenhe_zhuangtai=1
|
||||
)
|
||||
|
||||
return True, '申请成功', record
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"创建审核记录异常: {e}", exc_info=True)
|
||||
return False, '系统异常', None
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def create_shenhe_jilu_from_temp(user, temp_data):
|
||||
"""
|
||||
根据临时表数据创建审核记录(专供支付回调使用)
|
||||
参数 temp_data 是 KaohePayTemp 对象
|
||||
返回 (success, message, record)
|
||||
"""
|
||||
|
||||
try:
|
||||
logger.info(f"开始从临时表创建审核记录: 用户={user.yonghuid}, 订单={temp_data.dingdan_id}")
|
||||
|
||||
chenghao = Chenghao.objects.get(id=temp_data.tag_id)
|
||||
logger.info(f"获取标签成功: {chenghao.mingcheng}")
|
||||
|
||||
# 检查是否已拥有标签
|
||||
if YonghuChenghao.objects.filter(yonghu=user, chenghao=chenghao).exists():
|
||||
logger.warning(f"用户 {user.yonghuid} 已拥有标签 {chenghao.mingcheng}")
|
||||
return False, '您已拥有该标签,无需重复考核', None
|
||||
|
||||
# 检查是否有进行中的审核
|
||||
if ShenheJilu.objects.filter(
|
||||
shenqingren_id=user.yonghuid,
|
||||
chenghao=chenghao,
|
||||
zhuangtai__in=[0, 3]
|
||||
).exists():
|
||||
logger.warning(f"用户 {user.yonghuid} 有未完成的考核申请")
|
||||
return False, '您有未完成的考核申请,请等待结果', None
|
||||
|
||||
# 使用临时表中预计算好的次数和费用
|
||||
new_cishu = temp_data.cishu
|
||||
current_fee = temp_data.fee
|
||||
reapply = temp_data.reapply
|
||||
jilu_id = temp_data.jilu_id
|
||||
shenheguan_id = temp_data.shenheguan_id
|
||||
|
||||
logger.info(f"临时表数据: cishu={new_cishu}, fee={current_fee}, reapply={reapply}, jilu_id={jilu_id}, shenheguan_id={shenheguan_id}")
|
||||
|
||||
# 再次申请校验
|
||||
if reapply:
|
||||
if not jilu_id:
|
||||
logger.error("再次申请但未提供原记录ID")
|
||||
return False, '再次申请必须提供原记录ID', None
|
||||
last = ShenheJilu.objects.filter(
|
||||
jilu_id=jilu_id,
|
||||
shenqingren_id=user.yonghuid,
|
||||
zhuangtai=2
|
||||
).first()
|
||||
if not last:
|
||||
logger.error(f"原记录不存在或状态不是未通过: jilu_id={jilu_id}")
|
||||
return False, '原记录不存在或状态不是未通过', None
|
||||
if new_cishu != last.cishu + 1:
|
||||
logger.error(f"考核次数不一致: 临时表={new_cishu}, 原记录次数={last.cishu}")
|
||||
return False, '考核次数不一致', None
|
||||
logger.info(f"再次申请校验通过,原记录ID: {jilu_id}")
|
||||
|
||||
# 创建或更新审核记录
|
||||
if reapply and jilu_id:
|
||||
# 更新原记录
|
||||
final_kg_id = last.shenheguan_id
|
||||
if shenheguan_id and not last.shenheguan_id:
|
||||
final_kg_id = shenheguan_id
|
||||
final_zhuangtai = 0 if final_kg_id else 3
|
||||
if final_zhuangtai == 3:
|
||||
final_kg_id = None
|
||||
|
||||
ShenheJilu.objects.filter(pk=last.pk).update(
|
||||
cishu=new_cishu,
|
||||
jiaofei_jine=F('jiaofei_jine') + current_fee,
|
||||
dashou_youxi_id=temp_data.game_nick,
|
||||
dashou_beizhu=temp_data.remark,
|
||||
guize_neirong=chenghao.kaohe_guize or '',
|
||||
zhuangtai=final_zhuangtai,
|
||||
shenheguan_id=final_kg_id,
|
||||
)
|
||||
last.refresh_from_db()
|
||||
record = last
|
||||
|
||||
# 释放旧考核官
|
||||
if last.shenheguan_id != final_kg_id and last.shenheguan_id:
|
||||
UserShenheguan.objects.filter(user__yonghuid=last.shenheguan_id).update(shenhe_zhuangtai=0)
|
||||
logger.info(f"释放旧考核官: {last.shenheguan_id}")
|
||||
|
||||
logger.info(f"更新审核记录成功: jilu_id={record.jilu_id}, 新次数={new_cishu}")
|
||||
else:
|
||||
# 首次申请
|
||||
bankuai = chenghao.bankuai
|
||||
rule_text = chenghao.kaohe_guize or ''
|
||||
new_jilu_id = generate_unique_jilu_id()
|
||||
initial_zhuangtai = 0 if shenheguan_id else 3
|
||||
|
||||
record = ShenheJilu.objects.create(
|
||||
jilu_id=new_jilu_id,
|
||||
shenqingren_id=user.yonghuid,
|
||||
zhuangtai=initial_zhuangtai,
|
||||
bankuai=bankuai,
|
||||
chenghao=chenghao,
|
||||
cishu=new_cishu,
|
||||
jiaofei_jine=current_fee,
|
||||
dashou_youxi_id=temp_data.game_nick,
|
||||
dashou_beizhu=temp_data.remark,
|
||||
guize_neirong=rule_text,
|
||||
shenheguan_id=shenheguan_id if shenheguan_id else None,
|
||||
)
|
||||
logger.info(f"创建审核记录成功: jilu_id={new_jilu_id}, 状态={initial_zhuangtai}")
|
||||
|
||||
# 记录费用明细
|
||||
fee_detail, created = KaoheJiluFeiyong.objects.get_or_create(
|
||||
jilu=record,
|
||||
cishu=record.cishu,
|
||||
defaults={'jine': current_fee}
|
||||
)
|
||||
if created:
|
||||
logger.info(f"创建费用明细成功: 记录ID={record.jilu_id}, 金额={current_fee}")
|
||||
else:
|
||||
logger.warning(f"费用明细已存在: 记录ID={record.jilu_id}, 次数={record.cishu}")
|
||||
|
||||
# 更新考核官状态
|
||||
if record.zhuangtai == 0 and record.shenheguan_id:
|
||||
UserShenheguan.objects.filter(user__yonghuid=record.shenheguan_id).update(
|
||||
shenhe_zongshu=F('shenhe_zongshu') + 1,
|
||||
shenhe_zhuangtai=1
|
||||
)
|
||||
logger.info(f"更新考核官状态: {record.shenheguan_id}, 审核总数+1, 状态=忙碌")
|
||||
|
||||
logger.info(f"从临时表创建审核记录完成: jilu_id={record.jilu_id}")
|
||||
return True, '申请成功', record
|
||||
|
||||
except Chenghao.DoesNotExist:
|
||||
logger.error(f"标签不存在: tag_id={temp_data.tag_id}")
|
||||
return False, '标签不存在', None
|
||||
except Exception as e:
|
||||
logger.error(f"从临时表创建审核记录异常: {str(e)}", exc_info=True)
|
||||
return False, '系统异常', None
|
||||
947
rank/views.py
Normal file
947
rank/views.py
Normal file
@@ -0,0 +1,947 @@
|
||||
import json
|
||||
import logging
|
||||
from decimal import Decimal
|
||||
from django.db import models, transaction, IntegrityError
|
||||
from django.db.models import F, Q, OuterRef, Subquery, Count, Max
|
||||
from rest_framework.views import APIView
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
from .utils import get_tag_fee, create_shenhe_jilu, validate_shenheguan
|
||||
from .models import (
|
||||
YonghuChenghao, Chenghao, KaoheCishuFeiyong, KaoheJujueJilu,
|
||||
KaoheguanBankuai, Bankuai, ShenheJilu, KaoheJiluFeiyong
|
||||
)
|
||||
from users.models import UserShenheguan, UserMain, UserDashou
|
||||
from products.models import ShangpinLeixing
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class DashouBiaoqianView(APIView):
|
||||
"""获取当前打手所有称号标签"""
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
def post(self, request):
|
||||
try:
|
||||
yonghu = request.user
|
||||
# 查询用户的所有称号关联,一次连表取出
|
||||
relations = YonghuChenghao.objects.filter(
|
||||
yonghu=yonghu
|
||||
).select_related('chenghao')
|
||||
|
||||
chenghao_list = []
|
||||
for rel in relations:
|
||||
ch = rel.chenghao
|
||||
# 解析特效描述 JSON(前端需要对象)
|
||||
texiao_json = {}
|
||||
if ch.texiao_miaoshu:
|
||||
try:
|
||||
texiao_json = json.loads(ch.texiao_miaoshu)
|
||||
except json.JSONDecodeError:
|
||||
texiao_json = {}
|
||||
chenghao_list.append({
|
||||
'mingcheng': ch.mingcheng,
|
||||
'tubiao_url': ch.tubiao_url or '',
|
||||
'texiao_json': texiao_json,
|
||||
})
|
||||
|
||||
return Response({
|
||||
'code': 0,
|
||||
'msg': '成功',
|
||||
'data': {'chenghao_list': chenghao_list}
|
||||
})
|
||||
except Exception as e:
|
||||
logger.error(f"获取打手标签失败: {e}", exc_info=True)
|
||||
return Response({'code': 1, 'msg': '服务器错误', 'data': None})
|
||||
|
||||
|
||||
class BankuaiBiaoqianView(APIView):
|
||||
"""获取商品类型所属板块的所有标签"""
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
def post(self, request):
|
||||
leixing_id = request.data.get('leixing_id')
|
||||
if not leixing_id:
|
||||
return Response({'code': 1, 'msg': '缺少leixing_id'})
|
||||
|
||||
try:
|
||||
leixing = ShangpinLeixing.objects.select_related('bankuai').get(id=leixing_id)
|
||||
except ShangpinLeixing.DoesNotExist:
|
||||
return Response({'code': 2, 'msg': '商品类型不存在'})
|
||||
|
||||
bankuai = leixing.bankuai
|
||||
if not bankuai:
|
||||
return Response({'code': 0, 'data': {'biaoqian_list': []}})
|
||||
|
||||
# 获取该板块下所有类型的标签(leixing可以为dashou/shangjia等,这里先返回所有)
|
||||
chenghao_list = Chenghao.objects.filter(bankuai=bankuai)
|
||||
data = []
|
||||
for ch in chenghao_list:
|
||||
texiao_json = {}
|
||||
if ch.texiao_miaoshu:
|
||||
try:
|
||||
texiao_json = json.loads(ch.texiao_miaoshu)
|
||||
except:
|
||||
pass
|
||||
data.append({
|
||||
'id': ch.id,
|
||||
'mingcheng': ch.mingcheng,
|
||||
'texiao_json': texiao_json
|
||||
})
|
||||
return Response({'code': 0, 'data': {'biaoqian_list': data}})
|
||||
|
||||
|
||||
|
||||
|
||||
# 硬编码邀请码
|
||||
KAOHEGUAN_INVITE_CODE = 'KHG2026VIP'
|
||||
|
||||
class KaoheguanRegisterView(APIView):
|
||||
"""
|
||||
考核官注册接口
|
||||
POST /dengji/khgzc
|
||||
"""
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
def post(self, request):
|
||||
try:
|
||||
yonghu = request.user
|
||||
invite_code = request.data.get('inviteCode', '').strip()
|
||||
|
||||
if not invite_code:
|
||||
return Response({'code': 400, 'msg': '邀请码不能为空'})
|
||||
if invite_code != KAOHEGUAN_INVITE_CODE:
|
||||
return Response({'code': 400, 'msg': '邀请码错误'})
|
||||
|
||||
kg = UserShenheguan.objects.filter(user=yonghu).first()
|
||||
if kg:
|
||||
if kg.zhuangtai == 1:
|
||||
return Response({'code': 200, 'msg': '您已是考核官', 'data': self._build_data(kg)})
|
||||
else:
|
||||
return Response({'code': 400, 'msg': '账号已被封禁'})
|
||||
|
||||
with transaction.atomic():
|
||||
kg = UserShenheguan.objects.create(
|
||||
user=yonghu,
|
||||
zhuangtai=1,
|
||||
shenhe_zhuangtai=0,
|
||||
shenhe_zongshu=0,
|
||||
tongguo_zongshu=0,
|
||||
yue=0.00,
|
||||
zonge=0.00
|
||||
)
|
||||
return Response({'code': 200, 'msg': '注册成功', 'data': self._build_data(kg)})
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"考核官注册失败: {e}", exc_info=True)
|
||||
return Response({'code': 500, 'msg': '服务器内部错误'})
|
||||
|
||||
def _build_data(self, kg):
|
||||
bankuai_qs = KaoheguanBankuai.objects.filter(kaoheguan_id=kg.user.yonghuid).select_related('bankuai')
|
||||
bankuai_list = [{'bankuai_id': b.bankuai.bankuai_id, 'mingcheng': b.bankuai.mingcheng} for b in bankuai_qs]
|
||||
return {
|
||||
'zhuangtai': kg.zhuangtai,
|
||||
'shenhe_zongshu': kg.shenhe_zongshu,
|
||||
'tongguo_zongshu': kg.tongguo_zongshu,
|
||||
'yue': str(kg.yue),
|
||||
'zonge': str(kg.zonge),
|
||||
'shenhe_zhuangtai': kg.shenhe_zhuangtai,
|
||||
'bankuai_list': bankuai_list,
|
||||
'kaoheguanstatus': 1
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class KaoheguanRefreshView(APIView):
|
||||
"""
|
||||
考核官数据刷新接口
|
||||
POST /dengji/khgsx
|
||||
"""
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
def post(self, request):
|
||||
try:
|
||||
yonghu = request.user
|
||||
kg = UserShenheguan.objects.filter(user=yonghu).first()
|
||||
if not kg:
|
||||
return Response({'code': 400, 'msg': '您还未注册考核官'})
|
||||
|
||||
if kg.zhuangtai != 1:
|
||||
return Response({'code': 200, 'data': {'zhuangtai': kg.zhuangtai, 'kaoheguanstatus': 0}})
|
||||
|
||||
# 查询所属板块
|
||||
bankuai_qs = KaoheguanBankuai.objects.filter(kaoheguan_id=kg.user.yonghuid).select_related('bankuai')
|
||||
bankuai_list = [{'bankuai_id': b.bankuai.bankuai_id, 'mingcheng': b.bankuai.mingcheng} for b in bankuai_qs]
|
||||
|
||||
# 统计待审核 / 审核中的记录数量
|
||||
pending_count = ShenheJilu.objects.filter(
|
||||
shenheguan_id=yonghu.yonghuid,
|
||||
zhuangtai=0 # 审核中
|
||||
).count()
|
||||
|
||||
data = {
|
||||
'zhuangtai': kg.zhuangtai,
|
||||
'shenhe_zongshu': kg.shenhe_zongshu,
|
||||
'tongguo_zongshu': kg.tongguo_zongshu,
|
||||
'yue': str(kg.yue),
|
||||
'zonge': str(kg.zonge),
|
||||
'shenhe_zhuangtai': kg.shenhe_zhuangtai,
|
||||
'bankuai_list': bankuai_list,
|
||||
'kaoheguanstatus': 1,
|
||||
'is_renzheng': kg.is_renzheng, # 🆕 是否认证
|
||||
'pending_shenhe_count': pending_count # 🆕 审核中数量
|
||||
}
|
||||
return Response({'code': 200, 'data': data})
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"考核官刷新失败: {e}", exc_info=True)
|
||||
return Response({'code': 500, 'msg': '服务器内部错误'})
|
||||
|
||||
|
||||
|
||||
class ShenheDatingModuleView(APIView):
|
||||
"""审核大厅获取模块列表(板块 + 待审核数量 + 是否关联)"""
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
def post(self, request):
|
||||
try:
|
||||
yonghu = request.user
|
||||
related_ids = set(KaoheguanBankuai.objects.filter(kaoheguan_id=yonghu.yonghuid)
|
||||
.values_list('bankuai_id', flat=True))
|
||||
|
||||
bankuai_list = []
|
||||
for bk in Bankuai.objects.all():
|
||||
count = ShenheJilu.objects.filter(bankuai=bk, zhuangtai=3, shenheguan_id__isnull=True).count()
|
||||
bankuai_list.append({
|
||||
'bankuai_id': bk.bankuai_id,
|
||||
'mingcheng': bk.mingcheng,
|
||||
'count': count,
|
||||
'is_related': bk.bankuai_id in related_ids
|
||||
})
|
||||
|
||||
return Response({'code': 0, 'data': {'modules': bankuai_list}})
|
||||
except Exception as e:
|
||||
return Response({'code': 500, 'msg': str(e)}, status=500)
|
||||
|
||||
class ShenheDatingDataView(APIView):
|
||||
"""获取审核大厅待审核记录列表"""
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
def post(self, request):
|
||||
try:
|
||||
data = request.data
|
||||
bankuai_id = data.get('bankuai_id')
|
||||
page = int(data.get('page', 1))
|
||||
page_size = int(data.get('page_size', 5))
|
||||
|
||||
query = ShenheJilu.objects.filter(zhuangtai=3, shenheguan_id__isnull=True)
|
||||
if bankuai_id:
|
||||
query = query.filter(bankuai_id=bankuai_id)
|
||||
|
||||
total = query.count()
|
||||
offset = (page - 1) * page_size
|
||||
jilu_list = query.select_related('bankuai', 'chenghao').order_by('-create_time')[
|
||||
offset:offset + page_size]
|
||||
|
||||
records = []
|
||||
for jl in jilu_list:
|
||||
user = UserMain.objects.filter(yonghuid=jl.shenqingren_id).first()
|
||||
avatar = user.avatar if user else ''
|
||||
texiao_json = {}
|
||||
if jl.chenghao and jl.chenghao.texiao_miaoshu:
|
||||
try:
|
||||
texiao_json = json.loads(jl.chenghao.texiao_miaoshu)
|
||||
except:
|
||||
pass
|
||||
|
||||
# 新增字段:本次考核费用
|
||||
kaohe_feiyong = float(jl.jiaofei_jine) if jl.jiaofei_jine is not None else 0.0
|
||||
|
||||
records.append({
|
||||
'jilu_id': jl.jilu_id,
|
||||
'shenqingren_id': jl.shenqingren_id,
|
||||
'shenqingren_avatar': avatar,
|
||||
'dashou_youxi_id': jl.dashou_youxi_id or '',
|
||||
'dashou_beizhu': jl.dashou_beizhu or '',
|
||||
'bankuai_id': jl.bankuai.bankuai_id if jl.bankuai else None,
|
||||
'bankuai_mingcheng': jl.bankuai.mingcheng if jl.bankuai else '',
|
||||
'chenghao_id': jl.chenghao_id,
|
||||
'chenghao_mingcheng': jl.chenghao.mingcheng if jl.chenghao else '',
|
||||
'chenghao_texiao_json': texiao_json,
|
||||
'guize_neirong': jl.guize_neirong or '',
|
||||
'kaohe_feiyong': kaohe_feiyong, # 新增
|
||||
'create_time': jl.create_time.strftime('%Y-%m-%d %H:%M:%S') if jl.create_time else '',
|
||||
})
|
||||
|
||||
has_more = (page * page_size) < total
|
||||
return Response({'code': 0, 'data': {'list': records, 'has_more': has_more, 'total': total}})
|
||||
except Exception as e:
|
||||
return Response({'code': 500, 'msg': str(e)}, status=500)
|
||||
|
||||
class ShenheQiangdanView(APIView):
|
||||
"""
|
||||
审核官抢单(接审核任务)
|
||||
校验:身份、账号封禁、已有进行中审核、记录状态、不能审核自己、板块权限
|
||||
成功后更新考核官扩展表:审核总数+1,审核状态设为“审核中”
|
||||
"""
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
def post(self, request):
|
||||
try:
|
||||
yonghu = request.user
|
||||
jilu_id = request.data.get('jilu_id')
|
||||
if not jilu_id:
|
||||
return Response({'code': 400, 'msg': '记录ID不能为空'})
|
||||
|
||||
# 1. 检查考核官身份及账号是否被禁用
|
||||
kg = UserShenheguan.objects.filter(user=yonghu, zhuangtai=1).first()
|
||||
if not kg:
|
||||
return Response({'code': 403, 'msg': '您不是考核官或账号已被禁用'})
|
||||
|
||||
# 2. 检查是否有正在审核中的记录(zhuangtai=0),防止同时审核多个
|
||||
ongoing = ShenheJilu.objects.filter(
|
||||
shenheguan_id=yonghu.yonghuid, zhuangtai=0
|
||||
).exists()
|
||||
if ongoing:
|
||||
return Response({'code': 400, 'msg': '您有正在审核中的任务,请完成后再接新任务'})
|
||||
|
||||
with transaction.atomic():
|
||||
# 3. 行锁抢单:仅当状态为待审核(3)且无审核官时才能抢
|
||||
jilu = ShenheJilu.objects.select_for_update().filter(
|
||||
jilu_id=jilu_id,
|
||||
zhuangtai=3,
|
||||
shenheguan_id__isnull=True
|
||||
).first()
|
||||
if not jilu:
|
||||
return Response({'code': 400, 'msg': '该审核任务已被接走、状态变更或不存在'})
|
||||
|
||||
# 4. 不能审核自己
|
||||
if jilu.shenqingren_id == yonghu.yonghuid:
|
||||
return Response({'code': 400, 'msg': '不能审核自己提交的申请'})
|
||||
|
||||
# 5. 板块权限:考核官必须属于该板块
|
||||
is_related = KaoheguanBankuai.objects.filter(
|
||||
kaoheguan_id=yonghu.yonghuid,
|
||||
bankuai=jilu.bankuai
|
||||
).exists()
|
||||
if not is_related:
|
||||
return Response({'code': 400, 'msg': '您不属于该板块,无法审核'})
|
||||
|
||||
# 新增:6. 费用>0时,要求考核官已认证
|
||||
if jilu.jiaofei_jine and float(jilu.jiaofei_jine) > 0:
|
||||
if not kg.is_renzheng:
|
||||
return Response({'code': 400, 'msg': '本考核需要认证考核官接单,您尚未认证'})
|
||||
|
||||
# 7. 更新审核记录:分配给当前考核官,状态变为审核中
|
||||
jilu.zhuangtai = 0 # 审核中
|
||||
jilu.shenheguan_id = yonghu.yonghuid
|
||||
jilu.save()
|
||||
|
||||
# 8. 更新考核官扩展表:审核总数 +1,审核状态置为审核中(1)
|
||||
UserShenheguan.objects.filter(user=yonghu).update(
|
||||
shenhe_zongshu=F('shenhe_zongshu') + 1,
|
||||
shenhe_zhuangtai=1
|
||||
)
|
||||
|
||||
return Response({
|
||||
'code': 0,
|
||||
'msg': '抢单成功,请前往游戏内审核,审核完成后请到考核打分页面进行评定。',
|
||||
'data': {'bankuai_id': jilu.bankuai.bankuai_id}
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"审核官抢单异常: {str(e)}", exc_info=True)
|
||||
return Response({'code': 500, 'msg': '服务器内部错误'}, status=500)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class ShenheXiangqingView(APIView):
|
||||
"""获取当前考核官审核中的记录详情(新增待收考核费字段)"""
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
def post(self, request):
|
||||
try:
|
||||
yonghu = request.user
|
||||
kg = UserShenheguan.objects.filter(user=yonghu, zhuangtai=1).first()
|
||||
if not kg:
|
||||
return Response({'code': 403, 'msg': '您不是考核官或账号异常'})
|
||||
|
||||
page = int(request.data.get('page', 1))
|
||||
page_size = int(request.data.get('page_size', 10))
|
||||
|
||||
# 查询当前考核官名下状态为“审核中”的记录
|
||||
base_query = ShenheJilu.objects.filter(
|
||||
shenheguan_id=yonghu.yonghuid,
|
||||
zhuangtai=0
|
||||
).select_related('bankuai', 'chenghao')
|
||||
total = base_query.count()
|
||||
offset = (page - 1) * page_size
|
||||
jilu_list = base_query[offset:offset + page_size]
|
||||
|
||||
records = []
|
||||
for jl in jilu_list:
|
||||
user = UserMain.objects.filter(yonghuid=jl.shenqingren_id).first()
|
||||
avatar = user.avatar if user else ''
|
||||
texiao_json = {}
|
||||
if jl.chenghao and jl.chenghao.texiao_miaoshu:
|
||||
try:
|
||||
texiao_json = json.loads(jl.chenghao.texiao_miaoshu)
|
||||
except:
|
||||
pass
|
||||
|
||||
# 是否开启金牌
|
||||
is_jinpai = jl.chenghao.kaioi_jinpai if jl.chenghao else False
|
||||
|
||||
# 本次待收考核费(基于记录中的当前次数,从费用明细表查询)
|
||||
daishou_fei = 0.00
|
||||
fee_detail = KaoheJiluFeiyong.objects.filter(
|
||||
jilu=jl,
|
||||
cishu=jl.cishu
|
||||
).first()
|
||||
if fee_detail:
|
||||
daishou_fei = float(fee_detail.jine)
|
||||
else:
|
||||
# 兜底:若明细表无记录,尝试用通用费用表计算
|
||||
daishou_fei = 0.00
|
||||
# 上次失败原因
|
||||
last_fail_reason = ''
|
||||
last_fail = KaoheJujueJilu.objects.filter(
|
||||
jilu=jl,
|
||||
cishu=jl.cishu - 1
|
||||
).order_by('-create_time').first()
|
||||
if last_fail:
|
||||
last_fail_reason = last_fail.yuanyin
|
||||
|
||||
records.append({
|
||||
'jilu_id': jl.jilu_id,
|
||||
'shenqingren_id': jl.shenqingren_id,
|
||||
'shenqingren_avatar': avatar,
|
||||
'bankuai_mingcheng': jl.bankuai.mingcheng if jl.bankuai else '',
|
||||
'chenghao_mingcheng': jl.chenghao.mingcheng if jl.chenghao else '',
|
||||
'chenghao_texiao_json': texiao_json,
|
||||
'guize_neirong': jl.guize_neirong or '',
|
||||
'dashou_beizhu': jl.dashou_beizhu or '',
|
||||
'dashou_youxi_id': jl.dashou_youxi_id or '',
|
||||
'shenheguan_youxi_id': jl.shenheguan_youxi_id or '',
|
||||
'cishu': jl.cishu,
|
||||
'daishou_fei': daishou_fei, # 新增:待收考核费
|
||||
'last_fail_reason': last_fail_reason,
|
||||
'is_jinpai': is_jinpai,
|
||||
'create_time': jl.create_time.strftime('%Y-%m-%d %H:%M:%S') if jl.create_time else '',
|
||||
})
|
||||
|
||||
has_more = (page * page_size) < total
|
||||
return Response({'code': 0, 'data': {'list': records, 'has_more': has_more, 'total': total}})
|
||||
except Exception as e:
|
||||
return Response({'code': 500, 'msg': str(e)}, status=500)
|
||||
|
||||
class ShenheCaozuoView(APIView):
|
||||
"""
|
||||
考核官执行操作(同意/拒绝/转移/修改昵称),并更新考核官收益
|
||||
- 只有“同意”或“拒绝”才增加余额和总额,金额严格从 KaoheJiluFeiyong 表获取
|
||||
- 查不到费用则加 0 元,绝不影响流程
|
||||
- 转移、修改昵称等操作不涉及收益
|
||||
"""
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
def post(self, request):
|
||||
try:
|
||||
yonghu = request.user
|
||||
# 1. 验证考核官身份及账号状态
|
||||
kg = UserShenheguan.objects.filter(user=yonghu, zhuangtai=1).first()
|
||||
if not kg:
|
||||
return Response({'code': 403, 'msg': '账号异常,无法操作'})
|
||||
|
||||
jilu_id = request.data.get('jilu_id')
|
||||
caozuo = request.data.get('caozuo') # agree / reject / transfer / modify_nick
|
||||
if not jilu_id or not caozuo:
|
||||
return Response({'code': 400, 'msg': '缺少必要参数'})
|
||||
|
||||
with transaction.atomic():
|
||||
# 2. 锁定审核记录,确保属于当前考核官且状态为审核中(0)
|
||||
jilu = ShenheJilu.objects.select_for_update().filter(
|
||||
jilu_id=jilu_id,
|
||||
shenheguan_id=yonghu.yonghuid,
|
||||
zhuangtai=0
|
||||
).first()
|
||||
if not jilu:
|
||||
return Response({'code': 400, 'msg': '该记录不存在或不属于您'})
|
||||
|
||||
# 3. 本次操作产生的收入(仅通过/拒绝时有意义)
|
||||
daishou_fei = 0.00
|
||||
|
||||
# 4. 根据操作类型执行对应业务逻辑
|
||||
if caozuo == 'agree':
|
||||
# --- 通过考核 ---
|
||||
# 查询本次考核应得的费用(基于记录ID和当前次数)
|
||||
fee_detail = KaoheJiluFeiyong.objects.filter(
|
||||
jilu=jilu,
|
||||
cishu=jilu.cishu
|
||||
).first()
|
||||
if fee_detail:
|
||||
daishou_fei = float(fee_detail.jine)
|
||||
# 找不到就保持 0,绝不使用任何默认值
|
||||
|
||||
jilu.zhuangtai = 1
|
||||
jilu.save()
|
||||
|
||||
# 授予标签
|
||||
if jilu.chenghao:
|
||||
yh = UserMain.objects.get(yonghuid=jilu.shenqingren_id)
|
||||
if not YonghuChenghao.objects.filter(yonghu=yh, chenghao=jilu.chenghao).exists():
|
||||
YonghuChenghao.objects.create(yonghu=yh, chenghao=jilu.chenghao)
|
||||
# 如果标签开启了金牌,同步更新打手称号
|
||||
if jilu.chenghao.kaioi_jinpai:
|
||||
dashou_prof = UserDashou.objects.filter(user=yh).first()
|
||||
if dashou_prof:
|
||||
dashou_prof.chenghao = '金牌选手'
|
||||
dashou_prof.save()
|
||||
|
||||
elif caozuo == 'reject':
|
||||
# --- 拒绝考核 ---
|
||||
yuanyin = request.data.get('yuanyin', '')
|
||||
if not yuanyin.strip():
|
||||
return Response({'code': 400, 'msg': '请填写拒绝原因'})
|
||||
|
||||
# 查询本次考核应得的费用(拒绝时同样获得收入)
|
||||
fee_detail = KaoheJiluFeiyong.objects.filter(
|
||||
jilu=jilu,
|
||||
cishu=jilu.cishu
|
||||
).first()
|
||||
if fee_detail:
|
||||
daishou_fei = float(fee_detail.jine)
|
||||
# 找不到就保持 0
|
||||
|
||||
jilu.zhuangtai = 2
|
||||
jilu.save()
|
||||
# 记录拒绝原因
|
||||
KaoheJujueJilu.objects.create(
|
||||
jilu=jilu,
|
||||
cishu=jilu.cishu,
|
||||
shenheguan_id=yonghu.yonghuid,
|
||||
yuanyin=yuanyin
|
||||
)
|
||||
|
||||
# 新增:不合格时,如果考核官未认证,则清空考核官ID和游戏昵称
|
||||
if not kg.is_renzheng:
|
||||
jilu.shenheguan_id = None
|
||||
jilu.shenheguan_youxi_id = ''
|
||||
jilu.save(update_fields=['shenheguan_id', 'shenheguan_youxi_id'])
|
||||
|
||||
elif caozuo == 'transfer':
|
||||
# 转移考核官:清空考核官信息,状态回退为待审核
|
||||
jilu.shenheguan_id = None
|
||||
jilu.shenheguan_youxi_id = None
|
||||
jilu.zhuangtai = 3
|
||||
jilu.save()
|
||||
# 转移不更新收益,直接返回
|
||||
|
||||
|
||||
elif caozuo == 'modify_nick':
|
||||
# 修改考核官游戏昵称
|
||||
youxi_id = request.data.get('youxi_id', '').strip()
|
||||
if not youxi_id:
|
||||
return Response({'code': 400, 'msg': '请输入游戏昵称'})
|
||||
jilu.shenheguan_youxi_id = youxi_id
|
||||
jilu.save()
|
||||
return Response({'code': 0, 'msg': '修改成功'})
|
||||
|
||||
else:
|
||||
return Response({'code': 400, 'msg': '无效的操作类型'})
|
||||
|
||||
# 5. 更新考核官收益(仅“通过”或“拒绝”时执行)
|
||||
if caozuo in ('transfer'):
|
||||
update_fields = {
|
||||
|
||||
'shenhe_zhuangtai': 0, # 设为空闲
|
||||
}
|
||||
UserShenheguan.objects.filter(user=yonghu).update(**update_fields)
|
||||
if caozuo in ('agree', 'reject'):
|
||||
update_fields = {
|
||||
'yue': F('yue') + Decimal(str(daishou_fei)),
|
||||
'zonge': F('zonge') + Decimal(str(daishou_fei)),
|
||||
'shenhe_zhuangtai': 0, # 设为空闲
|
||||
}
|
||||
# 只有同意时才增加“通过总数”
|
||||
if caozuo == 'agree':
|
||||
update_fields['tongguo_zongshu'] = F('tongguo_zongshu') + 1
|
||||
|
||||
# 审核总数不再增加
|
||||
UserShenheguan.objects.filter(user=yonghu).update(**update_fields)
|
||||
|
||||
return Response({'code': 0, 'msg': '操作成功'})
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"考核操作异常: {str(e)}", exc_info=True)
|
||||
return Response({'code': 500, 'msg': '服务器内部错误'}, status=500)
|
||||
|
||||
|
||||
|
||||
|
||||
# dengji/views.py
|
||||
class KaoheJinpaiTagsView(APIView):
|
||||
"""获取考核金牌页面的标签和板块信息"""
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
def post(self, request):
|
||||
try:
|
||||
user = request.user
|
||||
# 获取用户已拥有的标签名称集合
|
||||
owned_names = set(
|
||||
YonghuChenghao.objects.filter(yonghu=user, chenghao__leixing='dashou')
|
||||
.values_list('chenghao__mingcheng', flat=True)
|
||||
)
|
||||
|
||||
# 板块列表
|
||||
plate_list = []
|
||||
for bk in Bankuai.objects.all():
|
||||
tags = Chenghao.objects.filter(bankuai=bk, leixing='dashou')
|
||||
tag_list = []
|
||||
for tag in tags:
|
||||
# 费用列表
|
||||
fee_objs = KaoheCishuFeiyong.objects.filter(chenghao=tag).order_by('cishu')
|
||||
fee_list = [{'cishu': f.cishu, 'feiyong': float(f.feiyong)} for f in fee_objs]
|
||||
|
||||
# 若没有记录,补充默认费用
|
||||
if not fee_list:
|
||||
fee_list = [{'cishu': 1, 'feiyong': 5.00}]
|
||||
|
||||
tag_list.append({
|
||||
'id': tag.id,
|
||||
'name': tag.mingcheng,
|
||||
'texiao_json': json.loads(tag.texiao_miaoshu) if tag.texiao_miaoshu else {},
|
||||
'jinpai': tag.kaioi_jinpai,
|
||||
'rule': tag.kaohe_guize or '',
|
||||
'fee_list': fee_list,
|
||||
'owned': tag.mingcheng in owned_names,
|
||||
})
|
||||
|
||||
if tag_list:
|
||||
plate_list.append({
|
||||
'bankuai_id': bk.bankuai_id,
|
||||
'mingcheng': bk.mingcheng,
|
||||
'tags': tag_list
|
||||
})
|
||||
|
||||
# 新增:返回所有在职考核官信息(用于指定考核官)
|
||||
kaoheguan_list = []
|
||||
for kg in UserShenheguan.objects.filter(zhuangtai=1).select_related('user'):
|
||||
uid = kg.user.yonghuid
|
||||
avatar = kg.user.avatar or ''
|
||||
# 获取考核官的打手昵称(从打手扩展表)
|
||||
dashou_nick = ''
|
||||
dashou_prof = UserDashou.objects.filter(user=kg.user).first()
|
||||
if dashou_prof:
|
||||
dashou_nick = dashou_prof.nicheng or ''
|
||||
kaoheguan_list.append({
|
||||
'yonghuid': uid,
|
||||
'avatar': avatar,
|
||||
'dashou_nick': dashou_nick,
|
||||
'is_renzheng': kg.is_renzheng,
|
||||
'shenhe_zhuangtai': kg.shenhe_zhuangtai,
|
||||
})
|
||||
|
||||
return Response({
|
||||
'code': 0,
|
||||
'data': {
|
||||
'plate_list': plate_list,
|
||||
'my_tags': list(owned_names),
|
||||
'kaoheguan_list': kaoheguan_list, # 新增
|
||||
}
|
||||
})
|
||||
except Exception as e:
|
||||
return Response({'code': 500, 'msg': str(e)}, status=500)
|
||||
|
||||
|
||||
class KaoheJiluView(APIView):
|
||||
"""获取打手本人的考核记录(支持筛选状态)"""
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
def post(self, request):
|
||||
try:
|
||||
user = request.user
|
||||
status = request.data.get('status', 'pending') # pending / passed
|
||||
page = int(request.data.get('page', 1))
|
||||
page_size = int(request.data.get('page_size', 5))
|
||||
|
||||
if status == 'pending':
|
||||
# 进行中/未通过:审核中(0)、待审核(3)、未通过(2)
|
||||
query = ShenheJilu.objects.filter(
|
||||
shenqingren_id=user.yonghuid,
|
||||
zhuangtai__in=[0, 2, 3]
|
||||
)
|
||||
else:
|
||||
query = ShenheJilu.objects.filter(
|
||||
shenqingren_id=user.yonghuid,
|
||||
zhuangtai=1 # 已通过
|
||||
)
|
||||
|
||||
total = query.count()
|
||||
records = query.order_by('-create_time')[(page-1)*page_size : page*page_size]
|
||||
|
||||
data = []
|
||||
for jl in records:
|
||||
# 汇总缴纳总额
|
||||
total_fee = KaoheJiluFeiyong.objects.filter(jilu=jl).aggregate(
|
||||
total=models.Sum('jine')
|
||||
)['total'] or 0.00
|
||||
|
||||
# 上次拒绝原因(最近一条)
|
||||
last_fail = KaoheJujueJilu.objects.filter(jilu=jl).order_by('-create_time').first()
|
||||
fail_reason = last_fail.yuanyin if last_fail else ''
|
||||
|
||||
# 考核官头像
|
||||
kg_user = UserMain.objects.filter(yonghuid=jl.shenheguan_id).first()
|
||||
kg_avatar = kg_user.avatar if kg_user else ''
|
||||
|
||||
data.append({
|
||||
'jilu_id': jl.jilu_id,
|
||||
'chenghao_name': jl.chenghao.mingcheng if jl.chenghao else '',
|
||||
'bankuai_name': jl.bankuai.mingcheng if jl.bankuai else '',
|
||||
'zhuangtai': jl.zhuangtai,
|
||||
'statusText': dict(ShenheJilu._meta.get_field('zhuangtai').choices).get(jl.zhuangtai, '未知'),
|
||||
'statusColor': {0: '#FFA500', 1: '#27ae60', 2: '#e74c3c', 3: '#3498db'}.get(jl.zhuangtai, '#888'),
|
||||
'shenheguan_id': jl.shenheguan_id,
|
||||
'shenheguan_avatar': kg_avatar,
|
||||
'dashou_youxi_id': jl.dashou_youxi_id,
|
||||
'dashou_beizhu': jl.dashou_beizhu,
|
||||
'cishu': jl.cishu,
|
||||
'total_fee': float(total_fee),
|
||||
'last_fail_reason': fail_reason,
|
||||
'create_time': jl.create_time.strftime('%Y-%m-%d %H:%M:%S'),
|
||||
# 为再次申请预留标签对象数据(前端可能用到)
|
||||
'tag_obj': {
|
||||
'id': jl.chenghao_id,
|
||||
'name': jl.chenghao.mingcheng if jl.chenghao else '',
|
||||
# 其他字段按需,但申请时会重新拉取
|
||||
} if jl.chenghao else None,
|
||||
})
|
||||
|
||||
has_more = (page * page_size) < total
|
||||
return Response({
|
||||
'code': 0,
|
||||
'data': {'list': data, 'has_more': has_more, 'total': total}
|
||||
})
|
||||
except Exception as e:
|
||||
return Response({'code': 500, 'msg': str(e)}, status=500)
|
||||
|
||||
|
||||
|
||||
|
||||
class KaoheFreeApplyView(APIView):
|
||||
"""免费申请考核(首次/再次,费用为0时调用)"""
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
def post(self, request):
|
||||
try:
|
||||
user = request.user
|
||||
tag_id = request.data.get('tag_id')
|
||||
game_nick = request.data.get('game_nick', '').strip()
|
||||
remark = request.data.get('remark', '').strip()
|
||||
reapply = request.data.get('reapply', False)
|
||||
jilu_id = request.data.get('jilu_id') if reapply else None
|
||||
shenheguan_id = request.data.get('shenheguan_id', '').strip() # 新增
|
||||
|
||||
if not tag_id or not game_nick:
|
||||
return Response({'code': 400, 'msg': '标签ID和游戏昵称必填'})
|
||||
|
||||
# 校验费用是否为0
|
||||
try:
|
||||
chenghao = Chenghao.objects.get(id=tag_id)
|
||||
except Chenghao.DoesNotExist:
|
||||
return Response({'code': 400, 'msg': '标签不存在'})
|
||||
|
||||
# 计算本次次数
|
||||
if reapply and jilu_id:
|
||||
last_record = ShenheJilu.objects.filter(
|
||||
jilu_id=jilu_id, shenqingren_id=user.yonghuid, zhuangtai=2
|
||||
).first()
|
||||
if not last_record:
|
||||
return Response({'code': 400, 'msg': '原记录不存在或状态不是未通过'})
|
||||
new_cishu = last_record.cishu + 1
|
||||
else:
|
||||
max_cishu = ShenheJilu.objects.filter(
|
||||
shenqingren_id=user.yonghuid, chenghao=chenghao, zhuangtai__in=[1,2]
|
||||
).aggregate(max=models.Max('cishu'))['max'] or 0
|
||||
new_cishu = max_cishu + 1
|
||||
|
||||
fee = get_tag_fee(chenghao, new_cishu)
|
||||
if fee > 0:
|
||||
return Response({'code': 400, 'msg': '您有未通过的记录请查看并重考'})
|
||||
|
||||
# 新增:如果指定了考核官,进行合法性校验
|
||||
if shenheguan_id:
|
||||
valid, err = validate_shenheguan(shenheguan_id, chenghao.bankuai, fee, user)
|
||||
if not valid:
|
||||
return Response({'code': 400, 'msg': err})
|
||||
|
||||
# 调用公共创建逻辑
|
||||
success, msg, record = create_shenhe_jilu(
|
||||
user, tag_id, game_nick, remark, reapply, jilu_id,
|
||||
shenheguan_id=shenheguan_id # 新增参数
|
||||
)
|
||||
if success:
|
||||
return Response({'code': 0, 'msg': msg, 'data': {'jilu_id': record.jilu_id}})
|
||||
else:
|
||||
return Response({'code': 400, 'msg': msg})
|
||||
except Exception as e:
|
||||
return Response({'code': 500, 'msg': str(e)}, status=500)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class KaoheJiluListView(APIView):
|
||||
"""
|
||||
获取当前考核官的历史审核记录
|
||||
路径:POST /dengji/khghqkhjl
|
||||
权限:JWT Token (考核官)
|
||||
参数:
|
||||
bankuai_id : int (可选,0或空表示全部)
|
||||
status : int (可选,0-全部 1-审核中 2-已通过 3-未通过)
|
||||
page : int (默认1)
|
||||
page_size : int (默认5)
|
||||
返回:
|
||||
list, has_more, total
|
||||
"""
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
def post(self, request):
|
||||
try:
|
||||
yonghu = request.user
|
||||
# 1. 验证考核官身份及账号状态
|
||||
kg = UserShenheguan.objects.filter(user=yonghu, zhuangtai=1).first()
|
||||
if not kg:
|
||||
return Response({'code': 403, 'msg': '您不是考核官或账号异常'})
|
||||
|
||||
# 2. 获取参数
|
||||
bankuai_id = request.data.get('bankuai_id')
|
||||
status = int(request.data.get('status', 0)) # 0全部 1审核中 2已通过 3未通过
|
||||
page = int(request.data.get('page', 1))
|
||||
page_size = int(request.data.get('page_size', 5))
|
||||
|
||||
# 3. 构建查询条件:只查当前考核官审核的记录
|
||||
base_query = ShenheJilu.objects.filter(shenheguan_id=yonghu.yonghuid)
|
||||
|
||||
# 板块筛选
|
||||
if bankuai_id and int(bankuai_id) > 0:
|
||||
base_query = base_query.filter(bankuai_id=int(bankuai_id))
|
||||
|
||||
# 状态筛选(前端传的状态映射到后端zhuangtai字段)
|
||||
status_map = {
|
||||
0: None, # 全部不筛选
|
||||
1: 0, # 审核中
|
||||
2: 1, # 已通过
|
||||
3: 2, # 未通过
|
||||
}
|
||||
if status_map.get(status) is not None:
|
||||
base_query = base_query.filter(zhuangtai=status_map[status])
|
||||
|
||||
# 4. 计数与分页
|
||||
total = base_query.count()
|
||||
offset = (page - 1) * page_size
|
||||
jilu_list = base_query.order_by('-create_time')[offset:offset + page_size]
|
||||
|
||||
# 5. 预取关联数据,减少查询次数
|
||||
jilu_list = jilu_list.select_related('bankuai', 'chenghao')
|
||||
# 为每条记录预取费用明细和拒绝记录(通过 related_name 或手动过滤)
|
||||
# 由于 KaoheJiluFeiyong 和 KaoheJujueJilu 通过外键指向 ShenheJilu (to_field='jilu_id'),
|
||||
# 可以使用 prefetch_related
|
||||
jilu_ids = [j.jilu_id for j in jilu_list]
|
||||
fee_dict = {}
|
||||
reject_dict = {}
|
||||
if jilu_ids:
|
||||
# 批量获取所有费用明细
|
||||
fee_qs = KaoheJiluFeiyong.objects.filter(jilu_id__in=jilu_ids).order_by('cishu')
|
||||
for fee in fee_qs:
|
||||
if fee.jilu_id not in fee_dict:
|
||||
fee_dict[fee.jilu_id] = []
|
||||
fee_dict[fee.jilu_id].append({'cishu': fee.cishu, 'jine': float(fee.jine)})
|
||||
|
||||
# 批量获取所有拒绝记录
|
||||
reject_qs = KaoheJujueJilu.objects.filter(jilu_id__in=jilu_ids).order_by('cishu')
|
||||
for rej in reject_qs:
|
||||
if rej.jilu_id not in reject_dict:
|
||||
reject_dict[rej.jilu_id] = []
|
||||
reject_dict[rej.jilu_id].append({
|
||||
'cishu': rej.cishu,
|
||||
'yuanyin': rej.yuanyin,
|
||||
'create_time': rej.create_time.strftime('%Y-%m-%d %H:%M:%S') if rej.create_time else ''
|
||||
})
|
||||
|
||||
# 6. 批量获取申请人信息(昵称和头像)
|
||||
applicant_ids = {j.shenqingren_id for j in jilu_list}
|
||||
user_map = {}
|
||||
if applicant_ids:
|
||||
users = UserMain.objects.filter(yonghuid__in=applicant_ids).select_related('dashou_profile')
|
||||
for u in users:
|
||||
avatar = u.avatar or ''
|
||||
nicheng = ''
|
||||
try:
|
||||
# 打手扩展表可能有 nicheng
|
||||
nicheng = u.dashou_profile.nicheng if u.dashou_profile else ''
|
||||
except UserDashou.DoesNotExist:
|
||||
pass
|
||||
user_map[u.yonghuid] = {
|
||||
'avatar': avatar,
|
||||
'nicheng': nicheng or f'用户{u.yonghuid}'
|
||||
}
|
||||
|
||||
# 7. 组装数据
|
||||
records = []
|
||||
for jl in jilu_list:
|
||||
user_info = user_map.get(jl.shenqingren_id, {'avatar': '', 'nicheng': '未知'})
|
||||
# 标签特效JSON
|
||||
texiao_json = {}
|
||||
if jl.chenghao and jl.chenghao.texiao_miaoshu:
|
||||
try:
|
||||
texiao_json = json.loads(jl.chenghao.texiao_miaoshu)
|
||||
except:
|
||||
pass
|
||||
|
||||
# 汇总总缴纳费用
|
||||
fee_items = fee_dict.get(jl.jilu_id, [])
|
||||
total_fee = sum(item['jine'] for item in fee_items)
|
||||
|
||||
records.append({
|
||||
'jilu_id': jl.jilu_id,
|
||||
'shenqingren_id': jl.shenqingren_id,
|
||||
'shenqingren_avatar': user_info['avatar'],
|
||||
'shenqingren_nicheng': user_info['nicheng'],
|
||||
'bankuai_mingcheng': jl.bankuai.mingcheng if jl.bankuai else '',
|
||||
'chenghao_mingcheng': jl.chenghao.mingcheng if jl.chenghao else '',
|
||||
'chenghao_texiao_json': texiao_json,
|
||||
'zhuangtai': jl.zhuangtai, # 0审核中 1通过 2未通过 3待审核
|
||||
'cishu': jl.cishu,
|
||||
'total_fee': total_fee,
|
||||
'dashou_youxi_id': jl.dashou_youxi_id or '',
|
||||
'dashou_beizhu': jl.dashou_beizhu or '',
|
||||
'shenheguan_youxi_id': jl.shenheguan_youxi_id or '',
|
||||
'guize_neirong': jl.guize_neirong or '',
|
||||
'create_time': jl.create_time.strftime('%Y-%m-%d %H:%M:%S') if jl.create_time else '',
|
||||
'update_time': jl.update_time.strftime('%Y-%m-%d %H:%M:%S') if jl.update_time else '',
|
||||
'fee_list': fee_items,
|
||||
'reject_list': reject_dict.get(jl.jilu_id, []),
|
||||
})
|
||||
|
||||
has_more = (page * page_size) < total
|
||||
return Response({
|
||||
'code': 0,
|
||||
'data': {
|
||||
'list': records,
|
||||
'has_more': has_more,
|
||||
'total': total
|
||||
}
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"获取考核记录异常: {str(e)}", exc_info=True)
|
||||
return Response({'code': 500, 'msg': '服务器内部错误'}, status=500)
|
||||
Reference in New Issue
Block a user