签入版本
This commit is contained in:
@@ -0,0 +1,408 @@
|
||||
# 完整代码清单
|
||||
|
||||
本章汇总 Example 案例模块涉及的全部文件,便于开发时快速查阅和复制。
|
||||
|
||||
## 后端文件清单
|
||||
|
||||
### 1. 数据模型 `application/example/models.py`
|
||||
|
||||
```python
|
||||
from django.db import models
|
||||
from application.models import BaseModel
|
||||
from utils.common import get_table_name
|
||||
|
||||
|
||||
class Example(BaseModel):
|
||||
"""案例模型类"""
|
||||
name = models.CharField(null=False, max_length=100, db_index=True,
|
||||
verbose_name="案例名称", db_comment='案例名称')
|
||||
avatar = models.CharField(null=True, blank=True, max_length=255,
|
||||
verbose_name="案例图片", db_comment='案例图片')
|
||||
TYPE_CHOICES = ((1, "类型1"), (2, "类型2"), (3, "类型3"), (4, "类型4"),)
|
||||
type = models.IntegerField(null=False, choices=TYPE_CHOICES,
|
||||
verbose_name="案例类型", db_comment='案例类型')
|
||||
STATUS_CHOICES = ((1, "正常"), (2, "禁用"),)
|
||||
status = models.IntegerField(null=False, choices=STATUS_CHOICES,
|
||||
verbose_name="案例状态", db_comment='案例状态')
|
||||
sort = models.IntegerField(null=False,
|
||||
verbose_name="排序", db_comment='排序')
|
||||
|
||||
class Meta:
|
||||
db_table = get_table_name('example')
|
||||
db_table_comment = "案例表"
|
||||
verbose_name = "案例表"
|
||||
verbose_name_plural = verbose_name
|
||||
ordering = ("sort",)
|
||||
```
|
||||
|
||||
### 2. 表单验证 `application/example/forms.py`
|
||||
|
||||
```python
|
||||
from django import forms
|
||||
from application.example import models
|
||||
|
||||
|
||||
class ExampleForm(forms.ModelForm):
|
||||
"""案例表单验证类"""
|
||||
name = forms.CharField(required=True, max_length=100, error_messages={
|
||||
'required': '案例名称不能为空', 'max_length': '案例名称长度不得超过100个字符'})
|
||||
avatar = forms.CharField(required=False, max_length=255, error_messages={
|
||||
'max_length': '案例图片长度不得超过255个字符'})
|
||||
type = forms.IntegerField(required=True, min_value=1, max_value=4, error_messages={
|
||||
'required': '案例类型不能为空', 'min_value': '案例类型值不能小于1', 'max_value': '案例类型值不能大于4'})
|
||||
status = forms.IntegerField(required=True, min_value=1, max_value=2, error_messages={
|
||||
'required': '案例状态不能为空', 'min_value': '案例状态值不能小于1', 'max_value': '案例状态值不能大于2'})
|
||||
sort = forms.IntegerField(required=True, error_messages={'required': '排序不能为空'})
|
||||
|
||||
class Meta:
|
||||
model = models.Example
|
||||
fields = ['name', 'avatar', 'type', 'status', 'sort']
|
||||
```
|
||||
|
||||
### 3. 业务逻辑层 `application/example/services.py`
|
||||
|
||||
```python
|
||||
import json
|
||||
import logging
|
||||
from django.core.paginator import Paginator, PageNotAnInteger, InvalidPage, EmptyPage
|
||||
from application.example import forms
|
||||
from application.example.models import Example
|
||||
from config.env import DJANGO_FILE_URL
|
||||
from constant.constants import PAGE_SIZE
|
||||
from utils import R, regular
|
||||
from utils.common import get_file_url, format_datetime, parse_request_body, save_file
|
||||
from utils.security import get_username
|
||||
|
||||
|
||||
def get_example_page(request):
|
||||
"""查询案例分页数据"""
|
||||
try:
|
||||
page_no = int(request.GET.get('pageNo', 1))
|
||||
page_size = int(request.GET.get('pageSize', PAGE_SIZE))
|
||||
query = Example.objects.filter(is_delete=False)
|
||||
query = _apply_filters(query, request)
|
||||
query = query.order_by("sort")
|
||||
paginator = Paginator(query, page_size)
|
||||
try:
|
||||
page_list = paginator.page(page_no)
|
||||
except (PageNotAnInteger, InvalidPage, EmptyPage):
|
||||
page_list = paginator.page(1)
|
||||
page_no = 1
|
||||
page_data = _build_page_data(page_list, paginator, page_no, page_size)
|
||||
return R.ok(data=page_data)
|
||||
except Exception as e:
|
||||
logging.error(f"查询案例分页数据异常: {str(e)}")
|
||||
return R.failed(msg="查询失败,请稍后重试")
|
||||
|
||||
|
||||
def add_example(request):
|
||||
"""添加案例"""
|
||||
data, error = parse_request_body(request)
|
||||
if error:
|
||||
return R.failed(msg=error)
|
||||
form = forms.ExampleForm(data)
|
||||
if not form.is_valid():
|
||||
return R.failed(msg=regular.get_err(form))
|
||||
try:
|
||||
cleaned_data = form.cleaned_data
|
||||
avatar = cleaned_data.get('avatar')
|
||||
if avatar:
|
||||
avatar = save_file(avatar, "example")
|
||||
Example.objects.create(
|
||||
name=cleaned_data.get('name'), avatar=avatar,
|
||||
type=cleaned_data.get('type'), status=cleaned_data.get('status'),
|
||||
sort=cleaned_data.get('sort'),
|
||||
create_user=get_username(request), update_user=get_username(request))
|
||||
return R.ok(msg="创建成功")
|
||||
except Exception as e:
|
||||
logging.error(f"添加案例异常: {str(e)}")
|
||||
return R.failed(msg="添加失败,请稍后重试")
|
||||
|
||||
|
||||
def update_example(request):
|
||||
"""更新案例"""
|
||||
data, error = parse_request_body(request)
|
||||
if error:
|
||||
return R.failed(msg=error)
|
||||
instance_id = data.get('id')
|
||||
if not instance_id or not str(instance_id).isdigit() or int(instance_id) <= 0:
|
||||
return R.failed("案例ID无效")
|
||||
instance_id = int(instance_id)
|
||||
form = forms.ExampleForm(data)
|
||||
if not form.is_valid():
|
||||
return R.failed(msg=regular.get_err(form))
|
||||
try:
|
||||
instance = Example.objects.filter(id=instance_id, is_delete=False).first()
|
||||
if not instance:
|
||||
return R.failed("案例不存在")
|
||||
cleaned_data = form.cleaned_data
|
||||
avatar = cleaned_data.get('avatar')
|
||||
if avatar and avatar != instance.avatar:
|
||||
avatar = save_file(avatar, "example")
|
||||
else:
|
||||
avatar = instance.avatar
|
||||
instance.name = cleaned_data.get('name')
|
||||
instance.avatar = avatar
|
||||
instance.type = cleaned_data.get('type')
|
||||
instance.status = cleaned_data.get('status')
|
||||
instance.sort = cleaned_data.get('sort')
|
||||
instance.update_user = get_username(request)
|
||||
instance.save()
|
||||
return R.ok(msg="更新成功")
|
||||
except Exception as e:
|
||||
logging.error(f"更新案例异常,ID: {instance_id}, 错误: {str(e)}")
|
||||
return R.failed(msg="更新失败,请稍后重试")
|
||||
|
||||
|
||||
def delete_examples(instance_ids):
|
||||
"""删除案例(批量删除)"""
|
||||
if not instance_ids:
|
||||
return R.failed("记录ID不存在")
|
||||
try:
|
||||
id_list = [int(id_str.strip()) for id_str in instance_ids.split(',') if id_str.strip()]
|
||||
if not id_list:
|
||||
return R.failed("无效的记录ID")
|
||||
updated_count = Example.objects.filter(id__in=id_list, is_delete=False).update(is_delete=True)
|
||||
return R.ok(msg=f"本次共删除{updated_count}条数据")
|
||||
except ValueError:
|
||||
return R.failed("记录ID格式错误")
|
||||
|
||||
|
||||
def update_example_status(request):
|
||||
"""更新案例状态"""
|
||||
data, error = parse_request_body(request)
|
||||
if error:
|
||||
return R.failed(msg=error)
|
||||
instance_id = data.get('id')
|
||||
if not instance_id or not str(instance_id).isdigit() or int(instance_id) <= 0:
|
||||
return R.failed("案例ID无效")
|
||||
instance_id = int(instance_id)
|
||||
status = data.get('status')
|
||||
if status is None:
|
||||
return R.failed("状态值不能为空")
|
||||
try:
|
||||
status = int(status)
|
||||
if status not in [1, 2]:
|
||||
return R.failed("状态值无效")
|
||||
except ValueError:
|
||||
return R.failed("状态值格式错误")
|
||||
try:
|
||||
instance = Example.objects.filter(id=instance_id, is_delete=False).first()
|
||||
if not instance:
|
||||
return R.failed("案例不存在")
|
||||
instance.status = status
|
||||
instance.update_user = get_username(request)
|
||||
instance.save()
|
||||
return R.ok(msg="状态更新成功")
|
||||
except Exception as e:
|
||||
logging.error(f"更新案例状态异常,ID: {instance_id}, 错误: {str(e)}")
|
||||
return R.failed(msg="状态更新失败,请稍后重试")
|
||||
```
|
||||
|
||||
### 4. 视图层 `application/example/views.py`
|
||||
|
||||
```python
|
||||
from django.utils.decorators import method_decorator
|
||||
from django.views import View
|
||||
from application.example import services
|
||||
from config.env import DJANGO_DEMO
|
||||
from middleware.login_middleware import check_login
|
||||
from middleware.permission_middleware import PermissionRequired
|
||||
from utils import R
|
||||
from application.operation_log.constants import LogType
|
||||
from application.operation_log.decorators import operation_log
|
||||
|
||||
|
||||
@method_decorator(check_login, name="get")
|
||||
class ExamplePageView(PermissionRequired, View):
|
||||
"""案例分页数据查询视图"""
|
||||
permission_required = ("sys:example:page",)
|
||||
|
||||
@operation_log(title="案例管理-查询分页列表", log_type=LogType.QUERY)
|
||||
def get(self, request):
|
||||
return services.get_example_page(request)
|
||||
|
||||
|
||||
@method_decorator(check_login, name="post")
|
||||
class ExampleAddView(PermissionRequired, View):
|
||||
"""添加案例视图"""
|
||||
permission_required = ("sys:example:add",)
|
||||
|
||||
@operation_log(title="案例管理-添加记录", log_type=LogType.ADD)
|
||||
def post(self, request):
|
||||
if DJANGO_DEMO:
|
||||
return R.failed("演示环境,暂无操作权限")
|
||||
return services.add_example(request)
|
||||
|
||||
|
||||
@method_decorator(check_login, name="put")
|
||||
class ExampleUpdateView(PermissionRequired, View):
|
||||
"""更新案例视图"""
|
||||
permission_required = ('sys:example:update',)
|
||||
|
||||
@operation_log(title="案例管理-更新记录", log_type=LogType.UPDATE)
|
||||
def put(self, request):
|
||||
if DJANGO_DEMO:
|
||||
return R.failed("演示环境,暂无操作权限")
|
||||
return services.update_example(request)
|
||||
|
||||
|
||||
@method_decorator(check_login, name="delete")
|
||||
class ExampleDeleteView(PermissionRequired, View):
|
||||
"""删除案例视图"""
|
||||
permission_required = ('sys:example:delete',)
|
||||
|
||||
@operation_log(title="案例管理-删除记录", log_type=LogType.DELETE)
|
||||
def delete(self, request, id):
|
||||
if DJANGO_DEMO:
|
||||
return R.failed("演示环境,暂无操作权限")
|
||||
return services.delete_examples(id)
|
||||
```
|
||||
|
||||
### 5. 路由配置 `application/example/urls.py`
|
||||
|
||||
```python
|
||||
from django.urls import path
|
||||
from application.example import views
|
||||
|
||||
urlpatterns = [
|
||||
path('page', views.ExamplePageView.as_view()),
|
||||
path('list', views.ExampleListView.as_view()),
|
||||
path('detail/<int:id>', views.ExampleDetailView.as_view()),
|
||||
path('add', views.ExampleAddView.as_view()),
|
||||
path('update', views.ExampleUpdateView.as_view()),
|
||||
path('delete/<str:id>', views.ExampleDeleteView.as_view()),
|
||||
path('status', views.ExampleStatusView.as_view()),
|
||||
path('list', views.ExampleDataView.as_view()),
|
||||
]
|
||||
```
|
||||
|
||||
### 6. 应用配置 `application/example/apps.py`
|
||||
|
||||
```python
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class ExampleConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'application.example'
|
||||
```
|
||||
|
||||
### 7. 主路由注册(追加到 `application/urls.py`)
|
||||
|
||||
```python
|
||||
# 案例模块路由
|
||||
path('example/', include('application.example.urls')),
|
||||
```
|
||||
|
||||
### 8. settings.py 注册应用
|
||||
|
||||
在 `INSTALLED_APPS` 中添加:
|
||||
|
||||
```python
|
||||
INSTALLED_APPS = [
|
||||
...
|
||||
'application.example',
|
||||
]
|
||||
```
|
||||
|
||||
## 前端文件清单
|
||||
|
||||
### 9. API 请求 `ui/src/api/tool/example.ts`
|
||||
|
||||
```typescript
|
||||
import { http } from '@/utils/http/axios';
|
||||
|
||||
export function getExamplePage(params?) {
|
||||
return http.request({ url: '/example/page', method: 'GET', params });
|
||||
}
|
||||
|
||||
export function getExampleList(params?) {
|
||||
return http.request({ url: '/example/list', method: 'GET', params });
|
||||
}
|
||||
|
||||
export function getExampleDetail(id) {
|
||||
return http.request({ url: '/example/detail/' + id, method: 'get' });
|
||||
}
|
||||
|
||||
export function exampleAdd(data: any) {
|
||||
return http.request({ url: '/example/add', method: 'POST', data });
|
||||
}
|
||||
|
||||
export function exampleUpdate(data: any) {
|
||||
return http.request({ url: '/example/update', method: 'PUT', data });
|
||||
}
|
||||
|
||||
export function exampleDelete(id) {
|
||||
return http.request({ url: '/example/delete/' + id, method: 'DELETE' });
|
||||
}
|
||||
```
|
||||
|
||||
### 10. 页面视图(5 个文件)
|
||||
|
||||
| 文件 | 说明 |
|
||||
|:----|:----|
|
||||
| `ui/src/views/tool/example/index.vue` | 主页面:搜索 + 表格 + 操作 |
|
||||
| `ui/src/views/tool/example/edit.vue` | 编辑弹窗:新增/编辑表单 |
|
||||
| `ui/src/views/tool/example/detail.vue` | 详情弹窗:查看记录详情 |
|
||||
| `ui/src/views/tool/example/columns.ts` | 表格列定义 |
|
||||
| `ui/src/views/tool/example/querySchemas.ts` | 搜索表单 Schema |
|
||||
|
||||
参考 [前端页面视图](/zh/volume2/fe-view) 中的完整代码。
|
||||
|
||||
## 文件总览
|
||||
|
||||
```
|
||||
后端(application/example/)
|
||||
├── models.py # 数据模型
|
||||
├── forms.py # 表单验证
|
||||
├── services.py # 业务逻辑层
|
||||
├── views.py # 视图层
|
||||
├── urls.py # 路由配置
|
||||
├── apps.py # 应用配置
|
||||
├── admin.py # Django Admin 注册
|
||||
└── migrations/ # 数据库迁移文件
|
||||
|
||||
前端(ui/src/)
|
||||
├── api/tool/
|
||||
│ └── example.ts # API 请求封装
|
||||
└── views/tool/example/
|
||||
├── index.vue # 主页面
|
||||
├── edit.vue # 编辑弹窗
|
||||
├── detail.vue # 详情弹窗
|
||||
├── columns.ts # 表格列定义
|
||||
└── querySchemas.ts # 搜索表单 Schema
|
||||
|
||||
注册文件
|
||||
├── application/urls.py # 主路由注册
|
||||
├── application/settings.py # INSTALLED_APPS 注册
|
||||
└── 数据库菜单表 # 菜单和权限节点
|
||||
```
|
||||
|
||||
## 开发检查清单
|
||||
|
||||
完成后端开发后,按顺序检查:
|
||||
|
||||
- [ ] `models.py` 已定义模型,表名使用 `get_table_name()` 加前缀
|
||||
- [ ] `forms.py` 已定义表单类,中文错误提示
|
||||
- [ ] `services.py` 已实现所有 CRUD 函数
|
||||
- [ ] `views.py` 已定义视图类 + 权限装饰器 + 操作日志
|
||||
- [ ] `urls.py` 已配置路由
|
||||
- [ ] `application/urls.py` 已注册模块路由
|
||||
- [ ] `application/settings.py` 已注册应用
|
||||
- [ ] 菜单管理中已添加权限节点
|
||||
|
||||
完成前端开发后,按顺序检查:
|
||||
|
||||
- [ ] `api/tool/example.ts` 已封装所有接口
|
||||
- [ ] `views/tool/example/index.vue` 主页面已实现
|
||||
- [ ] `views/tool/example/edit.vue` 编辑弹窗已实现
|
||||
- [ ] `views/tool/example/detail.vue` 详情弹窗已实现
|
||||
- [ ] `views/tool/example/columns.ts` 列定义已配置
|
||||
- [ ] `views/tool/example/querySchemas.ts` 搜索 Schema 已配置
|
||||
- [ ] 后端菜单已配置组件路径
|
||||
- [ ] 页面可正常访问和操作
|
||||
|
||||
## 总结
|
||||
|
||||
完整模块涉及后端 6 个文件(models/forms/services/views/urls/apps)+ 路由注册 + 应用注册 + 权限配置,前端 5 个文件(index.vue/edit.vue/detail.vue/columns.ts/querySchemas.ts)+ API 文件。代码生成器可根据数据库表自动生成全套代码。
|
||||
Reference in New Issue
Block a user