备注

193 阅读2分钟

env.js

/*
 * @Description: 后台地址配置文件
 */
module.exports = {
  development: {
    apiUrl: "http://192.168.212.13:8010",
    socketUrl: "http://192.168.212.13:9099"
  },
  debug: {
    apiUrl: "http://192.168.212.13:8010",
    socketUrl: "http://192.168.212.13:9099"
  },
  test: {
    apiUrl: "http://192.168.212.63:8010",
    socketUrl: "http://192.168.212.63:9099"
  },
  production: {
    apiUrl: "http://183.240.131.12:8010",
    socketUrl: "http://183.240.131.12:9099"
  }
};

http.js

/*
 * @Description: 封装axios
 */

import Vue from 'vue'
import axios from 'axios'; // 引入axios
import QS from 'qs'; // 引入qs模块,用来序列化post类型的数据
import router from '../router'
import apiUrl from './env';

axios.defaults.baseURL = apiUrl[process.env.NODE_ENV].apiUrl


const pending = {}
const CancelToken = axios.CancelToken
const removePending = (key, isRequest = false) => {
  if (pending[key] && isRequest) {
    pending[key]('取消重复请求')
  }
  delete pending[key]
}
const getRequestIdentify = (config, isReuest = false) => {
  let url = config.url
  if (isReuest) {
    url = config.baseURL + config.url.substring(1, config.url.length)
  }
  return config.method === 'get' ? encodeURIComponent(url + JSON.stringify(config.params)) : encodeURIComponent(config.url + JSON.stringify(config.data))
}

let [oldServer, newServer] = [null, null];
// 环境的切换(暂时改用本地代理跨域,以下代码暂时不启用)
const env = process.env.NODE_ENV

//ElementUIUEDITOR_CONFIG.serverUrl = `${apiUrl[env].apiUrl}/ueditor/config`;
// setStore({
//   name: "serviceOption",
//   content: {
//     isDebug: true,
//     fileUrl: `${apiUrl[env].apiUrl}/file/white/download?filePath=`,
//     socketUrl: apiUrl[env].socketUrl
//   }
// })

/*
if (env !== 'development') {
  oldServer = "/api";
  newServer = "";
  axios.defaults.baseURL = apiUrl[env].apiUrl;
}
*/

// 请求超时时间
// axios.defaults.timeout = 10000;

// post请求头
// axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';

let windowLoadingcontrol = null;
let windowAjaxTime = {
  start: null,
  end: null
};
// 请求拦截器
axios.interceptors.request.use(config => {
  // 处理短时间内重复的请求
  // let requestData = getRequestIdentify(config, true);
  // removePending(requestData, true);
  // config.cancelToken = new CancelToken((c) => {
  //   pending[requestData] = c
  // });
  // 按规则重写请求路径
  // if (oldServer !== null && newServer !== null) {
  //   if (Array.isArray(oldServer)) {
  //     oldServer.forEach((item, index) => {
  //       config.url = config.url.replace(item, newServer[index]);
  //     })
  //   } else {
  //     config.url = config.url.replace(oldServer, newServer);
  //   }
  // };
  //showLoading();
  // 给每次请求写入开始时间 方便后面计算结束时间
  windowAjaxTime.start = new Date().getTime();

  // 每次发送请求之前判断是否存在token,如果存在,则统一在http请求的header都加上token,不用每次请求都手动添加了
  // 即使本地存在token,也有可能token是过期的,所以在响应拦截器中要对返回状态进行判断

  const token = 1;
  if (token) {
    config.headers.Authorization = 'Bearer ' + token;
  }
  return config;
}, error => {
  // hideLoading();
  return Promise.error(error);
})

// 响应拦截器
axios.interceptors.response.use(response => {
  clearTimeout(windowLoadingcontrol);
  windowLoadingcontrol = setTimeout(() => {
    // hideLoading();
  }, 300);
  const resData = response.data;

  // console.log('响应拦截器', response);
  if (Number(resData.code) === 200) {
    windowAjaxTime.end = new Date().getTime();
    response.data.resTime = windowAjaxTime.end - windowAjaxTime.start;
    return Promise.resolve(response);
    // blob不拦截
    /* if (response.data.constructor === Blob) {
      return Promise.resolve(response);
    } */
  } else {
    Vue.prototype.$message.error(resData.message)
    return Promise.reject(response);
  }
}, (error) => {
  // hideLoading();
  // console.log(error.response);
  // 服务器状态码不是200的情况
  if (error.response.status === 401 || error.response.status === 401) {
    // 登录过期则跳转登录页面,并携带当前页面的路径
    // 在登录成功后返回当前页面,这一步需要在登录页操作。
    Vue.prototype.$message.error("账号过期,请重新登录");
    removeStore({ name: 'access_token' });
    removeStore({ name: 'userInfo' });
    router.replace({
      path: '/login',
      query: {
        redirect: router.currentRoute.fullPath
      }
    });
    this.$socket.close();
  } else {
    /* switch (error.response.status) {
      // 登录过期则跳转登录页面,并携带当前页面的路径
      // 在登录成功后返回当前页面,这一步需要在登录页操作。
      case 401:
        removeStore({ name: 'access_token' });
        removeStore({ name: 'userInfo' });
        this.$socket.close();
        router.replace({
          path: '/login',
          query: {
            redirect: router.currentRoute.fullPath
          }
        });
        location.reload();
        break;

      default:
        break;
    } */
    Vue.prototype.$message.error(error.response.data.message || "服务出错了,请稍后再试")
  }

  return Promise.reject(error)
})

/**
 * get方法,对应get请求
 * @param {String} url [请求的url地址]
 * @param {Object} params [请求时携带的参数]
 */
function get(url, params) {
  // 以下是对含有数组的参数的处理方式,根据目前要求合理选择
  // QS.stringify({ids: [1, 2, 3]}, { indices: false })
  //形式: ids=1&ids=2&ids=3
  // QS.stringify({ids: [1, 2, 3]}, {arrayFormat: ‘indices‘})
  //形式: ids[0]=1&ids1]=2&ids[2]=3
  // QS.stringify({ids: [1, 2, 3]}, {arrayFormat: ‘brackets‘})
  //形式:ids[]=1&ids[]=2&ids[]=3
  // QS.stringify({ids: [1, 2, 3]}, {arrayFormat: ‘repeat‘})
  //形式: ids=1&ids=2&ids=3
  const dealObjectValue = (obj) => {
    let param = {};
    if (obj === null || obj === undefined || obj === "") return param;
    for (let key in obj) {
      if (Array.isArray(obj[key])) {
        const arr = obj[key].find((item) => {
          if (item !== null && item !== undefined && item !== "") return item
        })
        if (arr) {
          param[key] = obj[key];
        }
      } else if (obj[key] instanceof Object) {
        param[key] = dealObjectValue(obj[key]);
      } else if (obj[key] !== null && obj[key] !== undefined && obj[key] !== "") {
        param[key] = obj[key];
      }
    }
    return param;
  };
  const newParams = dealObjectValue(params);
  return new Promise((resolve, reject) => {
    axios.get(url, {
      params: newParams,
      paramsSerializer: function (params) {
        return QS.stringify(params, { arrayFormat: 'indices' })
      }
    })
      .then(res => {
        resolve(res.data);
      })
      .catch(err => {
        reject(err.data)
      })
  });
}

/**
 * post方法,对应post请求
 * @param {String} url [请求的url地址]
 * @param {Object} params [请求时携带的参数]
 * @param {Object/String} config [Object:post请求配置,一般情况下用于设置请求头headers,不传是按默认配置;String:"json"]
 */
function post(url, params, config) {
  return new Promise((resolve, reject) => {
    let parameters = params;
    if (!config) {
      parameters = url.indexOf('/core/') >= 0 ? params : QS.stringify(params);
    } else if (config === "json") {
      config = {
        headers: { 'Content-Type': 'application/json;charset=utf-8' }
      }
    }
    axios.post(url, parameters, config)
      .then(res => {
        resolve(res.data);
      })
      .catch(err => {
        reject(err.data)
      })
  });
}

/**
 * put方法, 对应put请求
 * @param {String} url [请求的url地址]
 * @param {Object} params [请求时携带的参数]
 * @param {Object/String} config [Object:post请求配置,一般情况下用于设置请求头headers,不传是按默认配置;String:"json"]
 */
function put(url, params, config) {
  return new Promise((resolve, reject) => {
    let parameters = params;
    if (!config) {
      parameters = QS.stringify(params);
    }
    axios.put(url, parameters)
      .then(res => {
        resolve(res.data);
      })
      .catch(err => {
        reject(err.data)
      })
  });
}

/**
 * del方法, 对应delete请求
 * @param {String} url [请求的url地址]
 * @param {Object} params [请求时携带的参数]
 */
function del(url, params) {
  return new Promise((resolve, reject) => {
    // 此类型参数传递为url传递方式
    axios.delete(url, { params: params })
      // 此类型参数传递为对象传递
      // axios.delete(url, { data: params })
      // axios.delete(url, QS.stringify({ data: params }))
      .then(res => {
        resolve(res.data);
      })
      .catch(err => {
        reject(err.data)
      })
  });
}

/**
 * upload方法   文件上传
 * @param {Array} files [文件对象数组]
 * @param {String} url [接口url]  默认值 '/api/file-service/file/upload'
 * @param {String} paramName [文件参数命名] 默认值 'files'
 * @param {Object} otherParam [其余参数]
 */
function upload(files, url, paramName, otherParam) {
  url = url || '/api/file/upload';
  paramName = paramName || 'file';
  let param = new FormData(); //创建form对象
  if (Object.prototype.isPrototypeOf(otherParam) && Object.keys(otherParam).length !== 0) {
    for (const key in otherParam) {
      if (otherParam.hasOwnProperty(key)) {
        const element = otherParam[key];
        param.append(key, element);
      }
    }
  }
  files.map((item) => {
    param.append(paramName, item);//通过append向form对象添加数据
  })
  let config = {
    headers: { 'Content-Type': 'multipart/form-data' }
  };
  return new Promise((resolve, reject) => {
    axios.post(url, param, config)
      .then(res => {
        resolve(res.data);
      })
      .catch(err => {
        reject(err.data)
      })
  });
}

/**
 * download方法
 * @param {String} type [请求的方式]
 * @param {Object} params [请求时携带的参数]
 * @param {Boolean} isDownLoad [是否下载] 默认值 true
 */
function download(params, isDownLoad = true) {
  let config = {
    params: params,
    headers: {
      'content-disposition': "attachment;filename*=UTF-8",
      'Content-Type': 'application/x-download;charset=utf-8'
    },
    responseType: 'blob'
  };
  return new Promise((resolve, reject) => {
    axios.get("/api/file/download", config)
      .then(res => {
        if (!res) return;
        const disposition = res.headers["content-disposition"];
        const fileNameFromHeader = (disposition) => {
          var result = null;
          if (disposition && /filename=.*/ig.test(disposition)) {
            result = disposition.match(/filename=.*/ig);
            return decodeURI(escape(result[0].split('=')[1]));
          }
          return null;
        }
        const fileName = fileNameFromHeader(disposition);
        let url = window.URL.createObjectURL(res.data);
        resolve([url, fileName]);
        if (!isDownLoad) return;
        let link = document.createElement('a');
        link.style.display = 'none';
        link.href = url;
        link.setAttribute('download', fileName);
        document.body.appendChild(link);
        link.click();
      })
      .catch(err => {
        reject(err.data)
      })
  });
}

/**
 * downloadEz方法
 * @param {String} type [请求的方式]
 * @param {String} url [请求的url地址]
 * @param {Object} params [请求时携带的参数]
 * @param {String} fileType [导出文件类型] 默认值 xls
 * @param {String} fileName [导出文件名称] 默认值 导出文件
 * @param {Boolean} isDownLoad [是否下载] 默认值 true
 */
function downloadEx(url, params, fileName, isDownLoad = true) {
  let fileType = 'xlsx';
  fileName = fileName || '导出文件';
  let config = {
    params: params,
    headers: {
      'content-disposition': "attachment;filename=total." + fileType,
      'Content-Type': 'application/x-download;charset=utf-8'
    },
    responseType: 'blob'
  };
  return new Promise((resolve, reject) => {
    axios.get(url, config)
      .then(err => {
        if (!err) return;
        let url = window.URL.createObjectURL(err.data);
        resolve(url);
        if (!isDownLoad) return;
        let link = document.createElement('a');
        link.style.display = 'none';
        link.href = url;
        link.setAttribute('download', `${fileName}.${fileType}`);
        document.body.appendChild(link);
        link.click();
      })
      .catch(err => {
        reject(err.data)
      })
  });
}

export default {
  get,
  post,
  put,
  del,
  upload,
  download,
  downloadEx,
  all: axios.all,
  spread: axios.spread
}

roter.js

/*
 * @Description:
 */
/*
 * @Description:
 */
import Vue from 'vue'
import Router from 'vue-router'
import Home from '@/pages/Home'
import Test from '@/pages/Test'
import Upload from '@/pages/Upload'
Vue.use(Router)

export default new Router({
  mode: 'history',
  routes: [
    {
      path: '/',
      name: 'Home',
      component: Home
    },
    {
      path: '/test',
      name: 'Test',
      component: Test
    },
    {
      path: '/upload',
      name: 'Upload',
      component: Upload
    }
  ]
})


app.vue

<!--
 * @Description:
-->
<template>
  <div id="app">
    <router-view/>
  </div>
</template>

<script>
export default {
  name: 'App'
}
</script>

<style>
</style>

main.js

/*
 * @Description:
 */
/*
 * @Description:
 */
// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import 'element-ui/lib/theme-chalk/index.css';



import Vue from 'vue'
import App from './App'
import router from './router'
import axios_ from './api/http' // axios封装
import ElementUI from 'element-ui';

Vue.config.productionTip = false
Vue.prototype.axios = axios_; // 挂载到Vue实例上面
Vue.use(ElementUI)

/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
  components: { App },
  template: '<App/>'
})

Upload.js

<!--
 * @Description:
-->
<!--
 * @Description:上传图片
-->
<template>
  <div class="upload">
    <!-- 图片上传 -->
    <div class="cell">
      <el-upload :show-file-list="false"
        class="avatar-uploader"
        action=""
        :http-request="uploadImg"
        :before-upload="beforeAvatarUpload">
        <img v-if="pic1" :src="pic1" class="avatar">
        <i v-else class="el-icon-plus avatar-uploader-icon"></i>
      </el-upload>
      <p>图片1</p>
    </div>
    <div class="cell">
      <el-upload :show-file-list="false"
        class="avatar-uploader"
        action=""
        :http-request="uploadImg"
        :before-upload="beforeAvatarUpload">
        <img v-if="pic1" :src="pic2" class="avatar">
        <i v-else class="el-icon-plus avatar-uploader-icon"></i>
      </el-upload>
      <p>图片2</p>
    </div>
  </div>
</template>
<script>
  export default {
    name:"Upload",
    data() {
      return {
        pic1:'http://119.45.146.73:8889/pic/white/download?filePath=/home/file/upload/20210331/timg.jpg',
        pic2:'',
        pic3:'',
        pic4:'',
        pic5:'',
        pic6:'',
        pic7:'',
        pic8:'',
      };
    },
    methods: {
      // 头像上传
    async uploadImg(file) {
      const avatar = await this.axios.upload([file.file]);
      this.pic1 = avatar
      this.$message.success('图片1修改成功');
    },
    beforeAvatarUpload(file) {
      const isJPG = file.type === 'image/jpeg' || file.type === 'image/png';
      const isLt2M = file.size / 1024 / 1024 < 2;
      if (!isJPG) {
        this.$message.error('上传头像图片只能是 JPG 或者 PNG 格式!');
      }
      if (!isLt2M) {
        this.$message.error('上传头像图片大小不能超过 2MB!');
      }
      return isJPG && isLt2M;
    },
    }
  }
</script>
<style>
  .avatar-uploader .el-upload {
    border: 1px dashed #d9d9d9;
    border-radius: 6px;
    cursor: pointer;
    position: relative;
    overflow: hidden;
  }
  .avatar-uploader .el-upload:hover {
    border-color: #409EFF;
  }
  .avatar-uploader-icon {
    font-size: 28px;
    color: #8c939d;
    width: 178px;
    height: 178px;
    line-height: 178px;
    text-align: center;
  }
  .avatar {
    width: 178px;
    height: 178px;
    display: block;
  }
</style>