更新了软删除
This commit is contained in:
40
User/migrations/0014_operationlog.py
Normal file
40
User/migrations/0014_operationlog.py
Normal file
@@ -0,0 +1,40 @@
|
||||
# Generated migration for operation log
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('User', '0013_add_is_deleted_fields'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='OperationLog',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('operator', models.CharField(max_length=100)),
|
||||
('operator_id', models.IntegerField(blank=True, null=True)),
|
||||
('operation_type', models.CharField(max_length=50)),
|
||||
('module', models.CharField(max_length=50)),
|
||||
('action', models.CharField(max_length=200)),
|
||||
('target_type', models.CharField(max_length=100)),
|
||||
('target_id', models.CharField(blank=True, max_length=100, null=True)),
|
||||
('target_name', models.CharField(blank=True, max_length=200, null=True)),
|
||||
('old_data', models.TextField(blank=True, null=True)),
|
||||
('new_data', models.TextField(blank=True, null=True)),
|
||||
('ip_address', models.CharField(blank=True, max_length=50, null=True)),
|
||||
('user_agent', models.CharField(blank=True, max_length=500, null=True)),
|
||||
('request_path', models.CharField(blank=True, max_length=500, null=True)),
|
||||
('remark', models.TextField(blank=True, null=True)),
|
||||
('create_time', models.DateTimeField(auto_now_add=True)),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '操作日志',
|
||||
'verbose_name_plural': '操作日志',
|
||||
'db_table': 'operation_log',
|
||||
'ordering': ['-create_time'],
|
||||
},
|
||||
),
|
||||
]
|
||||
@@ -44,3 +44,27 @@ class Approval(models.Model):
|
||||
is_deleted = models.BooleanField(default=False) # 软删除标记
|
||||
|
||||
|
||||
class OperationLog(models.Model):
|
||||
"""操作日志模型 - 记录高风险操作"""
|
||||
operator = models.CharField(max_length=100) # 操作人用户名
|
||||
operator_id = models.IntegerField(null=True, blank=True) # 操作人ID
|
||||
operation_type = models.CharField(max_length=50) # 操作类型:DELETE, CREATE, UPDATE, APPROVE等
|
||||
module = models.CharField(max_length=50) # 模块:User, Business, Finance等
|
||||
action = models.CharField(max_length=200) # 操作描述:删除用户、创建立项等
|
||||
target_type = models.CharField(max_length=100) # 目标类型:User, ProjectRegistration等
|
||||
target_id = models.CharField(max_length=100, null=True, blank=True) # 目标ID
|
||||
target_name = models.CharField(max_length=200, null=True, blank=True) # 目标名称(如用户名、项目名等)
|
||||
old_data = models.TextField(null=True, blank=True) # 操作前的数据(JSON格式)
|
||||
new_data = models.TextField(null=True, blank=True) # 操作后的数据(JSON格式)
|
||||
ip_address = models.CharField(max_length=50, null=True, blank=True) # IP地址
|
||||
user_agent = models.CharField(max_length=500, null=True, blank=True) # 用户代理
|
||||
request_path = models.CharField(max_length=500, null=True, blank=True) # 请求路径
|
||||
remark = models.TextField(null=True, blank=True) # 备注
|
||||
create_time = models.DateTimeField(auto_now_add=True) # 操作时间
|
||||
|
||||
class Meta:
|
||||
db_table = 'operation_log'
|
||||
ordering = ['-create_time']
|
||||
verbose_name = '操作日志'
|
||||
verbose_name_plural = '操作日志'
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from django.urls import path
|
||||
from .views import CreateUserView,LoginView,EditorialStaffView,PersonnelDetailsView,DepartmentView,PersonnelListView,AddDepartment,DeleteDepartment,Personlist,roxyExhibition,approvalProcessing,personneldisplay,DeleteUser
|
||||
from .views import CreateUserView,LoginView,EditorialStaffView,PersonnelDetailsView,DepartmentView,PersonnelListView,AddDepartment,DeleteDepartment,Personlist,roxyExhibition,approvalProcessing,personneldisplay,DeleteUser,OperationLogView
|
||||
urlpatterns = [
|
||||
path('create-user',CreateUserView.as_view(),name='create-user'),
|
||||
path('login',LoginView.as_view(),name='login'),
|
||||
@@ -14,4 +14,5 @@ urlpatterns = [
|
||||
path('approval_processing',approvalProcessing.as_view(),name='approval_processing'),
|
||||
path('personneldisplay',personneldisplay.as_view(),name='personneldisplay'),
|
||||
path('deleteUser',DeleteUser.as_view(),name='deleteUser'),
|
||||
path('operation-log',OperationLogView.as_view(),name='operation-log'),
|
||||
]
|
||||
@@ -1,6 +1,9 @@
|
||||
"""
|
||||
审批相关的工具函数
|
||||
"""
|
||||
import json
|
||||
from datetime import datetime
|
||||
from .models import OperationLog, User
|
||||
|
||||
def is_department_id(value):
|
||||
"""
|
||||
@@ -60,3 +63,75 @@ def format_personincharge(value, is_department=False):
|
||||
# 审批员用户名:保持原样,但确保是字符串
|
||||
return str(value).strip()
|
||||
|
||||
|
||||
def log_operation(request, operation_type, module, action, target_type, target_id=None,
|
||||
target_name=None, old_data=None, new_data=None, remark=None):
|
||||
"""
|
||||
记录操作日志
|
||||
|
||||
Args:
|
||||
request: Django request对象
|
||||
operation_type: 操作类型(DELETE, CREATE, UPDATE, APPROVE等)
|
||||
module: 模块名称(User, Business, Finance等)
|
||||
action: 操作描述(如"删除用户"、"创建立项"等)
|
||||
target_type: 目标类型(如User, ProjectRegistration等)
|
||||
target_id: 目标ID
|
||||
target_name: 目标名称(如用户名、项目名等)
|
||||
old_data: 操作前的数据(字典,会自动转换为JSON)
|
||||
new_data: 操作后的数据(字典,会自动转换为JSON)
|
||||
remark: 备注信息
|
||||
|
||||
Returns:
|
||||
OperationLog对象
|
||||
"""
|
||||
try:
|
||||
# 获取操作人信息
|
||||
token = request.META.get('token') or request.META.get('HTTP_AUTHORIZATION', '').replace('Bearer ', '')
|
||||
operator = '未知用户'
|
||||
operator_id = None
|
||||
|
||||
if token:
|
||||
try:
|
||||
user = User.objects.get(token=token, is_deleted=False)
|
||||
operator = user.username
|
||||
operator_id = user.id
|
||||
except User.DoesNotExist:
|
||||
pass
|
||||
|
||||
# 获取IP地址
|
||||
ip_address = request.META.get('HTTP_X_FORWARDED_FOR', '').split(',')[0].strip()
|
||||
if not ip_address:
|
||||
ip_address = request.META.get('REMOTE_ADDR', '')
|
||||
|
||||
# 获取用户代理
|
||||
user_agent = request.META.get('HTTP_USER_AGENT', '')
|
||||
|
||||
# 转换数据为JSON字符串
|
||||
old_data_str = json.dumps(old_data, ensure_ascii=False) if old_data else None
|
||||
new_data_str = json.dumps(new_data, ensure_ascii=False) if new_data else None
|
||||
|
||||
# 创建日志记录
|
||||
log = OperationLog.objects.create(
|
||||
operator=operator,
|
||||
operator_id=operator_id,
|
||||
operation_type=operation_type,
|
||||
module=module,
|
||||
action=action,
|
||||
target_type=target_type,
|
||||
target_id=str(target_id) if target_id else None,
|
||||
target_name=target_name,
|
||||
old_data=old_data_str,
|
||||
new_data=new_data_str,
|
||||
ip_address=ip_address,
|
||||
user_agent=user_agent,
|
||||
request_path=request.path,
|
||||
remark=remark
|
||||
)
|
||||
return log
|
||||
except Exception as e:
|
||||
# 日志记录失败不应该影响主业务流程
|
||||
import logging
|
||||
logger = logging.getLogger(__name__)
|
||||
logger.error(f"记录操作日志失败: {str(e)}")
|
||||
return None
|
||||
|
||||
|
||||
209
User/views.py
209
User/views.py
@@ -4,7 +4,7 @@ from rest_framework.response import Response
|
||||
from rest_framework import status
|
||||
import json
|
||||
import ast
|
||||
from .models import User, Approval, Department
|
||||
from .models import User, Approval, Department, OperationLog
|
||||
from business.models import permission
|
||||
from finance.models import Income, Accounts, Payment, Reimbursement, BonusChange
|
||||
from finance.models import Invoice
|
||||
@@ -15,7 +15,7 @@ from django.contrib.sessions.backends.db import SessionStore
|
||||
from django.db.models import Count, Q
|
||||
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
|
||||
from collections import defaultdict
|
||||
from .utils import is_department_id
|
||||
from .utils import is_department_id, log_operation
|
||||
|
||||
|
||||
class CreateUserView(APIView):
|
||||
@@ -157,6 +157,28 @@ class CreateUserView(APIView):
|
||||
user.role.add(*role_list)
|
||||
if department_id:
|
||||
user.department.add(*department_id)
|
||||
|
||||
# 记录操作日志
|
||||
new_data = {
|
||||
'id': user.id,
|
||||
'username': user.username,
|
||||
'account': user.account,
|
||||
'position': user.position,
|
||||
'team': user.team,
|
||||
'state': user.state
|
||||
}
|
||||
log_operation(
|
||||
request=request,
|
||||
operation_type='CREATE',
|
||||
module='User',
|
||||
action='新增用户',
|
||||
target_type='User',
|
||||
target_id=user.id,
|
||||
target_name=user.username,
|
||||
new_data=new_data,
|
||||
remark=f'新增用户:{user.username}(账号:{user.account})'
|
||||
)
|
||||
|
||||
return Response({'message': '添加人员成功', 'code': 0}, status=status.HTTP_200_OK)
|
||||
except Exception as e:
|
||||
# 捕获数据库操作异常
|
||||
@@ -276,7 +298,44 @@ class EditorialStaffView(APIView):
|
||||
role_id = [role_id]
|
||||
user.role.set(role_id)
|
||||
|
||||
# 记录操作前的数据
|
||||
old_data = {
|
||||
'id': user.id,
|
||||
'username': user.username,
|
||||
'account': user.account,
|
||||
'position': user.position,
|
||||
'team': user.team,
|
||||
'state': user.state,
|
||||
'salary': user.salary
|
||||
}
|
||||
|
||||
user.save()
|
||||
|
||||
# 记录操作后的数据
|
||||
new_data = {
|
||||
'id': user.id,
|
||||
'username': user.username,
|
||||
'account': user.account,
|
||||
'position': user.position,
|
||||
'team': user.team,
|
||||
'state': user.state,
|
||||
'salary': user.salary
|
||||
}
|
||||
|
||||
# 记录操作日志
|
||||
log_operation(
|
||||
request=request,
|
||||
operation_type='UPDATE',
|
||||
module='User',
|
||||
action='编辑用户信息',
|
||||
target_type='User',
|
||||
target_id=user.id,
|
||||
target_name=user.username,
|
||||
old_data=old_data,
|
||||
new_data=new_data,
|
||||
remark=f'编辑用户信息:{user.username}(账号:{user.account})'
|
||||
)
|
||||
|
||||
return Response({'message': '修改成功', 'code': 0}, status=status.HTTP_200_OK)
|
||||
|
||||
|
||||
@@ -310,6 +369,18 @@ class LoginView(APIView):
|
||||
user.token = token
|
||||
user.save()
|
||||
|
||||
# 记录登录日志
|
||||
log_operation(
|
||||
request=request,
|
||||
operation_type='LOGIN',
|
||||
module='User',
|
||||
action='用户登录',
|
||||
target_type='User',
|
||||
target_id=user.id,
|
||||
target_name=user.username,
|
||||
remark=f'用户登录:{user.username}(账号:{user.account})'
|
||||
)
|
||||
|
||||
# 创建会话
|
||||
session = SessionStore()
|
||||
session.create()
|
||||
@@ -505,9 +576,29 @@ class DeleteDepartment(APIView):
|
||||
return Response({'status': 'error', 'message': '删除失败,该部门还存在人员,请及时转移', 'code': 1},
|
||||
status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
# 记录操作前的数据
|
||||
old_data = {
|
||||
'id': dep.id,
|
||||
'username': dep.username
|
||||
}
|
||||
|
||||
# 软删除:更新 is_deleted 字段
|
||||
dep.is_deleted = True
|
||||
dep.save()
|
||||
|
||||
# 记录操作日志
|
||||
log_operation(
|
||||
request=request,
|
||||
operation_type='DELETE',
|
||||
module='User',
|
||||
action='删除部门',
|
||||
target_type='Department',
|
||||
target_id=dep.id,
|
||||
target_name=dep.username,
|
||||
old_data=old_data,
|
||||
remark=f'删除部门:{dep.username}'
|
||||
)
|
||||
|
||||
return Response({'message': '删除成功', 'code': 0}, status=status.HTTP_200_OK)
|
||||
|
||||
|
||||
@@ -805,7 +896,121 @@ class DeleteUser(APIView):
|
||||
except User.DoesNotExist:
|
||||
return Response({'status': 'error', 'message': '用户不存在', 'code': 1}, status=status.HTTP_404_NOT_FOUND)
|
||||
|
||||
# 记录操作前的数据
|
||||
old_data = {
|
||||
'id': user.id,
|
||||
'username': user.username,
|
||||
'account': user.account,
|
||||
'state': user.state,
|
||||
'position': user.position,
|
||||
'team': user.team
|
||||
}
|
||||
|
||||
# 软删除:更新 is_deleted 字段
|
||||
user.is_deleted = True
|
||||
user.save()
|
||||
|
||||
# 记录操作日志
|
||||
log_operation(
|
||||
request=request,
|
||||
operation_type='DELETE',
|
||||
module='User',
|
||||
action='删除用户',
|
||||
target_type='User',
|
||||
target_id=user.id,
|
||||
target_name=user.username,
|
||||
old_data=old_data,
|
||||
remark=f'删除用户:{user.username}(账号:{user.account})'
|
||||
)
|
||||
|
||||
return Response({'message': '删除成功', 'code': 0}, status=status.HTTP_200_OK)
|
||||
|
||||
|
||||
class OperationLogView(APIView):
|
||||
"""操作日志查询接口"""
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
"""
|
||||
查询操作日志
|
||||
支持按操作人、操作类型、模块、时间范围等条件查询
|
||||
"""
|
||||
page = request.data.get('page', 1)
|
||||
per_page = request.data.get('per_page', 20)
|
||||
operator = request.data.get('operator') # 操作人
|
||||
operation_type = request.data.get('operation_type') # 操作类型
|
||||
module = request.data.get('module') # 模块
|
||||
target_type = request.data.get('target_type') # 目标类型
|
||||
start_time = request.data.get('start_time') # 开始时间
|
||||
end_time = request.data.get('end_time') # 结束时间
|
||||
|
||||
# 构建查询条件
|
||||
query = Q()
|
||||
|
||||
if operator:
|
||||
query &= Q(operator__icontains=operator)
|
||||
|
||||
if operation_type:
|
||||
query &= Q(operation_type=operation_type)
|
||||
|
||||
if module:
|
||||
query &= Q(module=module)
|
||||
|
||||
if target_type:
|
||||
query &= Q(target_type=target_type)
|
||||
|
||||
if start_time:
|
||||
try:
|
||||
start_datetime = datetime.datetime.strptime(start_time, "%Y-%m-%d")
|
||||
query &= Q(create_time__gte=start_datetime)
|
||||
except:
|
||||
pass
|
||||
|
||||
if end_time:
|
||||
try:
|
||||
end_datetime = datetime.datetime.strptime(end_time, "%Y-%m-%d")
|
||||
# 结束时间包含当天,所以加一天
|
||||
end_datetime = end_datetime + datetime.timedelta(days=1)
|
||||
query &= Q(create_time__lt=end_datetime)
|
||||
except:
|
||||
pass
|
||||
|
||||
# 查询日志
|
||||
logs = OperationLog.objects.filter(query).order_by('-create_time')
|
||||
total = logs.count()
|
||||
|
||||
# 分页
|
||||
paginator = Paginator(logs, per_page)
|
||||
try:
|
||||
logs_page = paginator.page(page)
|
||||
except PageNotAnInteger:
|
||||
logs_page = paginator.page(1)
|
||||
except EmptyPage:
|
||||
logs_page = paginator.page(paginator.num_pages)
|
||||
|
||||
# 格式化数据
|
||||
data = []
|
||||
for log in logs_page.object_list:
|
||||
data.append({
|
||||
'id': log.id,
|
||||
'operator': log.operator,
|
||||
'operator_id': log.operator_id,
|
||||
'operation_type': log.operation_type,
|
||||
'module': log.module,
|
||||
'action': log.action,
|
||||
'target_type': log.target_type,
|
||||
'target_id': log.target_id,
|
||||
'target_name': log.target_name,
|
||||
'ip_address': log.ip_address,
|
||||
'request_path': log.request_path,
|
||||
'remark': log.remark,
|
||||
'create_time': log.create_time.strftime('%Y-%m-%d %H:%M:%S'),
|
||||
'old_data': json.loads(log.old_data) if log.old_data else None,
|
||||
'new_data': json.loads(log.new_data) if log.new_data else None,
|
||||
})
|
||||
|
||||
return Response({
|
||||
'message': '查询成功',
|
||||
'total': total,
|
||||
'data': data,
|
||||
'code': 0
|
||||
}, status=status.HTTP_200_OK)
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
# Generated by Django 4.2.25 on 2025-12-31 04:26
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('business', '0025_add_is_deleted_fields'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='bid',
|
||||
name='BiddingAnnouncement',
|
||||
field=models.TextField(),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='projectregistration',
|
||||
name='contract',
|
||||
field=models.TextField(),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='role',
|
||||
name='permissionId',
|
||||
field=models.CharField(max_length=1000),
|
||||
),
|
||||
]
|
||||
@@ -4,7 +4,7 @@ from rest_framework import status
|
||||
import json
|
||||
import ast
|
||||
from User.models import User, Approval
|
||||
from User.utils import format_personincharge
|
||||
from User.utils import format_personincharge, log_operation
|
||||
from .models import PreFiling, ProjectRegistration, Bid, Case, Invoice, Caselog, SealApplication, Warehousing, \
|
||||
RegisterPlatform, Announcement, LawyerFlie, Schedule, permission, role
|
||||
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
|
||||
@@ -33,7 +33,7 @@ class registration(APIView):
|
||||
if not all([times, description, Undertaker]):
|
||||
return Response({'status': 'error', 'message': '缺少参数', 'code': 1}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
PreFiling.objects.create(
|
||||
prefiling = PreFiling.objects.create(
|
||||
times=times,
|
||||
client_username=client_username,
|
||||
party_username=party_username,
|
||||
@@ -41,6 +41,26 @@ class registration(APIView):
|
||||
Undertaker=Undertaker,
|
||||
submit=user
|
||||
)
|
||||
|
||||
# 记录操作日志
|
||||
new_data = {
|
||||
'id': prefiling.id,
|
||||
'client_username': prefiling.client_username,
|
||||
'party_username': prefiling.party_username,
|
||||
'undertaker': prefiling.Undertaker
|
||||
}
|
||||
log_operation(
|
||||
request=request,
|
||||
operation_type='CREATE',
|
||||
module='Business',
|
||||
action='新增预立案登记',
|
||||
target_type='PreFiling',
|
||||
target_id=prefiling.id,
|
||||
target_name=f'{prefiling.client_username} vs {prefiling.party_username}',
|
||||
new_data=new_data,
|
||||
remark=f'新增预立案登记:委托人 {prefiling.client_username},相对方 {prefiling.party_username}'
|
||||
)
|
||||
|
||||
return Response({'message': '登记成功', 'code': 0}, status=status.HTTP_200_OK)
|
||||
|
||||
|
||||
@@ -214,6 +234,27 @@ class Project(APIView):
|
||||
type="立项登记",
|
||||
user_id=pro.id
|
||||
)
|
||||
|
||||
# 记录操作日志
|
||||
new_data = {
|
||||
'id': pro.id,
|
||||
'contract_no': pro.ContractNo,
|
||||
'type': pro.type,
|
||||
'responsiblefor': pro.responsiblefor,
|
||||
'times': pro.times
|
||||
}
|
||||
log_operation(
|
||||
request=request,
|
||||
operation_type='CREATE',
|
||||
module='Business',
|
||||
action='新增立项登记',
|
||||
target_type='ProjectRegistration',
|
||||
target_id=pro.id,
|
||||
target_name=pro.ContractNo,
|
||||
new_data=new_data,
|
||||
remark=f'新增立项登记:合同编号 {pro.ContractNo},负责人 {pro.responsiblefor}'
|
||||
)
|
||||
|
||||
return Response({'message': '登记成功', 'code': 0}, status=status.HTTP_200_OK)
|
||||
|
||||
|
||||
@@ -387,9 +428,29 @@ class EditProject(APIView):
|
||||
pro.state = "审核中"
|
||||
update_fields_list.append('state')
|
||||
|
||||
# 记录操作前的数据
|
||||
old_data = {
|
||||
'id': pro.id,
|
||||
'contract_no': original_ContractNo,
|
||||
'type': original_type,
|
||||
'responsiblefor': original_responsiblefor,
|
||||
'times': original_times,
|
||||
'charge': original_charge
|
||||
}
|
||||
|
||||
if update_fields_list:
|
||||
pro.save(update_fields=update_fields_list)
|
||||
|
||||
# 记录操作后的数据
|
||||
new_data = {
|
||||
'id': pro.id,
|
||||
'contract_no': pro.ContractNo,
|
||||
'type': pro.type,
|
||||
'responsiblefor': pro.responsiblefor,
|
||||
'times': pro.times,
|
||||
'charge': pro.charge
|
||||
}
|
||||
|
||||
today = datetime.datetime.now()
|
||||
formatted_date = today.strftime("%Y-%m-%d")
|
||||
Approval.objects.create(
|
||||
@@ -401,6 +462,20 @@ class EditProject(APIView):
|
||||
type="立项登记",
|
||||
user_id=pro.id
|
||||
)
|
||||
|
||||
# 记录操作日志
|
||||
log_operation(
|
||||
request=request,
|
||||
operation_type='UPDATE',
|
||||
module='Business',
|
||||
action='编辑立项登记',
|
||||
target_type='ProjectRegistration',
|
||||
target_id=pro.id,
|
||||
target_name=pro.ContractNo,
|
||||
old_data=old_data,
|
||||
new_data=new_data,
|
||||
remark=f'编辑立项登记:合同编号 {pro.ContractNo}'
|
||||
)
|
||||
|
||||
return Response({'message': '编辑成功', 'code': 0}, status=status.HTTP_200_OK)
|
||||
|
||||
@@ -429,9 +504,36 @@ class DeleteProject(APIView):
|
||||
if case_exists:
|
||||
return Response({'status': 'error', 'message': '该立项已被案件管理关联,无法删除', 'code': 1}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
# 记录操作前的数据
|
||||
try:
|
||||
prefiling = PreFiling.objects.get(id=pro.user_id, is_deleted=False)
|
||||
old_data = {
|
||||
'id': pro.id,
|
||||
'contract_no': pro.ContractNo,
|
||||
'type': pro.type,
|
||||
'responsiblefor': pro.responsiblefor,
|
||||
'client_username': prefiling.client_username if prefiling else None
|
||||
}
|
||||
except:
|
||||
old_data = {'id': pro.id, 'contract_no': pro.ContractNo}
|
||||
|
||||
# 软删除:更新 is_deleted 字段
|
||||
pro.is_deleted = True
|
||||
pro.save()
|
||||
|
||||
# 记录操作日志
|
||||
log_operation(
|
||||
request=request,
|
||||
operation_type='DELETE',
|
||||
module='Business',
|
||||
action='删除立项登记',
|
||||
target_type='ProjectRegistration',
|
||||
target_id=pro.id,
|
||||
target_name=pro.ContractNo,
|
||||
old_data=old_data,
|
||||
remark=f'删除立项登记:合同编号 {pro.ContractNo}'
|
||||
)
|
||||
|
||||
return Response({'message': '删除成功', 'code': 0}, status=status.HTTP_200_OK)
|
||||
|
||||
|
||||
@@ -608,9 +710,30 @@ class DeleteBid(APIView):
|
||||
except Bid.DoesNotExist:
|
||||
return Response({'status': 'error', 'message': '投标登记不存在', 'code': 1}, status=status.HTTP_404_NOT_FOUND)
|
||||
|
||||
# 记录操作前的数据
|
||||
old_data = {
|
||||
'id': bid.id,
|
||||
'project_name': bid.ProjectName,
|
||||
'times': bid.times
|
||||
}
|
||||
|
||||
# 软删除:更新 is_deleted 字段
|
||||
bid.is_deleted = True
|
||||
bid.save()
|
||||
|
||||
# 记录操作日志
|
||||
log_operation(
|
||||
request=request,
|
||||
operation_type='DELETE',
|
||||
module='Business',
|
||||
action='删除投标登记',
|
||||
target_type='Bid',
|
||||
target_id=bid.id,
|
||||
target_name=bid.ProjectName,
|
||||
old_data=old_data,
|
||||
remark=f'删除投标登记:{bid.ProjectName}'
|
||||
)
|
||||
|
||||
return Response({'message': '删除成功', 'code': 0}, status=status.HTTP_200_OK)
|
||||
|
||||
|
||||
@@ -866,9 +989,30 @@ class DeleteCase(APIView):
|
||||
except Case.DoesNotExist:
|
||||
return Response({'status': 'error', 'message': '案件管理不存在', 'code': 1}, status=status.HTTP_404_NOT_FOUND)
|
||||
|
||||
# 记录操作前的数据
|
||||
old_data = {
|
||||
'id': case.id,
|
||||
'times': case.times,
|
||||
'state': case.state
|
||||
}
|
||||
|
||||
# 软删除:更新 is_deleted 字段
|
||||
case.is_deleted = True
|
||||
case.save()
|
||||
|
||||
# 记录操作日志
|
||||
log_operation(
|
||||
request=request,
|
||||
operation_type='DELETE',
|
||||
module='Business',
|
||||
action='删除案件管理',
|
||||
target_type='Case',
|
||||
target_id=case.id,
|
||||
target_name=f'案件-{case.id}',
|
||||
old_data=old_data,
|
||||
remark=f'删除案件管理:ID {case.id}'
|
||||
)
|
||||
|
||||
return Response({'message': '删除成功', 'code': 0}, status=status.HTTP_200_OK)
|
||||
|
||||
|
||||
@@ -1888,9 +2032,27 @@ class DeleteRermission(APIView):
|
||||
ID = request.data.get('id')
|
||||
try:
|
||||
perm = permission.objects.get(id=ID, is_deleted=False)
|
||||
# 记录操作前的数据
|
||||
old_data = {
|
||||
'id': perm.id,
|
||||
'permission_name': perm.permission_name,
|
||||
'permission_logo': perm.permission_logo
|
||||
}
|
||||
# 软删除:更新 is_deleted 字段
|
||||
perm.is_deleted = True
|
||||
perm.save()
|
||||
# 记录操作日志
|
||||
log_operation(
|
||||
request=request,
|
||||
operation_type='DELETE',
|
||||
module='Business',
|
||||
action='删除权限',
|
||||
target_type='Permission',
|
||||
target_id=perm.id,
|
||||
target_name=perm.permission_name,
|
||||
old_data=old_data,
|
||||
remark=f'删除权限:{perm.permission_name}'
|
||||
)
|
||||
return Response({'message': '删除成功', 'code': 0}, status=status.HTTP_200_OK)
|
||||
except permission.DoesNotExist:
|
||||
return Response({'status': 'error', 'message': '权限不存在', 'code': 1}, status=status.HTTP_404_NOT_FOUND)
|
||||
@@ -1938,9 +2100,27 @@ class DeleteRole(APIView):
|
||||
id = request.data.get('id')
|
||||
try:
|
||||
r = role.objects.get(id=id, is_deleted=False)
|
||||
# 记录操作前的数据
|
||||
old_data = {
|
||||
'id': r.id,
|
||||
'role_name': r.RoleName,
|
||||
'permission_id': r.permissionId
|
||||
}
|
||||
# 软删除:更新 is_deleted 字段
|
||||
r.is_deleted = True
|
||||
r.save()
|
||||
# 记录操作日志
|
||||
log_operation(
|
||||
request=request,
|
||||
operation_type='DELETE',
|
||||
module='Business',
|
||||
action='删除角色',
|
||||
target_type='Role',
|
||||
target_id=r.id,
|
||||
target_name=r.RoleName,
|
||||
old_data=old_data,
|
||||
remark=f'删除角色:{r.RoleName}'
|
||||
)
|
||||
return Response({'message': '删除成功', 'code': 0}, status=status.HTTP_200_OK)
|
||||
except role.DoesNotExist:
|
||||
return Response({'status': 'error', 'message': '角色不存在', 'code': 1}, status=status.HTTP_404_NOT_FOUND)
|
||||
|
||||
123
finance/views.py
123
finance/views.py
@@ -4,7 +4,7 @@ from rest_framework import status
|
||||
import json
|
||||
import ast
|
||||
from User.models import User,Approval,Department
|
||||
from User.utils import format_personincharge
|
||||
from User.utils import format_personincharge, log_operation
|
||||
import datetime
|
||||
from .models import Invoice,Income,Accounts,Payment,Reimbursement,BonusChange
|
||||
from utility.utility import flies
|
||||
@@ -68,6 +68,28 @@ class UserRegister(APIView):
|
||||
)
|
||||
|
||||
user.save(update_fields=['card', 'salary', 'username', 'Dateofjoining', 'position'])
|
||||
|
||||
# 记录操作日志
|
||||
new_data = {
|
||||
'user_id': user.id,
|
||||
'username': user.username,
|
||||
'card': user.card,
|
||||
'position': user.position,
|
||||
'salary': user.salary,
|
||||
'state': user.state
|
||||
}
|
||||
log_operation(
|
||||
request=request,
|
||||
operation_type='CREATE',
|
||||
module='Finance',
|
||||
action='新增财务登记',
|
||||
target_type='User',
|
||||
target_id=user.id,
|
||||
target_name=user.username,
|
||||
new_data=new_data,
|
||||
remark=f'新增财务登记:{user.username},岗位 {user.position},薪资 {user.salary}'
|
||||
)
|
||||
|
||||
return Response({'message': '登记成功', 'code': 0}, status=status.HTTP_200_OK)
|
||||
|
||||
|
||||
@@ -117,6 +139,27 @@ class issueAnInvoice(APIView):
|
||||
type="开票",
|
||||
user_id = invoice.id
|
||||
)
|
||||
|
||||
# 记录操作日志
|
||||
new_data = {
|
||||
'id': invoice.id,
|
||||
'contract_no': invoice.ContractNo,
|
||||
'amount': invoice.amount,
|
||||
'type': invoice.type,
|
||||
'unit': invoice.unit
|
||||
}
|
||||
log_operation(
|
||||
request=request,
|
||||
operation_type='CREATE',
|
||||
module='Finance',
|
||||
action='新增开票申请',
|
||||
target_type='Invoice',
|
||||
target_id=invoice.id,
|
||||
target_name=invoice.ContractNo,
|
||||
new_data=new_data,
|
||||
remark=f'新增开票申请:合同号 {invoice.ContractNo},金额 {invoice.amount}'
|
||||
)
|
||||
|
||||
return Response({'message': '提交成功', 'code': 0}, status=status.HTTP_200_OK)
|
||||
|
||||
|
||||
@@ -223,9 +266,42 @@ class EditInvoice(APIView):
|
||||
invoice.bank = bank
|
||||
update_fields_list.append('bank')
|
||||
|
||||
# 记录操作前的数据
|
||||
old_data = {
|
||||
'id': invoice.id,
|
||||
'contract_no': invoice.ContractNo,
|
||||
'amount': invoice.amount,
|
||||
'type': invoice.type,
|
||||
'unit': invoice.unit
|
||||
}
|
||||
|
||||
if update_fields_list:
|
||||
invoice.save(update_fields=update_fields_list)
|
||||
|
||||
# 记录操作后的数据
|
||||
invoice.refresh_from_db()
|
||||
new_data = {
|
||||
'id': invoice.id,
|
||||
'contract_no': invoice.ContractNo,
|
||||
'amount': invoice.amount,
|
||||
'type': invoice.type,
|
||||
'unit': invoice.unit
|
||||
}
|
||||
|
||||
# 记录操作日志
|
||||
log_operation(
|
||||
request=request,
|
||||
operation_type='UPDATE',
|
||||
module='Finance',
|
||||
action='编辑开票申请',
|
||||
target_type='Invoice',
|
||||
target_id=invoice.id,
|
||||
target_name=invoice.ContractNo,
|
||||
old_data=old_data,
|
||||
new_data=new_data,
|
||||
remark=f'编辑开票申请:合同号 {invoice.ContractNo}'
|
||||
)
|
||||
|
||||
return Response({'message': '编辑成功', 'code': 0}, status=status.HTTP_200_OK)
|
||||
|
||||
|
||||
@@ -247,9 +323,31 @@ class DeleteInvoice(APIView):
|
||||
except Invoice.DoesNotExist:
|
||||
return Response({'status': 'error', 'message': '开票申请不存在', 'code': 1}, status=status.HTTP_404_NOT_FOUND)
|
||||
|
||||
# 记录操作前的数据
|
||||
old_data = {
|
||||
'id': invoice.id,
|
||||
'contract_no': invoice.ContractNo,
|
||||
'amount': invoice.amount,
|
||||
'unit': invoice.unit
|
||||
}
|
||||
|
||||
# 软删除:更新 is_deleted 字段
|
||||
invoice.is_deleted = True
|
||||
invoice.save()
|
||||
|
||||
# 记录操作日志
|
||||
log_operation(
|
||||
request=request,
|
||||
operation_type='DELETE',
|
||||
module='Finance',
|
||||
action='删除开票申请',
|
||||
target_type='Invoice',
|
||||
target_id=invoice.id,
|
||||
target_name=invoice.ContractNo,
|
||||
old_data=old_data,
|
||||
remark=f'删除开票申请:合同号 {invoice.ContractNo},金额 {invoice.amount}'
|
||||
)
|
||||
|
||||
return Response({'message': '删除成功', 'code': 0}, status=status.HTTP_200_OK)
|
||||
|
||||
|
||||
@@ -1329,6 +1427,15 @@ class DeleteUserDeparture(APIView):
|
||||
except (User.DoesNotExist, ValueError):
|
||||
return Response({'status': 'error', 'message': '用户不存在', 'code': 1}, status=status.HTTP_404_NOT_FOUND)
|
||||
|
||||
# 记录操作前的数据
|
||||
old_data = {
|
||||
'user_id': user.id,
|
||||
'username': user.username,
|
||||
'state': user.state,
|
||||
'dateofdeparture': str(user.Dateofdeparture) if user.Dateofdeparture else None,
|
||||
'approval_id': approval.id
|
||||
}
|
||||
|
||||
# 恢复用户状态
|
||||
user.state = "在职"
|
||||
user.Dateofdeparture = None
|
||||
@@ -1338,5 +1445,19 @@ class DeleteUserDeparture(APIView):
|
||||
approval.is_deleted = True
|
||||
approval.save()
|
||||
|
||||
# 记录操作日志
|
||||
log_operation(
|
||||
request=request,
|
||||
operation_type='DELETE',
|
||||
module='Finance',
|
||||
action='删除离职登记',
|
||||
target_type='Approval',
|
||||
target_id=approval.id,
|
||||
target_name=f'离职登记-{user.username}',
|
||||
old_data=old_data,
|
||||
new_data={'user_id': user.id, 'username': user.username, 'state': '在职'},
|
||||
remark=f'删除离职登记,恢复用户 {user.username} 状态为"在职"'
|
||||
)
|
||||
|
||||
return Response({'message': '删除成功,用户状态已恢复为"在职"', 'code': 0}, status=status.HTTP_200_OK)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user