diff --git a/env/.env b/env/.env index 03c7ecf..eb594ff 100644 --- a/env/.env +++ b/env/.env @@ -1,15 +1,25 @@ -VITE_APP_TITLE = 'unibest' +VITE_APP_TITLE = 'ruoyi-vue-pro' VITE_APP_PORT = 9000 VITE_UNI_APPID = 'H57F2ACE4' -VITE_WX_APPID = 'wxa2abb91f64032a2b' +VITE_WX_APPID = 'wx90bcb2127c1d8720' # h5部署网站的base,配置到 manifest.config.ts 里的 h5.router.base VITE_APP_PUBLIC_BASE=/unibest/ -VITE_SERVER_BASEURL = 'https://ukw0y1.laf.run' -VITE_UPLOAD_BASEURL = 'https://ukw0y1.laf.run/upload' +VITE_SERVER_BASEURL = 'http://localhost:48080/admin-api' +VITE_UPLOAD_BASEURL = 'http://localhost:48080/upload' # h5是否需要配置代理 VITE_APP_PROXY=false -VITE_APP_PROXY_PREFIX = '/api' +VITE_APP_PROXY_PREFIX = '/admin-api' + + +# 租户开关 +VITE_APP_TENANT_ENABLE=true +# 验证码的开关 +VITE_APP_CAPTCHA_ENABLE=true +# 默认账户密码 +VITE_APP_DEFAULT_LOGIN_TENANT = 芋道源码 +VITE_APP_DEFAULT_LOGIN_USERNAME = admin +VITE_APP_DEFAULT_LOGIN_PASSWORD = admin123 \ No newline at end of file diff --git a/package.json b/package.json index 7d8b8da..04106a1 100644 --- a/package.json +++ b/package.json @@ -107,6 +107,7 @@ "@esbuild/darwin-arm64": "0.20.2", "@esbuild/darwin-x64": "0.20.2", "@iconify-json/carbon": "^1.1.35", + "@iconify-json/ic": "^1.2.1", "@rollup/rollup-darwin-x64": "^4.18.0", "@types/node": "^20.14.2", "@types/wechat-miniprogram": "^3.4.7", diff --git a/pages.config.ts b/pages.config.ts index c84a271..bd75c40 100644 --- a/pages.config.ts +++ b/pages.config.ts @@ -30,28 +30,34 @@ export default defineUniPages({ list: [ // 注意tabbar路由需要使用 layout:tabbar 布局 { - pagePath: 'pages/index/index', - text: '首页', - icon: 'home', - iconType: 'wot', - }, - { - pagePath: 'pages/about/about', - text: '关于', - icon: 'i-carbon-code', + pagePath: 'pages/message/index', + text: '消息', + icon: 'i-ic-outline-message', + iconType: 'unocss', + }, + { + pagePath: 'pages/colab/index', + text: '协作', + icon: 'i-ic-outline-handshake', + iconType: 'unocss', + }, + { + pagePath: 'pages/work/index', + text: '工作台', + icon: 'i-ic-baseline-apps', + iconType: 'unocss', + }, + { + pagePath: 'pages/contacts/index', + text: '通讯录', + icon: 'i-ic-baseline-contact-page', iconType: 'unocss', }, - // { - // pagePath: 'pages/my/index', - // text: '我的', - // icon: '/static/logo.svg', - // iconType: 'local', - // }, { pagePath: 'pages/my/index', text: '我的', - icon: 'iconfont icon-my', - iconType: 'iconfont', + icon: 'i-ic-baseline-person', + iconType: 'unocss', }, ], }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8b40ecd..576f4d6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -78,6 +78,9 @@ importers: '@iconify-json/carbon': specifier: ^1.1.35 version: 1.1.35 + '@iconify-json/ic': + specifier: ^1.2.1 + version: 1.2.1 '@rollup/rollup-darwin-x64': specifier: ^4.18.0 version: 4.18.0 @@ -1185,6 +1188,9 @@ packages: '@iconify-json/carbon@1.1.35': resolution: {integrity: sha512-zKqioWceqFRiLJvxpjcCpVP3j2YcokYshlbwSAHBhOih5XNUymUS3hm1kpV4KljMI1xWH96UcozHaaf6x4YzdA==} + '@iconify-json/ic@1.2.1': + resolution: {integrity: sha512-UjL/bjJP/T5EV881+hTzcfTKVo0KEUjhnMiJcLtPzNgPtU2KZZmRx8BSKKR61H4CN/5FTEbyawGyG0aEt3SwGQ==} + '@iconify/types@2.0.0': resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==} @@ -6887,6 +6893,10 @@ snapshots: dependencies: '@iconify/types': 2.0.0 + '@iconify-json/ic@1.2.1': + dependencies: + '@iconify/types': 2.0.0 + '@iconify/types@2.0.0': {} '@iconify/utils@2.1.24': diff --git a/src/App.vue b/src/App.vue index d0dface..21c41bb 100644 --- a/src/App.vue +++ b/src/App.vue @@ -13,6 +13,10 @@ onHide(() => { diff --git a/src/pages/about/components/request.vue b/src/pages/about/components/request.vue deleted file mode 100644 index 89a656d..0000000 --- a/src/pages/about/components/request.vue +++ /dev/null @@ -1,56 +0,0 @@ - -{ - layout: 'demo', - style: { - navigationBarTitleText: '请求', - }, -} - - - - - diff --git a/src/pages/about/components/upload.vue b/src/pages/about/components/upload.vue deleted file mode 100644 index 07f81f5..0000000 --- a/src/pages/about/components/upload.vue +++ /dev/null @@ -1,30 +0,0 @@ - -{ - layout: 'default', - style: { - navigationBarTitleText: '上传-状态一体化', - }, -} - - - - - - - diff --git a/src/pages/colab/index.vue b/src/pages/colab/index.vue new file mode 100644 index 0000000..9437be7 --- /dev/null +++ b/src/pages/colab/index.vue @@ -0,0 +1,22 @@ + +{ + layout: 'tabbar', + style: { + navigationBarTitleText: '协作', + }, +} + + + + + + + diff --git a/src/pages/contacts/components/ContactsItem.vue b/src/pages/contacts/components/ContactsItem.vue new file mode 100644 index 0000000..a4246a9 --- /dev/null +++ b/src/pages/contacts/components/ContactsItem.vue @@ -0,0 +1,41 @@ + + + + + + diff --git a/src/pages/contacts/index.vue b/src/pages/contacts/index.vue new file mode 100644 index 0000000..7e5fe60 --- /dev/null +++ b/src/pages/contacts/index.vue @@ -0,0 +1,113 @@ + +{ + layout: 'tabbar', + style: { + navigationStyle: 'custom', + navigationBarTitleText: '通讯录', + }, +} + + + + + + + diff --git a/src/pages/contacts/mock.js b/src/pages/contacts/mock.js new file mode 100644 index 0000000..1896f17 --- /dev/null +++ b/src/pages/contacts/mock.js @@ -0,0 +1,70 @@ +export default [ + { + id: 1, + name: '芋道集团', + isLeaf: false, + children: [ + { + id: 11, + parentId: 1, + name: 'IT中心', + isLeaf: false, + children: [ + { + id: 111, + parentId: 11, + name: '马青楷', + post: 'CTO', + avatar: '/static/images/avatar3.jpg', + isLeaf: true, + }, + { + id: 112, + parentId: 11, + name: '王伟', + post: '前端开发', + avatar: '/static/images/avatar2.jpg', + isLeaf: true, + }, + { + id: 113, + parentId: 11, + name: '王博', + post: '技术主管', + avatar: '/static/images/avatar1.jpg', + isLeaf: true, + }, + ], + }, + { + id: 12, + parentId: 1, + name: '行政部门', + isLeaf: true, + }, + ], + }, + { + id: 2, + name: '中软集团', + isLeaf: false, + children: [ + { + id: 21, + parentId: 2, + name: '中软IT', + isLeaf: false, + children: [ + { + id: 211, + parentId: 21, + name: '马青楷', + post: 'CTO', + isLeaf: true, + avatar: '/static/images/avatar3.jpg', + }, + ], + }, + ], + }, +] diff --git a/src/pages/index/index.vue b/src/pages/index/index.vue deleted file mode 100644 index 893ed8f..0000000 --- a/src/pages/index/index.vue +++ /dev/null @@ -1,57 +0,0 @@ - - -{ - layout: 'tabbar', - style: { - navigationStyle: 'custom', - navigationBarTitleText: '首页', - }, -} - - - - - - diff --git a/src/pages/login/components/LoginForm.vue b/src/pages/login/components/LoginForm.vue new file mode 100644 index 0000000..50b115c --- /dev/null +++ b/src/pages/login/components/LoginForm.vue @@ -0,0 +1,146 @@ + + + + diff --git a/src/pages/login/index.vue b/src/pages/login/index.vue new file mode 100644 index 0000000..fd4deba --- /dev/null +++ b/src/pages/login/index.vue @@ -0,0 +1,73 @@ + +{ + style: { + navigationBarTitleText: '登录页面', + }, +} + + + + + + + diff --git a/src/pages/message/components/MessageItem.vue b/src/pages/message/components/MessageItem.vue new file mode 100644 index 0000000..a1ad1fe --- /dev/null +++ b/src/pages/message/components/MessageItem.vue @@ -0,0 +1,45 @@ + + + + + + + diff --git a/src/pages/message/index.vue b/src/pages/message/index.vue new file mode 100644 index 0000000..edc77e5 --- /dev/null +++ b/src/pages/message/index.vue @@ -0,0 +1,40 @@ + +{ + layout: 'tabbar', + style: { + navigationBarTitleText: '消息', + }, +} + + + + + + + diff --git a/src/pages/message/mock.js b/src/pages/message/mock.js new file mode 100644 index 0000000..6589646 --- /dev/null +++ b/src/pages/message/mock.js @@ -0,0 +1,92 @@ +export default [ + { + title: 'IT中心工作群', + content: '今天下午2点到5点,开部门会议,请各位提前准备好汇报材料。', + time: '昨天 15:30', + avatar: '/static/images/avatar1.jpg', + }, + { + title: '产品设计讨论组', + content: '关于新功能的设计稿,大家有什么建议可以在群里提出来。', + time: '昨天 18:45', + avatar: '/static/images/avatar2.jpg', + }, + { + title: '前端开发小组', + content: '明天开始进行项目代码review,请各位准备好自己的代码。', + time: '今天 09:00', + avatar: '/static/images/avatar3.jpg', + }, + { + title: '公司年会筹备组', + content: '年会节目征集开始了,欢迎大家积极报名参加!', + time: '今天 10:20', + avatar: '/static/images/avatar4.jpg', + }, + { + title: '技术分享会', + content: '本周五下午的技术分享会主题是“Vue 3的新特性”,不要错过哦。', + time: '今天 14:30', + avatar: '/static/images/avatar5.jpg', + }, + { + title: 'IT中心工作群', + content: '今天下午2点到5点,开部门会议,请各位提前准备好汇报材料。', + time: '昨天 15:30', + avatar: '/static/images/avatar1.jpg', + }, + { + title: '产品设计讨论组', + content: '关于新功能的设计稿,大家有什么建议可以在群里提出来。', + time: '昨天 18:45', + avatar: '/static/images/avatar2.jpg', + }, + { + title: '前端开发小组', + content: '明天开始进行项目代码review,请各位准备好自己的代码。', + time: '今天 09:00', + avatar: '/static/images/avatar3.jpg', + }, + { + title: '公司年会筹备组', + content: '年会节目征集开始了,欢迎大家积极报名参加!', + time: '今天 10:20', + avatar: '/static/images/avatar4.jpg', + }, + { + title: '技术分享会', + content: '本周五下午的技术分享会主题是“Vue 3的新特性”,不要错过哦。', + time: '今天 14:30', + avatar: '/static/images/avatar5.jpg', + }, + { + title: 'IT中心工作群', + content: '今天下午2点到5点,开部门会议,请各位提前准备好汇报材料。', + time: '昨天 15:30', + avatar: '/static/images/avatar2.jpg', + }, + { + title: '产品设计讨论组', + content: '关于新功能的设计稿,大家有什么建议可以在群里提出来。', + time: '昨天 18:45', + avatar: '/static/images/avatar1.jpg', + }, + { + title: '前端开发小组', + content: '明天开始进行项目代码review,请各位准备好自己的代码。', + time: '今天 09:00', + avatar: '/static/images/avatar3.jpg', + }, + { + title: '公司年会筹备组', + content: '年会节目征集开始了,欢迎大家积极报名参加!', + time: '今天 10:20', + avatar: '/static/images/avatar2.jpg', + }, + { + title: '技术分享会', + content: '本周五下午的技术分享会主题是“Vue 3的新特性”,不要错过哦。', + time: '今天 14:30', + avatar: '/static/images/avatar4.jpg', + }, +] diff --git a/src/pages/my/index.vue b/src/pages/my/index.vue index 169627b..19cb4d1 100644 --- a/src/pages/my/index.vue +++ b/src/pages/my/index.vue @@ -8,11 +8,121 @@ diff --git a/src/pages/work/index.vue b/src/pages/work/index.vue new file mode 100644 index 0000000..47e7ae9 --- /dev/null +++ b/src/pages/work/index.vue @@ -0,0 +1,48 @@ + +{ + layout: 'tabbar', + style: { + navigationBarTitleText: '工作台', + }, +} + + + + + + + diff --git a/src/service/login/LoginAPI.ts b/src/service/login/LoginAPI.ts new file mode 100644 index 0000000..4b844b6 --- /dev/null +++ b/src/service/login/LoginAPI.ts @@ -0,0 +1,21 @@ +import { http, httpGet, httpPost } from '@/utils/http' + +export const login = (data) => { + return http({ + url: '/system/auth/login', + method: 'POST', + data, + }) +} + +export const loginOut = () => { + return httpPost('/system/auth/logout') +} + +export const getInfo = (): Promise => { + return httpGet('/system/auth/get-permission-info') +} + +export const getTenantIdByName = (name: string) => { + return httpGet('/system/tenant/get-id-by-name', { name }) +} diff --git a/src/static/images/avatar1.jpg b/src/static/images/avatar1.jpg new file mode 100644 index 0000000..9d0c8ad Binary files /dev/null and b/src/static/images/avatar1.jpg differ diff --git a/src/static/images/avatar2.jpg b/src/static/images/avatar2.jpg new file mode 100644 index 0000000..62ccbbf Binary files /dev/null and b/src/static/images/avatar2.jpg differ diff --git a/src/static/images/avatar3.jpg b/src/static/images/avatar3.jpg new file mode 100644 index 0000000..898248d Binary files /dev/null and b/src/static/images/avatar3.jpg differ diff --git a/src/static/images/avatar4.jpg b/src/static/images/avatar4.jpg new file mode 100644 index 0000000..23d5047 Binary files /dev/null and b/src/static/images/avatar4.jpg differ diff --git a/src/static/images/avatar5.jpg b/src/static/images/avatar5.jpg new file mode 100644 index 0000000..673ffda Binary files /dev/null and b/src/static/images/avatar5.jpg differ diff --git a/src/static/images/contacts.png b/src/static/images/contacts.png new file mode 100644 index 0000000..312a5a1 Binary files /dev/null and b/src/static/images/contacts.png differ diff --git a/src/static/images/empty.png b/src/static/images/empty.png new file mode 100644 index 0000000..9e16702 Binary files /dev/null and b/src/static/images/empty.png differ diff --git a/src/static/images/login-bg.png b/src/static/images/login-bg.png new file mode 100644 index 0000000..c749afd Binary files /dev/null and b/src/static/images/login-bg.png differ diff --git a/src/store/user.ts b/src/store/user.ts index 82bd873..0c6e902 100644 --- a/src/store/user.ts +++ b/src/store/user.ts @@ -1,35 +1,74 @@ import { defineStore } from 'pinia' import { ref } from 'vue' +import { getAccessToken, removeToken } from '@/utils/auth' +import { getInfo, loginOut } from '@/service/login/LoginAPI' -const initState = { nickname: '', avatar: '' } +const initState = { + permissions: [], + roles: [], + isSetUser: false, + user: { + id: 0, + avatar: '', + nickname: '', + deptId: 0, + }, +} export const useUserStore = defineStore( 'user', () => { - const userInfo = ref({ ...initState }) + // state - const setUserInfo = (val: IUserInfo) => { - userInfo.value = val + const userInfo = ref({ ...initState }) + + // actions methods + const setUserInfoAction = async () => { + if (!getAccessToken()) { + // 获取不到accessToken,直接返回 + resetState() + return + } + + const data = await getInfo() + userInfo.value = { + ...data, + isSetUser: true, + } } - const clearUserInfo = () => { - userInfo.value = { ...initState } + const setUserAvatarAction = async (avatar: string) => { + userInfo.value.user.avatar = avatar } - // 一般没有reset需求,不需要的可以删除 - const reset = () => { - userInfo.value = { ...initState } - } - const isLogined = computed(() => !!userInfo.value.token) + const setUserNicknameAction = async (nickname: string) => { + userInfo.value.user.nickname = nickname + } + + const LogOut = async () => { + await loginOut() + removeToken() + resetState() + } + + const resetState = () => { + console.log('initState', initState) + userInfo.value = initState + console.log('重置userInfo', userInfo.value) + } + + // 暴露到外面的方法 return { userInfo, - setUserInfo, - clearUserInfo, - isLogined, - reset, + setUserInfoAction, + setUserAvatarAction, + setUserNicknameAction, + LogOut, + resetState, } }, { + // 持久化 persist: true, }, ) diff --git a/src/style/index.scss b/src/style/index.scss index 86184d9..4a9f82c 100644 --- a/src/style/index.scss +++ b/src/style/index.scss @@ -15,4 +15,8 @@ page { // 修改按钮背景色 // --wot-button-primary-bg-color: green; + + // + --wot-search-light-bg: #f2f3f7; + --wot-search-input-radius: 5px; } diff --git a/src/types/system.d.ts b/src/types/system.d.ts new file mode 100644 index 0000000..403f1f6 --- /dev/null +++ b/src/types/system.d.ts @@ -0,0 +1,20 @@ +type UserVO = { + id: number + avatar: string + nickname: string + deptId: number +} + +type UserInfoVO = { + // USER 缓存 + permissions: string[] + roles: string[] + isSetUser: boolean + user: UserVO +} + +declare namespace JSX { + interface IntrinsicElements { + block: any // 或者更具体的类型定义 + } +} diff --git a/src/types/uni-pages.d.ts b/src/types/uni-pages.d.ts index f73e4a9..b2589ec 100644 --- a/src/types/uni-pages.d.ts +++ b/src/types/uni-pages.d.ts @@ -4,14 +4,17 @@ // Generated by vite-plugin-uni-pages interface NavigateToOptions { - url: "/pages/index/index" | - "/pages/about/about" | + url: "/pages/work/index" | + "/pages/colab/index" | + "/pages/contacts/index" | + "/pages/login/index" | + "/pages/message/index" | "/pages/my/index"; } interface RedirectToOptions extends NavigateToOptions {} interface SwitchTabOptions { - url: "/pages/index/index" | "/pages/about/about" | "/pages/my/index" + url: "/pages/message/index" | "/pages/colab/index" | "/pages/work/index" | "/pages/contacts/index" | "/pages/my/index" } type ReLaunchOptions = NavigateToOptions | SwitchTabOptions; diff --git a/src/utils/auth.ts b/src/utils/auth.ts new file mode 100644 index 0000000..9799614 --- /dev/null +++ b/src/utils/auth.ts @@ -0,0 +1,37 @@ +const AccessTokenKey = 'ACCESS_TOKEN' +const RefreshTokenKey = 'REFRESH_TOKEN' +const TenantIdKey = 'tenantId' + +// ========== Token 相关 ========== + +// 获取 Token +export function getAccessToken() { + return uni.getStorageSync(AccessTokenKey) +} + +// 获取 RefreshToken +export function getRefreshToken() { + return uni.getStorageSync(RefreshTokenKey) +} + +// 设置 Token +export function setToken(token) { + uni.setStorageSync(AccessTokenKey, token.accessToken) + uni.setStorageSync(RefreshTokenKey, token.refreshToken) +} + +// 移除 Token +export function removeToken() { + uni.removeStorageSync(AccessTokenKey) + uni.removeStorageSync(RefreshTokenKey) +} + +// ========== 租户相关 ========== + +export const getTenantId = () => { + return uni.getStorageSync(TenantIdKey) +} + +export const setTenantId = (username: string) => { + uni.setStorageSync(TenantIdKey, username) +} diff --git a/src/utils/common.ts b/src/utils/common.ts new file mode 100644 index 0000000..998061e --- /dev/null +++ b/src/utils/common.ts @@ -0,0 +1,28 @@ +/** + * 显示模态弹窗 + * @param content 提示的标题 + */ +export function showConfirm(content: string) { + return new Promise((resolve, reject) => { + uni.showModal({ + title: '提示', + content, + cancelText: '取消', + confirmText: '确定', + success: function (res) { + resolve(res) + }, + }) + }) +} + +/** + * 显示消息提示框 + * @param content 提示的标题 + */ +export function toast(content: string) { + uni.showToast({ + title: content, + icon: 'none', + }) +} diff --git a/src/utils/errorCode.ts b/src/utils/errorCode.ts new file mode 100644 index 0000000..abb3409 --- /dev/null +++ b/src/utils/errorCode.ts @@ -0,0 +1,7 @@ +export default { + '401': '认证失败,无法访问系统资源', + '403': '当前操作没有权限', + '404': '访问资源不存在', + '500': '服务器错误', + default: '系统未知错误,请反馈给管理员', +} diff --git a/src/utils/http.ts b/src/utils/http.ts index 4e3f38c..edc41c4 100644 --- a/src/utils/http.ts +++ b/src/utils/http.ts @@ -1,8 +1,28 @@ import { CustomRequestOptions } from '@/interceptors/request' +import { useUserStore } from '@/store' +import { getAccessToken, getRefreshToken, setToken } from '@/utils/auth' +import { showConfirm, toast } from '@/utils/common' +import { getEvnBaseUrl } from '@/utils' +import errorCode from './errorCode' + +/* + 双token刷新说明 + 1. token和tenantId都是在拦截器中赋值 + 2. 后端并不直接更改http statusCode,而是返回一个重新包装后的对象, + 所以不能使用失败回调函数就行判断token是否过期需要重新获取 + 3. 应该在success中,解析res,如果code是401,则说明token过期,需要重新获取 +*/ + +// 是否正在刷新中 +let isRefreshToken = false +// 请求的方法栈 +let requestList = [] +// 请求基准地址 +const baseUrl = getEvnBaseUrl() export const http = (options: CustomRequestOptions) => { // 1. 返回 Promise 对象 - return new Promise>((resolve, reject) => { + return new Promise((resolve, reject) => { uni.request({ ...options, dataType: 'json', @@ -10,25 +30,97 @@ export const http = (options: CustomRequestOptions) => { responseType: 'json', // #endif // 响应成功 - success(res) { - // 状态码 2xx,参考 axios 的设计 - if (res.statusCode >= 200 && res.statusCode < 300) { - // 2.1 提取核心数据 res.data - resolve(res.data as IResData) - } else if (res.statusCode === 401) { - // 401错误 -> 清理用户信息,跳转到登录页 - // userStore.clearUserInfo() - // uni.navigateTo({ url: '/pages/login/login' }) - reject(res) - } else { - // 其他错误 -> 根据后端错误信息轻提示 - !options.hideErrorToast && - uni.showToast({ - icon: 'none', - title: (res.data as IResData).msg || '请求错误', + async success(res) { + const resp = res.data as IResData + const { data, code, msg } = resp + + if (code === 401) { + // 未授权 + const userStore = useUserStore() + + if (!isRefreshToken) { + // 设置为正在刷新 + isRefreshToken = true + + // 1. 如果获取不到刷新令牌,则只能执行登出操作 + if (!getRefreshToken()) { + showConfirm('登录状态已过期,您可以继续留在该页面,或者重新登录?').then( + (res: any) => { + if (res.confirm) { + // 清除缓存起来的用户信息 + userStore.LogOut().then((res) => { + uni.reLaunch({ url: '/pages/login/index' }) + }) + } + }, + ) + } + + // 2. 刷新accesstoken + try { + const refreshTokenRes: any = await refreshToken() + if (refreshTokenRes.data.code !== 0) { + // 如果获取不到refresh token,就直接跳转到登录页面 + showConfirm('登录状态已过期,您可以继续留在该页面,或者重新登录?').then( + (res: any) => { + if (res.confirm) { + // 清除缓存起来的用户信息 + userStore.LogOut().then((res) => { + uni.reLaunch({ url: '/pages/login/index' }) + }) + } + }, + ) + const rejMsg = '无效的会话,或者会话已过期,请重新登录。' + reject(rejMsg) + } + + // 2.1 刷新成功,则回放队列的请求 + 当前请求 + setToken(refreshTokenRes.data.data) + options.header.Authorization = 'Bearer ' + getAccessToken() + // 将所有的请求方法都进行调用 + requestList.forEach((cb) => { + cb() + }) + // 调用之后就清空 + requestList = [] + + // 到达这里,属于是请求已经失败了,需要重新请求的 + // 所以这里是一个递归调用 + resolve(http(options)) + } catch (e) { + // 为什么需要 catch 异常呢?刷新失败时,请求因为 Promise.reject 触发异常。 + // 2.2 刷新失败,只回放队列的请求 + requestList.forEach((cb) => { + cb() + }) + const rejMsg = '无效的会话,或者会话已过期,请重新登录。' + reject(rejMsg) + } finally { + requestList = [] + isRefreshToken = false + } + } else { + // 添加到队列,等待刷新获取到新的令牌 + return new Promise((resolve) => { + requestList.push(() => { + options.header.Authorization = 'Bearer ' + getAccessToken() + resolve(http(options)) + }) }) - reject(res) + } + } else if (code === 500) { + // 服务器错误 + toast(msg) + reject(errorCode['500']) + } else if (code !== 0) { + // 其他的错误 + // ps:ruoyi-vue-pro 的success 的code,默认是0而不是200 + toast(msg) + reject(code) } + + resolve(data) }, // 响应失败 fail(err) { @@ -78,3 +170,13 @@ export const httpPost = ( http.get = httpGet http.post = httpPost + +const refreshToken = async () => { + return await uni.request({ + method: 'POST', + url: baseUrl + '/system/auth/refresh-token?refreshToken=' + getRefreshToken(), + header: { + 'tenant-id': 1, + }, + }) +} diff --git a/src/utils/index.ts b/src/utils/index.ts index 70131bf..853a739 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -131,16 +131,16 @@ export const getEvnBaseUrl = () => { const { miniProgram: { envVersion }, } = uni.getAccountInfoSync() - + // 开发、体验、正式版 三种不同的小程序都可以配置不同的后端url switch (envVersion) { case 'develop': - baseUrl = 'https://ukw0y1.laf.run' + baseUrl = 'http://localhost:48080/admin-api' break case 'trial': - baseUrl = 'https://ukw0y1.laf.run' + baseUrl = 'http://localhost:48080/admin-api' break case 'release': - baseUrl = 'https://ukw0y1.laf.run' + baseUrl = 'http://localhost:48080/admin-api' break } }