Django之入門 CMDB系統 (五) 先後端分離以前端

Django之入門 CMDB系統 (五) 先後端分離以前端


前言

做者: 何全,github地址: https://github.com/hequan2017 QQ交流羣: 620176501css

經過此教程完成從零入門,可以獨立編寫一個簡單的CMDB系統。html

目前主流的方法開發方式,分爲2種:mvc 和 mvvc方式。本教程爲 mvvc(先後端分離)的入門教程。前端

教程項目地址: https://github.com/hequan2017/panda/vue

教程文檔地址: https://github.com/hequan2017/pandaAdminreact

說明

  • 架構框架選擇
    • vue (入門簡單,自學能夠跟着官網例子入門)
    • d2Admin (基於element,樣式外觀好看,例子較多)
  • 開發工具
    • vs code

相較於react, vue入門更簡單,基於模板語法,適合從mvc方式 按部就班到 mvvc方式。webpack

模板選擇爲 基於element的模板. iview如今已經轉爲收費方式,不太適合我的開發者練習使用。antd vue版本 沒有合適的 admin模板,因此放棄了.ios

vue-element-admin 和 d2admin 差很少,資料文檔都很是全。看我的選擇。git

demo

Django之入門 CMDB系統 (五) 先後端分離以前端

框架文檔

git clone https://github.com/d2-projects/d2-admin-start-kit

├─.DS_Store 
├─.browserslistrc ------------------- // 目標瀏覽器配置
├─.env ------------------------------ // 基礎環境變量配置
├─.env.development ------------------ // 開發模式下的環境變量配置
├─.env.netlify ---------------------- // Netlify 構建時的環境變量
├─.env.nomock ----------------------- // 無 mock 數據構建模式下的環境變量
├─.env.travis ----------------------- // Travis 構建時的環境變量
├─.eslintignore --------------------- // ESLint 的忽略目錄配置
├─.eslintrc.js ---------------------- // ESLint 的配置文件
├─.github --------------------------- // Github 配置
│ └─ISSUE_TEMPLATE ------------------ // GitHub issue 模板
├─.gitignore ------------------------ // git 的忽略配置
├─.postc***c.js --------------------- // postcss 插件設置
├─.travis.yml ----------------------- // Travis 配置文件
├─LICENSE --------------------------- // 開源協議
├─README.md ------------------------- // 介紹
├─README.zh.md ---------------------- // 中文介紹 在碼雲倉庫下自動加載這個文件
├─babel.config.js ------------------- // babel 設置
├─cdnrefresh-dirs.txt --------------- // 自動構建後在七牛 CDN 上刷新的目錄
├─d2-admin.babel -------------------- // 多國語設置軟件 BabelEdit 的項目文件
├─doc ------------------------------- // 文檔素材
│ └─image 
├─jest.config.js -------------------- // 單元測試配置
├─jsconfig.json --------------------- // 指定根文件和 JavaScript 語言服務提供的功能選項
├─package-lock.json ----------------- // 鎖定依賴版本
├─package.json ---------------------- // 項目信息和依賴
├─public ---------------------------- // 靜態資源文件夾,不通過 webpack 處理
│ ├─html ---------------------------- // 用於演示加載靜態頁面的資源
│ ├─icon.ico ------------------------ // 網站圖標
│ ├─image 
│ │ ├─baidu-pan-logo.png 
│ │ ├─loading ----------------------- // index.html 使用的加載圖標
│ │ └─theme ------------------------- // 主題圖片資源
│ │   ├─d2 
│ │   ├─line 
│ │   ├─star 
│ │   ├─tomorrow-night-blue 
│ │   └─violet 
│ ├─index.html ---------------------- // 網站的基礎頁面模板
│ ├─lib ----------------------------- // 靜態依賴
│ │ └─UEditor ----------------------- // 編輯器
│ └─markdown ------------------------ // 用於展現 Markdown 遠程加載資源的文件
├─qiniu-config ---------------------- // 用於構建展現網站的七牛設置
├─qshell ---------------------------- // 七牛 SDK
├─src ------------------------------- // 主要的代碼目錄
│ ├─App.vue ------------------------- // 項目根組件
│ ├─api ----------------------------- // 請求接口
│ ├─assets -------------------------- // 資源文件夾
│ │ ├─style ------------------------- // 樣式資源
│ │ │ ├─animate --------------------- // 頁面過渡動畫
│ │ │ ├─fixed ----------------------- // 覆蓋一些組件庫的默認樣式
│ │ │ ├─public-class.scss ----------- // 導出能夠直接使用的 class
│ │ │ ├─public.scss ----------------- // 導出全部公用的 scss 資源
│ │ │ ├─theme ----------------------- // 主題樣式相關
│ │ │ │ ├─d2 
│ │ │ │ ├─line 
│ │ │ │ ├─register.scss ------------- // 註冊全部主題樣式
│ │ │ │ ├─star 
│ │ │ │ ├─theme-base.scss ----------- // 每一個主題共用的樣式
│ │ │ │ ├─theme.scss ---------------- // 每一個主題特有的設置
│ │ │ │ ├─tomorrow-night-blue 
│ │ │ │ └─violet 
│ │ │ └─unit ------------------------ // scss 的基礎變量
│ │ └─svg-icons --------------------- // svg 圖標
│ │   ├─icons ----------------------- // 用來存放圖標的文件夾
│ │   └─index.js -------------------- // 自動導入全部符合條件的圖標
│ ├─components ---------------------- // 組件
│ │ ├─d2-container 
│ │ ├─d2-container-frame 
│ │ ├─d2-count-up 
│ │ ├─d2-highlight 
│ │ ├─d2-icon 
│ │ ├─d2-icon-select 
│ │ ├─d2-icon-svg 
│ │ ├─d2-icon-svg-select 
│ │ ├─d2-link-btn 
│ │ ├─d2-markdown 
│ │ ├─d2-mde 
│ │ ├─d2-module-index-banner 
│ │ ├─d2-module-index-menu 
│ │ ├─d2-quill 
│ │ ├─d2-ueditor 
│ │ ├─highlight-styles -------------- // 代碼高亮樣式
│ │ └─index.js ---------------------- // 組件註冊
│ ├─i18n.js ------------------------- // 國際化配置
│ ├─layout -------------------------- // 佈局
│ │ └─header-aside ------------------ // 具備頂欄加側邊欄的佈局
│ ├─libs ---------------------------- // 一些通用的方法
│ │ ├─util.cookies.js 
│ │ ├─util.db.js 
│ │ ├─util.import.development.js ---- // 開發環境下使用的頁面導入方法
│ │ ├─util.import.production.js ----- // 開發環境下使用的頁面導入方法
│ │ ├─util.js 
│ │ └─util.log.js 
│ ├─locales ------------------------- // 國際化語言配置
│ │ ├─en.json 
│ │ ├─ja.json 
│ │ ├─zh-chs.json 
│ │ └─zh-cht.json 
│ ├─main.js ------------------------- // 程序主入口
│ ├─menu ---------------------------- // 靜態的菜單數據
│ │ ├─index.js 
│ │ └─modules 
│ │   ├─demo-business.js 
│ │   ├─demo-charts.js 
│ │   ├─demo-components.js 
│ │   ├─demo-d2-crud.js 
│ │   ├─demo-element.js 
│ │   ├─demo-frame.js 
│ │   ├─demo-playground.js 
│ │   └─demo-plugins.js 
│ ├─mock 
│ │ ├─api --------------------------- // 須要註冊的接口
│ │ ├─d2-mock ----------------------- // 簡化接口註冊的工具
│ │ └─index.js ---------------------- // mock 數據自動註冊
│ ├─plugin -------------------------- // 插件
│ │ ├─axios ------------------------- // 網絡請求
│ │ ├─d2admin ----------------------- // 統一註冊系統必須的資源
│ │ ├─error ------------------------- // 錯誤攔截
│ │ ├─log --------------------------- // 日誌
│ │ └─open -------------------------- // 新窗口打開
│ ├─router -------------------------- // 路由
│ │ ├─index.js ---------------------- // 註冊路由以及設置攔截規則
│ │ ├─modules ----------------------- // 預先設置好的靜態路由
│ │ │ ├─business.js 
│ │ │ ├─charts.js 
│ │ │ ├─components.js 
│ │ │ ├─d2-crud.js 
│ │ │ ├─element.js 
│ │ │ ├─frame.js 
│ │ │ ├─playground.js 
│ │ │ └─plugins.js 
│ │ └─routes.js --------------------- // 導入全部路由
│ ├─setting.js ---------------------- // 全局設置
│ ├─store --------------------------- // vuex
│ │ ├─index.js ---------------------- // vuex 註冊主入口
│ │ └─modules ----------------------- // 模塊目錄
│ │   └─d2admin --------------------- // 系統自帶模塊,業務模塊建議在同級新建
│ │     ├─index.js ------------------ // 模塊主入口
│ │     └─modules ------------------- // 子模塊
│ │       ├─account.js -------------- // 用戶身份
│ │       ├─color.js ---------------- // 主題顏色
│ │       ├─db.js ------------------- // 本地數據庫
│ │       ├─fullscreen.js ----------- // 全屏
│ │       ├─gray.js ----------------- // 灰度模式
│ │       ├─log.js ------------------ // 日誌
│ │       ├─menu.js ----------------- // 菜單
│ │       ├─page.js ----------------- // 多頁面控制
│ │       ├─releases.js ------------- // 版本
│ │       ├─search.js --------------- // 全局搜索
│ │       ├─size.js ----------------- // 全局尺寸
│ │       ├─theme.js ---------------- // 主題
│ │       ├─transition.js ----------- // 過渡效果
│ │       ├─ua.js ------------------- // 瀏覽器信息
│ │       └─user.js ----------------- // 用戶信息
│ └─views --------------------------- // 頁面視圖
│   ├─demo -------------------------- // 演示頁面
│   │ ├─business -------------------- // 業務頁面演示
│   │ │ ├─index 
│   │ │ ├─issues 
│   │ │ └─table 
│   │ ├─charts ---------------------- // 圖表
│   │ │ ├─index 
│   │ │ └─list 
│   │ │   ├─_data 
│   │ │   ├─_mixin 
│   │ │   ├─bar 
│   │ │   ├─candle 
│   │ │   ├─funnel 
│   │ │   ├─gauge 
│   │ │   ├─heatmap 
│   │ │   ├─histogram 
│   │ │   ├─line 
│   │ │   ├─map 
│   │ │   ├─pie 
│   │ │   ├─radar 
│   │ │   ├─ring 
│   │ │   ├─sankey 
│   │ │   ├─scatter 
│   │ │   ├─tree 
│   │ │   └─waterfall 
│   │ ├─components ------------------ // 內置組件演示
│   │ │ ├─container 
│   │ │ ├─contextmenu 
│   │ │ ├─countup 
│   │ │ ├─editor-quill 
│   │ │ ├─editor-simpleMDE 
│   │ │ ├─editor-ueditor 
│   │ │ ├─highlight 
│   │ │ ├─icon 
│   │ │ ├─index 
│   │ │ ├─json-tree 
│   │ │ ├─layout 
│   │ │ └─markdown 
│   │ ├─d2-crud --------------------- // D2CRUD 表格封裝演示
│   │ ├─element --------------------- // Element UI 組件
│   │ ├─frame ----------------------- // 嵌套第三方頁面演示
│   │ ├─playground ------------------ // 試驗檯
│   │ │ ├─add-routes ---------------- // 動態添加路由
│   │ │ ├─db ------------------------ // 數據持久化
│   │ │ ├─env ----------------------- // 環境變量
│   │ │ ├─index 
│   │ │ ├─locales ------------------- // 多國語
│   │ │ ├─log ----------------------- // 日誌
│   │ │ ├─page-argu ----------------- // 頁面參數
│   │ │ ├─page-cache ---------------- // 頁面緩存
│   │ │ └─store --------------------- // 全局狀態控制
│   │ │   ├─fullscreen 
│   │ │   ├─gray 
│   │ │   ├─menu 
│   │ │   ├─page 
│   │ │   ├─size 
│   │ │   ├─theme 
│   │ │   ├─transition 
│   │ │   └─ua 
│   │ └─plugins --------------------- // 插件演示
│   │   ├─better-scroll 
│   │   ├─clipboard-polyfill 
│   │   ├─day 
│   │   ├─export 
│   │   ├─import 
│   │   ├─index 
│   │   ├─js-cookie 
│   │   └─mock 
│   └─system ------------------------ // 系統頁面
│     ├─error 
│     ├─function 
│     │ ├─redirect ------------------ // 重定向
│     │ └─refresh ------------------- // 刷新
│     ├─index 
│     ├─log 
│     └─login 
├─tests ----------------------------- // 單元測試
├─tools 
│ └─vue-filename-injector ----------- // 用於對每一個組件注入源代碼位置的插件
└─vue.config.js --------------------- // vue-cli3 的項目配置文件

登陸部分

  • src/modules/d2admin/modules/account.js #主要爲 前端登陸信息 狀態 保存和讀取
try {
      AccountLoginInfo(res.token)
        .then(resinfo => {
          const data = resinfo.data    /*  獲取後端用戶信息*/
          console.log(resinfo)
          dispatch(               
            'd2admin/user/set',
            {
              name: resinfo.name
            },
            { root: true }
          )
          resolve(data)
        })
        .catch(err => {
          reject(err)
        })
    } catch (error) {
      reject(error)
    }
  • src/api/sys.login.js # 設置獲取 token 和 info
import request from '@/plugin/axios'

export function AccountLogin (data) {
  return request({
    url: '/api/token',
    method: 'post',
    data
  })
}
export const AccountLoginInfo = token => {
  return request({
    url: '/system/api/user_info',
    data: {
      token
    },
    method: 'post'
  })
}
  • 登陸token攔截設置 src\plugin\axios\index.js
// 請求攔截器
service.interceptors.request.use(
  config => {
    // 在請求發送以前作一些處理
    const token = util.cookies.get('token')
    // 讓每一個請求攜帶token-- ['X-Token']爲自定義key 請根據實際狀況自行修改
    // config.headers[''] = token
    if (token) {
      config.headers['Authorization'] = `token ${token}`
    }
    return config
  },
  error => {
    // 發送失敗
    console.log(error)
    return Promise.reject(error)
  }
)
  • 用戶信息調用例子
import { mapState, mapActions } from 'vuex'
export default {
  computed: {
    ...mapState('d2admin/user', [
      'info'
    ])
  },

/*  info 爲 上面保存的信息,這裏能夠在用戶登陸後 直接讀取*/
{{info.name ? `你好 ${info.name}` : '未登陸'}}

增刪改查例子

  • 路由

  • src/api/sys.login.js
import request from '@/plugin/axios'

export const TestGetList = parameter => {
  return request({
    url: `/system/test?${parameter}`,
    method: 'get'
  })
}

export const TestCreate = data => {
  return request({
    url: '/system/test',
    data: data,
    method: 'post'
  })
}

export const TestGetInfo = id => {
  return request({
    url: `/system/test/${id}`,
    method: 'get'
  })
}

export const TestUpdate = (id, data) => {
  return request({
    url: `/system/test/${id}`,
    data: data,
    method: 'PUT'
  })
}

export const TestDelete = id => {
  return request({
    url: `/system/test/${id}`,
    method: 'delete'
  })
}
  • src/asset/index.vue
<template>
  <d2-container>
    <template slot="header">演示頁面</template>
    <el-input v-model="input"
              placeholder="請輸入姓名"
              style="width:200px;"
              prefix-icon="el-icon-search"
              clearable></el-input> 
    <el-button type="primary"
               icon="el-icon-search"
               @click="search">搜索</el-button>
    <br /><br />
    <d2-crud ref="d2Crud"
             :columns="columns"
             :data="data"
             add-title="資產管理"
             :add-template="addTemplate"
             :form-options="formOptions"
             :add-rules="addRules"
             :edit-rules="addRules"
             :edit-template="editTemplate"
             :rowHandle="rowHandle"
             @row-add="handleRowAdd"
             @row-edit="handleRowEdit"
             @row-remove="handleRowRemove"
             :pagination="pagination"
             @dialog-cancel="handleDialogCancel"
             @el-icon-more="handleInfo"
             @pagination-current-change="paginationCurrentChange">
      <el-button slot="header"
                 style="margin-bottom: 5px"
                 @click="addRow">新增</el-button>
    </d2-crud>
  </d2-container>
</template>

<script>

import { TestGetList, TestCreate, TestUpdate, TestDelete, TestGetInfo } from '@api/sys.login'
export default {
  data () {
    return {
      columns: [
        {
          title: '日期',
          key: 'date'
        },
        {
          title: '姓名',
          key: 'name'
        },
        {
          title: '地址',
          key: 'address'
        }
      ],
      data: [
      ],
      input: '',
      addTemplate: {
        date: {
          title: '日期',
          value: '2016-05-05'
        },
        name: {
          title: '姓名',
          value: '王小虎'
        },
        address: {
          title: '地址',
          value: '上海市普陀區金沙江路 1520 弄'
        }
      },
      formOptions: {
        labelWidth: '80px',
        labelPosition: 'left',
        saveLoading: false
      },
      pagination: {
        currentPage: 1,
        pageSize: 10,
        total: 0
      },
      addRules: {
        date: [{ required: true, message: '請輸入日期', trigger: 'blur' }],
        name: [{ required: true, message: '請輸入姓名', trigger: 'blur' }],
        address: [{ required: true, message: '請輸入地址', trigger: 'blur' }]
      },
      rowHandle: {
        columnHeader: '編輯表格',
        edit: {
          icon: 'el-icon-edit',
          type: 'primary',
          text: '編輯',
          size: 'small',
          show (index, row) {
            return true
          },
          disabled (index, row) {
            return false
          }
        },
        custom: [
          {
            text: '詳情',
            type: 'info',
            size: 'small',
            fixed: 'right',
            emit: 'el-icon-more'
          }
        ],
        remove: {
          icon: 'el-icon-delete',
          size: 'small',
          fixed: 'right',
          confirm: true,
          show (index, row) {
            return true
          },
          disabled (index, row) {
            return false
          }
        }
      },
      editTemplate: {
        date: {
          title: '日期',
          value: ''
        },
        name: {
          title: '姓名',
          value: ''
        },
        address: {
          title: '地址',
          value: ''
        },
        forbidEdit: {
          title: '禁用按鈕',
          value: false,
          component: {
            show: false
          }
        },
        showEditButton: {
          title: '顯示按鈕',
          value: true,
          component: {
            show: false
          }
        }
      }
    }
  },
  created () {
    this.test_get_list()
  },
  methods: {
    handleInfo ({ index, row }) {
      TestGetInfo(row.id).then(res => {
        this.$alert(`${res.date} ${res.address}`, `${res.name}`, {
          confirmButtonText: '肯定'
        }).catch(err => {
          console.log(`獲取信息錯誤 ${err}`)
        })
      })
    },
    test_get_list (parameter) {
      TestGetList(parameter).then(res => {
        console.log(res)
        this.data = res.results
        this.pagination.total = res.count
      }).catch(err => {
        console.log(`獲取信息錯誤 ${err}`)
      })
    },
    paginationCurrentChange (currentPage) {
      TestGetList(`page=${currentPage}`).then(res => {
        console.log(res)
        this.data = res.results
        this.pagination.total = res.count
      }).catch(err => {
        console.log(`獲取信息錯誤 ${err}`)
      })
      this.pagination.currentPage = currentPage
      // this.fetchData()
    },
    addRow () {
      this.$refs.d2Crud.showDialog({
        mode: 'add'
      })
    },
    search () {
      this.test_get_list(`name=${this.input}`)
    },
    handleRowAdd (row, done) {
      this.formOptions.saveLoading = true
      TestCreate(row).then(res => {
      }).catch(err => {
        console.log(err)
      })
      setTimeout(() => {
        this.$message({
          message: '保存成功',
          type: 'success'
        })
        done()
        this.formOptions.saveLoading = false
        this.test_get_list()
      }, 300)
    },
    handleDialogCancel (done) {
      this.$message({
        message: '取消',
        type: 'warning'
      })
      done()
    },
    handleRowEdit ({ index, row }, done) {
      this.formOptions.saveLoading = true
      this.addTemplate.data = row.data
      this.addTemplate.name = row.name
      this.addTemplate.address = row.address
      TestUpdate(row.id, row).then(res => {
      }).catch(err => {
        console.log(err)
      })
      setTimeout(() => {
        this.$message({
          message: '編輯成功',
          type: 'success'
        })
        done()
        this.formOptions.saveLoading = false
        this.test_get_list()
      }, 300)
    },
    handleRowRemove ({ index, row }, done) {
      TestDelete(row.id).then(res => {
      }).catch(err => {
        console.log(err)
      })
      setTimeout(() => {
        console.log(index)
        console.log(row)
        this.$message({
          message: '刪除成功',
          type: 'success'
        })
        done()
        this.test_get_list()
      }, 300)
    }
  }
}
</script>
  • src/router/routers.js
const frameIn = [
  {
    path: '/',
    redirect: { name: 'index' },
    component: layoutHeaderAside,
    children: [
      // 首頁
      {
        path: 'index',
        name: 'index',
        meta: {
          auth: true
        },
        component: _import('system/index')
      },
      // 演示頁面
      {
        path: 'asset',
        name: 'asset',
        meta: {
          title: '演示頁面',
          auth: true
        },
        component: _import('asset/index')
      },
      {
        path: 'log',
        name: 'log',
        meta: {
          title: '前端日誌',
          auth: true
        },
        component: _import('system/log')
      },
      // 刷新頁面 必須保留
      {
        path: 'refresh',
        name: 'refresh',
        hidden: true,
        component: _import('system/function/refresh')
      },
      // 頁面重定向 必須保留
      {
        path: 'redirect/:route*',
        name: 'redirect',
        hidden: true,
        component: _import('system/function/redirect')
      }
    ]
  }
]

部署

npm install

npm run dev

相關文章
相關標籤/搜索