Advertisement

Django后台数据获取展示

阅读量:

随后继续采用[Django REST Framework]作为后端框架的技术基础,并采用[Vite]技术构建基于[Vue 3]的前端开发平台

1.跨域获取后台接口并展示

  • 安装Axios
复制代码
    npm install axios --save
  • 前端查看后端所有定义的接口
复制代码
 // 访问后端定义的可视化Api接口文档

    
 http://ip:8000/docs/
    
 // 定义的学生类信息
    
 http://ip:8000/api/v1/students/
  • 前端对后端发起请求
复制代码
 // 导入 axios

    
 import axios from 'axios'
    
  
    
 // 页面一加载便获取axios请求
    
  
    
 <script>
    
     // 获取所有信息
    
     const getStudents = () => {
    
     // axios请求
    
     axios.get('http://192.168.20.110:8000/api/v1/students/').then((res)=>{
    
         // 请求成功
    
         console.log('成功',res)
    
     }).catch((error)=>{
    
         // 请求失败
    
         console.log('失败',error)
    
     })
    
     }
    
     // 定义页面加载时自动执行的函数
    
     const autoRun= () => {
    
     // 获取所有信息
    
     getStudents() 
    
     }
    
     // 调用自动执行函数执行
    
     autoRun() 
    
 </script>
    
    
    
    
    TypeScript
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-18/dTDyIP0ZoHt2lf9xRWjqK6cagiSv.png)
  • 后端配置环境
复制代码
 // 或者直接在0.0.0.0:8000下

    
 python manage.py runserver 0.0.0.0:8000
    
  
    
 // 后端开启跨域,安装组件
    
 pip install django-cors-headers
    
 // 注册
    
 INSTALLED_APPS[
    
     'corsheaders'
    
 ]
    
 // 添加到中间件中
    
 MIDDLEWARE = [
    
     'django.middleware.security.SecurityMiddleware',
    
     'django.contrib.sessions.middleware.SessionMiddleware',
    
     'corsheaders.middleware.CorsMiddleware',# 跨域请求
    
     'django.middleware.common.CommonMiddleware',
    
     'django.middleware.csrf.CsrfViewMiddleware',
    
     'django.contrib.auth.middleware.AuthenticationMiddleware',
    
     'django.contrib.messages.middleware.MessageMiddleware',
    
     'django.middleware.clickjacking.XFrameOptionsMiddleware',
    
 ]
    
 # ======跨域配置======
    
 # 后端是否支持对 Cookis访问
    
 CORS_ALLOW_CREDENTIALS = True
    
 # 白名单地址
    
 CORS_ORIGIN_WHITELIST = (
    
     'http://192.168.20.110:8080',
    
 )
    
    
    
    
    python
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-18/EVrBfCOdyeWjNgUJAmh46xslq5ob.png)
  • 跨域获取所有信息
复制代码
 // 导入 axios

    
 import axios from 'axios'
    
  
    
 // 添加信息获取提示
    
 import { ElMessage } from 'element-plus'
    
  
    
 // 页面一加载便获取axios请求
    
  
    
 <script>
    
     // 获取所有信息
    
     const getStudents = () => {
    
     // axios请求
    
     axios.get('http://192.168.20.110:8000/api/v1/students/').then((res)=>{
    
         // 请求成功
    
         // console.log('成功',res)
    
         // 判断是否成功
    
         if (res.status==200){
    
             // 成功执行
    
             Data.students = res.data.results
    
             // 将记录总数绑定到分页的total
    
             Data.total = res.data.count
    
             ElMessage({
    
                 message: '数据加载成功!',
    
                 type: 'success',
    
             })
    
         }
    
     }).catch((error)=>{
    
         // 请求失败
    
         console.log('失败',error)
    
     })
    
     }
    
     // 定义页面加载时自动执行的函数
    
     const autoRun= () => {
    
     // 获取所有信息
    
     getStudents() 
    
     }
    
     // 调用自动执行函数执行
    
     autoRun() 
    
 </script>
    
    
    
    
    TypeScript
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-18/wEC1igtPNS5ynfzurBH38XIDFmpa.png)
  • 分页优化
复制代码
 <script lang="ts" setup>

    
 import { ref, reactive } from "vue"
    
 import {More,Edit,Delete} from "@element-plus/icons-vue"
    
 import axios from 'axios'
    
 // 添加信息获取提示
    
 import { ElMessage } from 'element-plus'
    
  
    
  
    
 // 定义存储集合
    
 var Data = reactive({
    
     // 定义输入的查询条件
    
     q_str: ref(""),
    
     // 存储从后台获取的所有院系信息
    
     FacultyOptions: reactive([
    
     {
    
         value:1,
    
         label:'计算机学院'
    
     },
    
     {
    
         value:2,
    
         label:'外语学院'
    
     },
    
     ]),
    
     // 存储选择院系后的值
    
     FacultySelected: ref(""),
    
  
    
      // 存储从后台获取的所有专业信息
    
      MajorOptions: reactive([
    
     {
    
         value:1,
    
         label:'计算机专业'
    
     },
    
     {
    
         value:2,
    
         label:'外语专业'
    
     },
    
     ]),
    
     // 存储选择专业后的值
    
     MajorSelected: ref(""),
    
     // ===表格区域定义====
    
     students: reactive([
    
     
    
     ]),
    
     // =====分页====
    
     // 当前页
    
     currentsPage: ref(1),
    
     // 每页显示的数据量
    
     pageSize: ref(15),
    
     // 总数据量所有记录条数
    
     total: ref(0),
    
 });
    
  
    
 // 分页中修改每页的pageSize
    
 const handleSizeChange=(size: any)=>{
    
   // 修改记录条数
    
   Data.pageSize = size
    
   // 重新获取所有信息
    
   getStudents()
    
 }
    
  
    
 // 分页中修改每页的currentsPage
    
 const handleCurrentChange=(page: any)=>{
    
   // 修改当前页
    
   Data.currentsPage = page
    
   // 重新获取所有信息
    
   getStudents()
    
 }
    
  
    
 // ======前后端交互======
    
 // 获取所有信息
    
 const getStudents = () => {
    
     // 定义一个集合存储分页参数
    
     let params = {
    
         page: Data.currentsPage,
    
         size: Data.pageSize
    
     }
    
     // axios请求
    
     axios.get('http://192.168.20.110:8000/api/v1/students/',{params:params}).then((res)=>{
    
         // 请求成功
    
         console.log('成功',res)
    
         // 判断是否成功
    
         if (res.status==200){
    
             // 成功执行
    
             Data.students = res.data.results
    
             // 将记录总数绑定到分页的total
    
             Data.total = res.data.count
    
             // 成功提示
    
             ElMessage({
    
               message: '数据加载成功!',
    
               type: 'success',
    
             })
    
  
    
         }
    
     }).catch((error)=>{
    
         // 请求失败
    
         console.log('失败',error)
    
     })
    
     }
    
     // 定义页面加载时自动执行的函数
    
     const autoRun= () => {
    
     // 获取所有信息
    
     getStudents() 
    
     }
    
     // 调用自动执行函数执行
    
     autoRun() 
    
  
    
 </script>
    
    
    
    
    TypeScript
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-18/iWPsRXuLFf5zNxVgaBjwmocIC9hk.png)
  • 院系/专业信息展示优化

学生表仅存储了专业的ID字段;专业表中包含有院系的ID字段;为了将学生详细信息中的专业与院系信息同步到数据库中,在后端需要序列化这两个表格的数据结构。

学生表仅存储了专业的ID字段;专业表中包含有院系的ID字段;为了将学生详细信息中的专业与院系信息同步到数据库中,在后端需要序列化这两个表格的数据结构。

复制代码
 // serializer.py

    
 # 导入模块
    
 # models中的类与接口转换
    
 from rest_framework import serializers
    
 from studentweb.models import *
    
  
    
 # 学院序列化类
    
 class FacultySerializer(serializers.ModelSerializer):
    
  
    
     class Meta:
    
     model = Faculty
    
     fields = '__all__'
    
  
    
 # 专业序列化类
    
 class MajorSerializer(serializers.ModelSerializer):
    
     # 序列化学院id
    
     faculty = FacultySerializer()
    
     class Meta:
    
     model = Major
    
     fields = '__all__'
    
  
    
 # 学生序列化类
    
 class StudentSerializer(serializers.ModelSerializer):
    
     # 序列化专业信息
    
     major = MajorSerializer()
    
     class Meta:
    
     model = Student
    
     fields = '__all__'
    
    
    
    
    python
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-18/XmSy0glO9MF5GRiLrZ4dhJKHDTVN.png)
复制代码
 // 专业的名字:major.name

    
 // 院系的名字:major.faculty.name
    
 {
    
       "sno": "950001",
    
       "major": {
    
     "id": 2,
    
     "faculty": {
    
       "id": 1,
    
       "name": "计算机学院"
    
     },
    
     "name": "计算机网络"
    
       },
    
       "name": "王晓宇",
    
       "gender": "男",
    
       "birthday": "2022-03-01",
    
       "mobile": "13099881122",
    
       "email": "wangxiaoyu@qq.com",
    
       "address": "上海市闵行区春都路88号",
    
       "image": ""
    
     },
    
    
    
    
    TypeScript
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-18/2zQ4Zh9mXxpGyRwYOIaFesEvMPBV.png)
  • 表格绑定展示
复制代码
 // 更改前端表格展示数据

    
  <el-table-column prop="major.faculty.name" label="院系" align="center" width="120" />
    
  <el-table-column prop="major.name" label="专业" align="center" width="120" />
    
    
    
    
    python
  • 表格过长数据处理
复制代码
 // 过长信息不展示完全使用'...'显示

    
  
    
 // 标签添加 :show-overflow-tooltip="true"属性
    
    
    
    
    python

2.Axios模块化请求

  • request脚本实现
复制代码
 // 新建 /src/utils/request.ts

    
 // 封装 axios代码实现模块化
    
  
    
 // 1.导入
    
 import axios from 'axios'
    
 // 2.创建一个Axios的app
    
 const request = axios.create({
    
     // 定义基本 URL
    
     baseURL: 'http://192.168.__.___:8000/api/v1/',
    
     // 设置超时
    
     timeout: 5000,
    
     
    
 })
    
  
    
 // 3.暴露
    
 export default request 
    
    
    
    
    TypeScript
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-18/2FNQ96ycKWPLTApfGq7Z3SwUnRxz.png)
复制代码
 // 添加request.ts配置的axios

    
  
    
 <script lang="ts" setup>
    
 // 导入request
    
 import request from "../../utils/request";
    
 import { ref, reactive } from "vue"
    
 import {More,Edit,Delete} from "@element-plus/icons-vue"
    
  
    
 // 添加信息获取提示
    
 import { ElMessage } from 'element-plus'
    
  
    
  
    
 // 定义存储集合
    
 var Data = reactive({
    
     // 定义输入的查询条件
    
     q_str: ref(""),
    
     // 存储从后台获取的所有院系信息
    
     FacultyOptions: reactive([
    
     {
    
         value:1,
    
         label:'计算机学院'
    
     },
    
     {
    
         value:2,
    
         label:'外语学院'
    
     },
    
     ]),
    
     // 存储选择院系后的值
    
     FacultySelected: ref(""),
    
  
    
      // 存储从后台获取的所有专业信息
    
      MajorOptions: reactive([
    
     {
    
         value:1,
    
         label:'计算机专业'
    
     },
    
     {
    
         value:2,
    
         label:'外语专业'
    
     },
    
     ]),
    
     // 存储选择专业后的值
    
     MajorSelected: ref(""),
    
     // ===表格区域定义====
    
     students: reactive([
    
     
    
     ]),
    
     // =====分页====
    
     // 当前页
    
     currentsPage: ref(1),
    
     // 每页显示的数据量
    
     pageSize: ref(15),
    
     // 总数据量所有记录条数
    
     total: ref(0),
    
 });
    
  
    
 // 分页中修改每页的pageSize
    
 const handleSizeChange=(size: any)=>{
    
   // 修改记录条数
    
   Data.pageSize = size
    
   // 重新获取所有信息
    
   getStudents()
    
 }
    
  
    
 // 分页中修改每页的currentsPage
    
 const handleCurrentChange=(page: any)=>{
    
   // 修改当前页
    
   Data.currentsPage = page
    
   // 重新获取所有信息
    
   getStudents()
    
 }
    
  
    
 // ======前后端交互======
    
 // 获取所有信息
    
 const getStudents = () => {
    
     // 定义一个集合存储分页参数
    
     let params = {
    
         page: Data.currentsPage,
    
         size: Data.pageSize
    
     }
    
     // axios请求
    
     request.get('students/',{params:params}).then((res)=>{
    
         // 请求成功
    
         console.log('成功',res)
    
         // 判断是否成功
    
         if (res.status==200){
    
             // 成功执行
    
             Data.students = res.data.results
    
             // 将记录总数绑定到分页的total
    
             Data.total = res.data.count
    
             // 成功提示
    
             ElMessage({
    
               message: '数据加载成功!',
    
               type: 'success',
    
             })
    
  
    
         }
    
     }).catch((error)=>{
    
         // 请求失败
    
         console.log('失败',error)
    
     })
    
     }
    
     // 定义页面加载时自动执行的函数
    
     const autoRun= () => {
    
     // 获取所有信息
    
     getStudents() 
    
     }
    
     // 调用自动执行函数执行
    
     autoRun() 
    
  
    
 </script>
    
    
    
    
    TypeScript
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-18/xMP79rYa5zWK1JV8XDqTENHFb6tf.png)
  • Api数据集及请求类型以及url优化 接口实现
复制代码
 // 新建 /src/api/students.ts(majors.ts/facultys.ts)

    
  
    
 // 导入
    
 import request from "../utils/request";
    
  
    
 // RESTFUL ---> 6个接口【获取所有,添加,获取某一个,修改,删除】
    
  
    
 // ====获取所有====
    
 const getAll = (params ?: any) => {
    
     // request
    
     return request({
    
     method: "GET",
    
     url: "/students",
    
     params,
    
     })
    
 }
    
  
    
 // ====添加====
    
 const add= (data: any) => {
    
     // request
    
     return request({
    
     method: "POST",
    
     url: "/students",
    
     data,
    
     })
    
 }
    
 // ====获取单一数据====
    
 const getOne=(id: any) => {
    
     // request
    
     return request({
    
     method: "GET",
    
     url: `/students/${id}`,
    
     })
    
 }
    
 // ====修改====
    
 const edit=(id: any, data: any) => {
    
     // request
    
     return request({
    
     method: "PUT",
    
     url: `/students/${id}`,
    
     data
    
     })
    
 }
    
 // ====删除====
    
 const del = (id: any) => {
    
     // request
    
     return request({
    
     method: "DELETE",
    
     url: `/students/${id}`,
    
     })
    
 }
    
 export default {
    
     getAll,
    
     add,
    
     getOne,
    
     edit,
    
     del,
    
     // 也可以直接在此处定义其他的 api
    
 }
    
  
    
    
    
    
    TypeScript
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-18/XL49Euh6mdwAlrPjts0KV7T3Gfyv.png)
复制代码
 // 新建 index.ts用于导入所有api

    
  
    
 // 导入所有
    
 import studentApi from "./students"
    
 import majorsApi from "./majors"
    
 import facultysApi from "./facultys"
    
  
    
 // 封装并发布
    
 export default {
    
     studentApi,
    
     majorsApi,
    
     facultysApi,    
    
 }
    
    
    
    
    TypeScript
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-18/o0OtsXnJHUVRWlrYdC4qw52ezMSx.png)
复制代码
 // 使用 上述定义的接口

    
  
    
 <script lang="ts" setup>
    
 import { ref, reactive } from "vue"
    
 import {More,Edit,Delete} from "@element-plus/icons-vue"
    
 // 导入API
    
 import indexApi from '../../api/index'
    
 // 添加信息获取提示
    
 import { ElMessage } from 'element-plus'
    
  
    
  
    
 // 定义存储集合
    
 var Data = reactive({
    
     // 定义输入的查询条件
    
     q_str: ref(""),
    
     // 存储从后台获取的所有院系信息
    
     FacultyOptions: reactive([
    
     {
    
         value:1,
    
         label:'计算机学院'
    
     },
    
     {
    
         value:2,
    
         label:'外语学院'
    
     },
    
     ]),
    
     // 存储选择院系后的值
    
     FacultySelected: ref(""),
    
  
    
      // 存储从后台获取的所有专业信息
    
      MajorOptions: reactive([
    
     {
    
         value:1,
    
         label:'计算机专业'
    
     },
    
     {
    
         value:2,
    
         label:'外语专业'
    
     },
    
     ]),
    
     // 存储选择专业后的值
    
     MajorSelected: ref(""),
    
     // ===表格区域定义====
    
     students: reactive([
    
     
    
     ]),
    
     // =====分页====
    
     // 当前页
    
     currentsPage: ref(1),
    
     // 每页显示的数据量
    
     pageSize: ref(15),
    
     // 总数据量所有记录条数
    
     total: ref(0),
    
 });
    
  
    
 // 分页中修改每页的pageSize
    
 const handleSizeChange=(size: any)=>{
    
   // 修改记录条数
    
   Data.pageSize = size
    
   // 重新获取所有信息
    
   getStudents()
    
 }
    
  
    
 // 分页中修改每页的currentsPage
    
 const handleCurrentChange=(page: any)=>{
    
   // 修改当前页
    
   Data.currentsPage = page
    
   // 重新获取所有信息
    
   getStudents()
    
 }
    
  
    
 // ======前后端交互======
    
 // 获取所有信息
    
 const getStudents = () => {
    
     // 定义一个集合存储分页参数
    
     let params = {
    
         page: Data.currentsPage,
    
         size: Data.pageSize
    
     }
    
     // axios请求
    
     indexApi.studentApi.getAll(params).then((res)=>{
    
         // 请求成功
    
         console.log('成功',res)
    
         // 判断是否成功
    
         if (res.status==200){
    
             // 成功执行
    
             Data.students = res.data.results
    
             // 将记录总数绑定到分页的total
    
             Data.total = res.data.count
    
             // 成功提示
    
             ElMessage({
    
               message: '数据加载成功!',
    
               type: 'success',
    
             })
    
  
    
         }
    
     }).catch((error)=>{
    
         // 请求失败
    
         console.log('失败',error)
    
     })
    
     }
    
     // 定义页面加载时自动执行的函数
    
     const autoRun= () => {
    
     // 获取所有信息
    
     getStudents() 
    
     }
    
     // 调用自动执行函数执行
    
     autoRun() 
    
  
    
 </script>
    
  
    
 <template>
    
     <!-- 1.顶部查询区域   styple="display: flax;"横向显示-->
    
     <el-form :inline="true"  class="demo-form-inline">
    
     <el-form-item label="查询条件">
    
       <el-input v-model="Data.q_str" placeholder="请输入查询条件" clearable />
    
     </el-form-item>
    
     <!-- 动态获取院系信息 -->
    
     <el-form-item label="院系">
    
       <el-select v-model="Data.FacultySelected" placeholder="请选择院系">
    
     <el-option 
    
     v-for="item in Data.FacultyOptions"
    
     :key="item.value"
    
     :label="item.label"
    
     :value="item.value" />
    
     <!-- <el-option label="Zone one" value="shanghai" />
    
     <el-option label="Zone two" value="beijing" /> -->
    
       </el-select>
    
     </el-form-item>
    
     <!-- 动态获取专业信息 -->
    
     <el-form-item label="专业">
    
       <el-select v-model="Data.MajorSelected" placeholder="请选择专业">
    
     <el-option 
    
     v-for="item in Data.MajorOptions"
    
     :key="item.value"
    
     :label="item.label"
    
     :value="item.value" />
    
     <!-- <el-option label="Zone one" value="shanghai" />
    
     <el-option label="Zone two" value="beijing" /> -->
    
       </el-select>
    
     </el-form-item>
    
     <!-- <el-form-item label="Activity time">
    
       <el-date-picker
    
     type="date"
    
     placeholder="Pick a date"
    
     clearable
    
       />
    
     </el-form-item> -->
    
     <el-form-item>
    
       <el-button type="primary">
    
     <!-- 引入方法1 -->
    
     <el-icon><component class="icons" is="Search"></component></el-icon>
    
     <span>查询</span></el-button>
    
       <el-button type="primary">
    
     <!-- 引入方法2 -->
    
     <el-icon><Finished /></el-icon>
    
     <span>全部</span></el-button>
    
       <el-button type="primary">
    
     <el-icon><Pointer /></el-icon>
    
     <span>添加</span></el-button>
    
     </el-form-item>
    
 </el-form>
    
     <!-- 2.表格信息部分 -->
    
     <el-table :data="Data.students" stripe border style="width: 100%" :header-cell-style="{ backgroundColor:'#409EFF',color:'#FFF',FontSize:'14px' }">
    
     <el-table-column label="序号" type="index" align="center" width="60" />
    
     <el-table-column prop="sno" label="学号" align="center" width="80" />
    
     <el-table-column prop="name" label="姓名" align="center" width="80" />
    
     <el-table-column prop="gender" label="性别" align="center" width="80"  />
    
     <el-table-column prop="birthday" label="出生日期" align="center" width="180" />
    
     <el-table-column prop="major.faculty.name" label="院系" align="center" width="120" :show-overflow-tooltip="true"/>
    
     <el-table-column prop="major.name" label="专业" align="center" width="120" />
    
     <el-table-column prop="mobile" label="电话" align="center" width="140" />
    
     <el-table-column prop="email" label="Email" align="center" width="180" :show-overflow-tooltip="true" />
    
     <el-table-column prop="address" label="地址" align="center" :show-overflow-tooltip="true"/>
    
     <!-- 按钮区域 -->
    
     <el-table-column label="操作" align="center">
    
         <el-button type="primary" :icon="More" circle size="small"/>
    
         <el-button type="warning" :icon="Edit" circle size="small"/>
    
         <el-button type="danger" :icon="Delete" circle size="small"/>
    
     </el-table-column>
    
  
    
     </el-table>
    
     <!-- 3.分页 currentPage4当前页 pageSize4每页大小 total记录条数 handleSizeChange改变每页大小 handleCurrentChange改变当前页  -->
    
     <el-pagination style="margin-top: 28px;"
    
     background
    
       v-model:current-page="Data.currentsPage"
    
       v-model:page-size="Data.pageSize"
    
       :page-sizes="[10,12,15,17,20,25,40,50]"
    
       layout="total, sizes, prev, pager, next, jumper"
    
       :total="Data.total"
    
       @size-change="handleSizeChange"
    
       @current-change="handleCurrentChange"
    
     />
    
 </template>
    
  
    
 <style scoped>
    
 .demo-form-inline .el-input {
    
   --el-input-width: 220px;
    
 }
    
  
    
 .demo-form-inline .el-select {
    
   --el-select-width: 220px;
    
 }
    
  
    
 </style>
    
    
    
    
    TypeScript
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-18/QtA52mDs8u07wjkIJViayfTCXOeH.png)
  • 院系联级下拉框实现
复制代码
 // 1.重新定义FacultyOptions 结构

    
 // 定义存储集合
    
 var Data = reactive({
    
     // 存储从后台获取的所有院系信息
    
     FacultyOptions: reactive([
    
     { id:"",name:""}, 
    
     ])
    
 }),
    
 // 定义页面加载时自动执行的函数
    
  
    
 // 获取所有信息
    
 const getStudents = () => {
    
     // 定义一个集合存储分页参数
    
     let params = {
    
         page: Data.currentsPage,
    
         size: Data.pageSize
    
     }
    
     // axios请求
    
     indexApi.studentApi.getAll(params).then((res)=>{
    
         // 请求成功
    
         console.log('成功',res)
    
         // 判断是否成功
    
         if (res.status==200){
    
             // 成功执行
    
             Data.students = res.data.results
    
             // 将记录总数绑定到分页的total
    
             Data.total = res.data.count
    
             // 成功提示
    
             ElMessage({
    
               message: '数据加载成功!',
    
               type: 'success',
    
             })
    
  
    
         }
    
     }).catch((error)=>{
    
         // 请求失败
    
         console.log('失败',error)
    
     })
    
      }
    
  
    
 // 2.获取所有院系信息
    
 const getFacultys = ()=> {
    
     // 请求
    
     indexApi.facultysApi.getAll().then((res)=>{
    
     // console.log(res.data)
    
     Data.FacultyOptions = res.data.results;
    
   })
    
     
    
 }
    
  
    
     
    
 // 3.定义页面加载时自动执行的函数
    
 const autoRun= () => {
    
     // 获取所有信息
    
     getStudents() 
    
     // 获取院系填充信息
    
     getFacultys()
    
 }
    
  
    
  
    
  
    
 // 调用自动执行函数执行
    
 autoRun() 
    
  
    
 4.更改院系标签值
    
 <!-- 动态获取院系信息  clearable filterable 添加过滤-->
    
     <el-form-item label="院系">
    
       <el-select v-model="Data.FacultySelected" placeholder="请选择院系" clearable filterable>
    
     <el-option 
    
     v-for="item in Data.FacultyOptions"
    
     :key="item.id"
    
     :label="item.name"
    
     :value="item.id" />
    
     <!-- <el-option label="Zone one" value="shanghai" />
    
     <el-option label="Zone two" value="beijing" /> -->
    
       </el-select>
    
     </el-form-item>
    
    
    
    
    TypeScript
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-18/zgeTQVoPZc9h761IXlA3Su0YxadU.png)
  • 专业联动院系下拉框实现
复制代码
 <script lang="ts" setup>

    
 import { ref, reactive } from "vue"
    
 import {More,Edit,Delete} from "@element-plus/icons-vue"
    
 // 导入API
    
 import indexApi from '../../api/index'
    
 // 添加信息获取提示
    
 import { ElMessage } from 'element-plus'
    
  
    
  
    
  
    
 // 定义存储集合
    
 var Data = reactive({
    
     // 定义输入的查询条件
    
     q_str: ref(""),
    
     // 存储从后台获取的所有院系信息
    
     FacultyOptions: reactive([
    
     { id:"",name:""}, 
    
     ]),
    
     // 存储选择院系后的值
    
     FacultySelected: ref(""),
    
  
    
      // 存储从后台获取的所有专业信息
    
      MajorOptions: reactive([
    
      {
    
       id: "",
    
       name: ""
    
     },
    
     ]),
    
     // 存储选择专业后的值
    
     MajorSelected: ref(""),
    
  
    
  
    
 // ======前后端交互======
    
  
    
 // 获取所有院系信息
    
 const getFacultys = ()=> {
    
   
    
   // 请求
    
   indexApi.facultysApi.getAll().then((res)=>{
    
     // console.log(res.data)
    
     Data.FacultyOptions = res.data.results;
    
   })
    
 };
    
 // 获取院系对应的专业信息
    
 const getMajors = () => {
    
   // 准备条件
    
   let params = {
    
     // http://192.168.20.110:8000/api/v1/majors/?name=&faculty=1
    
     name:'',
    
     faculty: Data.FacultySelected
    
   }
    
   // 请求
    
   indexApi.majorsApi.getAll(params).then((res)=>{
    
     // console.log(res.data.results)
    
     Data.MajorOptions = res.data.results;
    
   })
    
 };
    
  
    
  
    
 // 定义页面加载时自动执行的函数
    
 const autoRun= () => {
    
     // 获取所有信息
    
     getStudents() 
    
     // 获取院系填充信息
    
     getFacultys()
    
 }
    
 // 调用自动执行函数执行
    
 autoRun() 
    
  
    
 </script>
    
  
    
 <template>
    
     <!-- 动态获取院系信息 -->
    
     <el-form-item label="院系">
    
       <el-select v-model="Data.FacultySelected" placeholder="请选择院系" clearable filterable @change="getMajors">
    
     <el-option 
    
     v-for="item in Data.FacultyOptions"
    
     :key="item.id"
    
     :label="item.name"
    
     :value="item.id" />
    
     <!-- <el-option label="Zone one" value="shanghai" />
    
     <el-option label="Zone two" value="beijing" /> -->
    
       </el-select>
    
     </el-form-item>
    
     <!-- 动态获取专业信息 -->
    
     <el-form-item label="专业">
    
       <el-select v-model="Data.MajorSelected" placeholder="请选择专业">
    
     <el-option 
    
     v-for="item in Data.MajorOptions"
    
     :key="item.id"
    
     :label="item.name"
    
     :value="item.id" />
    
    
    
       </el-select>
    
     </el-form-item>
    
     
    
     <el-form-item>
    
       <el-button type="primary">
    
     <!-- 引入方法1 -->
    
     <el-icon><component class="icons" is="Search"></component></el-icon>
    
     <span>查询</span></el-button>
    
       <el-button type="primary">
    
     <!-- 引入方法2 -->
    
     <el-icon><Finished /></el-icon>
    
     <span>全部</span></el-button>
    
       <el-button type="primary">
    
     <el-icon><Pointer /></el-icon>
    
     <span>添加</span></el-button>
    
     </el-form-item>
    
 </el-form>
    
 </template>
    
  
    
 <style scoped>
    
 .demo-form-inline .el-input {
    
   --el-input-width: 220px;
    
 }
    
  
    
 .demo-form-inline .el-select {
    
   --el-select-width: 220px;
    
 }
    
  
    
 </style>
    
    
    
    
    TypeScript
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-18/186YK3h4pxG2NW0fcolFE9ReagMU.png)
复制代码
 // 后端注意 filter.py Major筛选类的定义

    
  
    
 # Major的filter类
    
 class MajorFilter(FilterSet):
    
     # 重写支持模糊匹配的字段
    
     name = filters.CharFilter(field_name='name', lookup_expr='icontains')
    
  
    
     class Meta:
    
     model = Major
    
     fields = ('name','faculty')
    
    
    
    
    python
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-18/cHdmFhNIiGtBQV5ugxS4Tyefl8EL.png)
  • 面向对象思维优化Api接口
复制代码
 // 新建 api/apibase.ts 定义基础类

    
  
    
 // 导入
    
 import request from "../utils/request";
    
  
    
 export default class Apibase {
    
  
    
     // 定义属性
    
     public name : string;
    
  
    
     // 构造函数(器)
    
     constructor(name : string) {
    
     this.name = name;
    
     }
    
  
    
     // 方法
    
     public getAll = (params?: any) => {
    
     // request请求
    
     return request({
    
         method: "GET",
    
         url: `${this.name}`,
    
         params,
    
     })
    
     }
    
  
    
     // ====添加====
    
     public add= (data: any) => {
    
     // request
    
     return request({
    
         method: "POST",
    
         url: `${this.name}`,
    
         data,
    
     })
    
     }
    
     // ====获取单一数据====
    
     public getOne=(id: any) => {
    
     // request
    
     return request({
    
         method: "GET",
    
         url: `${this.name}/${id}`,
    
     })
    
     }
    
     // ====修改====
    
     public edit=(id: any, data: any) => {
    
     // request
    
     return request({
    
         method: "PUT",
    
         url: `${this.name}/${id}`,
    
         data
    
     })
    
     }
    
     // ====删除====
    
     public del = (id: any) => {
    
     // request
    
     return request({
    
         method: "DELETE",
    
         url: `${this.name}/${id}`,
    
     })
    
     }
    
 }
    
    
    
    
    TypeScript
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-18/aJlXMbvquwZN80idO9nzYWFETt4g.png)
复制代码
 // 调用基础类 api/index.ts

    
  
    
  
    
 // 导入基础类
    
 import Apibase from "./apibase"
    
  
    
 // 实例化对象
    
 let studentApi = new Apibase("students");
    
 let majorsApi = new Apibase("majors");
    
 let facultysApi = new Apibase("facultys");
    
  
    
 // 封装并发布
    
 export default {
    
     studentApi,
    
     majorsApi,
    
     facultysApi,    
    
 }
    
  
    
 // 删除/注销 facultys.ts、majors.ts、students.ts
    
    
    
    
    TypeScript
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-18/fYCZwLcs9vep8TN1jWE5nA2Qiz4V.png)
  • 联级信息过滤实现查询和展示全部的功能
复制代码
 // 输入关键字筛选实现

    
  
    
 // 后端输入筛选字段设置
    
 # 学生视图
    
 class StudentViewSet(ModelViewSet):
    
     """
    
     create:
    
     创建院系信息
    
     retrieve:
    
     获取院系信息详情数据
    
     update:
    
     完整更新院系信息
    
     partial_update:
    
     部分更新院系信息
    
     destroy:
    
     删除院系信息
    
     list:
    
     获取所有院系信息
    
     """
    
     queryset = Student.objects.all()
    
     serializer_class = StudentSerializer
    
     # 分页
    
     pagination_class = MyPageNumberPagination
    
     filter_class = StudentFilter
    
     # 指定查找匹配的字段
    
     search_fields = ('sno','name','mobile','email','address')
    
  
    
 // 前端获取所有信息中新增search筛选条件
    
  
    
 // 获取所有信息
    
 const getStudents = () => {
    
     // 定义一个集合存储分页参数
    
     let params = {
    
         page: Data.currentsPage,
    
         size: Data.pageSize,
    
         // 一对多,可以匹配多个字段 ?search=...
    
         search: Data.q_str
    
     }
    
     // axios请求
    
     indexApi.studentApi.getAll(params).then((res)=>{
    
         // 请求成功
    
         // console.log('成功',res)
    
         // 判断是否成功
    
         if (res.status==200){
    
             // 成功执行
    
             Data.students = res.data.results
    
             // 将记录总数绑定到分页的total
    
             Data.total = res.data.count
    
             // 成功提示
    
             ElMessage({
    
               message: '数据加载成功!',
    
               type: 'success',
    
             })
    
  
    
         }
    
     }).catch((error)=>{
    
         // 请求失败
    
         console.log('失败',error)
    
     })
    
 };
    
  
    
 // 绑定点击事件
    
 <el-button type="primary" @click="getStudents">
    
     <el-icon><component class="icons" is="Search"></component></el-icon>
    
     <span>查询</span>
    
 </el-button>
    
    
    
    
    TypeScript
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-18/SvLd6sgEbaU1WV3CkQMNnty9ZPRu.png)
复制代码
 // 点击全部按钮查询实现

    
 // 定义函数
    
 // 点击全部 清楚删选条件
    
 const listAllStudent = () =>{
    
   // 清空查询条件
    
   Data.q_str = ''
    
   // 重新获取所有信息
    
   getStudents()
    
 }
    
  
    
 // 绑定按钮
    
  
    
 <el-button type="primary" @click="listAllStudent">
    
     <el-icon><Finished /></el-icon>
    
     <span>全部</span>
    
 </el-button>
    
    
    
    
    TypeScript
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-18/64dxiJk52zXabOFgTGE7cfnwP8ZM.png)
复制代码
 # 院系筛选条件 http://ip/api/v1/students/?sno=&name=&mobile=&major=&faculty=5

    
  
    
 # 更改后端代码 filter.py
    
  
    
 class StudentFilter(FilterSet):
    
     # 重写支持模糊匹配的字段
    
     sno = filters.CharFilter(field_name='sno', lookup_expr='icontains')
    
     name = filters.CharFilter(field_name='name', lookup_expr='icontains')
    
     mobile = filters.CharFilter(field_name='mobile', lookup_expr='icontains')
    
     # 添加专业字段匹配
    
     major = filters.CharFilter(field_name='major')
    
     # 专业表跳转到学院表
    
     faculty = filters.CharFilter(field_name='major__faculty')
    
  
    
     class Meta:
    
     model = Student
    
     # 新增专业字段
    
     fields = ('sno','name','mobile','major')
    
  
    
 // 前端绑定
    
 // 获取所有信息
    
 const getStudents = () => {
    
     // 定义一个集合存储分页参数
    
     let params = {
    
         page: Data.currentsPage,
    
         size: Data.pageSize,
    
         // 一对多,可以匹配多个字段 ?search=...
    
         search: Data.q_str,
    
         // 添加=====院系字段 提供学院的 key====
    
         faculty: Data.FacultySelected,
    
     }
    
     // axios请求
    
     indexApi.studentApi.getAll(params).then((res)=>{
    
         // 请求成功
    
         // console.log('成功',res)
    
         // 判断是否成功
    
         if (res.status==200){
    
             // 成功执行
    
             Data.students = res.data.results
    
             // 将记录总数绑定到分页的total
    
             Data.total = res.data.count
    
             // 成功提示
    
             ElMessage({
    
               message: '数据加载成功!',
    
               type: 'success',
    
             })
    
  
    
         }
    
     }).catch((error)=>{
    
         // 请求失败
    
         console.log('失败',error)
    
     })
    
 };
    
  
    
 // 点击全部 清楚删选条件
    
 const listAllStudent = () =>{
    
   // 清空查询条件
    
   Data.q_str = ''
    
   // ======清空院系条件======
    
   Data.FacultySelected = ''
    
   // 重新获取所有信息
    
   getStudents()
    
 }
    
    
    
    
    python
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-18/koPUyQI4OjqRmLzfDGrN8l127nui.png)
复制代码
 // 专业信息筛选

    
  
    
 // 获取所有信息
    
 const getStudents = () => {
    
     // 定义一个集合存储分页参数
    
     let params = {
    
         page: Data.currentsPage,
    
         size: Data.pageSize,
    
         // 一对多,可以匹配多个字段 ?search=...
    
         search: Data.q_str,
    
         // 添加院系字段 提供学院的 key
    
         faculty: Data.FacultySelected,
    
         // 添加专业筛选
    
         major: Data.MajorSelected
    
     }
    
     // axios请求
    
     indexApi.studentApi.getAll(params).then((res)=>{
    
         // 请求成功
    
         // console.log('成功',res)
    
         // 判断是否成功
    
         if (res.status==200){
    
             // 成功执行
    
             Data.students = res.data.results
    
             // 将记录总数绑定到分页的total
    
             Data.total = res.data.count
    
             // 成功提示
    
             ElMessage({
    
               message: '数据加载成功!',
    
               type: 'success',
    
             })
    
  
    
         }
    
     }).catch((error)=>{
    
         // 请求失败
    
         console.log('失败',error)
    
     })
    
 };
    
  
    
 // 点击全部 清楚删选条件
    
 const listAllStudent = () =>{
    
   // 清空查询条件
    
   Data.q_str = ''
    
   Data.FacultySelected = ''
    
   Data.MajorSelected = ''
    
   // 重新获取所有信息
    
   getStudents()
    
 }
    
    
    
    
    TypeScript
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-18/zwVFsQHbxTC2vMdRDgYO73rXKSNi.png)
  • 配置Vue实例的全局变量
复制代码
 // 挂载全局对象

    
 // Vue2.0-->Vue.prototype.$api = api 
    
 // Vue3.0-->app.config.globalProperties.api = api
    
 // =====main.ts定义全局变量=====
    
 // 导入所有数据集的 Api
    
 import Apibase from './api/apibase'
    
 // 将 Api挂载到全局的属性
    
 app.config.globalProperties.api = Apibase
    
 // =====全局定义Api使用 info.vue=====
    
 import { ref, reactive, getCurrentInstance } from "vue"
    
 // 获取当前实例
    
 const indexApi = (getCurrentInstance() as any).proxy.api;
    
    
    
    
    TypeScript
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-18/FntzaIXovDKy1QYEhP8N4wlu7MHT.png)
  • 请求拦截器和响应拦截器

请求拦截器: 自动添加身份验证的token

复制代码
  
    
 // ====请求拦截器 utils/request.ts=====
    
  
    
 // ====封装 axios代码实现模块化====
    
 // 1.导入
    
 import axios from 'axios'
    
 // 2.创建一个Axios的app
    
 const request = axios.create({
    
     // 定义基本 URL
    
     baseURL: 'http://192.168.20.110:8000/api/v1/',
    
     // 设置超时
    
     timeout: 5000,
    
     
    
 })
    
  
    
 // ====请求拦截器(发请求request)基于上边创建的request====
    
 request.interceptors.request.use(
    
     (config: any) => {
    
     // 获取本地loalstorage中的toten
    
     let token = localStorage.getItem('toten')
    
     // 判断是否有token
    
     if(token) {
    
         // 如果有token,就在请求头中添加token
    
         config.headers.common['token'] = token
    
     }
    
     // 返回
    
     return config
    
     },
    
     (error: any) => {
    
     Promise.reject(error);
    
     },
    
 );
    
 // ====响应拦截器(反馈response) 基于上边创建的request====
    
 request.interceptors.response.use();
    
 // 3.暴露
    
 export default request 
    
  
    
  
    
 // ==========后端配置 settings.py========
    
 CORS_ALLOW_HEADERS = (
    
     'token',
    
     'jwt',
    
     'accept',
    
     'accept-encoding',
    
     'authorization',
    
     'content-type',
    
     'dnt',
    
     'origin',
    
     'user-agent',
    
     'x-csrftoken',
    
     'x-requested-with',
    
 )
    
  
    
  
    
    
    
    
    TypeScript
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-18/5PGdSRLvw6kxguj4baCtcpWhVJKn.png)

响应拦截器: 自动提示所有的请求报错信息

复制代码
 // ====封装 axios代码实现模块化====

    
 // 1.导入
    
 import axios from 'axios'
    
 import {ElMessage} from 'element-plus'
    
 // 2.创建一个Axios的app
    
 const request = axios.create({
    
     // 定义基本 URL
    
     baseURL: 'http://192.168.20.110:8000/api/v1/',
    
     // 设置超时
    
     timeout: 5000,
    
     
    
 })
    
  
    
 // ====请求拦截器(发请求request)基于上边创建的request====
    
 request.interceptors.request.use(
    
     (config: any) => {
    
     // 获取本地loalstorage中的toten
    
     let token = localStorage.getItem('toten')
    
     // 判断是否有token
    
     if(token) {
    
         // 如果有token,就在请求头中添加token
    
         config.headers.common['token'] = token
    
     }
    
     // 返回
    
     return config
    
     },
    
     (error: any) => {
    
     Promise.reject(error);
    
     },
    
 );
    
  
    
 // ====响应拦截器(反馈response) 基于上边创建的request====
    
 request.interceptors.response.use(
    
     (response: any) => response,
    
     (error: any) => {
    
     if (error && error.response) {
    
         error.data = {};
    
         switch (error.response.status) {
    
             case 400:
    
                 error.data.msg = '错误请求';
    
                 ElMessage.error(error.data.msg)
    
                 break
    
             case 401:
    
                 error.data.msg = '未授权,请重新登录';
    
                 ElMessage.error(error.data.msg)
    
                 break
    
             case 403:
    
                 error.data.msg = '拒绝访问';
    
                 ElMessage.error(error.data.msg)
    
                 break
    
             case 404:
    
                 error.data.msg = '请求错误,未找到该资源';
    
                 ElMessage.error(error.data.msg)
    
                 break
    
             case 405:
    
                 error.data.msg = '请求方法未允许';
    
                 ElMessage.error(error.data.msg)
    
                 break
    
             case 408:
    
                 error.data.msg = '请求超时';
    
                 ElMessage.error(error.data.msg)
    
                 break
    
             case 500:
    
                 error.data.msg = '服务器端出错';
    
                 ElMessage.error(error.data.msg)
    
                 break
    
             case 501:
    
                 error.data.msg = '网络未实现';
    
                 ElMessage.error(error.data.msg)
    
                 break
    
             case 502:
    
                 error.data.msg = '网络错误';
    
                 ElMessage.error(error.data.msg)
    
                 break
    
             case 503:
    
                 error.data.msg = '服务不可用';
    
                 ElMessage.error(error.data.msg)
    
                 break
    
             case 504:
    
                 error.data.msg = '网络超时';
    
                 ElMessage.error(error.data.msg)
    
                 break
    
             case 505:
    
                 error.data.msg = 'http版本不支持该请求';
    
                 ElMessage.error(error.data.msg)
    
                 break
    
             default:
    
                 error.data.msg = `连接错误${error.response.status}`;
    
                 ElMessage.error(error.data.msg)
    
         }
    
     } else {
    
         error.data.msg = "连接到服务器失败";
    
         ElMessage.error(error.data.msg)
    
     }
    
     return Promise.reject(error);
    
     }
    
 );
    
 // 3.暴露
    
 export default request 
    
    
    
    
    TypeScript
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-18/IK4F7VBOenP6t5mbSHhoc3ApETC9.png)

3.信息弹出层的布局和数据填充实现

  • 信息弹出层实现
复制代码
 // ========定义存储集合========

    
 var Data = reactive({
    
     // 定义输入的查询条件
    
     q_str: ref(""),
    
     // 存储从后台获取的所有院系信息
    
     FacultyOptions: reactive([
    
     { id:"",name:""}, 
    
     ]),
    
     // 存储选择院系后的值
    
     FacultySelected: ref(""),
    
  
    
      // 存储从后台获取的所有专业信息
    
      MajorOptions: reactive([
    
      {
    
       id: "",
    
       name: ""
    
     },
    
     ]),
    
     // 存储选择专业后的值
    
     MajorSelected: ref(""),
    
     // ===表格区域定义====
    
     students: reactive([
    
     
    
     ]),
    
     // =====分页====
    
     // 当前页
    
     currentsPage: ref(1),
    
     // 每页显示的数据量
    
     pageSize: ref(15),
    
     // 总数据量所有记录条数
    
     total: ref(0),
    
     // =====弹出层-----
    
     dialogFormVisible: ref(false),
    
 });
    
 // ====弹出层(顶部添加按钮)====
    
 const addStudent = () => {
    
   Data.dialogFormVisible = true;
    
 }
    
  
    
     
    
  
    
 <!-- 4.弹出层 -->
    
     <el-dialog v-model="Data.dialogFormVisible" title="学生信息" width="40%">
    
     <el-form :inline="true">
    
       <el-form-item label="学号:">
    
     <el-input placeholder="请输入" />
    
       </el-form-item>
    
       <el-form-item label="姓名:">
    
     <el-input placeholder="请输入" />
    
       </el-form-item>
    
       <el-form-item label="性别:" style="width: 20%;">
    
     <el-select placeholder="请选择">
    
       <el-option label="男" value="shanghai" />
    
       <el-option label="女" value="beijing" />
    
     </el-select>
    
       </el-form-item>
    
     
    
       <!-- 动态获取院系信息 -->
    
     <el-form-item style="width: 32%;" label="院系:">
    
       <el-select v-model="Data.FacultySelected" placeholder="请选择院系" clearable filterable @change="getMajors">
    
     <el-option 
    
     v-for="item in Data.FacultyOptions"
    
     :key="item.id"
    
     :label="item.name"
    
     :value="item.id" />
    
     <!-- <el-option label="Zone one" value="shanghai" />
    
     <el-option label="Zone two" value="beijing" /> -->
    
       </el-select>
    
     </el-form-item>
    
     <!-- 动态获取专业信息 -->
    
     <el-form-item style="width: 32%;" label="专业:">
    
       <el-select v-model="Data.MajorSelected" placeholder="请选择专业" clearable filterable>
    
     <el-option 
    
     v-for="item in Data.MajorOptions"
    
     :key="item.id"
    
     :label="item.name"
    
     :value="item.id" />
    
     <!-- <el-option label="Zone one" value="shanghai" />
    
     <el-option label="Zone two" value="beijing" /> -->
    
       </el-select>
    
     </el-form-item>
    
    
    
     <el-form-item label="电话:">
    
       <el-input placeholder="请输入" />
    
     </el-form-item>
    
     <el-form-item label="邮箱:">
    
       <el-input placeholder="请输入" />
    
     </el-form-item>
    
      <!-- 日期 -->
    
      <el-form-item style="width: 32%;" label="出生日期:">
    
       <el-date-picker
    
     type="date"
    
     placeholder="请选择日期"
    
     clearable
    
       />
    
     </el-form-item>
    
     <el-form-item style="width: 57%;" label="家庭住址:">
    
       <el-input  type="textarea" />
    
     </el-form-item>
    
     </el-form>
    
     <template #footer>
    
       <div class="dialog-footer">
    
     <el-button>取消</el-button>
    
     <el-button>提交</el-button>
    
       </div>
    
     </template>
    
   </el-dialog>
    
    
    
    
    TypeScript
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-18/MdRDx8Q2ZG5OjrnNfAbsJ6SThqlw.png)
  • 优化弹出层展示实现
复制代码
  
    
 // 弹出层定义
    
 // 定义存储集合
    
 var Data = reactive({
    
     // =====弹出层-----
    
     dialogFormVisible: ref(false),
    
     // 定义弹出层标题
    
     layerTitle: ref(""),
    
     // 定义表单双向绑定的值
    
     studentform: reactive({
    
       sno: ref(""),
    
       name: ref(""),
    
       gender: ref(""),
    
       birthday: ref(""),
    
       faculty: reactive({
    
     // 存储从后台获取的所有院系信息
    
     FacultyOptions: reactive([
    
       { id:"",name:""}, 
    
     ]),
    
     // 存储选择院系后的值
    
     FacultySelected: ref(""),
    
     }),
    
       major: reactive({
    
     // 存储从后台获取的所有专业信息
    
     MajorOptions: reactive([
    
     {
    
       id: "",
    
       name: ""
    
     },
    
     ]),
    
     // 存储选择专业后的值
    
     MajorSelected: ref(""),
    
     }),
    
       mobile: ref(""),
    
       email: ref(""),
    
       address: ref(""),
    
     })
    
 })
    
  
    
 // ====弹出层(顶部添加按钮)====
    
 const addStudent = () => {
    
   Data.dialogFormVisible = true;
    
   // 修改标题
    
   Data.layerTitle = '【添加学生信息】'
    
 }
    
  
    
 // *************************
    
 // 获取所有院系信息
    
 const getFacultysTC = ()=> {
    
   
    
   // 请求
    
   indexApi.facultysApi.getAll().then((res)=>{
    
     // console.log(res.data)
    
     Data.studentform.faculty.FacultyOptions = res.data.results;
    
   })
    
 };
    
 // 获取院系对应的专业信息
    
 const getMajorsTC = () => {
    
   // 准备条件
    
   let params = {
    
     // http://192.168.20.110:8000/api/v1/majors/?name=&faculty=1
    
     name:'',
    
     faculty: Data.studentform.faculty.FacultySelected
    
   }
    
   // 请求
    
   indexApi.majorsApi.getAll(params).then((res)=>{
    
     // console.log(res.data.results)
    
     Data.studentform.major.MajorOptions = res.data.results;
    
   })
    
 };
    
  
    
  
    
 // 关闭弹出层
    
 const closeLayer = () => {
    
   Data.dialogFormVisible = false;
    
 }
    
  
    
  
    
 // 定义页面加载时自动执行的函数
    
 const autoRun= () => {
    
     // 获取所有信息
    
     getStudents() 
    
     // 获取院系填充信息
    
     getFacultys()
    
     // 获取弹出层院系填充信息
    
     getFacultysTC()
    
 }
    
 // 调用自动执行函数执行
    
 autoRun() 
    
  
    
  
    
 // 动态标题绑定
    
 <!-- 标题 -->
    
 <template #title>
    
     <div style="font-size: 18px; color: #409eff; font-weight: bold; text-align: left">{{ Data.layerTitle}}</div>
    
 </template>
    
  
    
 // 表单数据显示
    
 <!-- 4.弹出层 -->
    
     <el-dialog v-model="Data.dialogFormVisible" width="40%">
    
       <!-- 标题 -->
    
    <template #title>
    
       <div style="font-size: 18px; color: #409eff; font-weight: bold; text-align: left">{{ Data.layerTitle}}</div>
    
    </template>
    
     <!--先在form上绑定 Data.studentform  -->
    
     <el-form v-model="Data.studentform" :inline="true">
    
       <!-- 然后在每一个值上进行绑定 -->
    
       <el-form-item label="学号:">
    
     <el-input v-model="Data.studentform.sno" placeholder="请输入" />
    
       </el-form-item>
    
       <el-form-item label="姓名:">
    
     <el-input v-model="Data.studentform.name" placeholder="请输入" />
    
       </el-form-item>
    
       <el-form-item label="性别:" style="width: 20%;">
    
     <el-select v-model="Data.studentform.gender" placeholder="请选择">
    
       <el-option label="男" value="shanghai" />
    
       <el-option label="女" value="beijing" />
    
     </el-select>
    
       </el-form-item>
    
     
    
       <!-- 动态获取院系信息 -->
    
     <el-form-item style="width: 32%;" label="院系:">
    
       <el-select v-model="Data.studentform.faculty.FacultySelected" placeholder="请选择院系" clearable filterable @change="getMajorsTC">
    
     <el-option 
    
     v-for="item in Data.studentform.faculty.FacultyOptions"
    
     :key="item.id"
    
     :label="item.name"
    
     :value="item.id" />
    
     <!-- <el-option label="Zone one" value="shanghai" />
    
     <el-option label="Zone two" value="beijing" /> -->
    
       </el-select>
    
     </el-form-item>
    
     <!-- 动态获取专业信息 -->
    
     <el-form-item style="width: 32%;" label="专业:">
    
       <el-select v-model="Data.studentform.major.MajorSelected" placeholder="请选择专业" clearable filterable>
    
     <el-option 
    
     v-for="item in Data.studentform.major.MajorOptions"
    
     :key="item.id"
    
     :label="item.name"
    
     :value="item.id" />
    
     <!-- <el-option label="Zone one" value="shanghai" />
    
     <el-option label="Zone two" value="beijing" /> -->
    
       </el-select>
    
     </el-form-item>
    
    
    
     <el-form-item label="电话:">
    
       <el-input v-model="Data.studentform.mobile" placeholder="请输入" />
    
     </el-form-item>
    
     <el-form-item label="邮箱:">
    
       <el-input v-model="Data.studentform.email" placeholder="请输入" />
    
     </el-form-item>
    
      <!-- 日期 -->
    
      <el-form-item style="width: 32%;" label="出生日期:">
    
       <el-date-picker
    
     type="date"
    
     placeholder="请选择日期"
    
     clearable
    
     v-model="Data.studentform.birthday"
    
       />
    
     </el-form-item>
    
     <el-form-item style="width: 57%;" label="家庭住址:">
    
       <el-input v-model="Data.studentform.address"  type="textarea" />
    
     </el-form-item>
    
     </el-form>
    
     <template #footer>
    
       <div class="dialog-footer">
    
     <el-button @click="closeLayer">取消</el-button>
    
     <el-button>提交</el-button>
    
       </div>
    
     </template>
    
   </el-dialog>
    
    
    
    
    TypeScript
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-18/k1B9bQUfJXh3SImnRtrG0L6oVwjF.png)
  • 三种状态加载弹出层实现
复制代码
 var Data = reactive({

    
     // 弹出层中表单元素是否可编辑定义
    
     isView: ref(false), // 是否为查看状态 默认不是
    
     sEdit: ref(false), // 是否为编辑状态 默认不是
    
 })
    
  
    
 // 查看信息
    
 const viewStudent = (row: any) => {
    
   Data.dialogFormVisible = true;
    
   // 修改标题
    
   Data.layerTitle = '【查看学生信息】'
    
   // 编辑状态
    
   Data.isEdit = false
    
   // 查看状态
    
   Data.isView = true
    
 }
    
  
    
 // 编辑信息
    
  const editStudent = (row: any) => {
    
   Data.dialogFormVisible = true;
    
   // 修改标题
    
   Data.layerTitle = '【编辑学生信息】'
    
   // 编辑状态
    
   Data.isEdit = true
    
   // 查看状态
    
   Data.isView = false
    
 }
    
  
    
  
    
 <!-- 按钮区域 -->
    
 <el-table-column label="操作" align="center">
    
     <el-button type="primary" :icon="More" @click="viewStudent" circle size="small"/>
    
     <el-button type="warning" :icon="Edit" @click="editStudent" circle size="small"/>
    
     <el-button type="danger" :icon="Delete" circle size="small"/>
    
 </el-table-column>
    
  
    
 <!-- 4.弹出层 -->
    
     <el-dialog v-model="Data.dialogFormVisible" width="40%">
    
       <!-- 标题 -->
    
    <template #title>
    
       <div style="font-size: 18px; color: #409eff; font-weight: bold; text-align: left">{{ Data.layerTitle}}</div>
    
    </template>
    
     <!--先在form上绑定 Data.studentform  -->
    
     <el-form v-model="Data.studentform" :inline="true">
    
       <!-- 然后在每一个值上进行绑定 -->
    
       <el-form-item label="学号:">
    
     <!-- 设置字段是否可编辑 :disabled="Data.isEdit || Data.isView" 若一个为 True则输入框即为禁用状态 -->
    
     <el-input v-model="Data.studentform.sno" :disabled="Data.isEdit || Data.isView" placeholder="请输入" />
    
       </el-form-item>
    
       <el-form-item label="姓名:">
    
     <el-input v-model="Data.studentform.name" :disabled="Data.isView" placeholder="请输入" />
    
       </el-form-item>
    
       <el-form-item label="性别:" style="width: 20%;">
    
     <el-select v-model="Data.studentform.gender" :disabled="Data.isView" placeholder="请选择">
    
       <el-option label="男" value="shanghai" />
    
       <el-option label="女" value="beijing" />
    
     </el-select>
    
       </el-form-item>
    
     
    
       <!-- 动态获取院系信息 -->
    
     <el-form-item style="width: 32%;" label="院系:">
    
       <el-select v-model="Data.studentform.faculty.FacultySelected" :disabled="Data.isView" placeholder="请选择院系" clearable filterable @change="getMajorsTC">
    
     <el-option 
    
     v-for="item in Data.studentform.faculty.FacultyOptions"
    
     :key="item.id"
    
     :label="item.name"
    
     :value="item.id" />
    
     <!-- <el-option label="Zone one" value="shanghai" />
    
     <el-option label="Zone two" value="beijing" /> -->
    
       </el-select>
    
     </el-form-item>
    
     <!-- 动态获取专业信息 -->
    
     <el-form-item style="width: 32%;" label="专业:">
    
       <el-select v-model="Data.studentform.major.MajorSelected" :disabled="Data.isView" placeholder="请选择专业" clearable filterable>
    
     <el-option 
    
     v-for="item in Data.studentform.major.MajorOptions"
    
     :key="item.id"
    
     :label="item.name"
    
     :value="item.id" />
    
     <!-- <el-option label="Zone one" value="shanghai" />
    
     <el-option label="Zone two" value="beijing" /> -->
    
       </el-select>
    
     </el-form-item>
    
    
    
     <el-form-item label="电话:">
    
       <el-input v-model="Data.studentform.mobile" :disabled="Data.isView" placeholder="请输入" />
    
     </el-form-item>
    
     <el-form-item label="邮箱:">
    
       <el-input v-model="Data.studentform.email" :disabled="Data.isView" placeholder="请输入" />
    
     </el-form-item>
    
      <!-- 日期 -->
    
      <el-form-item style="width: 32%;" label="出生日期:">
    
       <el-date-picker
    
     type="date"
    
     placeholder="请选择日期"
    
     clearable
    
     v-model="Data.studentform.birthday"
    
     :disabled="Data.isView"
    
       />
    
     </el-form-item>
    
     <el-form-item style="width: 57%;" label="家庭住址:">
    
       <el-input v-model="Data.studentform.address" :disabled="Data.isView"  type="textarea" />
    
     </el-form-item>
    
     </el-form>
    
     <template #footer>
    
       <div class="dialog-footer">
    
     <el-button @click="closeLayer">取消</el-button>
    
     <el-button v-show="!Data.isView">提交</el-button>
    
       </div>
    
     </template>
    
   </el-dialog>
    
    
    
    
    TypeScript
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-18/dFzLJBNeVRxXPWsfHY8EDhvy1Ora.png)
  • 实现填充数据到弹出层
复制代码
 var Data = reactive({

    
     // 定义表单双向绑定的值
    
     studentform: reactive({
    
       sno: ref(""),
    
       name: ref(""),
    
       gender: ref(""),
    
       birthday: ref(""),
    
       faculty: ref(""),
    
       major: ref(""),
    
       mobile: ref(""),
    
       email: ref(""),
    
       address: ref(""),
    
     }),
    
     // 弹出层中表单元素是否可编辑定义
    
     isView: ref(false), // 是否为查看状态 默认不是
    
     isEdit: ref(false), // 是否为编辑状态 默认不是
    
 });
    
  
    
 // 查看学生信息
    
 const viewStudent = (row: any) => {
    
   // 设定标题
    
   Data.layerTitle = "【查看学生信息】";
    
   // 设为查看
    
   Data.isView = true;
    
   // 可见
    
   Data.dialogFormVisible = true;
    
   // 当前行赋值为studentForm -- 深拷贝
    
   Data.studentform = JSON.parse(JSON.stringify(row));
    
 };
    
  
    
 // 编辑学生信息
    
 const editStudent = (row: any) => {
    
   // 设定标题
    
   Data.layerTitle = "【编辑学生信息】";
    
   // 设为编辑
    
   Data.isEdit = true;
    
   // 可见
    
   Data.dialogFormVisible = true;
    
   // 当前行赋值为studentForm -- 深拷贝
    
   console.log(row)
    
   // Data.studentform = row
    
   Data.studentform = JSON.parse(JSON.stringify(row));
    
 };
    
  
    
  
    
 // 关闭弹出层
    
 const closeLayer = () => {
    
   Data.dialogFormVisible = false;
    
   // 编辑和查看设置为False
    
   Data.isEdit = false;
    
   Data.isView = false;
    
   // 初始化表单
    
   Data.studentform.sno = "";
    
   Data.studentform.name = "";
    
   Data.studentform.gender = "";
    
   Data.studentform.birthday = "";
    
   Data.studentform.major = "";
    
   Data.studentform.faculty = "";
    
   Data.studentform.mobile = "";
    
   Data.studentform.email = "";
    
   Data.studentform.address = "";
    
 }
    
  
    
 <!-- 按钮区域 -->
    
 <el-table-column label="操作" align="center">
    
     <template #default="scope">
    
     <el-button type="primary" :icon="More" @click="viewStudent(scope.row)" circle size="small"/>
    
     <el-button type="warning" :icon="Edit" @click="editStudent(scope.row)" circle size="small"/>
    
     <el-button type="danger" :icon="Delete" circle size="small"/>
    
     </template>
    
 </el-table-column>
    
  
    
 <!-- 弹出层 -->
    
 <el-dialog v-model="Data.dialogFormVisible" width="40%" @close="closeLayer">
    
     <!-- 标题部分 -->
    
     <template #title>
    
       <div style="font-size: 18px; color: #409eff; font-weight: bold; text-align: left">
    
     {{ Data.layerTitle }}
    
       </div>
    
     </template>
    
  
    
  
    
     <el-form
    
       :model="Data.studentform"
    
       :inline="true"
    
       label-width="100px"
    
       ref="studentFormRef"
    
     >
    
       <el-form-item label="学号:" prop="sno">
    
     <el-input
    
       v-model="Data.studentform.sno"
    
       :disabled="Data.isEdit || Data.isView"
    
       :suffix-icon="Edit"
    
       placeholder="请输入"
    
     />
    
       </el-form-item>
    
       <el-form-item label="姓名:" prop="name">
    
     <el-input
    
       v-model="Data.studentform.name"
    
       :disabled="Data.isView"
    
       :suffix-icon="Edit"
    
       placeholder="请输入"
    
     />
    
       </el-form-item>
    
       <el-form-item label="性别:" style="width: 43%;" prop="gender">
    
     <el-select
    
       v-model="Data.studentform.gender"
    
       :disabled="Data.isView"
    
       placeholder="请选择"
    
     >
    
       <el-option label="男" value="男" />
    
       <el-option label="女" value="女" />
    
     </el-select>
    
       </el-form-item>
    
       <el-form-item label="出生日期:" prop="birthday" >
    
     <el-date-picker
    
       v-model="Data.studentform.birthday"
    
       type="date"
    
       placeholder="选择日期"
    
       style="width: 212px"
    
       :disabled="Data.isView"
    
       value-format="YYYY-MM-DD"
    
     ></el-date-picker>
    
       </el-form-item>
    
    
    
       <el-form-item label="电话:" prop="mobile">
    
     <el-input
    
       v-model="Data.studentform.mobile"
    
       :disabled="Data.isView"
    
       :suffix-icon="Edit"
    
       placeholder="请输入"
    
     />
    
       </el-form-item>
    
       <el-form-item label="邮箱:" prop="email">
    
     <el-input
    
       v-model="Data.studentform.email"
    
       :disabled="Data.isView"
    
       :suffix-icon="Edit"
    
       placeholder="请输入"
    
     />
    
       </el-form-item>
    
       <el-form-item label="家庭住址:" prop="address">
    
     <el-input
    
       v-model="Data.studentform.address"
    
       :suffix-icon="Edit"
    
       style="width: 555px"
    
       :disabled="Data.isView"
    
       placeholder="请输入"
    
     ></el-input>
    
       </el-form-item>
    
     </el-form>
    
     <template #footer>
    
       <span class="dialog-footer">
    
     <el-button type="primary" v-show="!Data.isView">提交</el-button>
    
     <el-button @click="closeLayer">取消</el-button>
    
       </span>
    
     </template>
    
   </el-dialog>
    
    
    
    
    TypeScript
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-18/Jnb8EAdG6NOMSBFj2XaTwfe47hut.png)
  • Cascader级联选择器使用
复制代码
 // *******后端取消默认分页 views.py*******

    
  
    
 # 学院视图
    
 class FacultyViewSet(ModelViewSet):
    
     queryset = Faculty.objects.all()
    
     serializer_class = FacultySerializer
    
     # 取消默认分页
    
     pagination_class = None
    
  
    
 # 专业视图
    
 class MajorViewSet(ModelViewSet):
    
     queryset = Major.objects.all()
    
     print(queryset)
    
     serializer_class = MajorSerializer
    
     # 取消默认分页
    
     pagination_class = None
    
    
    
    
    TypeScript
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-18/igMd4nYk1Q7cxE0LfOyGPJUauNIr.png)
复制代码
 // *********前端*********

    
  
    
 var Data = reactive({
    
 // 弹出层级联选择器定义
    
 layerFacultyMajor: reactive([]),
    
 // 弹出层选中的专业
    
 layerMajorSelected: ref(""),
    
 })
    
  
    
  
    
  
    
  
    
 // 查看学生信息
    
 const viewStudent = (row: any) => {
    
   // 设定标题
    
   Data.layerTitle = "【查看学生信息】";
    
   // 设为查看
    
   Data.isView = true;
    
   // 可见
    
   Data.dialogFormVisible = true;
    
   // 当前行赋值为studentForm -- 深拷贝
    
   Data.studentform = JSON.parse(JSON.stringify(row));
    
   Data.layerMajorSelected = row.major.id
    
 };
    
  
    
 // 编辑学生信息
    
 const editStudent = (row: any) => {
    
   // 设定标题
    
   Data.layerTitle = "【编辑学生信息】";
    
   // 设为编辑
    
   Data.isEdit = true;
    
   // 可见
    
   Data.dialogFormVisible = true;
    
   // 当前行赋值为studentForm -- 深拷贝
    
   console.log(row)
    
   // Data.studentform = row
    
   Data.studentform = JSON.parse(JSON.stringify(row));
    
   Data.layerMajorSelected = row.major.id
    
 };
    
  
    
  
    
 // 关闭弹出层
    
 const closeLayer = () => {
    
   Data.dialogFormVisible = false;
    
   // 编辑和查看设置为False
    
   Data.isEdit = false;
    
   Data.isView = false;
    
   // 初始化表单
    
   Data.studentform.sno = "";
    
   Data.studentform.name = "";
    
   Data.studentform.gender = "";
    
   Data.studentform.birthday = "";
    
   Data.studentform.major = "";
    
   Data.studentform.faculty = "";
    
   Data.studentform.mobile = "";
    
   Data.studentform.email = "";
    
   Data.studentform.address = "";
    
   // 初始化表单专业的而选择
    
   Data.layerMajorSelected = "";
    
 }
    
 // 构建弹出层树状结构的学院和专业
    
 const getTreeMajor = async () =>{
    
   // 定义集合
    
   let allFacultys = reactive([]);
    
   let allMajors = reactive([]);
    
  
    
   // 获取所有院系
    
   await indexApi.facultysApi.getAll().then((res)=>{
    
     // console.log(res.data.results)
    
     allFacultys = res.data;
    
   });
    
  
    
   // 获取所有专业
    
   await indexApi.majorsApi.getAll().then((res)=>{
    
     console.log(res)
    
     allMajors = res.data;
    
   });
    
   // 组合数据
    
   for (let faculty of allFacultys) {
    
     // 定义需要的结构
    
     var obj = reactive({
    
       value: `${faculty.id}-${faculty.name}`,
    
       label: faculty.name,
    
       children: [],
    
     });
    
     // 遍历院系填充obj的children
    
     for (let major of allMajors) {
    
       // 判断当前专业是否隶属于当前院系
    
       if (major.faculty.id === faculty.id) {
    
     //添加
    
     obj.children.push({
    
       value: major.id,
    
       label: major.name,
    
     });
    
       }
    
     }
    
  
    
     // 附加到
    
     Data.layerFacultyMajor.push(obj);
    
   }
    
 }
    
  
    
 // 定义页面加载时自动执行的函数
    
 const autoRun= () => {
    
     // 获取所有信息
    
     getStudents() 
    
     // 获取院系填充信息
    
     getFacultys()
    
     // 获取树状结构的学院和专业
    
     getTreeMajor()
    
 }
    
 // 调用自动执行函数执行
    
 autoRun() 
    
  
    
 // 定义级联标签
    
 <el-form-item label="学院/专业:">
    
 <el-cascader
    
 v-model="Data.layerMajorSelected"
    
 placeholder="选择专业"
    
 :options="Data.layerFacultyMajor"
    
 filterable
    
 style="width: 555px"
    
 :disabled="Data.isView"/>
    
 </el-form-item>
    
    
    
    
    TypeScript
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-18/UCwr5xi9GEHPNj8BOLdVKvzhXate.png)

4.表单校检

  • 表单提交前校检实现
复制代码
   // 弹出层表单的验证

    
   rules: reactive({
    
     sno: [
    
       { required: true, message: "学号不能为空", trigger: "blur" },
    
       {
    
     pattern: /^[9][5]\d{4}$/,
    
     message: "学号必须要是95开头的6位数字",
    
     trigger: "blur",
    
       },
    
     ],
    
     name: [
    
       { required: true, message: "姓名不能为空", trigger: "blur" },
    
       {
    
     pattern: /^[\u4e00-\u9fa5]{2,5}$/,
    
     message: "姓名需要2-5个汉字",
    
     trigger: "blur",
    
       },
    
     ],
    
     gender: [{ required: true, message: "性别不能为空", trigger: "blur" }],
    
     birthday: [
    
       { required: true, message: "出生日期不能为空", trigger: "blur" },
    
     ],
    
     major: [{ required: true, message: "专业信息不能为空", trigger: "blur" }],
    
     mobile: [
    
       { required: true, message: "手机号码不能为空", trigger: "blur" },
    
       {
    
     pattern: /^[1][3456789]\d{9}$/,
    
     message: "手机号码必须要符合规范",
    
     trigger: "blur",
    
       },
    
     ],
    
     email: [
    
       { required: true, message: "邮箱地址不能为空", trigger: "blur" },
    
       {
    
     pattern: /^[A-Za-z\d]+([-_.][A-Za-z\d]+)*@([A-Za-z\d]+[-.])+[A-Za-z\d]{2,4}$/,
    
     message: "邮箱地址必须要符合规范",
    
     trigger: "blur",
    
       },
    
     ],
    
     address: [{ required: true, message: "住址不能为空", trigger: "blur" }],
    
   }),
    
    
    
    
    TypeScript
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-18/NeYhc01gRViAGPJpFaQ2qzn6XBUo.png)
  • 应用到指定表单上
复制代码
 // 标签上绑定rules

    
  
    
 <el-form :model="Data.studentform" :inline="true" label-width="100px" :rules="Data.rules">
    
  
    
 // 使用 prop="" 应用在指定字段上
    
 <el-form-item label="学号:" prop="sno"></el-form-item>
    
  
    
 // 定义表单提交属性 ref="studentFormRef" 
    
 <el-form :model="Data.studentform" :inline="true" label-width="100px" ref="studentFormRef" :rules="Data.rules">
    
  
    
 // 获取当前的instance 校检规则
    
 const {proxy} = getCurrentInstance() as any
    
  
    
 // 提交按钮绑定
    
 <el-button type="primary" v-show="!Data.isView" @click="commitLayer">提交</el-button>
    
  
    
 // 弹出层表单提交
    
 const commitLayer = ()=> {
    
   // 提交
    
   proxy.$refs.studentFormRef.validate((vilid: boolean)=> {
    
     if(vilid){
    
       alert('符合要求')
    
     }
    
   })
    
 }
    
    
    
    
    TypeScript
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-18/cV1FMoLC6Kmp9wY3rDubtxIiWqzy.png)
  • 校检指定信息是否存在
复制代码
 // 校验学号是否存在

    
 const validateSNoExists = (rule: any, value: any, callback: any)=>{
    
   // 如果是修改,忽略校验
    
   if(Data.isEdit) callback();
    
     // 连接Student接口
    
     indexApi.studentApi.getAll({sno:value}).then((res)=>{
    
       // 判断是否存在
    
       if(res.data.count>0){
    
      callback(new Error("学号已存在!"))
    
       } else {
    
      callback()
    
       }
    
     })
    
 }
    
  
    
 // 添加自定义规则校检
    
 {validator: validateSNoExists, trigger: 'blur' }
    
  
    
 // 关闭弹出层中重置表单的校验 
    
 proxy.$refs.studentFormRef.resetFields();
    
    
    
    
    TypeScript
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-18/GCQe53cPH2dxX4lnL8tYraNTvbUo.png)

5.实现信息的增删改

  • 信息添加实现
复制代码
 # 后端自定义上传格式

    
 # 自定义上传定义
    
 from rest_framework.response import Response
    
 from rest_framework import status
    
  
    
 # 学生视图
    
 class StudentViewSet(ModelViewSet):
    
     queryset = Student.objects.all()
    
     serializer_class = StudentSerializer
    
     # 分页
    
     pagination_class = MyPageNumberPagination
    
  
    
     # 指定查找匹配的字段
    
     search_fields = ('sno','name','mobile','email','address')
    
  
    
     # 自定义添加格式
    
     def create(self, request, *args, **kwargs):
    
     # 接受传递的值
    
     rec = request.data
    
     # 添加
    
     try:
    
         Student.objects.create(sno= rec.get('sno'), name=rec.get('name'), gender=rec.get('gender'),birthday=rec.get('birthday'), major_id=rec.get('major'),
    
                                mobile= rec.get('mobile'), email=rec.get('email'), address=rec.get('address'),
    
                                image=rec.get('image'))
    
         return Response({'msg': '添加成功!'}, status=status.HTTP_201_CREATED)
    
     except Exception as e:
    
         return Response({'error': '添加学生失败'}, status=status.HTTP_400_BAD_REQUEST)
    
    
    
    
    python
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-18/GUtvs0896BTgrFSfQadDymnpMe5J.png)
复制代码
 // 前端定义上传数据格式

    
 // 弹出层表单提交
    
 const commitLayer = () => {
    
   // 提交
    
   proxy.$refs.studentFormRef.validate((vilid: boolean) => {
    
     if (vilid) {
    
       // 添加或者修改
    
       if(Data.isEdit){
    
     // 修改
    
       }else{
    
     // 添加选择的专业
    
     Data.studentform.major = Data.layerMajorSelected[1]
    
  
    
     // 添加
    
     indexApi.studentApi.add(Data.studentform).then((res)=>{
    
       // 重新加载数据
    
       getStudents()
    
       // 关闭弹出层 
    
       closeLayer();
    
       // 提示添加成功!
    
       ElMessage({
    
         message:"学生添加成功!",
    
         type:'success'
    
       })
    
     })
    
       }
    
     }
    
   })
    
 }
    
    
    
    
    TypeScript
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-18/BlmsHwvpVI3xiTuh5GOqSRXkr2cD.png)
  • 信息修改实现
复制代码
 # 后端定义

    
     def update(self, request, *args, **kwargs):
    
     # 接收传递的值
    
     rec = request.data
    
     # 添加
    
     try:
    
         Student.objects.filter(pk=kwargs.get('pk')).update(name=rec.get('name'), gender=rec.get('gender'),
    
                                                            birthday=rec.get('birthday'), major_id=rec.get('major'),
    
                                                            mobile=rec.get('mobile'), email=rec.get('email'),
    
                                                            address=rec.get('address'), image=rec.get('image'))
    
         return Response({'msg': '修改成功!'}, status=status.HTTP_201_CREATED)
    
     except Exception as e:
    
         return Response({'error': '修改学生失败'}, status=status.HTTP_400_BAD_REQUEST)
    
    
    
    
    python
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-18/6V4RHT1BcQpLdS9mlDgt3ovMu8AW.png)
复制代码
 // 前端定义

    
  
    
 // 弹出层表单提交
    
 const commitLayer = () => {
    
   // 提交
    
   proxy.$refs.studentFormRef.validate((vilid: boolean) => {
    
     if (vilid) {
    
       // 判断专业是否修改
    
       if (Data.layerMajorSelected[1]){
    
       Data.studentform.major = Data.layerMajorSelected[1];
    
     } else {
    
       Data.studentform.major = Data.layerMajorSelected;
    
     }
    
       // 添加或者修改
    
       if(Data.isEdit){
    
     // 修改
    
     indexApi.studentApi.edit(Data.studentform.sno, Data.studentform).then((res)=>{
    
         if(res.status === 201){
    
           // 重新加载数据
    
           getStudents();
    
           // 关闭弹出层 
    
           closeLayer();
    
           // 提示添加成功!
    
           ElMessage({
    
             message:"学生信息修改成功!",
    
             type:'success'
    
           })
    
         }
    
       })
    
       }else{
    
     // 添加选择的专业
    
     Data.studentform.major = Data.layerMajorSelected[1]
    
  
    
     // 添加
    
     indexApi.studentApi.add(Data.studentform).then((res)=>{
    
       // 重新加载数据
    
       getStudents()
    
       // 关闭弹出层 
    
       closeLayer();
    
       // 提示添加成功!
    
       ElMessage({
    
         message:"学生添加成功!",
    
         type:'success'
    
       })
    
     })
    
       }
    
     }
    
   })
    
 }
    
    
    
    
    TypeScript
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-18/SCu2FGnWN8oxgIwPZalisdpjDhkf.png)
  • 信息删除实现
复制代码
 // 实现信息删除

    
 const studentDel=(row:any)=>{
    
   let confirmStr = "您确定要删除学生信息【学号:" + row.sno + "\t 姓名:" + row.name + "】信息吗?";
    
   ElMessageBox.confirm(confirmStr).then(()=>{
    
     // 删除
    
     indexApi.studentApi.del(row.sno).then((res)=>{
    
       if(res.status === 204){
    
     // 重新加载数据
    
     getStudents()
    
     // 提示删除成功!
    
     ElMessage({
    
       message:"学生信息删除成功!",
    
       type:'success'
    
     })
    
       }
    
     }).catch((error) => {
    
       // 请求失败
    
       console.log('失败', error)
    
       // 提示删除失败
    
       ElMessage({
    
     message:"学生信息删除失败!",
    
     type:'error'
    
       })
    
     })
    
  
    
   })
    
 }
    
  
    
 // 删除按钮点击
    
 <el-button type="danger" :icon="Delete" @click="studentDel(scope.row)" circle size="small" />
    
    
    
    
    TypeScript
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-18/NSjfPBq0V456JXkEmoW3KwybnYO9.png)

6.图片上传实现

  • 图片上传后端接口实现
复制代码
 # 通用上传文件 /apps/utils/upload.py

    
  
    
 """
    
 本模板实现文件的上传:图片,视频,excel等
    
 当前的上传任务通过upload_file实现,upload_file中有三个参数,分别为:
    
 1) file --- 提交的文件
    
 2) path --- 存储的子目录
    
 3) type --- 文件命名的类型
    
      1 ---- 时间日期 + 随机值
    
      2 ---- uuid
    
   12. 返回值描述:
    
 成功: status: True, Data: 新写入的文件名
    
 失败:status: False, error:错误描述
    
   16. """
    
 # =========== 导入模块 ===========
    
 from datetime import datetime
    
 import random
    
 import uuid
    
 from django.conf import settings
    
 import os
    
  
    
  
    
 def get_file_name_random_date():
    
     """根据日期获取随机值"""
    
     filename = datetime.now().strftime("%Y-%m-%d").replace("-", "")
    
     filename += str(random.randint(1000, 9999))
    
     return filename
    
  
    
  
    
 def update_file(file, path:str, type:int):
    
     """
    
    提供文件的上传
    
    :param file: 要上传的文件
    
    :param path: 提供的路径
    
    :param type: 随机命名的方式  1-- 时间日期随机值  2-- uuid
    
    :return:
    
    """
    
     # 定义一个new_name获取新路径
    
     new_name = ""
    
     # 判断
    
     if type == 1:
    
     new_name = get_file_name_random_date()
    
     elif type ==2:
    
     new_name = uuid.uuid4().hex
    
  
    
     # 拼接路径
    
     file_name = settings.MEDIA_ROOT + os.path.sep + path + os.path.sep + new_name + os.path.splitext(file.name)[1]
    
     # 开始写入
    
     try:
    
      f = open(file_name, 'wb')
    
      # 分多次写入
    
      for i in file.chunks():
    
          f.write(i)
    
      # 关闭
    
      f.close()
    
  
    
      # 返回
    
      return {'status': True, 'data':  new_name + os.path.splitext(file.name)[1] }
    
  
    
     except Exception as e:
    
     return {'status': False, 'error': '文件写入磁盘出现异常'}
    
    
    
    
    python
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-18/u9RXOyh6VqDCUQJsTxb2a5WKNBo4.png)
复制代码
 # 在原有的接口定义中添加自定义接口

    
  
    
 # 1.导入模块
    
 from rest_framework.decorators import action
    
 from utils import upload
    
  
    
 # 2.在student视图下定义 upload函数
    
 @action(methods=['post'], detail=False)
    
 def upload(self,request, *args, **kwargs):
    
     # 接受前台传递的文件
    
     rev_file = request.FILES.get('file')
    
     # 判断是否粗壮乃
    
     if not rev_file:
    
     return Response(status=status.HTTP_400_BAD_REQUEST)
    
     # 调用
    
     res = upload.update_file(rev_file,'images', 2)
    
     # 返回
    
     return Response(res)
    
    
    
    
    python
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-18/KDuv8ElF56XQCwqBWcx0NSUiZy7k.png)
  • 上传图片功能添加到 API
复制代码
 // 对于自定义新增接口,前端新建api接口处理

    
  
    
 // 某一类新增字段
    
  
    
 import Apibase from "./apibase";
    
 import request from "../utils/request";
    
  
    
 // 继承类
    
 export default class studentApi extends Apibase {
    
     // 构造器
    
     constructor(name: string) {
    
     super(name);
    
     }
    
     public upload = (data:any)=>{
    
     return request({
    
         method: 'post',
    
         url: `${this.name}/upload/`,
    
         data
    
     })
    
     }
    
 }
    
    
    
    
    TypeScript
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-18/EvfKzsplL7VewRT036m921WJQFGO.png)
  • 图片上传功能实现
复制代码
 const baseURL = 'http://192.168.20.110:8000/media/image/'

    
 // ==== 头像的上传 ==
    
 const uploadStudentImage = (file:any)=>{
    
    // ==== 文件在axios中一般封装在formdata类中
    
    // 1. 定义formData类
    
    let fileReq = new FormData();
    
    // 2. 把文件装在formData的容器中
    
    fileReq.append('file', file.file);
    
  
    
    // 请求 
    
    indexApi.studentApi.upload(fileReq).then((res)=>{
    
      Data.studentform.image =  baseURL + res.data.data;
    
    })
    
 }
    
  
    
 const handleAvatarSuccess =() =>{
    
   // 上传成功的回调
    
 }
    
  
    
 const beforeAvatarUpload=() =>{
    
   // 上传前的的回调
    
 }
    
  
    
  
    
 <!-- 图片的上传和展示 -->
    
     <el-upload
    
       class="avatar-uploader"
    
       :show-file-list="false"
    
       :http-request="uploadStudentImage"
    
       :on-success="handleAvatarSuccess"
    
       :before-upload="beforeAvatarUpload"
    
       style="margin: 20px auto"
    
  
    
     >
    
       <img v-if="Data.studentform.image" :src="Data.studentform.image" class="avatar" />
    
       <el-icon v-else class="avatar-uploader-icon"><plus /></el-icon>
    
     </el-upload>
    
    
    
    
    TypeScript
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-18/iy9dNXOL5uSt4HcGwbeqAmUDWTgk.png)

全部评论 (0)

还没有任何评论哟~