vue3后台项目创建

目录

1·创建项目

别名路径联想设置

自动按需导入element-plus

element-plus主题定制

axios配置

项目整体路由设计

2·项目准备

iconfont 图标库

fontawesome图标库

3·前端路由设计

3.1.修改vite.config.js,添加server

3.2在根目录下创建.env.dev文件

3.3.修改packge.json文件的dev模式

3.4在vite.config.js将获得到的接口ip获取到

 4·admin首页设计

4.1整体效果

 4.2拆分组件

4.2.1.admin.vue

4.2.2.components/admin/aside.vue

4.2.3.components/admin/topview.vue

4.2.4.components/admin/tables.vue

4.2.5.说明以及修改内容



1·创建项目

E:\python\Django>npm init  vue@latest
Need to install the following packages:
create-vue@3.10.3
Ok to proceed? (y) y

Vue.js - The Progressive JavaScript Framework

√ 请输入项目名称: ... vue3houtaitest
√ 是否使用 TypeScript 语法? ... 否 / 是
√ 是否启用 JSX 支持? ... 否 / 是
√ 是否引入 Vue Router 进行单页面应用开发? ... 否 / 是
√ 是否引入 Pinia 用于状态管理? ... 否 / 是
√ 是否引入 Vitest 用于单元测试? ... 否 / 是
√ 是否要引入一款端到端(End to End)测试工具? » 不需要
√ 是否引入 ESLint 用于代码质量检测? ... 否 / 是
√ 是否引入 Prettier 用于代码格式化? ... 否 / 是
√ 是否引入 Vue DevTools 7 扩展用于调试? (试验阶段) ... 否 / 是

正在初始化项目 E:\python\Django\vue3houtaitest...

项目初始化完成,可执行以下命令:

  cd vue3houtaitest
  npm install
  npm run dev

npm notice
npm notice New minor version of npm available! 10.2.4 -> 10.7.0
npm notice Changelog: https://github.com/npm/cli/releases/tag/v10.7.0
npm notice Run npm install -g npm@10.7.0 to update!
npm notice

安装依赖

npm ininstall

运行项目

npm run dev

在src先创建几个常用的文件夹

  • styles --->全局样式文件夹
  • utils ---->工具函数文件夹
  • directives --->全局指令文件夹
  • composables --->组合函数文件夹
  • apis ------>API接口文件夹
别名路径联想设置

jsconfig.json

{
  "compilerOptions": {
    "paths": {
      "@/*": ["./src/*"]
    }
  },

}

vite.config.js

import { fileURLToPath, URL } from 'node:url'

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    vue(),
  ],
  resolve: {
    alias: {
      '@': fileURLToPath(new URL('./src', import.meta.url))
    }
  }
})
自动按需导入element-plus

一个 Vue 3 UI 框架 | Element Plus (element-plus.org)

1.安装element-plus

npm install element-plus --save

2.安装unplugin-vue-components 和 unplugin-auto-import这两款插件

npm install -D unplugin-vue-components unplugin-auto-import

 3.vite.config.js配置

import { fileURLToPath, URL } from 'node:url'
//ElementPlu按需导入
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    vue(),
    //配置element-plus插件
    AutoImport({
      resolvers: [ElementPlusResolver()],
    }),
    Components({
      resolvers: [ElementPlusResolver()],
    }),
  ],
  
  resolve: {
    alias: {
      '@': fileURLToPath(new URL('./src', import.meta.url))
    }
  }
})
element-plus主题定制

1.安装scss

npm i sass -D

准备定制样式文件

styles/element/index.ascc

@forward 'element-plus/theme-chalk/src/common/var.scss' with(
    $colors:(
        'primary':(
            //主色
            'base':#27ba9b
        ),
        'success':(
            //成功
            'base':#1dc779
        ),
        'warning':(
            //警告
            'base':#ffb302
        ),
        'danger':(
            //危险
            'base':#e26237
        ),
        'error':(
            //错误
            'base':#cf4444
        ),
    )
)

对ElemrntPlus样式进行覆盖

vite.config.js

import { fileURLToPath, URL } from 'node:url'
//ElementPlu按需导入
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    vue(),
    //配置element-plus插件
    AutoImport({
      resolvers: [ElementPlusResolver()],
    }),
    Components({
      //1.配置elementPlus采用样式配置系统
      resolvers: [
        ElementPlusResolver({importStyle:"sass"}),
      ],
    }),
  ],
  
  resolve: {
    alias: {
      '@': fileURLToPath(new URL('./src', import.meta.url))
    }
  },
  css:{
    preprocessorOptions:{
      scss:{
        //2.自动导入定制化样式文件进行样式覆盖
        additionalData:`
        @use "@/styles/element/index.scss" as *;
        `,
      }
    }
  }
})
axios配置

1.安装axios

npm i axios

 2.配置接基础实例

  1. 1.接口基地址
  2. 2.接口请求超时时间
  3. 3.请求拦截器
  4. 4.响应拦截

在utils文件下创建

http.js

import axios from "axios";
const httpInstance = axios.create({
    baseURL:'http://pcpai-xiaotuxian-front-devtest.ithema.net',
    timeout:400
})

//拦截器
//axios请求拦截器
httpInstance.interceptors.request.use(config=>{
    return config

},e=>Preomise.reject(e))

//axions响应式拦截器
httpInstance.interceptors.response.use(res=>res.data,e=>{
    return Promise.reject(e)
})

export default httpInstance

在apis文件下创建测试接口

testAPI.js

import httpInstance from "@/utils/http";
export function getCategory(){
    return httpInstance({
        url:'home/category/head'
    })
}
项目整体路由设计

在views文件夹下创建login,和layout文件

login文件下创建index.vue文件作为项目的登录页面

layout文件下创建index.vue和admin.vue文件,index.vue作为网站的首页界面admin作为页面后台页面的登录接口,可以在以及路由的vue文件中的中添加二级路由出口

然后在toter文件下配置index.js

//createRouter 创建路由
//createWebHistory 创建history路由
import { createRouter, createWebHistory } from 'vue-router'
import Login from '@/views/login/index.vue'
import Index from '@/views/layout/index.vue'
import Admin from "@/views/layout/admin.vue"
const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes: [
  {
    path:'/',
    component:Login
  },
  {
    path:'/index',
    component:Index
  },
  {
    path:'/admin',
    component:Admin
  }
  ]
})

export default router

在APP.vue中添加以及路由出口

<script setup>

</script>

<template>
  <!-- //一级路由出口 -->
 <RouterView></RouterView>
</template>

<style scoped>

</style>

2·项目准备

iconfont 图标库

iconfont-阿里巴巴矢量图标库

下载后保存在assets文件下并在main.js中引入

import './assets/css/iconfont.css'

fontawesome图标库

Font Awesome,一套绝佳的图标字体库和CSS框架

npm install font-awesome --save

在main.js中引入

 import "font-awesome/css/font-awesome.min.css"

3·前端路由设计

3.1.修改vite.config.js,添加server
import { fileURLToPath, URL } from 'node:url'
//ElementPlu按需导入
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'



// https://vitejs.dev/config/
export default defineConfig({
  envPrefix:["api_"],
  plugins: [
    vue(),
    //配置element-plus插件
    AutoImport({
      resolvers: [ElementPlusResolver()],
    }),
    Components({
      //1.配置elementPlus采用样式配置系统
      resolvers: [
        ElementPlusResolver({importStyle:"sass"}),
      ],
    }),
  ],
  
  resolve: {
    alias: {
      '@': fileURLToPath(new URL('./src', import.meta.url))
    }
  },
  css:{
    preprocessorOptions:{
      scss:{
        //2.自动导入定制化样式文件进行样式覆盖
        additionalData:`
        @use "@/styles/element/index.scss" as *;
        `,
      }
    }
  },
  server:{
    proxy:{
      "/uploads":{
        target:"http://127.0.0.1:8000"
      }
    }
  }

})
3.2在根目录下创建.env.dev文件
api_backend = "http://127.0.0.1:8000"
3.3.修改packge.json文件的dev模式
"scripts": {
    "dev": "vite --mode dev",
    "build": "vite build",
    "preview": "vite preview",
    "lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs --fix --ignore-path .gitignore"
  },
3.4在vite.config.js将获得到的接口ip获取到
import { fileURLToPath, URL } from 'node:url'
//ElementPlu按需导入
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
import { defineConfig, loadEnv } from 'vite'
import vue from '@vitejs/plugin-vue'


export default ({mode})=>{
  const BaseUrl = loadEnv(mode,process.cwd())
  const env = loadEnv(mode, process.cwd())
  console.log(env)
  // console.log(process)


return defineConfig({
  envPrefix:["VITE_"],
  plugins: [
    vue(),
    //配置element-plus插件
    AutoImport({
      resolvers: [ElementPlusResolver()],
    }),
    Components({
      //1.配置elementPlus采用样式配置系统
      resolvers: [
        ElementPlusResolver({importStyle:"sass"}),
      ],
    }),
  ],
  
  resolve: {
    alias: {
      '@': fileURLToPath(new URL('./src', import.meta.url))
    }
  },
  css:{
    preprocessorOptions:{
      scss:{
        //2.自动导入定制化样式文件进行样式覆盖
        additionalData:`
        @use "@/styles/element/index.scss" as *;
        `,
      }
    }
  },
  server:{
    proxy:{
      "/uploads":{
        target:BaseUrl
      }
    }
  }

})
}

 4·admin首页设计

4.1整体效果

首先将admin主要显示界面大概设计出来

我的理想样子如下: 

views/layout/admin.vue

​​<template>
  <div class="pvb_admin">
    <div class="aside">
      <div class="aside_log">
        <img src="../../../src/assets/images/logo.png">
      </div>
      <div class="aside_title">
        Double_后台
      </div>
      <div class="aside_body">
        <el-row class="tac">

          <el-col :span="24">
            <h5 class="mb-2">菜单</h5>
            <el-menu active-text-color="#ffd04b" background-color="#545c64" class="el-menu-vertical-demo"
              default-active="2" text-color="#fff" @open="handleOpen" @close="handleClose">
              <el-form v-for="menu in data.menu_list" :key="menu">
                <el-sub-menu :index="menu" v-if="menu.level === 1">
                  <template #title>
                    <el-icon>
                      <location />
                    </el-icon>
                    <span @click="goto(menu.path)"><i :class="menu.icon"></i>{{ menu.title }}</span>
                  </template>
                  <el-menu-item :index="menuitems" v-for="menuitems in menu.children" :key="menuitems.path">
                    <span @click="goto(menuitems.path)" :index="menuitems.path" v-if="menuitems.children.length === 0"><i
                        :class="menuitems.icon"></i>{{ menuitems.title }}</span>
                  </el-menu-item>
                </el-sub-menu>
              </el-form>
            </el-menu>
          </el-col>
        </el-row>
      </div>
    </div>
    <div class="main">
      <header>
        <div class="left">
          <el-breadcrumb :separator-icon="ArrowRight">
            <el-breadcrumb-item :to="{ path: '/' }">index</el-breadcrumb-item>
            <el-breadcrumb-item :to="{ path: '/admin' }">admin</el-breadcrumb-item>
            <el-breadcrumb-item :to="{ path: '/index' }">index</el-breadcrumb-item>
          </el-breadcrumb>
        </div>
        <div class="right">
          <i class="iconfont icon-tupian"></i>
          <i class="iconfont icon-suofang1"></i>
          <i class="iconfont icon-taiyang-copy"></i>
          <i class="iconfont icon-suofang"></i>
          <div class="avatar">
            <img src="../../../src/assets/images/logo.png">

          </div>
          <div class="down">
            <el-dropdown>
              <span class="el-dropdown-link">
                <i class="iconfont icon-down1"></i>
              </span>
              <template v-slot:dropdown>
                <el-dropdown-menu>
                  <el-dropdown-item>个人中心</el-dropdown-item>
                  <el-dropdown-item>退出登录</el-dropdown-item>
                </el-dropdown-menu>
              </template>
            </el-dropdown>
          </div>
        </div>

      </header>
      <div class="tabs">tabs</div>
      <main>main

      </main>
    </div>
  </div>
</template>
<script setup>
import { reactive, ref } from "vue";
console.log("sss", import.meta.env)
const data = reactive({
  menu_list: [
    {
      id: 2,
      level: 1,
      icon: "iconfont  icon-yonghu1",
      title: "用户管理",
      name: "/index",
      children: []
    },
    {
      id: 3,
      level: 1,
      icon: "iconfont  icon-tupian",
      title: "图片管理",
      path: "/admin",
      children: []
    },
    {
      id: 4,
      level: 1,
      icon: "iconfont  icon-shuju",
      title: "数据管理",
      path: "/manger",
      children: []
    },
    {
      id: 5,
      level: 1,
      icon: "iconfont  icon-xitong",
      title: "系统设置",
      path: "/system",
      children: [
        {
          id: 51,
          level: 2,
          icon: "iconfont  icon-shuju",
          title: "数据管理1",
          path: "/system/test1",
          children: []
        },
      ]
    },
  ],
})
import { useRouter } from "vue-router";
const router = useRouter()
function goto(roouter_path) {
  console.log(roouter_path, 111)
  router.push(
    roouter_path
  )
}
</script>
<style lang="scss">
.pvb_admin {
  width: 100%;
  display: flex;

  .aside {
    width: 240px;
    height: 100vh;
    background-color: #02141b;

    .aside_log {
      width: 100%;
      background-color: rgb(141, 136, 133);
      flex-direction: column;
      display: flex;
      justify-content: center;
      align-items: center;

      img {
        margin-top: 10px;
        margin-bottom: 10px;
        width: 70px;
        height: 70px;

      }
    }

    .aside_title {
      display: flex;
      justify-content: center;
      align-items: center;
    }

    .aside_body {
      margin-top: 40px;

      .mb-2 {
        display: flex;
        font-size: large;
        color: #f0eeee;
        justify-content: center;
        align-items: center;
      }

    }

  }

  .main {
    width: calc(100% - 240px);

    header {


      height: 60px;
      padding: 0 20px;
      display: flex;
      justify-content: space-between;
      align-items: center;

      .right {
        display: flex;
        justify-content: space-between;
        align-items: center;

        i {
          margin-right: 15px;
          font-size: 15px;
        }

        i:hover {
          color: #27ba9b;
        }

        img {
          width: 40px;
          height: 40px;
          border-radius: 50%;


        }

        .down {
          margin-top: 5px;
          height: auto;
        }
      }
    }

    .tabs {
      background-color: rgb(46, 49, 49);
      height: 30px;
      border: 1px solid #f0eeee;
    }

    main {
      background-color: yellowgreen;
      height: calc(100vh - 90px);
    }
  }
}
</style>
 4.2拆分组件

通过开始设计的页面进项组件拆分

4.2.1.admin.vue
<template>
  <div class="pvb_admin">
    <Aside></Aside>
    <div class="main">
      <Topview></Topview>

      <Tables></Tables>
      <main>
        <!-- //admin路由出口 -->
        <RouterView></RouterView>
      </main>
    </div>
  </div>
</template>
<script setup>
import Aside from "@/components/admin/aside.vue"
import Topview from "@/components/admin/topview.vue"
import Tables from "@/components/admin/tables.vue"

</script>
<style lang="scss">
.pvb_admin {
  width: 100%;
  display: flex;

  .main {
    width: calc(100% - 240px);

    main {
      background-color: yellowgreen;
      height: calc(100vh - 90px);
    }
  }
}
</style>

 其中有aside,topview,tables组件,分别对应左侧菜单栏,顶部信息栏,中间tabls路由导航栏

分别在components/admin下创建组件文件

4.2.2.components/admin/aside.vue
<template>
  <div class="aside">
    <div class="aside_log">
      <img src="../../../src/assets/images/logo.png">
    </div>
    <div class="aside_title">
      Double_后台
    </div>
    <div class="aside_body">
      <el-row class="tac">
        <el-col :span="24">
          <h5 class="mb-2">菜单</h5>
          <el-menu active-text-color="#ffd04b" background-color="#545c64" class="el-menu-vertical-demo"
            default-active="2" text-color="#fff" @open="handleOpen" @close="handleClose">
            <el-form v-for="menu in data.menu_list" :key="menu">
              <el-sub-menu :index="menu" v-if="menu.level === 1">
                <template #title>
                  <el-icon>
                    <location />
                  </el-icon>
                  <span @click="goto(menu.path)"><i :class="menu.icon"></i>{{ menu.title }}</span>
                </template>
                <el-menu-item :index="menuitems" v-for="menuitems in menu.children" :key="menuitems.path">
                  <span @click="goto(menuitems.path)" :index="menuitems.path" v-if="menuitems.children.length === 0"><i
                      :class="menuitems.icon"></i>{{ menuitems.title }}</span>
                </el-menu-item>
              </el-sub-menu>
            </el-form>
          </el-menu>
        </el-col>
      </el-row>
    </div>
  </div>
</template>

<script setup>
import { reactive } from "vue";

const data = reactive({
  menu_list: [
    {
      id: 2,
      level: 1,
      icon: "iconfont  icon-yonghu1",
      title: "用户管理",
      path: "/admin/user_list",
      children: []
    },
    {
      id: 3,
      level: 1,
      icon: "iconfont  icon-tupian",
      title: "图片管理",
      path: "/admin/image_list",
      children: []
    },
    {
      id: 4,
      level: 1,
      icon: "iconfont  icon-shuju",
      title: "数据管理",
      path: "/admin/data_list",
      children: []
    },
    {
      id: 5,
      level: 1,
      icon: "iconfont  icon-xitong",
      title: "系统设置",
      path: "/admin/system",
      children: [
        {
          id: 51,
          level: 2,
          icon: "iconfont  icon-shuju",
          title: "数据管理1",
          path: "/admin/system_info",
          children: []
        },
      ]
    },
  ],
})
import { useRouter } from "vue-router";
const router = useRouter()
function goto(roouter_path) {
  router.push(
    roouter_path
  )
}
</script>
<style lang="scss">
.aside {
  width: 240px;
  height: 100vh;
  background-color: #02141b;

  .aside_log {
    width: 100%;
    background-color: rgb(141, 136, 133);
    flex-direction: column;
    display: flex;
    justify-content: center;
    align-items: center;

    img {
      margin-top: 10px;
      margin-bottom: 10px;
      width: 70px;
      height: 70px;

    }
  }

  .aside_title {
    display: flex;
    justify-content: center;
    align-items: center;
  }

  .aside_body {
    margin-top: 40px;

    .mb-2 {
      display: flex;
      font-size: large;
      color: #f0eeee;
      justify-content: center;
      align-items: center;
    }

  }

}
</style>
4.2.3.components/admin/topview.vue
<template>
  <header>
    <div class="left">
      <el-breadcrumb :separator-icon="ArrowRight">
        <el-breadcrumb-item :to="{ path: '/' }">index</el-breadcrumb-item>
        <el-breadcrumb-item :to="{ path: '/admin' }">admin</el-breadcrumb-item>
        <el-breadcrumb-item :to="{ path: '/index' }">index</el-breadcrumb-item>
      </el-breadcrumb>
    </div>
    <div class="right">
      <i class="iconfont icon-tupian"></i>
      <i class="iconfont icon-suofang1"></i>
      <i class="iconfont icon-taiyang-copy"></i>
      <i class="iconfont icon-suofang"></i>
      <div class="avatar">
        <img src="../../../src/assets/images/logo.png">

      </div>
      <div class="down">
        <el-dropdown>
          <span class="el-dropdown-link">
            <i class="iconfont icon-down1"></i>
          </span>
          <template v-slot:dropdown>
            <el-dropdown-menu>
              <el-dropdown-item>个人中心</el-dropdown-item>
              <el-dropdown-item>退出登录</el-dropdown-item>
            </el-dropdown-menu>
          </template>
        </el-dropdown>
      </div>
    </div>
  </header>
</template>

<script setup>
</script>
<style lang="scss">
header {


  height: 60px;
  padding: 0 20px;
  display: flex;
  justify-content: space-between;
  align-items: center;

  .right {
    display: flex;
    justify-content: space-between;
    align-items: center;

    i {
      margin-right: 15px;
      font-size: 15px;
    }

    i:hover {
      color: #27ba9b;
    }

    img {
      width: 40px;
      height: 40px;
      border-radius: 50%;


    }

    .down {
      margin-top: 5px;
      height: auto;
    }
  }
}
</style>
4.2.4.components/admin/tables.vue
<template>
  <div class="tabs">tabs</div>
</template>

<script setup>
</script>

<style lang="scss">
.tabs {
  background-color: rgb(46, 49, 49);
  height: 30px;
  border: 1px solid #f0eeee;
}
</style>
4.2.5.说明以及修改内容

修改了aside.vue中的men_list侧边栏的跳转路由路径,并在views/admin下创建对应的文件

例如data_list.vue(暂时没有设计内容)

<template>
    <dev>数据列表</dev>
</template>
<script setup></script>
<script lang="scss"></script>

还要再index.js中添加对应的路由才能够实现跳转

index.js

//createRouter 创建路由
//createWebHistory 创建history路由
import { createRouter, createWebHistory } from 'vue-router'
import Login from '@/views/login/index.vue'
import Index from '@/views/layout/index.vue'
import Admin from "@/views/layout/admin.vue"
import UserList from "@/views/admin/user_list.vue"
import ImageList from "@/views/admin/image_list.vue"
import DataList from "@/views/admin/data_list.vue"
import System from "@/views/admin/system.vue"
import SystemInfo from "@/views/admin/system_info.vue"

const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes: [
  {
    path:'/',
    component:Login
  },
  {
    path:'/index',
    component:Index
  },
  {
    path:'/admin',
    component:Admin,
    children:[
      {
        path:'user_list',
        component:UserList
      },
      {
        path:'image_list',
        component:ImageList
      },
      {
        path:'data_list',
        component:DataList
      },
      {
        path:'system',
        component:System,
      },
      {
        path:'system_info',
        component:SystemInfo
      },
    ]
  }
  ]
})

export default router

最后的效果是会再admin的路由入口展示不同的信息,但是拆分之后各个模块更见容易管理

 5.user_list.vue 界面设计

5.1.实现增删改查功能
<template>
  <div class="pvb_container">
    <div class="pvb_search">
      <el-input v-model="input2" style="width: 240px" placeholder="Type something" :prefix-icon="Search" />
    </div>
    <div class="pvb_actions">
      <el-button type="primary">批量删除</el-button>
      <el-button type="success" @click="data.dialogOverflowVisible = true, data.addOredit = 'add'">添加</el-button>
    </div>
    <div class="input_model">
      <el-dialog v-model="data.dialogOverflowVisible" :title="data.addOredit == 'add' ? '添加' : '修改'" width="400" draggable
        overflow>
        <el-input class="input" v-model="data.editOraddinput.name" style="width: 280px" placeholder="姓名" />
        <el-input class="input" v-model="data.editOraddinput.ip" style="width: 280px" placeholder="IP" />
        <el-input class="input" v-model="data.editOraddinput.dep" style="width: 280px" placeholder="部门" />
        <el-input class="input" v-model="data.editOraddinput.project" style="width: 280px" placeholder="项目" />
        <template #footer>
          <div class="dialog-footer">
            <el-button @click="dialogOverflowVisible = false">Cancel</el-button>
            <el-button type="primary" @click="commit">
              Confirm
            </el-button>
          </div>
        </template>
      </el-dialog>
    </div>

    <div class="pvb_tables">
      <el-table :data="data.tableData" style="width: 100%" @selection-change="handleSelectionChange">
        <el-table-column type="selection" width="55" />
        <el-table-column prop="name" label="用户名称" width="180" />
        <el-table-column prop="ip" label="Ip" width="180" />
        <el-table-column prop="dep" label="部门" />
        <el-table-column prop="project" label="项目">
          <template v-slot="scope">
            <el-button type="primary" @click="deldata(scope.row)">删除</el-button>
            <el-button type="success" @click="update(scope.row)">修改</el-button>

          </template>
        </el-table-column>

      </el-table>

    </div>
    <div class="pvb_pages">
      <el-pagination small background layout="prev, pager, next" :total="50" class="mt-4" />
    </div>
  </div>
</template>
<script setup>
import { reactive, ref } from "vue";
import { IpControl_listApi, IpControl_CreateApi, IpControl_OneApi, IpControl_UpdateApi, IpControl_DelApi } from "@/apis/ip_control_api"
const data = reactive({
  current_row_id: '',
  addOredit: '',
  page_total: 1,
  dialogOverflowVisible: false,
  tableData: [
    {
      name: 1,
      ip: '2016-05-03',
      dep: 'Tom',
      project: 'No. 189, Grove St, Los Angeles',
    },

  ],
  editOraddinput:
  {
    name: 1,
    ip: '2016-05-03',
    dep: 'Tom',
    project: 'No. 189, Grove St, Los Angeles',
  },



}

)
//
getlist()
async function getlist() {
  const res = await IpControl_listApi()
  data.tableData = res.data
}


async function commit() {
  data.dialogOverflowVisible = false
  console.log(data.current_row_id)
  if (data.addOredit == 'add') {
    console.log(data.editOraddinput)
    const res = await IpControl_CreateApi(data.editOraddinput)
  }
  else {
    console.log(data.current_row_id)
    await IpControl_UpdateApi(data.current_row_id, data.editOraddinput)
  }
}

async function update(row) {
  data.addOredit = 'update'
  data.dialogOverflowVisible = true
  data.current_row_id = row.id
  const res = await IpControl_OneApi(row.id)
  data.editOraddinput = res.data


}

async function deldata(row) {
  await IpControl_DelApi(row.id)
}


</script>
<style lang="scss">
.pvb_container {
  background-color: white;

  .pvb_search {
    padding: 10px;
    border-bottom: 1px solid #fff;
  }

  .pvb_actions {
    padding: 10px;
  }

  .input_model {
    .input {
      padding-left: 25%;
      margin-bottom: 10px;
    }
  }

  .pvb_tables {
    padding: 10px;
    height: 500px;
  }

  .pvb_pages {
    display: flex;
    justify-content: center;
    padding: 10px;
    margin-bottom: 20px;
  }
}
</style>

ip_control_api.js

后端接口API

import httpInstance from "@/utils/http";
// 查所有
export function IpControl_listApi(){
    return httpInstance.get("api/permission/")
}
// 创建
export function IpControl_CreateApi(data){
    return httpInstance.post("api/permission/",data)
}
// 查单个
export function IpControl_OneApi(id){
    return httpInstance.get("api/permission"+"/"+id+"/")
}
// 改
export function IpControl_UpdateApi(id,data){
    return httpInstance.put("api/permission"+"/"+id+"/",data)
}
// 删除
export function IpControl_DelApi(id){
    return httpInstance.delete("api/permission"+"/"+id+"/")
}

5.2.添加分页以及搜索功能

userlist.vue

<template>
  <div class="pvb_container">
    <div class="pvb_search">
      <el-input v-model="search_.search_value" style="width: 240px" placeholder="Type something"
        @input="handleSearch" />
    </div>
    <div class="pvb_actions">
      <el-button type="danger">批量删除</el-button>
      <el-button type="success" @click="data.dialogOverflowVisible = true, data.addOredit = 'add'">添加</el-button>
    </div>
    <div class="input_model">
      <el-dialog v-model="data.dialogOverflowVisible" :title="data.addOredit == 'add' ? '添加' : '修改'" width="400"
        draggable overflow>
        <el-input class="input" v-model="data.editOraddinput.name" style="width: 280px" placeholder="姓名" />
        <el-input class="input" v-model="data.editOraddinput.ip" style="width: 280px" placeholder="IP" />
        <el-input class="input" v-model="data.editOraddinput.dep" style="width: 280px" placeholder="部门" />
        <el-input class="input" v-model="data.editOraddinput.project" style="width: 280px" placeholder="项目" />
        <template #footer>
          <div class="dialog-footer">
            <el-button @click="dialogOverflowVisible = false">Cancel</el-button>
            <el-button type="primary" @click="commit">
              Confirm
            </el-button>
          </div>
        </template>
      </el-dialog>
    </div>

    <div class="pvb_tables">
      <el-table :data="data.tableData" style="width: 100%" @selection-change="handleSelectionChange">
        <el-table-column type="selection" width="55" />
        <el-table-column prop="name" label="用户名称" width="180" />
        <el-table-column prop="ip" label="Ip" width="180" />
        <el-table-column prop="dep" label="部门" />
        <el-table-column prop="project" label="项目" />
        <el-table-column prop="actions" label="操作">
          <template v-slot="scope">
            <el-button type="warning" @click="update(scope.row)">修改</el-button>
            <el-button type="danger" @click="deldata(scope.row)">删除</el-button>


          </template>
        </el-table-column>

      </el-table>

    </div>
    <div class="pvb_pages">
      <el-pagination small background layout="prev, pager, next" :total="page_.page_toal" class="mt-4"
        @current-change="handelCurrentChenge" />
    </div>
  </div>
</template>
<script setup>
import { reactive, ref, inject } from "vue";
import { IpControl_listApi, IpControl_CreateApi, IpControl_OneApi, IpControl_UpdateApi, IpControl_DelApi, IpControl_SearchApi } from "@/apis/ip_control_api"
const reload = inject("reload");

const page_ = reactive({
  page_toal: 0,
  page_data: [],
  page_Size: 11,
  current_page: 0
})
const search_ = reactive({
  search_flag: false,
  search_data: [],
  search: '',
})
const data = reactive({
  current_row_id: '',
  addOredit: '',
  dialogOverflowVisible: false,
  tableData: [
    {
      name: 1,
      ip: '',
      dep: '',
      project: '',
      actions: ''
    },

  ],
  editOraddinput:
  {
    name: 1,
    ip: '',
    dep: '',
    project: '',
  },

}

)

getlist()
async function getlist() {
  const res = await IpControl_listApi()
  if (res.code == 200) {
    search_.search_flag = false
    data.tableData = res.data
    page_.page_data = res.data
    page_.page_toal = res.total

  }
  else {
    ElMessage.error('获取失败')
  }

}


async function commit() {
  data.dialogOverflowVisible = false
  console.log(data.current_row_id)
  if (data.addOredit == 'add') {
    const res = await IpControl_CreateApi(data.editOraddinput)
    if (res.code == 200) {
      ElMessage.success('添加成功')
      reload()
    }
    else {
      ElMessage.error('添加失败')
    }


  }
  else {
    const res = await IpControl_UpdateApi(data.current_row_id, data.editOraddinput)
    if (res.code == 200) {
      ElMessage.success('修改成功')
      reload()
    }
    else {
      ElMessage.error('修改失败')
      return
    }


  }
}

async function update(row) {
  data.addOredit = 'update'
  data.dialogOverflowVisible = true
  data.current_row_id = row.id
  const res = await IpControl_OneApi(row.id)
  data.editOraddinput = res.data
}

async function deldata(row) {
  const res = await IpControl_DelApi(row.id)
  if (res.code == 200) {
    ElMessage.success('删除成功')
    reload()
  }
  else {
    ElMessage.error('删除失败')
    return
  }

}
async function handleSearch() {
  search_.search_flag = true
  const res = await IpControl_SearchApi(search_.search_value)
  search_.search_data = res.data
  if (res.total != 0) {
    data.tableData = res.data
  }

}
const handelCurrentChenge = page => {
  page_.current_page = page
  const index = page_.page_Size * (page - 1)
  const end = page_.page_Size * page
  var tables = []
  for (let i = index; i < end; i++) {
    if (page_.page_data[i] && search_.search_flag == false) {
      tables.push(page_.page_data[i])
    }
    else if (search_.search_data[i] && search_.search_flag) {
      tables.push(search_.search_data[i])
    }

    data.tableData = tables
  }

}
</script>
<style lang="scss">
.pvb_container {
  background-color: white;

  .pvb_search {
    padding: 10px;
    border-bottom: 1px solid #fff;
  }

  .pvb_actions {
    padding: 10px;
  }

  .input_model {
    .input {
      padding-left: 25%;
      margin-bottom: 10px;

    }
  }

  .pvb_tables {
    height: 710px;
    overflow: hidden;
    margin-left: 10%;
    width: 1243px;
  }

  .pvb_pages {
    display: flex;
    justify-content: center;
    margin-top: 30px;
  }
}
</style>
5.2.1新增后端数据接口
import httpInstance from "@/utils/http";
// 查所有
export function IpControl_listApi(){
    return httpInstance.get("api/permission/")
}
// 创建
export function IpControl_CreateApi(data){
    return httpInstance.post("api/permission/",data)
}
// 查单个
export function IpControl_OneApi(id){
    return httpInstance.get("api/permission"+"/"+id+"/")
}
// 改
export function IpControl_UpdateApi(id,data){
    return httpInstance.put("api/permission"+"/"+id+"/",data)
}
// 删除
export function IpControl_DelApi(id){
    return httpInstance.delete("api/permission"+"/"+id+"/")
}
//搜索
export function IpControl_SearchApi(search){
    return httpInstance.get("api/permission/"+"?search="+search)
}
5.2.2新增刷新方法

在APP.vue



<template>
  <!-- //一级路由出口 -->
 <RouterView v-if="isRouter"></RouterView>
</template>
<script setup>
import { provide,nextTick,ref } from 'vue';
//刷新
const isRouter = ref(true);
const reload=()=>{
  isRouter.value = false
  nextTick(()=>{
    isRouter.value = true
  })
}
provide('reload',reload)
</script>
<style scoped lang="scss">


*{
  padding: 0;
  margin: 0;
  box-sizing: border-box;
}
</style>

效果展示

6图片管理

7标签管理

8文章管理

9接入md组件

9-1引入组件

参考文档:MdEditorV3 Documentation (imzbf.github.io)icon-default.png?t=N7T8https://imzbf.github.io/md-editor-v3/zh-CN/demo

npm install md-editor-v3

 deomo

<template>
  <MdEditor v-model="text" />
</template>

<script setup>
import { ref } from 'vue';
import { MdEditor } from 'md-editor-v3';
import 'md-editor-v3/lib/style.css';

const text = ref('Hello Editor!');
</script>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值