同社は、主に各プロジェクトのビジネスロジックを除いたバックオフィス管理プロジェクトは、実際には、テンプレートの共通セットで行うことができませんでした。
ログインロジック
各システムには、ログアウトして、独自のロジックを持っており、フロントエンドは、私たちは何をする必要があり、実際に、ログオンする権利を持ってログオンし、ユーザー情報やメニュー情報にアクセスするための許可を取得するには、背景を要求しています。でvue
開発中のプロジェクト、我々は通常、グローバルルーティングフックを決定するために、このシリーズで行います。
router.beforeEach(async(to, from, next) => {
NProgress.start();
await store.dispatch('SetConfigApi'); // 获取配置
await store.dispatch('SetApi'); // 设置基本配置
const token = await store.dispatch('getToken'); // 获取token
if (token) {
// 用户信息不存在
if (!store.getters.userInfo) {
await store.dispatch('GetUser'); // 获取用户信息
const menuList = await store.dispatch('GetMenu', localRoute); // 获取菜单
await store.dispatch('GenerateRoutes', localRoute);
router.addRoutes(store.getters.addRoutes);
...
} else {
next();
}
} else {
if (whiteList.includes(to.path)) {
// 在免登录白名单,直接进入
next();
} else {
window.location.href = store.getters.api.IPORTAL_LOCAL_API;
NProgress.done();
}
}
});
复制代码
ユーザーは、システム構成情報を取得するには、システムに入り、コンフィギュレーション情報は、フロントエンドすることができた場合json
のインタフェースを、ファイル、またはバックグラウンド;このように、プロジェクトへの柔軟な構成変更することができますが、常にプロジェクトの中にパッケージ死ぬことはありません運用・保守の子供を指示するブーツは、それに対応する構成情報を変更することができます。
権限のメニュー
前のメニューをルーティングは、前面に死ぬために直接書き込まれますが、我々はこのルートへの直接アクセスを持っている場合、あなたはまだこの機能ページに入力することができます。後から動的に直接ルートを追加するように変更しましたrouter.addRoutes
。
- まずフロントエンドメニューのリストを取得
- 取得したリストのメニューに基づくユーザーメニューサイクルのルートセットを追加します。
- 動的にルートを追加
特定のビュー
要求プログラム
アイテムの要求が使用されaxios
、要求を処理するために、当社の迎撃に追加することができますによって処理することができaxios.CancelToken
、特にコードを見て、要求を繰り返します。
// 设置请求统一信息
import axios from 'axios';
import store from '@/store/index.js';
import qs from 'qs';
import { messages } from './msg-box.js';
const service = axios.create({
timeout: 300000, // 超时设置
withCredentials: true // 跨域请求
});
let hasLogoutStatus = false; // 是否某个请求存在需要退出的状态
const queue = []; // 请求队列
const CancelToken = axios.CancelToken; // axios内置的中断方法
/**
* 拼接请求的url和方法;
* 同样的`url + method` 可以视为相同的请求
* @param {Object} config 请求头对象
*/
const token = config => {
return `${config.url}_${config.method}`;
};
/**
* 中断重复的请求,并从队列中移除
* @param {Object} config 请求头对象
*/
const removeQueue = config => {
for (let i = 0, size = queue.length; i < size; i++) {
const task = queue[i];
if (!task) return;
// 出现401,403状态码中断后续请求
const isLogout = token(config).includes('logout');
// 退出接口跳过中断逻辑
if (!isLogout && hasLogoutStatus) {
task.token();
queue.splice(i, 1);
} else {
const cancelMethods = ['post', 'put', 'delete']; // 需要中断的请求方式
const { method } = config;
if (cancelMethods.includes(method)) {
if (task.token === token(config)) {
task.cancel();
queue.splice(i, 1);
}
}
}
}
};
/**
* 请求错误统一处理
* @param {Object} response 错误对象
*/
const errorHandle = response => {
// eslint-disable-next-line prettier/prettier
const { status, data: { message = '' }} = response;
let msg = message;
if (!message) {
switch (status) {
case 401:
msg = '您没有权限访问此操作!';
break;
case 403:
msg = '您的登录状态已失效,请重新登录。';
break;
case 424:
msg = response.data.error;
break;
default:
msg = '服务请求异常,请刷新重试。';
}
}
hasLogoutStatus = status === 401 || status === 403;
if (hasLogoutStatus) {
messages('error', msg, () => {
store.dispatch('Logout');
});
}
messages('error', msg);
};
// 请求拦截器
service.interceptors.request.use(
config => {
// 中断之前的同名请求
removeQueue(config);
// 添加cancelToken
config.cancelToken = new CancelToken(c => {
queue.push({ token: token(config), cancel: c });
});
// 登录后添加token
if (store.getters.token) {
config.headers['Authorization'] =
store.getters.token.token_type + ' ' + store.getters.token.access_token;
}
return config;
},
error => {
return Promise.reject(error);
}
);
// 响应拦截器
service.interceptors.response.use(
response => {
// 在请求完成后,自动移出队列
removeQueue(response.config);
// 关闭全局按钮Loading响应
store.dispatch('CancalLoading');
// 错误码处理
if (response.status !== 200) {
return Promise.reject(response);
}
return response;
},
error => {
const { response } = error;
if (response) {
// 错误处理
errorHandle(response);
return Promise.reject(response);
} else {
// 请求超时
if (error.message.includes('timeout')) {
console.log('超时了');
messages('error', '请求已超时,请刷新或检查互联网连接');
} else {
// 断网,可以展示断网组件
console.log('断网了');
messages('error', '请检查网络是否已连接');
}
}
}
);
export default {
get: (url, data = {}) => {
return new Promise((resolve, reject) => {
service
.get(store.getters.api.API + url, { params: data })
.then(response => {
resolve(response.data);
})
.catch(error => {
reject(error);
});
}).catch(error => {
throw new Error(error);
});
},
post: (url, data = {}) => {
return new Promise((resolve, reject) => {
service
.post(store.getters.api.API + url, data, {
headers: {
'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8'
},
withCredentials: true,
transformRequest: [
data => {
return qs.stringify(data);
}
]
})
.then(response => {
resolve(response.data);
})
.catch(error => {
reject(error);
});
}).catch(error => {
return Promise.reject(error);
});
},
...
/**
* blob下载
* @param {String} url 请求地址
* @param {String} method 请求方式 默认`get`
* @param {Object} data 请求数据
*/
exportFile({ url = '', data = {}, method = 'get' }) {
return new Promise((resolve, reject) => {
const isPost =
method.toLocaleUpperCase() === 'POST'
? {
headers: { 'Content-Type': 'application/json' },
data
}
: {
params: data
};
const downConfig = {
withCredentials: true,
responseType: 'blob',
...isPost
};
service
// eslint-disable-next-line no-unexpected-multiline
[method](store.getters.api.API + url, downConfig)
.then(response => {
resolve(response);
})
.catch(error => {
reject(error);
});
}).catch(error => {
return Promise.reject(error);
});
}
};
复制代码
要求が参照ファイルであることが要求される場合http.js
、また、に連結させることができるvue
プロトタイプ、構成要素は、で使用されますthis.$http
// user.js
import http from '@/utils/http.js';
export function getUser() {
return http.get('/user');
}
// main.js
Vue.prototype.$http = http;
复制代码
ボタンのロード処理
ボタンloading
、本明細書で使用される効果は、少し長くに応じて背景シーンを処理することができるstore
治療のカプセル化を。
// loading.js
import Vue from 'vue';
const loading = {
state: {},
mutations: {
SET_LOADING: (state, data) => {
const isObject =
Object.prototype.toString.call(data) === '[object Object]';
if (!isObject) return;
Object.keys(data).forEach(key => {
Vue.set(state, key, data[key]);
});
},
CANCAL_LOADING: state => {
Object.keys(state).forEach(key => {
Vue.delete(state, key);
});
}
},
actions: {
SetLoading({ commit }, data) {
commit('SET_LOADING', data);
},
CancalLoading({ commit }, data) {
commit('CANCAL_LOADING', data);
}
}
};
export default loading;
// http.js
service.interceptors.response.use(
response => {
// 关闭全局按钮Loading响应
store.dispatch('CancalLoading');
...
})
复制代码
コンポーネント内で定義されました
<el-button :loading="btn.save" @click="handleClick">保存</el-button>
computed: {
btn() {
return this.$store.state.loading;
}
}
methods: {
handleClick() {
this.$store.dispatch('SetLoading', { save: true });
}
}
复制代码
彼らはより完璧に使用することができますloading
ではなく、各よりも、data
の定義。
概要
いくつかの治療法は、特定のコードよりバックエンドシステムを使用することができますビュー。
その他の要約記事:
ます。https://juejin.im/post/5cedfea96fb9a07ef06f761eで再現