开发了多角色登录与鉴权接口:实现了普通用户、企业和管理员的登录分流,并支持Token验证。

开发了权限控制接口:实现了通过数据库分配菜单权限节点,控制接口访问安全。
开发了实名认证中心:实现了个人身份证信息与企业营业执照的提交与审核接口。
开发了任务与协作大厅核心业务:实现了任务的发布、接单、状态流转以及专家邀约接口。
配置了全局环境变量与数据库引擎:集成了 PostgreSQL 数据库、Redis 缓存与 MinIO 对象存储。
This commit is contained in:
2026-04-28 16:32:02 +08:00
commit 23855ef0e4
94 changed files with 4950 additions and 0 deletions

0
opc_cert/__init__.py Normal file
View File

3
opc_cert/admin.py Normal file
View File

@@ -0,0 +1,3 @@
from django.contrib import admin
# Register your models here.

6
opc_cert/apps.py Normal file
View File

@@ -0,0 +1,6 @@
from django.apps import AppConfig
class OpcCertConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'opc_cert'

View File

@@ -0,0 +1,40 @@
# Generated by Django 4.2.30 on 2026-04-25 09:46
from django.db import migrations, models
import uuid
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='OpcCertification',
fields=[
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
('real_name', models.CharField(max_length=64)),
('id_card', models.TextField(blank=True, null=True)),
('skills', models.JSONField(default=list)),
('experience', models.TextField(blank=True, null=True)),
('resume_url', models.CharField(blank=True, max_length=512, null=True)),
('attachments', models.JSONField(default=list)),
('status', models.CharField(choices=[('PENDING', '待审核'), ('APPROVED', '已通过'), ('REJECTED', '已驳回')], default='PENDING', max_length=16)),
('reject_reason', models.TextField(blank=True, null=True)),
('reviewed_at', models.DateTimeField(blank=True, null=True)),
('rating', models.SmallIntegerField(blank=True, null=True)),
('rating_tags', models.JSONField(default=list)),
('rating_note', models.TextField(blank=True, null=True)),
('rated_at', models.DateTimeField(blank=True, null=True)),
('version', models.SmallIntegerField(default=1)),
('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now=True)),
],
options={
'db_table': 'opc_certifications',
},
),
]

View File

@@ -0,0 +1,33 @@
# Generated by Django 4.2.30 on 2026-04-25 09:46
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
initial = True
dependencies = [
('opc_cert', '0001_initial'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.AddField(
model_name='opccertification',
name='rated_by',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='rated_certifications', to=settings.AUTH_USER_MODEL),
),
migrations.AddField(
model_name='opccertification',
name='reviewer',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='reviewed_certifications', to=settings.AUTH_USER_MODEL),
),
migrations.AddField(
model_name='opccertification',
name='user',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='opc_certifications', to=settings.AUTH_USER_MODEL),
),
]

View File

32
opc_cert/models.py Normal file
View File

@@ -0,0 +1,32 @@
import uuid
from django.db import models
class CertStatus(models.TextChoices):
PENDING = 'PENDING', '待审核'
APPROVED = 'APPROVED', '已通过'
REJECTED = 'REJECTED', '已驳回'
class OpcCertification(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
user = models.ForeignKey('users.User', on_delete=models.CASCADE, related_name='opc_certifications')
real_name = models.CharField(max_length=64)
id_card = models.TextField(null=True, blank=True)
skills = models.JSONField(default=list)
experience = models.TextField(null=True, blank=True)
resume_url = models.CharField(max_length=512, null=True, blank=True)
attachments = models.JSONField(default=list)
status = models.CharField(max_length=16, choices=CertStatus.choices, default=CertStatus.PENDING)
reject_reason = models.TextField(null=True, blank=True)
reviewer = models.ForeignKey('users.User', on_delete=models.SET_NULL, null=True, blank=True, related_name='reviewed_certifications')
reviewed_at = models.DateTimeField(null=True, blank=True)
rating = models.SmallIntegerField(null=True, blank=True)
rating_tags = models.JSONField(default=list)
rating_note = models.TextField(null=True, blank=True)
rated_by = models.ForeignKey('users.User', on_delete=models.SET_NULL, null=True, blank=True, related_name='rated_certifications')
rated_at = models.DateTimeField(null=True, blank=True)
version = models.SmallIntegerField(default=1)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
db_table = 'opc_certifications'

21
opc_cert/serializers.py Normal file
View File

@@ -0,0 +1,21 @@
from rest_framework import serializers
from .models import OpcCertification
class OpcCertificationSerializer(serializers.ModelSerializer):
user_detail = serializers.SerializerMethodField()
class Meta:
model = OpcCertification
fields = '__all__'
read_only_fields = ['id', 'user', 'status', 'reviewer', 'reviewed_at', 'rating', 'rating_tags', 'rating_note', 'rated_by', 'rated_at', 'created_at', 'updated_at']
def get_user_detail(self, obj):
user = obj.user
return {
'id': user.id,
'username': user.username,
'nickname': user.nickname,
'avatar_url': user.avatar_url,
'email': user.email,
'phone': user.phone
}

3
opc_cert/tests.py Normal file
View File

@@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

10
opc_cert/urls.py Normal file
View File

@@ -0,0 +1,10 @@
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from .views import OpcCertificationViewSet
router = DefaultRouter()
router.register('certifications', OpcCertificationViewSet)
urlpatterns = [
path('', include(router.urls)),
]

91
opc_cert/views.py Normal file
View File

@@ -0,0 +1,91 @@
from rest_framework import viewsets, permissions, status
from rest_framework.response import Response
from rest_framework.decorators import action
from .models import OpcCertification, CertStatus
from .serializers import OpcCertificationSerializer
from django.utils import timezone
class OpcCertificationViewSet(viewsets.ModelViewSet):
"""
@author: xujl
Api说明: OPCOne Person Company专家认证申请接口视图。提供普通用户提交资质申请、管理员审核(approve)、驳回(reject)等核心流程。认证通过后自动授予OPC_USER角色。
"""
queryset = OpcCertification.objects.all()
serializer_class = OpcCertificationSerializer
permission_classes = [permissions.IsAuthenticated]
required_permissions = {
'GET': 'api:certs:read',
'POST': 'api:certs:write',
'PUT': 'api:certs:write',
'PATCH': 'api:certs:write',
'DELETE': 'api:certs:delete'
}
def get_permissions(self):
if self.action in ['create', 'destroy']:
return [permissions.IsAuthenticated()]
if self.action in ['list', 'retrieve']:
# Either it's their own, or they have admin permission
return [permissions.IsAuthenticated()]
if self.action in ['approve', 'reject']:
from users.permissions import HasAPIPermission
return [HasAPIPermission()]
return super().get_permissions()
def get_queryset(self):
user = self.request.user
from users.permissions import HasAPIPermission
# If user has the certs read permission or is superuser, show all
has_admin_perm = False
if user.is_superuser:
has_admin_perm = True
else:
from users.models import RolePermission
perms = set(RolePermission.objects.filter(role__userrole__user=user).values_list('permission__code', flat=True))
if 'api:certs:read' in perms or '*' in perms:
has_admin_perm = True
if has_admin_perm:
return OpcCertification.objects.all().order_by('-created_at')
return OpcCertification.objects.filter(user=user).order_by('-created_at')
def perform_create(self, serializer):
# 提交新申请前,只删除该用户的 PENDING 或 REJECTED 记录,保留已有的 APPROVED 记录
OpcCertification.objects.filter(user=self.request.user).exclude(status=CertStatus.APPROVED).delete()
serializer.save(user=self.request.user, status=CertStatus.PENDING)
@action(detail=True, methods=['post'])
def approve(self, request, pk=None):
cert = self.get_object()
if cert.status != CertStatus.PENDING:
return Response({'detail': '状态不允许该操作'}, status=status.HTTP_400_BAD_REQUEST)
cert.status = CertStatus.APPROVED
cert.reviewer = request.user
cert.reviewed_at = timezone.now()
cert.save()
# 管理员通过后,删除该用户所有的旧认证记录(包括旧的 APPROVED 记录),确保数据库只有最新的一条
OpcCertification.objects.filter(user=cert.user).exclude(id=cert.id).delete()
# 自动追加 OPC_USER 角色
from users.models import Role, UserRole
role_opc, _ = Role.objects.get_or_create(code='OPC_USER', defaults={'name': '认证专家', 'is_system': True})
UserRole.objects.get_or_create(user=cert.user, role=role_opc, defaults={'granted_by': request.user})
return Response({'status': '认证已通过,用户角色已更新'})
@action(detail=True, methods=['post'])
def reject(self, request, pk=None):
cert = self.get_object()
reason = request.data.get('reject_reason', '不符合要求')
cert.status = CertStatus.REJECTED
cert.reject_reason = reason
cert.reviewer = request.user
cert.reviewed_at = timezone.now()
cert.save()
return Response({'status': '认证已驳回'})