人资项目 笔记

news/2024/7/10 0:47:38 标签: vue

跨域: 非同源(协议, 域名, 端口一致)

解决开发环境的跨域问题

vue-cli配置webpack的反向代理

 在vue.config.js 里设置 module.exports = {
  devServer: {

 }

处理token:

在src/utils/auth.js中:

import Cookies from 'js-cookie' // 本地存储

const TokenKey = 'hrsaas-ihrm-token' // 设定一个独一无二的key

export function getToken() {
  return Cookies.get(TokenKey)
}

export function setToken(token) {
  return Cookies.set(TokenKey, token)
}

export function removeToken() {
  return Cookies.remove(TokenKey)
}

 在store/user.js中:

import { getToken, setToken, removeToken } from '@/utils/auth'
import { login } from '@/api/user'
const state = {
  token: getToken(), // 设置token为共享状态, 初始化vuex的时候, 就先从缓存中读取
}
const mutations = {
  setToken(state, token) {
    state.token = token
    setToken(token)
  },
  removeToken(state) {
    state.token = null // 先删除vuex的token
    removeToken() // 再清除本地存储中的
  }
}
const actions = {
  async login(context, data) {
    const result = await login(data)
    // 判断是否成功 是否有token值
    // if (result.data.success) {
    //   const token = result.data.data
    //   context.commit('setToken', token)
    // }
    // 已经在响应拦截器处理过了
    context.commit('setToken', result)
  }
}

export default {
  namespaced: true,
  state,
  mutations,
  actions
}

处理axios的响应拦截器

 在utils/request.js中:

import axios from 'axios'
import { Message } from 'element-ui'
const service = axios.create({
    baseURL: process.env.VUE_APP_BASE_API,
    timeout: 5000, // 设置超时时间
})

service.interceptors.request.use()

// 响应拦截器
service.interceptors.response.use(response => {
    // axios默认加了一层data
    const { success, message, data } = response.data
    // 要根据success的成功与否决定下面的操作
    if (success) {
        return data
    } else {
        // 失败了不能进then 应该进catch
        Message.error(message) // 提示错误信息
        return Promise.reject(new Error(message))
    }
}, error => {
    Message.error(error.message) // 提示错误信息
    return Promise.reject(error) // 返回执行错误 让当前的执行链跳出成功 直接进入catch
})

export default service

主页的token拦截处理

 在src/permission.js 中:

// 权限拦截在路由跳转 导航守卫

import router from "@/router"; // 引入路由实例
import store from "@/store"; // 引入vuex store实例
import NProgress from 'nprogress' // 引入一份进度条插件
import 'nprogress/nprogress.css' // 引入进度条样式

// 不需要导出 因为已经在main.js引入了 只需要让代码执行即可

// 前置守卫
// next是前置守卫必须执行的钩子  next必须执行 如果不执行 页面就死了
// next() 放过
// next(false) 跳转终止
// next(地址) 跳转到某个地址
const whiteList = ['/login', '/404'] // 定义白名单
router.beforeEach((to, from, next) => {
    NProgress.start() // 开启进度条
    if (store.getters.token) {
        // 有token
        if (to.path === 'login') {
            // 如果访问的是 登录页
            next('/') // 跳到主页
        } else {
            next() // 不去登录页 想去哪就去哪 直接放行 跳转
        }
    } else {
        // 没有token
        if (whiteList.includes(to.path)) {
            // 表示要去的地址在白名单
            next()
        } else {
            next('/login')
        }
    }
    NProgress.done() // 手动强制关闭一次  为了解决 手动切换地址时  进度条的不关闭的问题
})

// 后置守卫
router.afterEach(function () {
    NProgress.done() // 关闭进度条
})

将数组数据转化成树形结构

 实现:

  methods: {
    async getDepartments() {
      const result = await getDepartments();
      this.company = { name: result.companyName, manager: "负责人" };
      this.departs = result.depts; // 需要将其转化成树形结构
      const data = tranListToTreeData(result.depts, "");
      console.log(data);
    },
  },

// function testFn(list, pid) {
//   var arr = []
//   list.forEach(item => {
//     if (item.pid === pid) {
//       arr.push(item)
//     }
//   })
//   return arr
// }

export function tranListToTreeData(list, pid) {
  var arr = []
  list.forEach(item => {
    if (item.pid === pid) {
      // 只要进到if里的 都是一级的数据(pid:'')

      // 在这里需要去判断一级的数据的id有没有其他人作为pid, 如果有就说明这个一级是有二级目录的
      // const children = testFn(list, item.id)
      const children = tranListToTreeData(list, item.id)
      if (children.length > 0) {
        item.children = children
      }
      arr.push(item)
    }
  })
  return arr
}

自定义校验规则, 筛选:

  //   现在定义一个函数 这个函数的目的是 去找 同级部门下 是否有重复的部门名称
    const checkNameRepeat = async (rule, value, callback) => {
      // value就是表单里用户输入的值
      const { depts } = await getDepartments();
      var arr = depts.filter((item) => {
        return item.pid === this.treeNode.id;
      });
      var flag = arr.some((item) => {
        return item.name === value;
      });
      flag ? callback(new Error(`同级部门已经有${value}部门了`)) : callback();
    };

  //  检查编码重复
    const checkCodeRepeat = async (rule, value, callback) => {
      const { depts } = await getDepartments();
      var flag = depts.some((item) => {
        return item.code === value && value;
      });
      flag
        ? callback(new Error(`组织架构中已经有部门使用${value}编码了`))
        : callback();
    };

使用: 

  { trigger: "blur", validator: checkCodeRepeat },

sync修饰符

只要用sync修饰,就可以省略父组件的监听和方法,直接将值赋值给showDialog

// 子组件 update:固定写法 (update:props名称, 值)
this.$emit('update:showDialog', false) //触发事件
// 父组件 sync修饰符
<child  :showDialog.sync="showDialog" />

 // this.$parent 可以直接调用到父组件的实例 实际上就是父组件this

      this.$parent.getEmployeeList();  这样可以直接调用父的方法

导出:

// 导出所有
    exportAll() {
      const headers = {
        手机号: "mobile",
        姓名: "username",
        入职日期: "timeOfEntry",
        聘用形式: "formOfEmployment",
        转正日期: "correctionTime",
        工号: "workNumber",
        部门: "departmentName",
      };
      import("@/vendor/Export2Excel").then(async (excel) => {
        // console.log(excel);
        const { rows } = await getEmployeeList({ page: 1, size: 1000000 });
        const res = this.formatJson(headers, rows);
        excel.export_json_to_excel({
          header: res.headerKey,
          data: res.arr,
          filename: "员工数据",
          multiHeader: [["基本信息", "", "", "", "", "", "部门"]],
          merges: ["A1:F1", "G1:G2"],
          // 复杂表头: 合并
        });
      });
    },
    formatJson(headers, rows) {
      const headerKey = Object.keys(headers);
      const arr = [];
      rows.forEach((item) => {
        const itemArr = [];
        headerKey.forEach((key) => {
          if (["timeOfEntry", "correctionTime"].includes(headers[key])) {
            item[headers[key]] = new Date(item[headers[key]]).toLocaleString();
          }
          if (headers[key] === "formOfEmployment") {
            const flag = EmployeeEnum.hireType.find(
              (obj) => obj.id === item[headers[key]]
            );
            return flag ? flag.value : "未知";
          }
          itemArr.push(item[headers[key]]);
        });
        arr.push(itemArr);
      });
      return {
        headerKey,
        arr,
      };
    },

处理数据格式:

  async success({ header, results }) {
      // console.log(data);
      // 现在的数据: [{入职日期:'xxx', 姓名:'xx'}]
      // 期望的数据: [{timeOfEntry:'xxx', mobile:'xx'}]
      const userRelations = {
        入职日期: "timeOfEntry",
        手机号: "mobile",
        姓名: "username",
        转正日期: "correctionTime",
        工号: "workNumber",
      };
      const arr = [];
      results.forEach((item) => {
        const userInfo = {};
        // 遍历 取出所有的键
        Object.keys(item).forEach((key) => {
          userInfo[userRelations[key]] = item[key];
          if (["correctionTime", "timeOfEntry"].includes(userRelations[key])) {
            userInfo[userRelations[key]] = this.formatDate(item[key], "-");
          } else {
            userInfo[userRelations[key]] = item[key];
          }
        });
        arr.push(userInfo);
      });
      await importEmployee(arr); // 调用导入接口
      this.$router.back();
    },

日期时间处理:

  formatDate(numb, format) {
      const time = new Date((numb - 1) * 24 * 3600000 + 1);
      time.setYear(time.getFullYear() - 70);
      const year = time.getFullYear() + "";
      const month = time.getMonth() + 1 + "";
      const date = time.getDate() - 1 + "";
      if (format && format.length === 1) {
        return year + format + month + format + date;
      }
      return (
        year +
        (month < 10 ? "0" + month : month) +
        (date < 10 ? "0" + date : date)
      );
    },

文件上传的三种方式:

1.

  <!-- el-upload组件 该组件内部会自己使用原生的xhr进行请求的发送 -->
    <!-- list-type 是列表的类型 可选值text/picture/picture-card -->
    <!-- action 是上传的地址 -->
    <!-- name 是上传的文件字段名 -->
    <!-- headers 是请求头的信息 -->
    <!-- on-success 是上传成功的钩子函数, 这里可以获取到服务器返回的数据 -->
    <el-upload
      action="http://124.233.14.236:8060/admin/common/upload?type=images"
      list-type="picture-card"
      name="file"
      :headers="{ 'x-token': token }"
      :on-success="onSuccess"
    >
    </el-upload>

2.

  <!-- auto-upload 自动上传功能, 默认为true -->
    <!-- http-request 覆盖默认的上传行为, 自己写上传的逻辑功能 -->
    <!-- file-list 是默认展示的图片内容, 一般用于做回显功能, file-list 的数据不是双向绑定的 -->
    <el-upload
      action="#"
      list-type="picture-card"
      :http-request="httpRequest"
      :file-list="fileList"
      :on-remove="onRemove"
    >
      <i class="el-icon-plus"></i>
    </el-upload>
 methods: {
    onRemove(file) {
      console.log(file);
    },
    httpRequest(file) {
      // 准备数据
      let fd = new FormData();
      fd.append("file", file);
      // 发送请求
      axios
        .post(
          "http://124.233.14.236:8060/admin/common/upload?type=images",
          fd,
          {
            headers: { "x-token": this.token },
          }
        )
        .then((res) => {
          console.log(res.data);
        });
    },
  },

3.

 <el-upload
      list-type="picture-card"
      :file-list="fileList"
      :on-preview="onPreview"
      :on-remove="onRemove"
      :on-change="onChange"
      :before-upload="beforeUpload"
      :http-request="httpRequest"
      action="#"
      :class="{ hidden: fileComputed }"
    >

 onRemove移除事件

onPreview预览事件

onChange(file, fileList) {

      this.fileList = fileList.map((item) => item);

    },

 // 文件发送改变的时候触发==> 添加文件, 上传成功和上传失败时都会被调用

    // file 是选择的文件信息

    // fileList 是最新的上传列表

    // 不能使用push, 原因是因为会调用很多次, 就会不断push到里面去

beforeUpload上传前的操作

httpRequest上传

RBAC权限设计思想:

用户--角色--权限

 


http://www.niftyadmin.cn/n/1735329.html

相关文章

Python opencv库 tkinter 设计屏幕录制工具

有时, 我们在电脑上需要录屏, 或制作gif动画, 用于演示电脑操作等。如何使用Python来实现? 目录1.使用cv2库生成视频2.使用tkinter选择录制区域3.再次实现4.最终的程序5.拓展: 创建gif动画1.使用cv2库生成视频 首先, opencv和PIL库可通过命令pip install opencv-python pillo…

权限管理-动态路由的三种思路

思路1&#xff1a; 登录之后&#xff0c;后端根据该用户的角色查询当该用户的权限信息&#xff0c;这些权限信息包含的标识是和本地完整的动态路由的name是有匹配关系的。我们登录之后拿到权限标识和本地的动态路由进行匹配筛选出属于当前用户的动态路由&#xff0c;然后通过ro…

Python tkinter 设计pickle文件编辑器

在Python中, pickle是用于储存Python对象的模块。但pickle生成的文件是二进制类型, 不容易打开。 为此, 自己制作了一个小型pickle文件编辑器。 目录1.pickle 基础2.程序代码实现1.pickle 基础 pickle.load(file) 从已打开的 file object 文件 中读取打包后的对象。 pickle.l…

echarts 的使用/按钮权限/全局混入

echarts 的使用: // 1. 导入 或者 script外链资源 // 2. 初始化一个echart对象 let echart Echarts.init(挂载DOM节点) // 3. 设置配置项 echart.setOption({配置对象}) 配置对象翻阅文档即可&#xff01; mounted里面做第一次的渲染 请求数据回来之后再次渲染 按钮权限…

Python pyc文件 bytecode的压缩, 加壳和脱壳解析

我们常常看到, 自己用PyInstaller等库打包的exe被别人反编译。而源代码在exe文件中是以字节码形式存储的。掌握了字节码的加密技巧, 就可以防止源代码的反编译。 目录1.字节码是什么2.包装字节码3.压缩字节码4.加壳字节码(方法一)&#xff1a;修改co_code5.加壳字节码(方法二)&…

小程序笔记

什么是小程序? 小程序是一种不需要下载、安装即可使用的应用&#xff0c;它实现了应用触手可及的梦想&#xff0c;用户扫一扫或者搜一下就能打开应用&#xff0c;也 实现了用完即走的理念&#xff0c;用户不用安装太多应用&#xff0c;应用随处可用&#xff0c;但又无须安装卸…

Python pyd文件的制作和编译,以及程序源代码的保护

在Python程序开发后, 有可能想要保护程序的源代码, 避免被uncompyle6等库反编译。 目录pyd文件是什么安装Visual Studio C编译器方法1: 从py文件生成pyd文件 (常用)方法2: 编写C/C代码, 编译成pyd文件pyd文件是什么 pyd文件类似于DLL, 一般用C/C语言编译而成, 可用作模块导入P…

永久关闭IE 浏览器停止支持提示的方法 (针对360安全卫士或Windows 10)

最近, IE11浏览器已被微软官方停止支持, 用户打开原有的IE浏览器会看见各种提示, 给用户的使用带来了不便。本文介绍在Windows系统中关闭IE 浏览器停止支持提示的方法。 目录针对 Windows 10针对360安全卫士作者探索过程结语针对 Windows 10 打开IE浏览器右上角的设置按钮, 找…