一步步完整搭建一个图纸管理系统(Django+Vue3)——3、前后端交互

前言: 网上Django项目要么太老,要么不全。正好手里有个需求,借这个机会用django3.2加vue3(TS)一步步完整搭建一个图纸管理系统。一方面是记录,另一方面也回馈开源精神。希望和大家一起学习一起进步。本篇为前后端交互(最近更新7.26)

经过我们前期的努力,已经完成了后端前端的编写。那么接下来就是进行积木搭建的最后一步了!前后端交互!

三、前后端交互

1、前端跨域获取后端接口数据

这里简单说下这个流程大概是什么样子的:

a:前端如何发送获取数据的请求

axios-->Ajax

前端访问地址:http://localhost:8080/

b:后端接受请求,去数据库查询数据,返回json数据给前端

DRF --> 接口

前端访问地址:http://localhost:8000

c:前端把数据展示在页面中去

那什么是跨域呢?

前端当前的地址和后端访问的地址有三个中有一个不一样,就叫跨域

a.协议:http[都一样]

b.IP地址192.168.0.1 192.168.0.2 [不一样]

c.端口8080 8000 [不一样]

1.1 跨域获取所有图纸信息

先安装axios包:npm install axios@0.26.1

如何直接运行,会发现拿不到数据,因为我们没有对跨域进行处理

先在setting.py中加入

ini 复制代码
ALLOWED_HOSTS = ['*',]

然后在manage.py中加入

python 复制代码
import os
import sys
​
​
def main():
    """Run administrative tasks."""
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'TestPlatform.settings')
    try:
        from django.core.management import execute_from_command_line
    except ImportError as exc:
        raise ImportError(
            "Couldn't import Django. Are you sure it's installed and "
            "available on your PYTHONPATH environment variable? Did you "
            "forget to activate a virtual environment?"
        ) from exc
    execute_from_command_line(sys.argv)
​
​
if __name__ == "__main__":
    from django.core.management.commands.runserver import Command as Runserver
    Runserver.default_addr = 'localhost' # 修改默认地址  
    Runserver.default_port = '8000' # 修改默认端口  
    main()

这样可以保证后端运行都在localhost:8000

我们需要安装一个插件完成跨域

ini 复制代码
pip install django-cors-headers==3.11.0

安装好后配置:

最后在settings.py中加入

ini 复制代码
# ============跨域请求=============
CORS_ALLOW_CREDENTIALS = True
CORS_ORIGIN_WHITELIST = (
    'http://localhost:8080',
)

运行后会发现可以拿到后端数据了

进行代码优化,把获取的数据放到前端页面上

效果为:

为了友好型,如果加载车成功给一个提示语句

导入

javascript 复制代码
// 导入ElementPlus
import { ElMessage,ElMessageBox } from 'element-plus'

1.2 优化信息展示

对现实数据条数优化

我们发现拿到的数据现实属于什么传感器,属于什么项目都是id不是我们要的文字,对此我们需要这样处理:

less 复制代码
'''
@Project :gveInformationSystemBE 
@File    :serializer.py
@IDE     :PyCharm 
@Author  :HXW
@Date    :2023/5/23 15:48 
'''
# ===========
from rest_framework import serializers
from DrawingManagementSystem.models import Sensor, Project, Data, Drawing
​
​
# ----Sensor序列化类----
class SensorSerialzer(serializers.ModelSerializer):
    class Meta:
        model = Sensor
        fields = "__all__"
​
# ____Project序列化类____
class ProjectSerialzer(serializers.ModelSerializer):
    sensor = SensorSerialzer()
    class Meta:
        model = Project
        fields = "__all__"
​
# ____Data序列化类____
class DataSerialzer(serializers.ModelSerializer):
    project = ProjectSerialzer()
    class Meta:
        model = Data
        fields = "__all__"
​
# ____Drawing序列化类____
class DrawingSerialzer(serializers.ModelSerializer):
    data = DataSerialzer()
    class Meta:
        model = Drawing
        fields = "__all__"

效果为:

表格过长呢?

只需要在后面加:show-overflow-tooltip="true"

ruby 复制代码
 <!-- 2.表格部分 -->
      <el-table :data="Data.drawing" 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="material_code" label="物料编号" align="center" width="180" :show-overflow-tooltip="true"/>
      <el-table-column prop="drawing_name" label="材料名称" align="center" width="160" />
      <el-table-column prop="drawing_spec" label="规格/图纸号" align="center" width="180" :show-overflow-tooltip="true"/>
      <el-table-column prop="drawing_page" label="图纸页数" align="center" width="60" />
      <el-table-column prop="drawing_client_id" label="客户编号" align="center" width="180" :show-overflow-tooltip="true"/>
      <el-table-column prop="drawing_version" label="版本号" align="center" width="70" />
      <el-table-column prop="drawing_remark" label="备注" align="center" width="180" :show-overflow-tooltip="true"/>
      <el-table-column prop="modified" label="最后上传日期" align="center" width="160" />
      <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>

2、axios请求优化(一)

如果每次调用接口都要输入一堆实在是太麻烦了,这里可以进行简化

在src根目录新建api文件如下:

新建utils文化如下:

src\utils\request.ts

javascript 复制代码
// 导入
import axios from "axios";
​
// 创建一个Axios的app
const request = axios.create({
    baseURL:'http://localhost:8000/DrawingApi/v1/',
    timeout:5000
})
​
// 请求拦截器
​
// 响应拦截器
​
// 暴露
export default request

src\api\sensors.ts

typescript 复制代码
// 导入
import request from "../utils/request";
​
// RESTful 有(获取所有,添加,获取某一个,修改,删除)
​
// 获取所有
const getAll = (params:any) => {
    // request
    return request({
        method:'get',
        url:'Sensors/',
        params
    })
}
​
// 添加
const add = (data:any) => {
    // request
    return request({
        method:'post',
        url:'Sensors/',
        data
    })
}
​
// 获取单一数据
const getOne = (id:any) => {
    // request
    return request({
        method:'get',
        url:'Sensors/${id}/',
    })
}
​
// 修改
const edit = (id:any,data:any) => {
    // request
    return request({
        method:'put',
        url:'Sensors/${id}/',
        data
    })
}
​
// 删除
const del = (id:any,data:any) => {
    // request
    return request({
        method:'delete',
        url:'Sensors/${id}/',
    })
}
​
// 暴露所有
export default{
    getAll,getOne,edit,add,del
}

src\api\projects.ts

typescript 复制代码
// 导入
import request from "../utils/request";
​
// RESTful 有(获取所有,添加,获取某一个,修改,删除)
​
// 获取所有
const getAll = (params:any) => {
    // request
    return request({
        method:'get',
        url:'Projects/',
        params
    })
}
​
// 添加
const add = (data:any) => {
    // request
    return request({
        method:'post',
        url:'Projects/',
        data
    })
}
​
// 获取单一数据
const getOne = (id:any) => {
    // request
    return request({
        method:'get',
        url:'Projects/${id}/',
    })
}
​
// 修改
const edit = (id:any,data:any) => {
    // request
    return request({
        method:'put',
        url:'Projects/${id}/',
        data
    })
}
​
// 删除
const del = (id:any,data:any) => {
    // request
    return request({
        method:'delete',
        url:'Projects/${id}/',
    })
}
​
// 暴露所有
export default{
    getAll,getOne,edit,add,del
}

src\api\datas.ts

typescript 复制代码
// 导入
import request from "../utils/request";
​
// RESTful 有(获取所有,添加,获取某一个,修改,删除)
​
// 获取所有
const getAll = (params:any) => {
    // request
    return request({
        method:'get',
        url:'Datas/',
        params
    })
}
​
// 添加
const add = (data:any) => {
    // request
    return request({
        method:'post',
        url:'Datas/',
        data
    })
}
​
// 获取单一数据
const getOne = (id:any) => {
    // request
    return request({
        method:'get',
        url:'Datas/${id}/',
    })
}
​
// 修改
const edit = (id:any,data:any) => {
    // request
    return request({
        method:'put',
        url:'Datas/${id}/',
        data
    })
}
​
// 删除
const del = (id:any,data:any) => {
    // request
    return request({
        method:'delete',
        url:'Datas/${id}/',
    })
}
​
// 暴露所有
export default{
    getAll,getOne,edit,add,del
}

src\api\drawings.ts

typescript 复制代码
// 导入
import request from "../utils/request";
​
// RESTful 有(获取所有,添加,获取某一个,修改,删除)
​
// 获取所有
const getAll = (params:any) => {
    // request
    return request({
        method:'get',
        url:'Drawings/',
        params
    })
}
​
// 添加
const add = (data:any) => {
    // request
    return request({
        method:'post',
        url:'Drawings/',
        data
    })
}
​
// 获取单一数据
const getOne = (id:any) => {
    // request
    return request({
        method:'get',
        url:'Drawings/${id}/',
    })
}
​
// 修改
const edit = (id:any,data:any) => {
    // request
    return request({
        method:'put',
        url:'Drawings/${id}/',
        data
    })
}
​
// 删除
const del = (id:any,data:any) => {
    // request
    return request({
        method:'delete',
        url:'Drawings/${id}/',
    })
}
​
// 暴露所有
export default{
    getAll,getOne,edit,add,del
}

src\api\index.ts

javascript 复制代码
// 导入所有api
import sensors from "./sensors";
import projects from "./projects";
import datas from "./datas";
import drawings from "./drawings";
​
// 封装暴露
export default{
    sensors,projects,datas,drawings,
}

引用可为:

效果还是一样的:

3、把对应信息填充到下拉框

由于我们api都写好了,那么直接调用就好了:

ini 复制代码
script区域:
// 获取所有传感器的信息
const getSensors = () => {
  return Api.sensors.getAll().then((res)=>{
    Data.sensorOptions = res.data;
  })
}
// 获取所有项目的信息
const getProjects = () => {
  return Api.projects.getAll().then((res)=>{
    Data.projectOptions = res.data;
  })
}
// 获取所有资料的信息
const getDatas = () => {
  return Api.datas.getAll().then((res)=>{
    Data.dataOptions = res.data;
  })
}
​
template 区域:
<!-- 1.查询区域 -->
      <el-form :inline="true" class="demo-form-inline" style="display: flex">
        <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.sensorSelected" placeholder="请选择传感器" clearable filterable>
            <el-option 
            v-for="item in Data.sensorOptions"
            :key="item.id"
            :label="item.sensor_name"
            :value="item.id" />
          </el-select>
        </el-form-item>
        <el-form-item label="项目:">
          <el-select v-model="Data.projectSelected" placeholder="请选择项目" clearable filterable>
             <el-option 
            v-for="item in Data.projectOptions"
            :key="item.id"
            :label="item.project_name"
            :value="item.id" />
          </el-select>
        </el-form-item>
        <el-form-item label="资料:">
          <el-select v-model="Data.dataSelected" placeholder="请选择资料" clearable filterable>
            <el-option 
            v-for="item in Data.dataOptions"
            :key="item.id"
            :label="item.data_name"
            :value="item.id" />
          </el-select>
        </el-form-item>

对了 之前表格信息不全 进行补充

ruby 复制代码
 <!-- 2.表格部分 -->
      <el-table :data="Data.drawing" 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="material_code" label="物料编号" align="center" width="180" :show-overflow-tooltip="true"/>
      <el-table-column prop="drawing_name" label="材料名称" align="center" width="160" />
      <el-table-column prop="data.project.sensor.sensor_name" label="所属传感器" align="center" width="80" :show-overflow-tooltip="true"/>
      <el-table-column prop="data.project.project_name" label="所属项目" align="center" width="80" :show-overflow-tooltip="true"/>
      <el-table-column prop="drawing_spec" label="规格/图纸号" align="center" width="180" :show-overflow-tooltip="true"/>
      <el-table-column prop="drawing_page" label="图纸页数" align="center" width="60" />
      <el-table-column prop="drawing_client_id" label="客户编号" align="center" width="100" :show-overflow-tooltip="true"/>
      <el-table-column prop="drawing_version" label="版本号" align="center" width="70" />
      <el-table-column prop="drawing_remark" label="备注" align="center" width="180" :show-overflow-tooltip="true"/>
      <el-table-column prop="modified" label="最后上传日期" align="center" width="160" />
      <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>

效果为:

4、对树进行数据填充

这边树的处理是前端拼接的,理论上由后端进行处理传给前端,前端按照层级点击后进行加载。但是这里由于项目是我一个人编写,且未来项目其实数据量不会很大。所以我这里还是以项目跑起来为主,后期再优化

scss 复制代码
// 将数据拼接成树
const getTree = () => {
  Promise.all([getSensors(), getProjects(), getDatas()]).then(() => {
    // 组合
    for(let sensors of Data.sensorOptions){
    // 定义需要的结构
    var obj = reactive({
      value:`${sensors.id}-${sensors.sensor_name}`,
      label:sensors.sensor_name,
      children:[],
      depth: 1
    }) 
    // 遍历项目填充obj的children
    for(let project of Data.projectOptions){
      if(project.sensor.id === sensors.id){
        var obj1 = reactive({
          value:project.id,
          label:project.project_name,
          children:[],
          depth: 2
        });
        for(let data of Data.dataOptions){
          if(data.project.id === project.id){
            obj1.children.push({
              value:data.id,
              label:data.data_name,
              depth: 3
            });
          }
        }
        obj.children.push(obj1)
      }
    }
    Data.treeData.push(obj)
    }
  });
​
}
​
// 定义页面加载的时候自动执行的函数
const autoRun = () => {
  // 获取所有图纸信息
  getData();
  // 获取所有传感器的信息
  getSensors();
  getProjects();
  getDatas();
  getTree();
}
​
 <!-- 侧边栏 -->
      <div class="tree-container">
        <el-tree :data="Data.treeData" @node-click="nodeClick"></el-tree>
      </div>

效果为:

思考:这里如果通过树进行搜索的话,那我搜索的下拉框其实作用就不大了,且没有层级绑定。

这边暂时不进行修改,为了更好的展示项目知识点,方便今后其他项目需要进行修改。后期系统优化时候,再进行修改。

未完待续。。。

相关推荐
前端Hardy5 分钟前
HTML&CSS: 实现可爱的冰墩墩
前端·javascript·css·html·css3
2401_8574396910 分钟前
SpringBoot框架在资产管理中的应用
java·spring boot·后端
怀旧66612 分钟前
spring boot 项目配置https服务
java·spring boot·后端·学习·个人开发·1024程序员节
阿华的代码王国32 分钟前
【SpringMVC】——Cookie和Session机制
java·后端·spring·cookie·session·会话
web Rookie35 分钟前
JS类型检测大全:从零基础到高级应用
开发语言·前端·javascript
Au_ust42 分钟前
css:基础
前端·css
帅帅哥的兜兜42 分钟前
css基础:底部固定,导航栏浮动在顶部
前端·css·css3
yi碗汤园1 小时前
【一文了解】C#基础-集合
开发语言·前端·unity·c#
就是个名称1 小时前
购物车-多元素组合动画css
前端·css
infiniteWei1 小时前
【Lucene】全文检索 vs 顺序扫描,为何建立索引比逐个文件搜索更高效?
django·全文检索·lucene