【前端】Vue+Element UI案例:通用后台管理系统-代码总结

news2024/11/18 1:49:56

文章目录

    • 前言
    • 项目文件目录
    • api
      • mockServe
        • home.js
        • permission.js
      • index.js
      • mock.js
      • user.js
    • assert
    • components
      • CommonAside.vue
      • CommonHeader.vue
      • CommonTags.vue
    • data
      • echartsData
        • order.js
        • user.js
        • video.js
      • mockData
        • tableData.js
        • userData.js
        • videoData.js
      • CountData.js
      • MenuData.js
      • TableData.js
      • TableLabel.js
    • router
      • index.js
    • store
      • index.js
      • tab.js
    • utils
      • request.js
    • Views
      • Home.vue
      • Login.vue
      • Main.vue
      • Mall.vue
      • PageOne.vue
      • PageTwo.vue
      • User.vue
    • App.vue
    • main.js
    • 要安装的依赖

前言

本来不打算用博客的方式记录代码的,想用git把它上传到代码仓库。但是由于对git的使用不太熟悉,把写得完善的项目代码初始化掉了!!非常崩溃…后来废了很大力气才把代码找回来。

为了以后把代码搞丢后还能找回来,还是要写个博客来记录一下代码。

项目链接:https://pan.baidu.com/s/1fTh4m_OkqV2PIuWdCgE-QQ
提取码:35sv

项目文件目录

在这里插入图片描述

api

在这里插入图片描述

mockServe

home.js

// mock数据模拟
import Mock from 'mockjs'
// 导入数据
import videoData from '../../data/mockData/videoData'
import userData from '../../data/mockData/userData'
import tableData from '../../data/mockData/tableData'

// 图表数据
let List =[]
// 直接导出
export default {
    getStatisticalData: () => {
        //Mock.Random.float 产生随机数100到8000之间 保留小数 最小0位 最大0位
        for (let i = 0; i < 7; i++) {
            List.push(
                Mock.mock({
                    苹果: Mock.Random.float(100, 8000, 0, 0),
                    vivo: Mock.Random.float(100, 8000, 0, 0),
                    oppo: Mock.Random.float(100, 8000, 0, 0),
                    魅族: Mock.Random.float(100, 8000, 0, 0),
                    三星: Mock.Random.float(100, 8000, 0, 0),
                    小米: Mock.Random.float(100, 8000, 0, 0)
                })
            )
        }
        // 返回给浏览器的数据
        return {
            code: 20000,
            data: {
                // 饼图
                videoData,
                // 柱状图
                userData,
                // 折线图
                orderData: {
                    date: ['20191001', '20191002', '20191003', '20191004', '20191005', '20191006', '20191007'],
                    data: List
                },
                tableData
            }
        }
    }
}

permission.js

import Mock from 'mockjs'
export default {
    getMenu: config => {
        const { username, password } = JSON.parse(config.body)
        // 先判断用户是否存在
        // 判断账号和密码是否对应
        if (username === 'admin' && password === 'admin') {
            return {
                code: 20000,
                data: {
                    menu: [
                        {
                            path: '/home',
                            name: 'home',
                            label: '首页',
                            icon: 's-home',
                            url: 'Home.vue'
                        },
                        {
                            path: '/mall',
                            name: 'mall',
                            label: '商品管理',
                            icon: 'video-play',
                            url: 'Mall.vue'
                        },
                        {
                            path: '/user',
                            name: 'user',
                            label: '用户管理',
                            icon: 'user',
                            url: 'User.vue'
                        },
                        {
                            label: '其他',
                            icon: 'location',
                            children: [
                                {
                                    path: '/page1',
                                    name: 'page1',
                                    label: '页面1',
                                    icon: 'setting',
                                    url: 'PageOne.vue'
                                },
                                {
                                    path: '/page2',
                                    name: 'page2',
                                    label: '页面2',
                                    icon: 'setting',
                                    url: 'PageTwo.vue'
                                }
                            ]
                        }
                    ],
                    token: Mock.Random.guid(),
                    message: '获取成功'
                }
            }
        } else if (username === 'xiaoxiao' && password === 'xiaoxiao') {
            return {
                code: 20000,
                data: {
                    menu: [
                        {
                            path: '/home',
                            name: 'home',
                            label: '首页',
                            icon: 's-home',
                            url: 'Home.vue'
                        },
                        {
                            path: '/video',
                            name: 'video',
                            label: '商品管理',
                            icon: 'video-play',
                            url: 'Mall.vue'
                        }
                    ],
                    token: Mock.Random.guid(),
                    message: '获取成功'
                }
            }
        } else {
            return {
                code: -999,
                data: {
                    message: '密码错误'
                }
            }
        }

    }
}

index.js

import http from '../utils/request'

// 请求首页数据,直接把这个对象导出
export const getData = () => {
    // 返回一个promise
    return http.get('/home/getData')
}

// 下面四个:用户管理-后端-网络请求接口
export const getUser = (params) => {
    return http.get('/user/get/', params)
}

export const createUser = (data) => {
    return http.post('/user/create', data)
}

export const deleteUser = (data) => {
    return http.post('/user/del', data)
}

export const updateUser = (data) => {
    return http.post('/user/update', data)
}

// 登录权限
export const getMenu = (data) => {
    return http.post('/permission/getMenu',data)
}

mock.js

import Mock from 'mockjs'
import homeMock from '../api/mockServe/home'
import user from './user'
import permission from './mockServe/permission'

// 定义mock拦截
Mock.mock('/api/home/getData',homeMock)

// 用户管理:增删查改
Mock.mock(/\/api\/user\/get/,user.getUserList)
Mock.mock('/api/user/create','post',user.createUser)
Mock.mock('/api/user/update','post',user.updateUser)
Mock.mock('/api/user/del','post',user.deleteUser)

// 登录权限
Mock.mock(/api\/permission\/getMenu/,'post',permission.getMenu)

user.js

import Mock from 'mockjs'

// get请求从config.url获取参数,post从config.body中获取参数
function param2Obj (url) {
  const search = url.split('?')[1]
  if (!search) {
    return {}
  }
  return JSON.parse(
    '{"' +
    decodeURIComponent(search)
      .replace(/"/g, '\\"')
      .replace(/&/g, '","')
      .replace(/=/g, '":"') +
    '"}'
  )
}

let List = []
const count = 200

for (let i = 0; i < count; i++) {
  List.push(
    Mock.mock({
      id: Mock.Random.guid(),
      name: Mock.Random.cname(),
      addr: Mock.mock('@county(true)'),
      'age|18-60': 1,
      birth: Mock.Random.date(),
      sex: Mock.Random.integer(0, 1)
    })
  )
}

export default {
  /**
   * 获取列表
   * 要带参数 name, page, limt; name可以不填, page,limit有默认值。
   * @param name, page, limit
   * @return {{code: number, count: number, data: *[]}}
   */
  getUserList: config => {
    const { name, page = 1, limit = 20 } = param2Obj(config.url)
    // console.log('name:' + name, 'page:' + page, '分页大小limit:' + limit)
    const mockList = List.filter(user => {
      if (name && user.name.indexOf(name) === -1 && user.addr.indexOf(name) === -1) return false
      return true
    })
    const pageList = mockList.filter((item, index) => index < limit * page && index >= limit * (page - 1))
    return {
      code: 20000,
      count: mockList.length,
      list: pageList
    }
  },
  /**
   * 增加用户
   * @param name, addr, age, birth, sex
   * @return {{code: number, data: {message: string}}}
   */
  createUser: config => {
    const { name, addr, age, birth, sex } = JSON.parse(config.body)
    console.log(JSON.parse(config.body))
    List.unshift({
      id: Mock.Random.guid(),
      name: name,
      addr: addr,
      age: age,
      birth: birth,
      sex: sex
    })
    return {
      code: 20000,
      data: {
        message: '添加成功'
      }
    }
  },
  /**
   * 删除用户
   * @param id
   * @return {*}
   */
  deleteUser: config => {
    const { id } = JSON.parse(config.body)
    if (!id) {
      return {
        code: -999,
        message: '参数不正确'
      }
    } else {
      List = List.filter(u => u.id !== id)
      return {
        code: 20000,
        message: '删除成功'
      }
    }
  },
  /**
   * 批量删除
   * @param config
   * @return {{code: number, data: {message: string}}}
   */
  batchremove: config => {
    let { ids } = param2Obj(config.url)
    ids = ids.split(',')
    List = List.filter(u => !ids.includes(u.id))
    return {
      code: 20000,
      data: {
        message: '批量删除成功'
      }
    }
  },
  /**
   * 修改用户
   * @param id, name, addr, age, birth, sex
   * @return {{code: number, data: {message: string}}}
   */
  updateUser: config => {
    const { id, name, addr, age, birth, sex } = JSON.parse(config.body)
    const sex_num = parseInt(sex)
    List.some(u => {
      if (u.id === id) {
        u.name = name
        u.addr = addr
        u.age = age
        u.birth = birth
        u.sex = sex_num
        return true
      }
    })
    return {
      code: 20000,
      data: {
        message: '编辑成功'
      }
    }
  }
}

assert

这些图片在链接里:

在这里插入图片描述

components

在这里插入图片描述

CommonAside.vue

<template>
    <el-menu default-active="1-4-1" class="el-menu-vertical-demo" @open="handleOpen" @close="handleClose"
        :collapse="isCollapse" background-color="#545c64" text-color="#fff" active-text-color="#ffd04b">
        <!-- 要放到导航栏里面 -->
        <h3>{{ isCollapse ? "后台" : "通用后台管理系统" }}</h3>
        <!-- 观察数据,我们发现name是唯一标识 -->
        <!-- 查看文档,index是唯一标识 -->
        <el-menu-item @click="clickItem(item)" v-for="item in noChildren" :key="item.name" :index="item.name">
            <!-- 这里是字体图标,用模板字符串拼接,注意要动态绑定 -->
            <i :class="`el-icon-${item.icon}`"></i>
            <span slot="title">{{ item.label }}</span>
        </el-menu-item>
        <el-submenu v-for="item in hasChildren" :key="item.label" :index="item.label">
            <template slot="title">
                <i :class="`el-icon-${item.icon}`"></i>
                <span slot="title">{{ item.label }}</span>
            </template>
            <el-menu-item-group v-for="subItem in item.children" :key="subItem.name">
                <el-menu-item @click="clickItem(subItem)" :index="subItem.name">{{ subItem.label }}</el-menu-item>
            </el-menu-item-group>
        </el-submenu>
    </el-menu>
</template>

<style lang="less" scoped>
.el-menu-vertical-demo:not(.el-menu--collapse) {
    width: 200px;
    min-height: 400px;
}

.el-menu {
    height: 100vh;
    // Aside和Header之间没有边框缝隙
    border-right: none;

    h3 {
        text-align: center;
        line-height: 48px;
        color: #fff;
        font-size: 16px;
        font-weight: 400;
    }
}
</style>

<script>
import cookie from 'js-cookie'
export default {
    data() {
        return {

        };
    },
    methods: {
        handleOpen(key, keyPath) {
            console.log(key, keyPath);
        },
        handleClose(key, keyPath) {
            console.log(key, keyPath);
        },
        clickItem(item) {
            // 防止自己跳自己的报错
            if (this.$route.path !== item.path && !(this.$route.path === '/home' && (item.path === '/'))) {
                this.$router.push(item.path)
            }
            // 面包屑
            this.$store.commit('SelectMenu', item)
        }
    },
    computed: {
        noChildren() {
            // 如果没有children则返回true,会被过滤器留下
            return this.MenuData.filter(item => !item.children)
        },
        hasChildren() {
            return this.MenuData.filter(item => item.children)
        },
        // 要放到计算属性,自动计算
        isCollapse() {
            return this.$store.state.tab.isCollapse
        },
        // 获取菜单
        MenuData() {
            return JSON.parse(cookie.get('menu')) || this.$store.state.tab.menu
        }
    }
}
</script>

CommonHeader.vue

<template>
    <div class="header-container">
        <div class="l-content">
            <el-button @click="handleMenu" icon="el-icon-menu" size="mini"></el-button>
            <!-- 面包屑 -->
            <el-breadcrumb separator="/">
                <el-breadcrumb-item v-for="item in tags" :key="item.path" :to="{ path: item.path }">{{ item.label }}
                </el-breadcrumb-item>
            </el-breadcrumb>
        </div>
        <div class="r-content">
            <el-dropdown @command="handleClick">
                <span class="el-dropdown-link">
                    <img class="user" src="../assets/images/user.png" alt="">
                </span>
                <el-dropdown-menu slot="dropdown">
                    <el-dropdown-item>个人信息</el-dropdown-item>
                    <el-dropdown-item command="logout">退出</el-dropdown-item>
                </el-dropdown-menu>
            </el-dropdown>
        </div>
    </div>
</template>

<script>
import { mapState } from 'vuex'
import Cookie from 'js-cookie'
export default {
    methods: {
        handleMenu() {
            // 相当于调用这个方法
            this.$store.commit('CollapseMenu')
        },
        handleClick(command) {
            if (command === 'logout') {
                Cookie.remove('token')
                this.$router.push('/login')
            }
        }
    },
    computed: {
        ...mapState({
            tags: state => state.tab.tabList
        })
    }
}
</script>

<style lang="less" scoped>
.header-container {
    background-color: #333;
    height: 60px;

    // 让按钮和头像居中
    display: flex;
    justify-content: space-between;
    align-items: center;
    // 不要紧贴边框
    padding: 0 20px;

    .el-dropdown-link {
        cursor: pointer;
        color: #409EFF;

        .user {
            width: 40px;
            height: 40px;
            // 50%变圆形
            border-radius: 50%;
        }
    }
}

.l-content {
    display: flex;
    // 上下居中
    align-items: center;

    .el-breadcrumb {
        margin-left: 15px;

        // deep 强制生效
        /deep/.el-breadcrumb__item {
            .el-breadcrumb__inner {
                &.is-link {
                    color: #666;
                }
            }

            &:last-child {
                .el-breadcrumb__inner {
                    color: #fff;
                }
            }
        }
    }
}
</style>

CommonTags.vue

<template>
    <div class="tabs">
        <!-- closable是否可删除:除了"首页"都可删 -->
        <!-- effect:主题,当前主题是dark,其他事plain -->
        <el-tag v-for="(item, index) in tags" :key="item.path" :closable="item.name !== 'home'"
            :effect="item.name === $route.name ? 'dark' : 'plain'" @click="changeMenu(item)"
            @close="handleClose(item, index)">
            {{ item.label }}
        </el-tag>
    </div>
</template>

<script>
import { mapState } from 'vuex'

export default {
    methods: {
        changeMenu(item) {
            this.$router.push({ name: item.name })
        },
        handleClose(item, index) {
            // 删除面包屑数据
            this.$store.commit('closeTag', item)
            // 如果删除的刚好是自己
            if (item.name === this.$route.name) {
                const length = this.tags.length
                // 如果删除的是最后一个:跳到前一个
                if (length === index) {
                    this.$router.push({ name: this.tags[index - 1].name })
                }
                // 不是最后一个:往后一个
                else {
                    this.$router.push({ name: this.tags[index].name })
                }
            }
        }
    },
    computed: {
        ...mapState({
            tags: state => state.tab.tabList
        })
    }
}
</script>

<style lang="less" scoped>
.tabs{
    padding: 20px 20px 0 20px;

    .el-tag{
        margin-right: 15px;
        // 鼠标悬停:小手
        cursor: pointer;
    }
}
</style>

data

在这里插入图片描述

echartsData

order.js

const order = {
    legend: {
        // 图例文字颜色
        textStyle: {
            color: "#333",
        },
    },
    grid: {
        left: "20%",
    },
    // 提示框
    tooltip: {
        trigger: "axis",
    },
    xAxis: {
        type: "category", // 类目轴
        data: [],
        axisLine: {
            lineStyle: {
                color: "#17b3a3",
            },
        },
        axisLabel: {
            interval: 0,
            color: "#333",
        },
    },
    yAxis: [
        {
            type: "value",
            axisLine: {
                lineStyle: {
                    color: "#17b3a3",
                },
            },
        },
    ],
    color: ["#2ec7c9", "#b6a2de", "#5ab1ef", "#ffb980", "#d87a80", "#8d98b3"],
    series: [],
}

export default order

user.js

const user = {
    legend: {
        // 图例文字颜色
        textStyle: {
            color: "#333",
        },
    },
    grid: {
        left: "20%",
    },
    // 提示框
    tooltip: {
        trigger: "axis",
    },
    xAxis: {
        type: "category", // 类目轴
        data: [],
        axisLine: {
            lineStyle: {
                color: "#17b3a3",
            },
        },
        axisLabel: {
            interval: 0,
            color: "#333",
        },
    },
    yAxis: [
        {
            type: "value",
            axisLine: {
                lineStyle: {
                    color: "#17b3a3",
                },
            },
        },
    ],
    color: ["#2ec7c9", "#b6a2de"],
    series: [],
}

export default user

video.js

const video = {
    tooltip: {
        trigger: "item",
    },
    color: [
        "#0f78f4",
        "#dd536b",
        "#9462e5",
        "#a6a6a6",
        "#e1bb22",
        "#39c362",
        "#3ed1cf",
    ],
    series: [],
}

export default video

mockData

tableData.js

const tableData = [
    {
        name: 'oppo',
        todayBuy: 500,
        monthBuy: 3500,
        totalBuy: 22000
    },
    {
        name: 'vivo',
        todayBuy: 300,
        monthBuy: 2200,
        totalBuy: 24000
    },
    {
        name: '苹果',
        todayBuy: 800,
        monthBuy: 4500,
        totalBuy: 65000
    },
    {
        name: '小米',
        todayBuy: 1200,
        monthBuy: 6500,
        totalBuy: 45000
    },
    {
        name: '三星',
        todayBuy: 300,
        monthBuy: 2000,
        totalBuy: 34000
    },
    {
        name: '魅族',
        todayBuy: 350,
        monthBuy: 3000,
        totalBuy: 22000
    }
]

export default tableData

userData.js

// 柱状图
const userData = [
    {
        date: '周一',
        new: 5,
        active: 200
    },
    {
        date: '周二',
        new: 10,
        active: 500
    },
    {
        date: '周三',
        new: 12,
        active: 550
    },
    {
        date: '周四',
        new: 60,
        active: 800
    },
    {
        date: '周五',
        new: 65,
        active: 550
    },
    {
        date: '周六',
        new: 53,
        active: 770
    },
    {
        date: '周日',
        new: 33,
        active: 170
    }
]

export default userData

videoData.js

// 饼图
const videoData = [
    {
        name: '小米',
        value: 2999
    },
    {
        name: '苹果',
        value: 5999
    },
    {
        name: 'vivo',
        value: 1500
    },
    {
        name: 'oppo',
        value: 1999
    },
    {
        name: '魅族',
        value: 2200
    },
    {
        name: '三星',
        value: 4500
    }
]

export default videoData

CountData.js

const CountData = [
    {
        name: "今日支付订单",
        value: 1234,
        icon: "success",
        color: "#2ec7c9",
    },
    {
        name: "今日收藏订单",
        value: 210,
        icon: "star-on",
        color: "#ffb980",
    },
    {
        name: "今日未支付订单",
        value: 1234,
        icon: "s-goods",
        color: "#5ab1ef",
    },
    {
        name: "本月支付订单",
        value: 1234,
        icon: "success",
        color: "#2ec7c9",
    },
    {
        name: "本月收藏订单",
        value: 210,
        icon: "star-on",
        color: "#ffb980",
    },
    {
        name: "本月未支付订单",
        value: 1234,
        icon: "s-goods",
        color: "#5ab1ef",
    },
]
export default CountData

MenuData.js

const MenuData= [
    {
      path: '/',
      name: 'home',
      label: '首页',
      icon: 's-home',
      url: 'Home/Home'
    },
    {
      path: '/mall',
      name: 'mall',
      label: '商品管理',
      icon: 'video-play',
      url: 'MallManage/MallManage'
    },
    {
      path: '/user',
      name: 'user',
      label: '用户管理',
      icon: 'user',
      url: 'UserManage/UserManage'
    },
    {
      label: '其他',
      icon: 'location',
      children: [
        {
          path: '/page1',
          name: 'page1',
          label: '页面1',
          icon: 'setting',
          url: 'Other/PageOne'
        },
        {
          path: '/page2',
          name: 'page2',
          label: '页面2',
          icon: 'setting',
          url: 'Other/PageTwo'
        }
      ]
    }
]

export default MenuData

TableData.js

const TableData = [
    {
        name: 'oppo',
        todayBuy: 100,
        monthBuy: 300,
        totalBuy: 800
    },
    {
        name: 'vivo',
        todayBuy: 100,
        monthBuy: 300,
        totalBuy: 800
    },
    {
        name: '苹果',
        todayBuy: 100,
        monthBuy: 300,
        totalBuy: 800
    },
    {
        name: '小米',
        todayBuy: 100,
        monthBuy: 300,
        totalBuy: 800
    },
    {
        name: '三星',
        todayBuy: 100,
        monthBuy: 300,
        totalBuy: 800
    },
    {
        name: '魅族',
        todayBuy: 100,
        monthBuy: 300,
        totalBuy: 800
    }
]

export default TableData

TableLabel.js

const TableLabel={
    name:'课程',
    todayBuy:'今日购买',
    monthBuy:'本月购买',
    totalBuy:'总购买'
}

export default TableLabel

router

在这里插入图片描述

index.js

import Vue from "vue";
import VueRouter from "vue-router";
import Main from '../Views/Main'
// import Home from '../Views/Home.vue'
// import Mall from '../Views/Mall.vue'
// import User from '../Views/User.vue'
// import PageOne from '../Views/PageOne.vue'
// import PageTwo from '../Views/PageTwo.vue'
import Login from '../Views/Login.vue'
import Cookie from 'js-cookie'

Vue.use(VueRouter)

const routes = [
    // 主路由
    {
        path: '/',
        name:'Main',
        component: Main,
        redirect: '/home', // 重定向
        children: [
            // 子路由
            // { path: '/home', name: 'home', component: Home }, // 首页
            // { path: '/user', name: 'user', component: User }, // 用户管理
            // { path: '/mall', name: 'mall', component: Mall }, // 商品管理
            // { path: '/page1', name: 'page1', component: PageOne }, // 页面1
            // { path: '/page2', name: 'page2', component: PageTwo }, // 页面2
        ]
    },
    {
        path: '/login',
        name: 'login',
        component: Login
    }
]

const router = new VueRouter({
    routes
})

// 路由守卫:全局前置导航守卫
router.beforeEach((to, from, next) => {
    // 获取token
    const token = Cookie.get('token')

    if (!token && to.name !== 'login') {
        next({ name: 'login' })
    } else if (token && to.name === 'login') {
        next({ name: 'home' })
    } else {
        next()
    }
})


export default router

store

在这里插入图片描述

index.js

import Vue from "vue";
import Vuex from 'vuex';
import tab from './tab';

Vue.use(Vuex)

// 创建Vuex实例并导出
export default new Vuex.Store({
    modules:{
        tab
    }
})

tab.js

import Cookie from "js-cookie"

export default {
    state: {
        isCollapse: false,//导航栏是否折叠
        tabList: [
            {
                path: '/',
                name: 'home',
                label: '首页',
                icon: 's-home',
                url: 'Home/Home'
            }
        ],//面包屑的数据:点了哪个路由,首页是一定有的
        menu: [],//不同用户的菜单
    },
    mutations: {
        // 修改导航栏展开和收起的方法
        CollapseMenu(state) {
            state.isCollapse = !state.isCollapse
        },
        // 更新面包屑的数据
        SelectMenu(state, item) {
            // 如果点击的不在面包屑数据中,则添加
            const index = state.tabList.findIndex(val => val.name === item.name)
            if (index === -1) {
                state.tabList.push(item)
            }
        },
        // 删除tag:删除tabList中对应的item
        closeTag(state, item) {
            // 要删除的是state.tabList中的item
            const index = state.tabList.findIndex(val => val.name === item.name)
            state.tabList.splice(index, 1)
        },
        // 设置不同用户的菜单
        setMenu(state, val) {
            state.menu = val
            Cookie.set('menu', JSON.stringify(val))
        },
        // 动态添加路由
        addMenu(state, router) {
            // 判断Cookie
            if (!Cookie.get('menu')) return
            const menu = JSON.parse(Cookie.get('menu'))
            state.menu = menu

            const menuArray = []

            // 组装路由
            menu.forEach(item => {
                // 判断是否有子路由
                if (item.children) {
                    item.children = item.children.map(itemm => {
                        itemm.component = () => import(`../Views/${itemm.url}`)
                        return itemm
                    })
                    menuArray.push(...item.children)
                } else {
                    item.component = () => import(`../Views/${item.url}`)
                    menuArray.push(item)
                }
            });

            console.log(menuArray, 'menuArray');

            menuArray.forEach(item => {
                router.addRoute('Main', item)
            })
        }
    }
}

utils

在这里插入图片描述

request.js

import axios from "axios";

// 封装一个axios实例
const http = axios.create({
    // 通用请求的地址前缀
    baseURL: '/api',
    // 超时时间
    timeout: 100000
})

// 请求拦截器
http.interceptors.request.use(function (config) {
    // 在发送请求之前做什么
    return config;
}, function (error) {
    // 对请求错误做什么
    return Promise.reject(error);
})

// 添加响应拦截器
http.interceptors.response.use(function (response) {
    // 对响应数据做什么
    return response;
}, function (error) {
    // 对响应错误做什么
    return Promise.reject(error);
})

export default http

Views

在这里插入图片描述

Home.vue

<template>
    <el-row>
        <el-col :span="8">
            <!-- user卡片 -->
            <el-card>
                <div class="user">
                    <img src="../assets/images/user.png" alt="">
                    <div class="userInfo">
                        <p div class="name">Admin</p>
                        <p div class="access">超级管理员</p>
                    </div>
                </div>
                <div class="loginInfo">
                    <p>上次登录时间:<span>2021-7-19</span></p>
                    <p>上次登陆地点:<span>武汉</span></p>
                </div>
            </el-card>
            <!-- table卡片 -->
            <el-card style="margin-top: 20px;">
                <el-table :data="TableData" style="width: 100%">
                    <!-- 这里的val,key对应的是对象里的 -->
                    <el-table-column v-for="(value, key) in TableLabel" :prop="key" :label="value">
                    </el-table-column>
                </el-table>
            </el-card>
        </el-col>
        <el-col :span="16">
            <div class="num">
                <el-card v-for="item in CountData" :key="item.name" :body-style="{ display: 'flex', padding: 0 }">
                    <i class="icon" :class="`el-icon-${item.icon}`" :style="{ backgroundColor: item.color }"></i>
                    <div class="details">
                        <p class="price">{{ priceFormate(item.value) }}</p>
                        <p class="desc">{{ item.name }}</p>
                    </div>
                </el-card>
            </div>
            <!-- echarts图表 -->
            <div style="margin-left:20px">
                <!-- 折线图 -->
                <el-card style="height:280px">
                    <div ref="echarts1" style="height:280px"></div>
                </el-card>
                <div class="graph">
                    <!-- 柱状图 -->
                    <el-card style="height:280px">
                        <div ref="echarts2" style="height:280px"></div>
                    </el-card>
                    <!-- 饼状图 -->
                    <el-card style="height:320px">
                        <div ref="echarts3" style="height:320px"></div>
                    </el-card>
                </div>
            </div>
        </el-col>
    </el-row>
</template>

<script>
import TableLabel from '../data/TableLabel'
import CountData from '../data/CountData'
import { getData } from '../api/index'
import * as echarts from 'echarts'

// echarts的配置数据
import order from '../data/echartsData/order'
import user from '../data/echartsData/user'
import video from '../data/echartsData/video'

export default {
    data() {
        return {
            TableData: [],
            TableLabel,
            CountData
        }
    },
    methods: {
        priceFormate(price) {
            return "¥" + price
        }
    },
    mounted() {
        getData().then((data) => {
            // console.log(data);
            this.TableData = data.data.getStatisticalData.data.tableData

            // echarts图表

            // 折线图

            // 基于准备好的dom,初始化echarts实例
            const echarts1 = echarts.init(this.$refs.echarts1)
            var echarts1Option = order
            // ES6解构语法
            var { orderData, userData, videoData } = data.data.getStatisticalData.data

            // 获取x轴:要求是一个对象
            const xAxis = Object.keys(orderData.data[0])
            const xAxisData = {
                data: xAxis
            }

            // 配置
            echarts1Option.legend = xAxisData
            echarts1Option.xAxis = xAxisData
            echarts1Option.yAxis = {}
            echarts1Option.series = []

            // 配置series
            xAxis.forEach(key => {
                echarts1Option.series.push({
                    name: key,
                    type: 'line',
                    // key对应的orderData的所有值
                    data: orderData.data.map(item => item[key])
                })
            })

            // 使用刚指定的配置项和数据显示图表。
            echarts1.setOption(echarts1Option);

            // 柱状图
            const echarts2 = echarts.init(this.$refs.echarts2)
            var echarts2Option = user

            // 配置
            echarts2Option.xAxis.data = userData.map(item => item.date)
            echarts2Option.series = [
                {
                    name: '新增用户',
                    data: userData.map(item => item.new),
                    // 类型:bar是柱状图 
                    type: 'bar'
                }
                ,
                {
                    name: '活跃用户',
                    data: userData.map(item => item.active),
                    type: 'bar'
                }
            ]

            echarts2.setOption(echarts2Option);

            // 饼状图
            const echarts3 = echarts.init(this.$refs.echarts3)
            var echarts3Option = video
            echarts3Option.series = {
                data: videoData,
                type: 'pie'
            }
            echarts3.setOption(echarts3Option);
        })
    }
}
</script>

<style lang="less" scoped>
.user {
    // 垂直居中
    display: flex;
    align-items: center;

    // 外边距:分割线距离loginInfo的距离
    margin-bottom: 20px;
    // 内边距:分割线距离User的距离
    padding-bottom: 20px;
    border-bottom: 1px solid #ccc;

    img {
        width: 150px;
        height: 150px;
        border-radius: 50%;
        margin-right: 40px;
    }

    .userInfo {
        .name {
            font-size: 32px;
            margin-bottom: 10px;
        }

        .access {
            color: #999999;
        }
    }
}

.loginInfo {
    p {
        line-height: 28px;
        font-size: 14px;
        color: #999999;

        span {
            color: #666666;
            margin-left: 60px;
        }
    }
}

.num {
    display: flex;
    // 要换行
    flex-wrap: wrap;
    // 从头到尾均匀排列
    justify-content: space-between;
    margin-left: 20px;

    .el-card {
        width: 32%;
        margin-bottom: 20px;

        .icon {
            width: 80px;
            height: 80px;
            line-height: 80px;
            text-align: center;
            font-size: 30px;
            color: #fff;
        }

        .details {
            // 竖着排且居中
            display: flex;
            flex-direction: column;
            justify-content: center;

            margin-left: 15px;

            .price {
                font-size: 30px;
                margin-bottom: 10px;
                line-height: 30px;
                height: 30px;
            }

            .desc {
                font-size: 14px;
                color: #999;
                text-align: center;
            }
        }
    }
}

.graph {
    display: flex;
    // 两个靠边
    justify-content: space-between;
    margin-top: 20px;

    .el-card {
        width: 49%;
    }
}
</style>

Login.vue

<template>
    <el-form ref="form" class="login_container" :model="login" status-icon :rules="rules" label-width="70px">
        <!-- h3要放在里面:只能有一个根,且title也是表单的一部分 -->
        <h3 class="login_title">用户登录</h3>
        <!-- prop对应rules里的键 -->
        <el-form-item label="用户名" prop="username">
            <el-input v-model="login.username" autocomplete="off"></el-input>
        </el-form-item>

        <el-form-item label="密码" prop="password">
            <el-input type="password" v-model="login.password" autocomplete="off"></el-input>
        </el-form-item>

        <el-form-item>
            <el-button @click="submit" type="primary" style="margin-left:30px;margin-top:10px">提交</el-button>
        </el-form-item>
    </el-form>
</template>

<script>
import Cookie from 'js-cookie'
import { getMenu } from '../api/index'
export default {
    data() {
        return {
            // 登陆数据
            login: {
                username: '',
                password: ''
            },
            // 校验规则
            rules: {
                username: [{ required: 'true', message: '请输入用户名', trigger: 'blur' }],
                password: [{ required: 'true', message: '请输入用户名', trigger: 'blur' }]
            }
        }
    },
    methods: {
        submit() {
            // 表单的校验
            this.$refs.form.validate((valid) => {
                if (valid) {
                    // 传入表单数据
                    getMenu(this.login).then((data) => {
                        // console.log(data);
                        if(data.data.code===20000){
                            // 记录cookie
                            Cookie.set('token',data.data.data.token)
                            // 设置菜单
                            this.$store.commit('setMenu',data.data.data.menu)
                            // 动态添加路由
                            this.$store.commit('addMenu',this.$router)
                            // 跳转到首页
                            this.$router.push('/home')
                        }else{
                            // 验证失败的弹窗
                            this.$message.error(data.data.data.message);
                        }
                    })
                }
            })
        }
    }
}
</script>

<style lang="less" scoped>
.login_container {
    width: 350px;
    border: 1px solid #eaeaea;

    // 居中
    margin: 180px auto;

    padding: 35px 35px 15px 35px;

    // 让padding在width里面
    box-sizing: border-box;

    border-radius: 15px;
    background-color: #fff;
    box-shadow: 0 0 25px #cac6c6;

    .login_title {
        color: #505458;
        // 左右居中
        text-align: center;
        margin-bottom: 40px;
    }

    .el-input {
        width: 198px;
    }
}
</style>

Main.vue

<template>
    <el-container>
        <!-- width自适应,不然header与aside有间隔 -->
        <el-aside width="auto">
            <common-aside/>
        </el-aside>
        <el-container>
            <el-header>
                <common-header/>
            </el-header>
            <common-tags/>
            <el-main>
                <router-view></router-view>
            </el-main>
        </el-container>
    </el-container>
</template>

<script>
import CommonAside from '../components/CommonAside.vue'
import CommonHeader from '../components/CommonHeader.vue'
import CommonTags from '../components/CommonTags.vue'
export default {
    data(){
        return{}
    },
    components:{
        CommonAside,
        CommonHeader,
        CommonTags
    }
}
</script>

<style lang="less" scoped>
.el-header{
    padding:0;
}
</style>

Mall.vue

<template>
  <h1>Mall</h1>
</template>

<script>
export default {

}
</script>

<style>

</style>

PageOne.vue

<template>
    <h1>Page1</h1>
  </template>
  
  <script>
  export default {
  
  }
  </script>
  
  <style>
  
  </style>

PageTwo.vue

<template>
    <h1>Page2</h1>
  </template>
  
  <script>
  export default {
  
  }
  </script>
  
  <style>
  
  </style>

User.vue

<template>
  <div class="manage">
    <div class="manage-header">
      <!-- 新增按钮 -->
      <el-button type="primary" @click="handlecreate">+ 新增</el-button>

      <!-- 对话框:点击新增或编辑才会弹出表单 -->
      <!-- :before-close="closeDialog" 点击关闭的x之前要做的事情 -->
      <el-dialog :title="modalType == 0 ? '新建' : '编辑'" :visible.sync="dialogVisible" width="50%"
        :before-close="closeDialog">
        <!-- 表单Form -->
        <!-- ref=form:为了通过this.$refs调用组件的方法 -->
        <el-form :inline="true" :model="form" :rules="rules" ref="form" label-width="80px">
          <!-- 每一项表单域:el-form-item -->
          <el-form-item label="姓名" prop="name">
            <el-input placeholder="请输入姓名" v-model="form.name"></el-input>
          </el-form-item>

          <el-form-item label="年龄" prop="age">
            <el-input placeholder="请输入年龄" v-model="form.age"></el-input>
          </el-form-item>

          <el-form-item label="性别" prop="sex">
            <el-select v-model="form.sex" placeholder="请输入性别">
              <el-option label="" :value="1"></el-option>
              <el-option label="" :value="0"></el-option>
            </el-select>
          </el-form-item>

          <el-form-item label="出生日期">
            <el-form-item prop="birth">
              <el-date-picker type="date" placeholder="请选择日期" v-model="form.birth" value-format="yyyy-MM-DD">
              </el-date-picker>
            </el-form-item>
          </el-form-item>

          <el-form-item label="地址" prop="addr">
            <el-input placeholder="请输入地址" v-model="form.addr"></el-input>
          </el-form-item>
        </el-form>
        <div slot="footer" class="dialog-footer">
          <el-button @click="closeDialog">取 消</el-button>
          <el-button type="primary" @click="submit">确 定</el-button>
        </div>
      </el-dialog>

      <!-- 搜索框 -->
      <el-form :inline="true">
        <el-form-item>
          <el-input v-model="searchForm.name" placeholder="请输入名称"></el-input>
        </el-form-item>
        <el-form-item>
          <el-button type="primary" @click="search">查询</el-button>
        </el-form-item>
      </el-form>
    </div>
    <div class="common-table">
      <!-- 用户数据Table -->
      <el-table :data="tableData" stripe style="width: 100%" height="90%">
        <el-table-column prop="name" label="姓名">
        </el-table-column>
        <el-table-column prop="age" label="年龄">
        </el-table-column>
        <el-table-column prop="sex" label="性别">
          <template slot-scope="scope">
            <span>{{ scope.row.sex == 1 ? '男' : '女' }}</span>
          </template>
        </el-table-column>
        <el-table-column prop="birth" label="出生日期">
        </el-table-column>
        <el-table-column prop="addr" label="地址">
        </el-table-column>
        <!-- 自定义列 -->
        <el-table-column label="操作">
          <template slot-scope="scope">
            <el-button @click="handleEdit(scope.row)">编辑</el-button>
            <el-button type="danger" @click="handleDelete(scope.row)">删除</el-button>
          </template>
        </el-table-column>
      </el-table>
      <!-- 分页 -->
      <div class="pager">
        <el-pagination layout="prev, pager, next" :total="total" @current-change="currentChange">
        </el-pagination>
      </div>
    </div>
  </div>
</template>
  
<script>
import { getUser, createUser, deleteUser, updateUser } from '../api/index'
export default {
  data() {
    return {
      // 表单绑定的数据
      form: {
        name: '',
        age: '',
        sex: '',
        birth: '',
        addr: ''
      },
      // 表单验证规则
      rules: {
        name: [{ required: true, message: '请输入名称', trigger: 'blur' }],
        age: [{ required: true, message: '请输入年龄', trigger: 'blur' }],
        sex: [{ required: true, message: '请输入性别', trigger: 'blur' }],
        birth: [{ required: true, message: '请输入日期', trigger: 'blur' }],
        addr: [{ required: true, message: '请输入地址', trigger: 'blur' }],
      },
      // 表单是否打开
      dialogVisible: false,
      // 列表数据
      tableData: [],
      // 打开表单:新建0,编辑1
      modalType: 0,
      // 分页的对象
      pageData: {
        page: 1,
        limit: 20
      },
      // 分页页数
      total: 0,
      // 搜索框表单
      searchForm: {
        name: ''
      }
    }
  },
  methods: {
    // 获取列表数据
    getList() {
      // 由接口文档知传入一个对象:要返回的是当前页面数据和搜索到的数据的交集
      getUser({ params: { ...this.pageData, ...this.searchForm } }).then((data) => {
        this.tableData = data.data.list
        this.total = data.data.count || 0
      })
    },
    // 表单提交
    submit() {
      // 要用箭头函数,若用function会报错,不知道为什么
      this.$refs.form.validate((valid) => {
        // 符合校验
        if (valid) {
          // 提交数据
          if (this.modalType === 0) {
            // 新增
            createUser(this.form).then(() => {
              this.getList()
            })
          } else {
            // 编辑
            updateUser(this.form).then(() => {
              this.getList()
            })
          }
          // 清空,关闭
          this.closeDialog()
        }
      })
    },
    // 关闭对话框
    closeDialog() {
      // 先重置
      this.$refs.form.resetFields()
      // 后关闭
      this.dialogVisible = false
    },
    // 编辑按钮
    handleEdit(index) {
      this.modalType = 1
      this.openForm()
      // 深拷贝
      this.form = JSON.parse(JSON.stringify(index))
    },
    // 删除按钮
    handleDelete(index) {
      this.$confirm('此操作将永久删除该用户, 是否继续?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        // 删除操作:根据后端接口,参数是对象,id是唯一标识符
        deleteUser({ id: index.id }).then(() => {
          this.$message({
            type: 'success',
            message: '删除成功!'
          })
          this.getList()
        });
      }).catch(() => {
        // 点击取消:不删除了
        this.$message({
          type: 'info',
          message: '已取消删除'
        });
      });
    },
    // 新建按钮
    handlecreate() {
      this.modalType = 0
      this.openForm()
    },
    // 打开表单
    openForm() {
      this.dialogVisible = true
    },
    // 改变页码
    currentChange(val) {
      this.pageData.page = val
      this.getList()
    },
    // 搜索
    search() {
      this.getList()
    }
  },
  mounted() {
    this.getList()
  }
}
</script>
  
<style lang="less" scoped>
.manage {
  height: 100%;

  .manage-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
  }

  .common-table {
    height: 90%;
    position: relative;

    .pager {
      position: absolute;
      right:20px;
      bottom: 0;
    }
  }
}
</style>

App.vue

<template>
  <div id="app">
    <router-view></router-view>
  </div>
</template>

<script>
export default {
}
</script>

<style>
html,
body,
h3,
p {
  margin: 0;
  padding: 0
}
</style>

main.js

import Vue from 'vue'
import App from './App.vue'
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css';
import router from './router/index'
import store from './store/index'
import './api/mock'

Vue.config.productionTip = false
Vue.use(ElementUI)

new Vue({
  router,
  store,
  render: h => h(App),
  created() {
    store.commit('addMenu', router)
  }
}).$mount('#app')

要安装的依赖

"dependencies": {
    "axios": "^1.1.3",
    "core-js": "^3.8.3",
    "echarts": "^5.1.2",
    "element-ui": "^2.15.10",
    "js-cookie": "^3.0.1",
    "less": "^4.1.3",
    "less-loader": "^11.1.0",
    "mockjs": "^1.1.0",
    "vue": "^2.6.14",
    "vue-router": "^3.6.5",
    "vuex": "^3.6.2"
  }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/11628.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

389. 找不同(简单不一定知道)

问题描述&#xff1a; 给定两个字符串 s 和 t &#xff0c;它们只包含小写字母。 字符串 t 由字符串 s 随机重排&#xff0c;然后在随机位置添加一个字母。 请找出在 t 中被添加的字母。 示例 &#xff1a; 示例 1&#xff1a; 输入&#xff1a;s "abcd", t …

大学生抗疫逆行者网页作业 感动人物HTML网页代码成品 最美逆行者dreamweaver网页模板 致敬疫情感动人物网页设计制作

&#x1f389;精彩专栏推荐 &#x1f4ad;文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业&#xff1a; 【&#x1f4da;毕设项目精品实战案例 (10…

多维时序 | MATLAB实现ELM极限学习机多维时序预测(股票价格预测)

多维时序 | MATLAB实现ELM极限学习机多维时序预测(股票价格预测) 目录 多维时序 | MATLAB实现ELM极限学习机多维时序预测(股票价格预测)效果一览基本介绍程序设计结果输出参考资料效果一览 基本介绍

MySQL-僵持锁

前言 一个僵持锁&#xff08;deadlocks&#xff09;是指锁处于僵持的状态&#xff0c;持有锁的事务既得不到期望的资源&#xff0c;也不愿意释放其他事务需要的资源&#xff0c;也就是&#xff0c;多个锁相互之间都持有其他锁所需的资源&#xff0c;所有的事务都在等待各自需要…

防止重复下单(redis+数据库唯一索引requestId实现幂等)

文章目录为什么会重复下单如何防止重复下单利用数据库实现幂等利用Redis防重为什么会重复下单 为什么会重复下单&#xff0c;对于订单服务而言&#xff0c;就是接到了多个下单的请求&#xff0c;原因可能有很多&#xff0c;最常见的是这两种&#xff1a; 用户重复提交网络原因…

使用easygui制作app

【小白从小学Python、C、Java】 【计算机等级考试500强双证书】 【Python-数据分析】 使用easygui制作app [太阳]选择题 对于以下python代码表述错误的一项是? import easygui easygui.msgbox("我是msgbox","msgbox标题") choices["A",…

学生网页设计作业源码(HTML+CSS)——海贼王6页代码质量好

HTML实例网页代码, 本实例适合于初学HTML的同学。该实例里面有设置了css的样式设置&#xff0c;有div的样式格局&#xff0c;这个实例比较全面&#xff0c;有助于同学的学习,本文将介绍如何通过从头开始设计个人网站并将其转换为代码的过程来实践设计。 ⚽精彩专栏推荐&#x1…

【Pytorch with fastai】第 13 章 :卷积神经网络

&#x1f50e;大家好&#xff0c;我是Sonhhxg_柒&#xff0c;希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流&#x1f50e; &#x1f4dd;个人主页&#xff0d;Sonhhxg_柒的博客_CSDN博客 &#x1f4c3; &#x1f381;欢迎各位→点赞…

数据结构之线性表的顺序存储结构

配套环境 clion + g++ 顺序存储的定义 线性表的顺序存储结构,指的是用一段地址连续的存储单元一次存储线性表中的数据元素 设计思路 使用一维数组来实现顺序存储结构 存储空间:T* m_array 当前长度:int m_length 顺序存储结构的元素获取操作 判断目标位置是否合法 如…

Backblaze 2022 Q3 硬盘故障质量报告解读

在9月份&#xff0c;我们更新了Backblaze 2022上半年的中期质量报告解读&#xff08;Backblaze2022中期SSD故障质量报告解读&#xff09;&#xff0c;基于报告中的分析数据&#xff0c;Backblaze也向外界传递作证了一个信息&#xff1a;固态硬盘SSD的长期可靠性比机械硬盘HDD要…

听说某宝抢购脚本大家都会了?那就在来个某东茅台抢购脚本吧。

前言 某宝脚本一搜能搜一大堆&#xff0c;就是不知道具体有没有用&#xff0c;但是这款某东的代码于11-17还是可用的&#xff0c;大家拿去白嫖吧&#xff01; 需要用到的一些工具 Python版本&#xff1a;3.7.8相关模块&#xff1a;DecryptLogin模块&#xff1b;argparse模块&am…

webpack5 Preload / Prefetch

代码分离 | webpack 中文文档webpack 是一个模块打包器。它的主要目标是将 JavaScript 文件打包在一起&#xff0c;打包后的文件用于在浏览器中使用&#xff0c;但它也能够胜任转换&#xff08;transform&#xff09;、打包&#xff08;bundle&#xff09;或包裹&#xff08;pa…

【云原生 | 44】Docker搭建Registry私有仓库之管理访问权限

&#x1f341;博主简介&#xff1a; &#x1f3c5;云计算领域优质创作者 &#x1f3c5;2022年CSDN新星计划python赛道第一名 &#x1f3c5;2022年CSDN原力计划优质作者 &#x1f3c5;阿里云ACE认证高级工程师 &#x1f3c5;阿里云开发者社区专…

C++ Reference: Standard C++ Library reference: Containers: deque: deque: rend

C官网参考链接&#xff1a;https://cplusplus.com/reference/deque/deque/rend/ 公有成员函数 <deque> std::deque::rend C98 reverse_iterator rend(); const_reverse_iterator rend() const; C11 reverse_iterator rend() noexcept; const_reverse_iterator rend() c…

【Vue】VueX 的语法详解(3)

在VueX&#xff08;叉&#xff09;里面有一个潜移默化&#xff0c;或者说本质上的一个约束是什么&#xff1f; mutation里面只允许‍‍写同步代码&#xff0c;不允许写‍‍异步代码&#xff0c;虽然它不强制的限制你说你写了就给你报错&#xff0c;但实际上它的设计里面要求‍‍…

2022跨境出海:中东地区网红营销现状及特点

提到中东&#xff0c;大家的第一印象可能就是“头顶一块布&#xff0c;天下我最富”的土豪形象&#xff0c;近期的卡塔尔世界杯也再次给外界展示了他们的壕无人性。但由于宗教影响&#xff0c;他们的很多线下交际活动受到限制&#xff0c;也使得他们在互联网世界十分活跃&#…

申报须知,2022年滁州市各区县高新技术企业奖励政策变化,明光市

为了帮助企业提前准备和更好地开展2023年高新技术企业认定申报工作&#xff0c;安徽省大力鼓励企业申报高新技术企业&#xff0c;相应出台了相关政策&#xff0c;同时对于高企申报也有很多奖补&#xff0c;下面小编汇总了滁州市琅琊区、南谯区、天长市、明光市、来安县、全椒县…

jq扩展机制

1、在$挂上自定义函数方法&#xff1a; 如果想自定义函数方法&#xff0c;而且能通过$调用&#xff0c;那就需要用到extend&#xff08;&#xff09;方法&#xff1b;格式&#xff1a;$.extend({}) ; <script>$.extend({yiyi:function(){console.log("yiyi")}…

唯亚威VIAVI FI-60光纤识别器

光纤识别器可以轻松地识别光信号&#xff0c;而无需断开光缆或中断网络交通。也可以转换为光功率计&#xff08;OPM&#xff09;。 VIAVI FI-60 LFI能够使用户轻松检测光信号&#xff0c;而无需断开光缆或中断网络交通。FI-60 LFI还包括了独特的VIAVI SafeChekTM &#xff0c;…

特种劳动防护用品安全标志证书

特种劳动防护用品安全标志是确认特种劳动防护用品安全防护性能符合国家标准、行业标准,准许生产经营单位配发和使用该劳动防护用品的凭证。特种劳保用品是指在劳动作业生产过程中对人体起到保护作用的安全防护用品,与之对应的是普通劳保用品,如防护眼镜、劳保鞋等。常见的特种劳…