# CSS

  • src/assets/public.scss
$vm_base:375;  //设计图的宽度
@function vw($px) {
  @return ($px / $vm_base) * 100vw;
}

header,
main,
*{
  margin: 0;
  padding: 0;
}
html,#app{
  height: 100%;
}
div{
  box-sizing: border-box;
}
body{
  display: flex;
  flex-direction: column;
  height: 100%;
  background: $body_background_color;
}
footer{
  display: inline-block;
  width: 100%;
  height: vw(50);
  background: #f4f4f4;
}
header {
  width: 100%;
  height: vw(40);
}
main{
  width: 100%;
  height: 0;
  flex-grow: 1;
  overflow-y: scroll;
  -webkit-overflow-scrolling: touch;
  *{
    font-size: vw(15);
  }

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44

# 配置文件

npm i vant -S   //安装vant
1
  • main.js
import Vant from 'vant';
import 'vant/lib/index.css';

// 页面修改时修改浏览器标签栏
router.beforeEach((to, from, next) => {
  if (to.meta.title) {
    document.title = to.meta.title;
  }
  next();
});
1
2
3
4
5
6
7
8
9
10
  • vue.config.js
const webpack = require('webpack');

const publicPath = process.env.NODE_ENV === 'production' ? '/项目名称/' : '/';
module.exports = {
  // 内网穿透
  devServer: {
    host: '0.0.0.0',
    hot: true,
    disableHostCheck: true, // 解决无效的头部信息
    // port: 8081,
  },
  publicPath,
  lintOnSave: false,
  css: {
    loaderOptions: {
      // 设置 scss 公用变量文件
      sass: {
          //旧版
        data: '@import \'~@/assets/style/public.scss\';',
          //新版
       prependData: '@import "~@/assets/style/public.scss";',
      },
    },
  },
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
  • router
import Vue from 'vue';
import Router from 'vue-router';

Vue.use(Router);

const router = new Router({
  mode: 'history',
  base: '/survey-asked/',  //项目名  只有history模式需要
  routes: [
    {
      path: '/',
      name: 'login',
      component: () => import('@/views/login'),
      meta: { title: '登录' },
    },
  ],
});

export default router;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# axios请求 (opens new window)

npm install axios    //安装axios
1
  • 配置请求地址

接口请求地址 //puplic/config/configUrl.js

let baseURL = '';
switch (process.env.NODE_ENV) {
  // 开发环境
  case 'development':
    baseURL = {
      apiUrl: 'http://192.168.4.75:8084/api/',
      authUrl: 'http://192.168.4.75:9999/hg-auth/', // 授权地址 获取token
      userUrl: 'http://192.168.4.75:8088/', // 获取用户信息
    };
    break;
    // 线上环境
  case 'production':
    baseURL = {
      apiUrl: 'http://portal.honggu.cn:8000/bi-store/',
      authUrl: 'http://portal.honggu.cn:8000/hg-auth/', // 授权地址 获取token
      userUrl: 'http://portal.honggu.cn:8000/hg-admin/', // 获取用户信息
    };
    break;
  default:
}
export default baseURL;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# 拦截器 刷新token

配置拦截器白名单 //src/axios/api/whiteList.js

export default {
  // 不显示加载提示
  loading: ['auth/code', 'oauth/token', 'token/logout', 'external/getGuideInfo', 'external/guideChanges', 'user/info', 'role/menu'],

  // 不用添加店铺id
  nullStoreId: ['auth/code', 'oauth/token', 'token/logout', 'external/getGuideInfo', 'external/guideChanges', 'user/info', 'role/menu'],

  // 需要添加授权代码
  AuthorizationCode: ['auth/code', 'oauth/token'],
}
1
2
3
4
5
6
7
8
9
10

axios //src/axios/api/index.js

import axios from 'axios';
import { Toast, Loading } from 'vue-ydui/dist/lib.rem/dialog';
import { Dialog } from 'vant';
import router from '../../router/router';
import whiteList from '../whiteList';
import baseURL from '../../../public/config/configUrl';
// 创建一个错误
function errorCreate(msg) {
  const err = new Error(msg);
  throw err;
}

function getRfreshTokenFunc() {
  const params = {
    grant_type: 'refresh_token',
    refresh_token: window.localStorage.getItem('refresh_token'),
  };
  const headers = {
    Authorization: 'Basic Ymk6Ymk=',
  };
  return axios.get(`${baseURL.authUrl}oauth/token`, {
    params, headers,
  });
}
// 是否正在刷新
let isRefreshing = false;
// 被挂起的请求数组
let refreshSubscribers = [];

const service = axios.create({
  timeout: 6000 * 10,
});

// 请求拦截器
service.interceptors.request.use(
  (config) => {
    Loading.open('加载中');

    // 不显示加载中页面的接口  没有出现返回-1
    if (whiteList.loading.indexOf(config.url) !== -1) {
      Loading.close();
    }
    // 需要店铺id
    if (whiteList.nullStoreId.indexOf(config.url) === -1) {
      // 注入店铺ID,店铺切换是需更新storeNo
      if (config.method === 'get') {
        config.params.storeId = window.localStorage.getItem('storeNo');
      } else {
        config.data.storeId = window.localStorage.getItem('storeNo');
      }
    }

    let token = `Bearer ${window.localStorage.getItem('token')}`;
    // 需要授权代码
    if (whiteList.AuthorizationCode.indexOf(config.url) !== -1) {
      token = 'Basic Ymk6Ymk=';// 应用授权代码
    }

    // 添加headers参数
    if (token) {
      config.headers.Authorization = token;
    }
    return config;
  },
  ((error) => {
    // 对请求错误的处理
    Toast({
      mes: '请求失败',
      icon: 'error',
    });
    return Promise.reject(error);
  }),
);

// 响应拦截器
service.interceptors.response.use((response) => {
  Loading.close();
  // 对响应数据处理
  const { code } = response.data;

  switch (code) {
    case 0:
      return response.data;
    case 1: // 错误
      setTimeout(() => {
        router.replace({
          name: 'userNotFound',
          query: { info: response.data.msg },
        }, 1000);
      });
      break;
    case 401: // 请重新登录 // 无权限
      setTimeout(() => {
        router.replace({
          name: 'userNotFound',
          query: { info: response.data.msg },
        }, 1000);
      });
      break;
    default:
      // 不是正确的code   抛出异常
      errorCreate(Toast({
        mes: `${response.data.msg}`,
        icon: 'error',
      }));
  }
},
((error) => {
  Loading.close();
  const { config } = error;
  if (error && error.response) {
    switch (error && error.response.status) {
      case 400:
        Toast({
          mes: '对不起,页面走丢了(400)',
          icon: 'error',
        });
        break;
      case 401:
         //刷新token
        // 判断是否正在刷新
        if (error.response.data.code === 400) {
          if (!isRefreshing) {
            // 将刷新token的标准设为true
            isRefreshing = true;
            return getRfreshTokenFunc()
              .then((res) => {
                isRefreshing = false;
                // 更新 token refresh_token
                window.localStorage.setItem('token', res.data.access_token);
                window.localStorage.setItem('refresh_token', res.data.refresh_token);
                // 成功刷新token
                const token = `Bearer ${res.data.access_token}`;
                config.headers.Authorization = token;
                config.baseURL = '';
                // 执行数组里的函数,重新发起被挂起的请求
                refreshSubscribers.forEach(cb => cb(token));

                // 执行完成后,清空队列
                refreshSubscribers = [];

                // 字符串转换为json
                if (config.data) {
                  const obj = config.data;
                  const ret = JSON.parse(obj);
                  config.data = ret;
                }
                return service(config);
              })
              .catch((err) => {
                console.log('refresh token error', err);
                if (err.response.status === 426) {
                  Dialog.alert({
                    message: '登录已失效,请重新登录!',
                  }).then(() => {
                    WeixinJSBridge.call('closeWindow');
                    window.localStorage.clear();
                  });
                }
              })
              .finally(() => {
                isRefreshing = false;
              });
          }
          const retry = new Promise((resolve, reject) => {
            refreshSubscribers.push((token) => {
              // 因为config中的token是旧的,所以刷新token后要将新token传进来
              config.baseURL = '';
              config.headers.Authorization = token;

              // 字符串转换为json
              if (config.data) {
                const obj = config.data;
                const ret = JSON.parse(obj);
                config.data = ret;
              }
              resolve(service(config));
            });
          });
          return retry;
        }

        break;
      case 403:
        Toast({
          mes: '服务器繁忙,请稍后重试(403)',
          icon: 'error',
        });
        break;
      case 404:
        Toast({
          mes: '请求地址出错(404)',
          icon: 'error',
        });
        break;
      case 408:
        Toast({
          mes: '请求超时,请重新登录(408)',
          icon: 'error',
        });
        break;

      case 500:
        Toast({
          mes: '服务器繁忙,请稍后重试(500)',
          icon: 'error',
        });
        break;
      case 503:
        Toast({
          mes: '服务器繁忙,请稍后重试(503)',
          icon: 'error',
        });
        break;
      case 504:
        Toast({
          mes: '网络超时,请检查网络(504)',
          icon: 'error',
        });
        break;
      default:
        break;
    }
  } else {
    Toast({
      mes: '连接服务器失败',
      icon: 'error',
    });
  }
  return Promise.reject(error);
}));

export default service;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233

# api统一管理

  1. 方法一
    可以把请求写在很多个文件内
    缺点:每一个接口都需要在页面中引入
  • api接口 //src/api/api/index
import request from '@/axios/api';
import baseURL from '../../../public/config/configUrl';
const { apiUrl } = baseURL;
export function stockStyle(data) {
  return request({
   baseURL: apiUrl,
    url: 'stock/style',
    method: 'post',
    data,
  });
}
1
2
3
4
5
6
7
8
9
10
11
  • 页面调用
import {stockStyle} from '@/api/stock'

methods:{
   getInfo(){
     stockStyle({
       id:1
     })
   }
}
1
2
3
4
5
6
7
8
9
  1. 方法二
    只能把所有的请求写在一个js文件内 适合请求接口少的项目
    优点:不用每一个页面都引入接口
  • 所有接口的地址 //src/api/index.js
import request from '@/axios/index';

export default {
  getFactory(params) {
    return request({
      url: '/base/factory/list',
      method: 'get',
      params,
    });
  },
};
1
2
3
4
5
6
7
8
9
10
11
  • 在main.js中引入文件
import api from '@/api';
Vue.prototype.$http = api
1
2
  • 在页面中使用
 this.$http.getFactory({ pageSize: 10, page: 1, search: '' })
      .then((res) => {
        console.log(res);
      });
1
2
3
4
lastUpdate: 5/13/2021, 5:35:14 PM