| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915 |
- from rest_framework import viewsets
- from rest_framework.decorators import action
- from .models import ListModel, TypeListModel
- from . import serializers
- from utils.page import MyPageNumberPagination
- from rest_framework.filters import OrderingFilter
- from django_filters.rest_framework import DjangoFilterBackend
- from rest_framework.response import Response
- from .filter import Filter, TypeFilter
- from rest_framework.exceptions import APIException
- from .serializers import FileRenderSerializer
- from django.http import StreamingHttpResponse
- from .files import FileRenderCN, FileRenderEN
- from rest_framework.settings import api_settings
- from rest_framework import permissions
- from staff.models import ListModel as staff
- from userprofile.models import Users
- from django.utils import timezone
- from utils.md5 import Md5
- import random
- from django.contrib.auth.models import User
- from .models import Role, Permission # 新增角色和权限模型导入
- from operation_log.views import log_success_operation, log_failure_operation, log_operation
- class APIViewSet(viewsets.ModelViewSet):
- """
- retrieve:
- Response a data list(get)
- list:
- Response a data list(all)
- create:
- Create a data line(post)
- delete:
- Delete a data line(delete)
- partial_update:
- Partial_update a data(patch:partial_update)
- update:
- Update a data(put:update)
- """
- pagination_class = MyPageNumberPagination
- filter_backends = [DjangoFilterBackend, OrderingFilter, ]
- ordering_fields = ['id', "create_time", "update_time", ]
- filter_class = Filter
- def list(self, request, *args, **kwargs):
- # staff_name = str(request.GET.get('staff_name'))
- # check_code = request.GET.get('check_code')
- # if staff_name == None and check_code == None:
- # return super().list(request, *args, **kwargs)
- # elif staff_name != None and check_code == None:
- # return super().list(request, *args, **kwargs)
- # else:
- # staff_name_obj = ListModel.objects.filter(openid=self.request.auth.openid, staff_name=staff_name,
- # is_delete=False).first()
- # if staff_name_obj is None:
- # raise APIException({"detail": "用户名不存在"})
- # elif staff_name_obj.is_lock is True:
- # raise APIException({"detail": "用户已被锁定,请联系管理员"})
- # elif staff_name_obj.error_check_code_counter == 3:
- # staff_name_obj.is_lock = True
- # staff_name_obj.error_check_code_counter = 0
- # staff_name_obj.save()
- # raise APIException({"detail": "用户已被锁定,请联系管理员"})
- # if type(check_code) == str:
- # check_code = int(check_code)
- # if check_code != None:
- # if staff_name_obj.check_code != check_code:
- # staff_name_obj.error_check_code_counter = int(staff_name_obj.error_check_code_counter) + 1
- # staff_name_obj.save()
- # raise APIException({"detail": "验证码错误"})
- # else:
- # staff_name_obj.error_check_code_counter = 0
- # staff_name_obj.save()
- # return super().list(request, *args, **kwargs)
- # else:
- return super().list(request, *args, **kwargs)
- def get_project(self):
- try:
- id = self.kwargs.get('pk')
- return id
- except:
- return None
- def get_queryset(self):
- id = self.get_project()
- if self.request.user:
- if id is None:
- return ListModel.objects.filter(is_delete=False)
- else:
- return ListModel.objects.filter(id=id, is_delete=False)
- else:
- return ListModel.objects.none()
- def get_serializer_class(self):
- staff_name = self.request.auth.name
- staff_type = ListModel.objects.filter(staff_name=staff_name, is_delete=False).first().staff_type
- if staff_type not in ['admin', '主管', '管理员','经理']:
- if self.action in ['list', 'retrieve', 'destroy']:
- return serializers.userStaffGetSerializer
- elif self.action in ['create']:
- return serializers.userStaffPostSerializer
- elif self.action in ['update']:
- return serializers.userStaffUpdateSerializer
- elif self.action in ['partial_update']:
- return serializers.userStaffPartialUpdateSerializer
- else:
- return self.http_method_not_allowed(request=self.request)
- else:
- if self.action in ['list', 'retrieve', 'destroy']:
- return serializers.StaffGetSerializer
- elif self.action in ['create']:
- return serializers.StaffPostSerializer
- elif self.action in ['update']:
- return serializers.StaffUpdateSerializer
- elif self.action in ['partial_update']:
- return serializers.StaffPartialUpdateSerializer
- else:
- return self.http_method_not_allowed(request=self.request)
- def create(self, request, *args, **kwargs):
- data = self.request.data
- data['openid'] = self.request.auth.openid
-
- # 检查角色是否存在
- role_name = data.get('role')
- if role_name:
- role, created = Role.objects.get_or_create(name=role_name)
- data['role'] = role.id
-
- if ListModel.objects.filter(openid=data['openid'], staff_name=data['staff_name'], is_delete=False).exists():
- raise APIException({"detail": "Data exists"})
- else:
- app_code = Md5.md5(data['staff_name'] + '1')
- data['appid'] = app_code
- check_code = random.randint(1000, 9999)
- data['check_code'] = check_code
-
- # 创建/更新 Django auth 用户
- username = str(data['staff_name'])
- password = str(check_code)
- try:
- user = User.objects.get(username=username)
- user.set_password(password)
- user.save()
- except User.DoesNotExist:
- user = User.objects.create_user(username=username, password=password)
- ip = request.META.get('HTTP_X_FORWARDED_FOR') if request.META.get(
- 'HTTP_X_FORWARDED_FOR') else request.META.get('REMOTE_ADDR')
- # 创建/更新用户档案
- users_defaults = dict(
- name=str(data['staff_name']),
- openid=app_code, appid=app_code,
- t_code=Md5.md5(str(timezone.now())),
- developer=1, ip=ip
- )
- profile, created = Users.objects.get_or_create(user_id=user.id, defaults=users_defaults)
- if not created:
- # 同步基础字段
- profile.name = users_defaults['name']
- profile.openid = users_defaults['openid']
- profile.appid = users_defaults['appid']
- profile.ip = users_defaults['ip']
- profile.save()
-
- serializer = self.get_serializer(data=data)
- serializer.is_valid(raise_exception=True)
- serializer.save()
- headers = self.get_success_headers(serializer.data)
- try:
- log_success_operation(
- request=self.request,
- operation_content=f"创建员工:{data.get('staff_name', '未知')}",
- operation_level="new",
- operator=self.request.auth.name if hasattr(self.request, 'auth') and self.request.auth else None,
- object_id=serializer.data.get('id'),
- module_name="员工管理"
- )
- except Exception as e:
- pass # 日志记录失败不影响业务
- return Response(serializer.data, status=200, headers=headers)
- def update(self, request, pk):
- qs = self.get_object()
- # if qs.openid != self.request.auth.openid:
- # creator = ListModel.objects.filter(openid=self.request.auth.openid, is_delete=False)
- # raise APIException({"detail": "该用户不是您创建的,不能修改"})
- # else:
- data = self.request.data
-
- # 更新角色
- role_name = data.get('role')
- if role_name:
- role, created = Role.objects.get_or_create(name=role_name)
- data['role'] = role.id
-
- old_staff_name = qs.staff_name
- serializer = self.get_serializer(qs, data=data)
- serializer.is_valid(raise_exception=True)
- serializer.save()
- # 同步 Django auth 用户与用户档案
- new_staff_name = serializer.instance.staff_name
- if old_staff_name != new_staff_name:
- try:
- auth_user = User.objects.get(username=str(old_staff_name))
- auth_user.username = str(new_staff_name)
- auth_user.save()
- # 同步 userprofile.Users
- profile = Users.objects.filter(user_id=auth_user.id).first()
- if profile:
- profile.name = str(new_staff_name)
- profile.save()
- except User.DoesNotExist:
- # 如不存在旧账号,则以新名称创建
- auth_user = User.objects.create_user(username=str(new_staff_name), password=str(qs.check_code))
- Users.objects.get_or_create(user_id=auth_user.id, defaults=dict(
- name=str(new_staff_name), openid=qs.appid, appid=qs.appid,
- t_code=Md5.md5(str(timezone.now())), developer=1, ip=request.META.get('REMOTE_ADDR')
- ))
- headers = self.get_success_headers(serializer.data)
- try:
- log_success_operation(
- request=self.request,
- operation_content=f"更新员工 ID:{pk}:{data.get('staff_name', '未知')}",
- operation_level="update",
- operator=self.request.auth.name if hasattr(self.request, 'auth') and self.request.auth else None,
- object_id=pk,
- module_name="员工管理"
- )
- except Exception as e:
- pass
- return Response(serializer.data, status=200, headers=headers)
- def change_check_code(self, request, pk=None):
- """
- 修改员工验证码(密码)
- - 普通员工:只能修改自己的验证码
- - 管理/主管/管理员/经理:可修改任意员工验证码
- 请求体: { "new_check_code": 1234 }
- """
- target_staff = self.get_object()
- current_staff = ListModel.objects.filter(openid=self.request.auth.openid, is_delete=False).first()
- if current_staff is None:
- raise APIException({"detail": "当前用户不存在或未登录"})
- privileged_types = ['admin', '主管', '管理员', '经理']
- can_modify_any = str(current_staff.staff_type) in privileged_types
- if not can_modify_any and current_staff.id != target_staff.id:
- raise APIException({"detail": "无权限修改他人验证码"})
- new_code = request.data.get('new_check_code')
- try:
- new_code_int = int(new_code)
- except (TypeError, ValueError):
- raise APIException({"detail": "new_check_code 必须为4位数字"})
- if new_code_int < 0 or new_code_int > 9999:
- raise APIException({"detail": "new_check_code 必须为0-9999之间的数字"})
- # 更新staff表
- target_staff.check_code = new_code_int
- target_staff.error_check_code_counter = 0
- target_staff.is_lock = False
- target_staff.save()
- # 同步更新Django auth用户密码(用户名为staff_name)
- try:
- auth_user = User.objects.get(username=str(target_staff.staff_name))
- auth_user.set_password(str(new_code_int))
- auth_user.save()
- except User.DoesNotExist:
- # 若不存在则创建,保持行为幂等
- User.objects.create_user(username=str(target_staff.staff_name), password=str(new_code_int))
- try:
- log_success_operation(
- request=self.request,
- operation_content=f"修改员工验证码 ID:{target_staff.id},员工:{target_staff.staff_name}",
- operation_level="update",
- operator=self.request.auth.name if hasattr(self.request, 'auth') and self.request.auth else None,
- object_id=target_staff.id,
- module_name="员工管理"
- )
- except Exception as e:
- pass
- return Response({"message": "验证码已更新", "id": target_staff.id, "check_code": target_staff.check_code})
- def partial_update(self, request, pk):
- qs = self.get_object()
- if qs.openid != self.request.auth.openid:
- raise APIException({"detail": "Cannot Update Data Which Not Yours"})
- else:
- data = self.request.data
-
- # 更新角色
- role_name = data.get('role')
- if role_name:
- role, created = Role.objects.get_or_create(name=role_name)
- data['role'] = role.id
-
- old_staff_name = qs.staff_name
- serializer = self.get_serializer(qs, data=data, partial=True)
- serializer.is_valid(raise_exception=True)
- serializer.save()
- # 同步 Django auth 用户与用户档案
- new_staff_name = serializer.instance.staff_name
- if old_staff_name != new_staff_name:
- try:
- auth_user = User.objects.get(username=str(old_staff_name))
- auth_user.username = str(new_staff_name)
- auth_user.save()
- profile = Users.objects.filter(user_id=auth_user.id).first()
- if profile:
- profile.name = str(new_staff_name)
- profile.save()
- except User.DoesNotExist:
- auth_user = User.objects.create_user(username=str(new_staff_name), password=str(qs.check_code))
- Users.objects.get_or_create(user_id=auth_user.id, defaults=dict(
- name=str(new_staff_name), openid=qs.appid, appid=qs.appid,
- t_code=Md5.md5(str(timezone.now())), developer=1, ip=request.META.get('REMOTE_ADDR')
- ))
- headers = self.get_success_headers(serializer.data)
- try:
- log_success_operation(
- request=self.request,
- operation_content=f"部分更新员工 ID:{pk}",
- operation_level="update",
- operator=self.request.auth.name if hasattr(self.request, 'auth') and self.request.auth else None,
- object_id=pk,
- module_name="员工管理"
- )
- except Exception as e:
- pass
- return Response(serializer.data, status=200, headers=headers)
- def destroy(self, request, pk):
- qs = self.get_object()
- if qs.openid != self.request.auth.openid:
- raise APIException({"detail": "Cannot Delete Data Which Not Yours"})
- else:
- qs.is_delete = True
- qs.save()
- serializer = self.get_serializer(qs, many=False)
- headers = self.get_success_headers(serializer.data)
- try:
- log_success_operation(
- request=self.request,
- operation_content=f"删除员工 ID:{pk},员工名:{qs.staff_name}",
- operation_level="delete",
- operator=self.request.auth.name if hasattr(self.request, 'auth') and self.request.auth else None,
- object_id=pk,
- module_name="员工管理"
- )
- except Exception as e:
- pass
- return Response(serializer.data, status=200, headers=headers)
- class RoleViewSet(viewsets.ModelViewSet):
- """角色管理API"""
- queryset = Role.objects.all()
- serializer_class = serializers.RoleSerializer
- pagination_class = MyPageNumberPagination
- filter_backends = [DjangoFilterBackend, OrderingFilter]
- ordering_fields = ['id', "name"]
-
- def get_queryset(self):
- return Role.objects.all()
- class PermissionViewSet(viewsets.ModelViewSet):
- """权限管理API"""
- queryset = Permission.objects.all()
- serializer_class = serializers.PermissionSerializer
- # pagination_class = MyPageNumberPagination
- filter_backends = [DjangoFilterBackend, OrderingFilter]
- ordering_fields = ['id', "page"]
-
- def get_queryset(self):
- role = self.request.query_params.get('role')
- if role:
- return Permission.objects.filter(role__name=role)
- return Permission.objects.all()
- class RolePermissionViewSet(viewsets.ViewSet):
- """角色权限配置API"""
-
- def list(self, request):
- """获取所有角色类型"""
- roles = Role.objects.values_list('name', flat=True).distinct()
- return Response(list(roles))
-
- def reset_default_permissions(self, request):
- """恢复默认权限配置"""
- # 从 test_permission.py 导入配置
- PAGES = [
- {"primary_page": "stock", "path": "/stock/management", "components": ["view", "edit", "add", "delete", "export", "confirm", "adjust", "download"]},
- {"primary_page": "stock", "path": "/stock/stocklist", "components": ["view", "edit", "add", "delete", "export", "confirm", "adjust", "download"]},
- {"primary_page": "stock", "path": "/stock/stockbinlist", "components": ["view", "edit", "add", "delete", "export", "confirm", "adjust", "download"]},
- {"primary_page": "stock", "path": "/stock/emptybin", "components": ["view", "edit", "add", "delete", "export", "confirm", "adjust", "download"]},
- {"primary_page": "stock", "path": "/stock/occupiedbin", "components": ["view", "edit", "add", "delete", "export", "confirm", "adjust", "download"]},
- {"primary_page": "stock", "path": "/stock/binset", "components": ["view", "edit", "add", "delete", "export", "confirm", "adjust", "download"]},
- {"primary_page": "stock", "path": "/stock/handcount", "components": ["view", "edit", "add", "delete", "export", "confirm", "adjust", "download"]},
- {"primary_page": "erp", "path": "/erp/erpasn", "components": ["view", "edit", "add", "delete", "export", "confirm", "adjust", "download"]},
- {"primary_page": "erp", "path": "/erp/erpasnmaterial", "components": ["view", "edit", "add", "delete", "export", "confirm", "adjust", "download"]},
- {"primary_page": "erp", "path": "/erp/erpdnmaterial", "components": ["view", "edit", "add", "delete", "export", "confirm", "adjust", "download"]},
- {"primary_page": "erp", "path": "/erp/erpasnaudit", "components": ["view", "edit", "add", "delete", "export", "confirm", "adjust", "download"]},
- {"primary_page": "erp", "path": "/erp/erpdn", "components": ["view", "edit", "add", "delete", "export", "confirm", "adjust", "download"]},
- {"primary_page": "erp", "path": "/erp/erpsortstock", "components": ["view", "edit", "add", "delete", "export", "confirm", "adjust", "download"]},
- {"primary_page": "inbound", "path": "/inbound/asn", "components": ["view", "edit", "add", "delete", "export", "confirm", "adjust", "download"]},
- {"primary_page": "inbound", "path": "/inbound/predeliverystock", "components": ["view", "edit", "add", "delete", "export", "confirm", "adjust", "download"]},
- {"primary_page": "inbound", "path": "/inbound/preloadstock", "components": ["view", "edit", "add", "delete", "export", "confirm", "adjust", "download"]},
- {"primary_page": "inbound", "path": "/inbound/presortstock", "components": ["view", "edit", "add", "delete", "export", "confirm", "adjust", "download"]},
- {"primary_page": "inbound", "path": "/inbound/sortstock", "components": ["view", "edit", "add", "delete", "export", "confirm", "adjust", "download"]},
- {"primary_page": "inbound", "path": "/inbound/shortage", "components": ["view", "edit", "add", "delete", "export", "confirm", "adjust", "download"]},
- {"primary_page": "inbound", "path": "/inbound/more", "components": ["view", "edit", "add", "delete", "export", "confirm", "adjust", "download"]},
- {"primary_page": "inbound", "path": "/inbound/asnfinish", "components": ["view", "edit", "add", "delete", "export", "confirm", "adjust", "download"]},
- {"primary_page": "container", "path": "/container/containerlist", "components": ["view", "edit", "add", "delete", "export", "confirm", "adjust", "download"]},
- {"primary_page": "container", "path": "/container/containerdetail", "components": ["view", "edit", "add", "delete", "export", "confirm", "adjust", "download"]},
- {"primary_page": "container", "path": "/container/containercategory", "components": ["view", "edit", "add", "delete", "export", "confirm", "adjust", "download"]},
- {"primary_page": "container", "path": "/container/containeroperate", "components": ["view", "edit", "add", "delete", "export", "confirm", "adjust", "download"]},
- {"primary_page": "dashboard", "path": "/dashboard/inboundAndOutbound", "components": ["view", "edit", "add", "delete", "export", "confirm", "adjust", "download"]},
- {"primary_page": "dashboard", "path": "/dashboard/flows_statements", "components": ["view", "edit", "add", "delete", "export", "confirm", "adjust", "download"]},
- {"primary_page": "dashboard", "path": "/dashboard/flows", "components": ["view", "edit", "add", "delete", "export", "confirm", "adjust", "download"]},
- {"primary_page": "dashboard", "path": "/dashboard/flows_complex", "components": ["view", "edit", "add", "delete", "export", "confirm", "adjust", "download"]},
- {"primary_page": "dashboard", "path": "/dashboard/batchlog", "components": ["view", "edit", "add", "delete", "export", "confirm", "adjust", "download"]},
- {"primary_page": "dashboard", "path": "/dashboard/ContainerDetailLogModel", "components": ["view", "edit", "add", "delete", "export", "confirm", "adjust", "download"]},
- {"primary_page": "dashboard", "path": "/dashboard/MaterialChangeHistory", "components": ["view", "edit", "add", "delete", "export", "confirm", "adjust", "download"]},
- {"primary_page": "count", "path": "/count/detaillog", "components": ["view", "edit", "add", "delete", "export", "confirm", "adjust", "download"]},
- {"primary_page": "count", "path": "/count/batchoperatelog", "components": ["view", "edit", "add", "delete", "export", "confirm", "adjust", "download"]},
- {"primary_page": "count", "path": "/count/countbatchlog", "components": ["view", "edit", "add", "delete", "export", "confirm", "adjust", "download"]},
- {"primary_page": "count", "path": "/count/presortstock", "components": ["view", "edit", "add", "delete", "export", "confirm", "adjust", "download"]},
- {"primary_page": "count", "path": "/count/sortstock", "components": ["view", "edit", "add", "delete", "export", "confirm", "adjust", "download"]},
- {"primary_page": "count", "path": "/count/shortage", "components": ["view", "edit", "add", "delete", "export", "confirm", "adjust", "download"]},
- {"primary_page": "count", "path": "/count/containerDetail", "components": ["view", "edit", "add", "delete", "export", "confirm", "adjust", "download"]},
- {"primary_page": "count", "path": "/count/batch", "components": ["view", "edit", "add", "delete", "export", "confirm", "adjust", "download"]},
- {"primary_page": "count", "path": "/count/asnfinish", "components": ["view", "edit", "add", "delete", "export", "confirm", "adjust", "download"]},
- {"primary_page": "outbound", "path": "/outbound/dn", "components": ["view", "edit", "add", "delete", "export", "confirm", "adjust", "download"]},
- {"primary_page": "outbound", "path": "/outbound/freshorder", "components": ["view", "edit", "add", "delete", "export", "confirm", "adjust", "download"]},
- {"primary_page": "outbound", "path": "/outbound/neworder", "components": ["view", "edit", "add", "delete", "export", "confirm", "adjust", "download"]},
- {"primary_page": "outbound", "path": "/outbound/pickstock", "components": ["view", "edit", "add", "delete", "export", "confirm", "adjust", "download"]},
- {"primary_page": "outbound", "path": "/outbound/pickedstock", "components": ["view", "edit", "add", "delete", "export", "confirm", "adjust", "download"]},
- {"primary_page": "outbound", "path": "/outbound/pickinglist", "components": ["view", "edit", "add", "delete", "export", "confirm", "adjust", "download"]},
- {"primary_page": "outbound", "path": "/outbound/shippedstock", "components": ["view", "edit", "add", "delete", "export", "confirm", "adjust", "download"]},
- {"primary_page": "outbound", "path": "/outbound/backorder", "components": ["view", "edit", "add", "delete", "export", "confirm", "adjust", "download"]},
- {"primary_page": "outbound", "path": "/outbound/pod", "components": ["view", "edit", "add", "delete", "export", "confirm", "adjust", "download"]},
- {"primary_page": "outbound", "path": "/outbound/container_check", "components": ["view", "edit", "add", "delete", "export", "confirm", "adjust", "download"]},
- {"primary_page": "goods", "path": "/goods/goodslist", "components": ["view", "edit", "add", "delete", "export", "confirm", "adjust", "download"]},
- {"primary_page": "goods", "path": "/goods/goodsunit", "components": ["view", "edit", "add", "delete", "export", "confirm", "adjust", "download"]},
- {"primary_page": "goods", "path": "/goods/goodsclass", "components": ["view", "edit", "add", "delete", "export", "confirm", "adjust", "download"]},
- {"primary_page": "goods", "path": "/goods/goodsbrand", "components": ["view", "edit", "add", "delete", "export", "confirm", "adjust", "download"]},
- {"primary_page": "goods", "path": "/goods/goodscolor", "components": ["view", "edit", "add", "delete", "export", "confirm", "adjust", "download"]},
- {"primary_page": "goods", "path": "/goods/goodsspecs", "components": ["view", "edit", "add", "delete", "export", "confirm", "adjust", "download"]},
- {"primary_page": "goods", "path": "/goods/goodsshape", "components": ["view", "edit", "add", "delete", "export", "confirm", "adjust", "download"]},
- {"primary_page": "goods", "path": "/goods/goodsorigin", "components": ["view", "edit", "add", "delete", "export", "confirm", "adjust", "download"]},
- {"primary_page": "taskpage", "path": "/taskpage/task", "components": ["view", "edit", "add", "delete", "export", "confirm", "adjust", "download"]},
- {"primary_page": "warehouse", "path": "/warehouse/warehouseset", "components": ["view", "edit", "add", "delete", "export", "confirm", "adjust", "download"]},
- {"primary_page": "warehouse", "path": "/warehouse/department", "components": ["view", "edit", "add", "delete", "export", "confirm", "adjust", "download"]},
- {"primary_page": "warehouse", "path": "/warehouse/boundcodetype", "components": ["view", "edit", "add", "delete", "export", "confirm", "adjust", "download"]},
- {"primary_page": "warehouse", "path": "/warehouse/boundtype", "components": ["view", "edit", "add", "delete", "export", "confirm", "adjust", "download"]},
- {"primary_page": "warehouse", "path": "/warehouse/boundbusiness", "components": ["view", "edit", "add", "delete", "export", "confirm", "adjust", "download"]},
- {"primary_page": "warehouse", "path": "/warehouse/status", "components": ["view", "edit", "add", "delete", "export", "confirm", "adjust", "download"]},
- {"primary_page": "warehouse", "path": "/warehouse/product", "components": ["view", "edit", "add", "delete", "export", "confirm", "adjust", "download"]},
- {"primary_page": "staff", "path": "/staff/roles", "components": ["view", "edit", "add", "delete", "export", "confirm", "adjust", "download"]},
- {"primary_page": "staff", "path": "/staff/stafflist", "components": ["view", "edit", "add", "delete", "export", "confirm", "adjust", "download"]},
- {"primary_page": "staff", "path": "/staff/stafflist_check_code", "components": ["view", "edit", "add", "delete", "export", "confirm", "adjust", "download"]},
- {"primary_page": "staff", "path": "/staff/stafftype", "components": ["view", "edit", "add", "delete", "export", "confirm", "adjust", "download"]},
- {"primary_page": "staff", "path": "/staff/operationlog", "components": ["view", "edit", "add", "delete", "export", "confirm", "adjust", "download"]},
- {"primary_page": "uploadcenter", "path": "/uploadcenter/initializeupload", "components": ["view", "edit", "add", "delete", "export", "confirm", "adjust", "download"]},
- {"primary_page": "uploadcenter", "path": "/uploadcenter/addupload", "components": ["view", "edit", "add", "delete", "export", "confirm", "adjust", "download"]},
- {"primary_page": "downloadcenter", "path": "/downloadcenter/downloadinbound", "components": ["view", "edit", "add", "delete", "export", "confirm", "adjust", "download"]},
- {"primary_page": "downloadcenter", "path": "/downloadcenter/downloadoutbound", "components": ["view", "edit", "add", "delete", "export", "confirm", "adjust", "download"]},
- {"primary_page": "downloadcenter", "path": "/downloadcenter/downloadstocklist", "components": ["view", "edit", "add", "delete", "export", "confirm", "adjust", "download"]},
- {"primary_page": "downloadcenter", "path": "/downloadcenter/downloadgoodslist", "components": ["view", "edit", "add", "delete", "export", "confirm", "adjust", "download"]},
- {"primary_page": "downloadcenter", "path": "/downloadcenter/downloadbinlist", "components": ["view", "edit", "add", "delete", "export", "confirm", "adjust", "download"]},
- ]
-
- ROLES = {
- "管理员": {
- "description": "系统管理员,拥有所有权限",
- "page_access": "all",
- "component_access": "all"
- },
- "经理": {
- "description": "部门经理,拥有大部分管理权限",
- "page_access": [
- "/stock/management", "/stock/stockbinlist", "/stock/stocklist",
- "/erp/erpasn", "/erp/erpasnmaterial", "/erp/erpdnmaterial", "/erp/erpdn", "/erp/erpsortstock",
- "/inbound/asn", "/inbound/predeliverystock", "/inbound/sortstock",
- "/container/containerlist", "/container/containerdetail", "/container/containercategory", "/container/containeroperate",
- "/outbound/dn", "/outbound/backorder", "/outbound/container_check",
- "/taskpage/task",
- "/count/batch", "/count/countbatchlog", "/count/detaillog", "/count/batchoperatelog",
- "/dashboard/flows_statements", "/dashboard/flows", "/dashboard/MaterialChangeHistory", "/dashboard/batchlog", "/dashboard/ContainerDetailLogModel",
- "/warehouse/department", "/warehouse/boundcodetype", "/warehouse/boundtype", "/warehouse/boundbusiness", "/warehouse/status", "/warehouse/product",
- "/staff/stafflist", "/staff/stafflist_check_code", "/staff/stafftype", "/staff/operationlog"
- ],
- "component_access": "all"
- },
- "主管": {
- "description": "仓库主管,负责日常运营管理",
- "page_access": [
- "/stock/management", "/stock/stockbinlist", "/stock/stocklist",
- "/erp/erpasn", "/erp/erpasnmaterial", "/erp/erpdnmaterial", "/erp/erpdn", "/erp/erpsortstock",
- "/inbound/asn", "/inbound/predeliverystock", "/inbound/sortstock",
- "/container/containerlist", "/container/containerdetail", "/container/containercategory",
- "/outbound/dn", "/outbound/backorder", "/outbound/container_check",
- "/taskpage/task",
- "/count/batch", "/count/countbatchlog", "/count/detaillog", "/count/batchoperatelog",
- "/dashboard/flows_statements", "/dashboard/flows", "/dashboard/MaterialChangeHistory", "/dashboard/batchlog", "/dashboard/ContainerDetailLogModel",
- "/staff/stafflist", "/staff/stafftype", "/staff/operationlog"
- ],
- "component_access": ["view", "edit", "add", "delete", "export", "confirm", "adjust", "download"]
- },
- "操作员": {
- "description": "仓库操作员,负责具体操作",
- "page_access": [
- "/stock/management", "/stock/stockbinlist", "/stock/stocklist",
- "/erp/erpasn", "/erp/erpasnmaterial", "/erp/erpdnmaterial", "/erp/erpdn", "/erp/erpsortstock",
- "/inbound/asn", "/inbound/predeliverystock", "/inbound/sortstock",
- "/container/containerlist", "/container/containercategory",
- "/outbound/dn", "/outbound/backorder", "/outbound/container_check",
- "/taskpage/task",
- "/count/batch", "/count/countbatchlog", "/count/detaillog", "/count/batchoperatelog",
- "/staff/operationlog",
- "/dashboard/flows_statements", "/dashboard/flows"
- ],
- "component_access": ["view", "edit", "add", "download", "confirm"]
- },
- "查看员": {
- "description": "数据查看员,只能查看数据",
- "page_access": [
- "/stock/management", "/stock/stockbinlist",
- "/erp/erpasn", "/erp/erpasnmaterial", "/erp/erpdnmaterial", "/erp/erpdn", "/erp/erpsortstock",
- "/inbound/asn", "/inbound/predeliverystock", "/inbound/sortstock",
- "/container/containerlist", "/container/containercategory",
- "/outbound/dn", "/outbound/backorder", "/outbound/container_check",
- "/taskpage/task",
- "/count/batch", "/count/countbatchlog", "/count/detaillog", "/count/batchoperatelog",
- "/dashboard/flows_statements", "/dashboard/flows",
- "/staff/operationlog",
- ],
- "component_access": ["view", "download"]
- }
- }
-
- try:
- # 1. 创建所有权限
- created_perm_count = 0
- for page_info in PAGES:
- primary_page = page_info.get("primary_page")
- page_path = page_info["path"]
- components = page_info["components"]
-
- # 创建页面访问权限
- page_permission, created = Permission.objects.get_or_create(
- primary_page=primary_page,
- page=page_path,
- component=None,
- defaults={
- "name": f"{page_path} 页面访问",
- "description": f"访问 {page_path} 页面的权限",
- "enabled": True
- }
- )
- if created:
- created_perm_count += 1
-
- # 创建组件权限
- for component in components:
- comp_permission, created = Permission.objects.get_or_create(
- primary_page=primary_page,
- page=page_path,
- component=component,
- defaults={
- "name": f"{page_path} - {component} 组件",
- "description": f"在 {page_path} 页面使用 {component} 组件的权限",
- "enabled": True
- }
- )
- if created:
- created_perm_count += 1
-
- # 2. 恢复所有角色的默认权限
- all_permissions = Permission.objects.all()
- role_count = 0
- permission_count = 0
-
- for role_name, role_config in ROLES.items():
- role, created = Role.objects.get_or_create(
- name=role_name,
- defaults={"description": role_config["description"]}
- )
-
- if role:
- role_count += 1
-
- if role_config["page_access"] == "all":
- # 分配所有权限
- role.permissions.set(all_permissions)
- permission_count += all_permissions.count()
- else:
- # 分配特定权限
- assigned_permissions = []
-
- for page_path in role_config["page_access"]:
- # 获取页面权限
- page_perms = all_permissions.filter(
- page=page_path,
- component=None
- )
- assigned_permissions.extend(page_perms)
-
- # 获取组件权限
- comp_perms = all_permissions.filter(
- page=page_path,
- component__isnull=False
- )
-
- if role_config["component_access"] == "all":
- assigned_permissions.extend(comp_perms)
- else:
- for perm in comp_perms:
- if perm.component in role_config["component_access"]:
- assigned_permissions.append(perm)
-
- role.permissions.set(assigned_permissions)
- permission_count += len(assigned_permissions)
-
- try:
- log_success_operation(
- request=request,
- operation_content=f"恢复默认权限配置,创建权限数:{created_perm_count},更新角色数:{role_count}",
- operation_level="update",
- operator=request.auth.name if hasattr(request, 'auth') and request.auth else None,
- module_name="权限管理"
- )
- except Exception as e:
- pass
- return Response({
- "message": "默认权限已恢复成功",
- "created_permissions": created_perm_count,
- "roles_updated": role_count,
- "permissions_assigned": permission_count
- })
- except Exception as e:
- try:
- log_failure_operation(
- request=request,
- operation_content=f"恢复默认权限配置失败:{str(e)}",
- operation_level="update",
- operator=request.auth.name if hasattr(request, 'auth') and request.auth else None,
- module_name="权限管理"
- )
- except:
- pass
- return Response({
- "error": "恢复默认权限失败",
- "detail": str(e)
- }, status=500)
-
- def retrieve(self, request, pk=None):
- """获取特定角色的权限配置"""
- try:
- role = Role.objects.get(name=pk)
-
- serializer = serializers.RoleGETSerializer(role)
- return Response(serializer.data)
- except Role.DoesNotExist:
- return Response({"error": "Role not found"}, status=404)
-
- def update(self, request, pk=None):
- """更新角色权限(增量更新,只更新当前页面的权限)"""
- try:
- role = Role.objects.get(name=pk)
- permissions_data = request.data.get('permissions', [])
-
- if not permissions_data:
- return Response({"message": "No permissions to update"}, status=400)
-
- # 获取要更新的页面(从第一个权限中获取,因为所有权限应该属于同一页面)
- target_page = permissions_data[0].get('page') if permissions_data else None
- if not target_page:
- return Response({"error": "Page is required"}, status=400)
-
- # 获取当前页面已关联的权限,从角色中移除
- existing_perms = role.permissions.filter(page=target_page)
- # 从角色的权限中移除当前页面的所有权限
- role.permissions.remove(*existing_perms)
-
- # 添加/更新当前页面的权限
- # 注意:这里只控制角色与权限的关联关系,不修改权限对象本身的 enabled 状态
- new_perms = []
- for perm_data in permissions_data:
- # 确保所有权限都属于同一页面
- if perm_data.get('page') != target_page:
- continue
-
- # 如果 enabled 为 False,表示该角色不应该拥有此权限,跳过不添加
- if not perm_data.get('enabled', True):
- continue
-
- component = perm_data.get('component')
- # 处理 component 为 null 的情况
- if component is None or component == '':
- component = None
-
- # 获取或创建权限对象(不修改 enabled 状态)
- perm, created = Permission.objects.get_or_create(
- page=perm_data['page'],
- component=component,
- defaults={
- 'name': perm_data.get('name', f"{perm_data['page']}-{perm_data.get('component', 'page')}"),
- 'enabled': True, # 新创建的权限默认启用
- 'primary_page': perm_data.get('primary_page', ''),
- 'description': perm_data.get('description', '')
- }
- )
-
- # 不修改已存在权限的 enabled 状态,保持原有状态
-
- # 只将 enabled 为 True 的权限添加到角色
- new_perms.append(perm)
-
- # 批量添加新权限到角色(只添加 enabled 为 True 的权限)
- if new_perms:
- role.permissions.add(*new_perms)
-
- try:
- log_success_operation(
- request=request,
- operation_content=f"更新角色权限:{pk},页面:{target_page}",
- operation_level="update",
- operator=request.auth.name if hasattr(request, 'auth') and request.auth else None,
- module_name="权限管理"
- )
- except Exception as e:
- pass
- return Response({"message": "Permissions updated successfully"})
- except Role.DoesNotExist:
- return Response({"error": "Role not found"}, status=404)
- class RolePagePermissionViewSet(viewsets.ViewSet):
- """角色权限配置API"""
-
- def list(self, request):
- """获取所有角色类型"""
- roles = Role.objects.values_list('name', flat=True).distinct()
- return Response(list(roles))
-
- def retrieve(self, request, pk=None):
- """获取特定角色的权限配置"""
- try:
- role = Role.objects.get(name=pk)
- serializer = serializers.RolePageGETSerializer(role)
- return Response(serializer.data)
- except Role.DoesNotExist:
- return Response({"error": "Role not found"}, status=404)
-
- def get_page_permissions(self, request, pk=None):
- """获取特定角色的页面访问权限配置"""
- try:
- role = Role.objects.get(name=pk)
- primary_page = request.data.get('primary_page')
- if primary_page:
- fliterpermissions= role.permissions.filter(primary_page=primary_page)
- serializer = self.get_permissions_group(fliterpermissions)
- return Response(serializer)
-
- serializer = self.get_permissions_group(role.permissions.all())
- return Response(serializer)
- except Role.DoesNotExist:
- return Response({"error": "Role not found"}, status=404)
-
- def get_permissions_group(self, permissions):
- # 获取角色关联的所有权限并预取数据
-
-
- # 按page字段分组,只处理component为null的权限
- page_access = {}
- for perm in permissions:
- # 只处理页面访问权限(component为null)
- if perm.component is None:
- page_access[perm.page] = perm.enabled
-
- # 转换为前端需要的格式
- return [{"page": page, "enabled": enabled} for page, enabled in page_access.items()]
-
- class RolePageComponentPermissionViewSet(viewsets.ViewSet):
- """角色权限配置API"""
-
- def get_page_component_permissions(self, request, pk=None):
- """获取特定角色的页面访问权限配置"""
- try:
- role = Role.objects.get(name=pk)
- page = request.data.get('page')
- if page:
- fliterpermissions= role.permissions.filter(page=page)
- serializer = self.get_permissions_group(fliterpermissions)
- return Response(serializer)
-
- serializer = self.get_permissions_group(role.permissions.all())
- return Response(serializer)
- except Role.DoesNotExist:
- return Response({"error": "Role not found"}, status=404)
-
- def get_permissions_group(self, permissions):
- # 获取角色关联的所有权限并预取数据
-
- page_access = {}
- for perm in permissions:
- if perm.component is not None:
- page_access[perm.component] = perm.enabled
-
- # 转换为前端需要的格式
- return [{"component": component, "enabled": enabled} for component, enabled in page_access.items()]
- class TypeAPIViewSet(viewsets.ModelViewSet):
- """
- list:
- Response a data list(all)
- """
- pagination_class = MyPageNumberPagination
- filter_backends = [DjangoFilterBackend, OrderingFilter, ]
- ordering_fields = ['id', "create_time", "update_time", ]
- filter_class = TypeFilter
- def get_queryset(self):
- if self.request.user:
- return TypeListModel.objects.filter(openid='init_data')
- else:
- return TypeListModel.objects.none()
- def get_serializer_class(self):
- if self.action in ['list']:
- return serializers.StaffTypeGetSerializer
- else:
- return self.http_method_not_allowed(request=self.request)
- class FileDownloadView(viewsets.ModelViewSet):
- renderer_classes = (FileRenderCN,) + tuple(api_settings.DEFAULT_RENDERER_CLASSES)
- filter_backends = [DjangoFilterBackend, OrderingFilter, ]
- ordering_fields = ['id', "create_time", "update_time", ]
- filter_class = Filter
- def get_project(self):
- try:
- id = self.kwargs.get('pk')
- return id
- except:
- return None
- def get_queryset(self):
- id = self.get_project()
- if self.request.user:
- if id is None:
- return ListModel.objects.filter(openid=self.request.auth.openid, is_delete=False)
- else:
- return ListModel.objects.filter(openid=self.request.auth.openid, id=id, is_delete=False)
- else:
- return ListModel.objects.none()
- def get_serializer_class(self):
- if self.action in ['list']:
- return serializers.FileRenderSerializer
- else:
- return self.http_method_not_allowed(request=self.request)
- def get_lang(self, data):
- lang = self.request.META.get('HTTP_LANGUAGE')
- if lang:
- if lang == 'zh-hans':
- return FileRenderCN().render(data)
- else:
- return FileRenderEN().render(data)
- else:
- return FileRenderEN().render(data)
- def list(self, request, *args, **kwargs):
- from datetime import datetime
- dt = datetime.now()
- data = (
- FileRenderSerializer(instance).data
- for instance in self.filter_queryset(self.get_queryset())
- )
- renderer = self.get_lang(data)
- response = StreamingHttpResponse(
- renderer,
- content_type="text/csv"
- )
- response['Content-Disposition'] = "attachment; filename='staff_{}.csv'".format(
- str(dt.strftime('%Y%m%d%H%M%S%f')))
- try:
- log_success_operation(
- request=request,
- operation_content="下载员工列表文件",
- operation_level="download",
- operator=request.auth.name if hasattr(request, 'auth') and request.auth else None,
- module_name="员工管理"
- )
- except Exception as e:
- pass
- return response
|