From a7acb9dce00b8767dc55edfd7f10ad6c97631af5 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 29 May 2024 00:54:59 +0800 Subject: [PATCH] =?UTF-8?q?feat(=E7=99=BB=E5=BD=95)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pages.json | 51 ++++ pages/public/error.vue | 39 +++ peach/request/index.js | 488 +++++++++++++++++++------------------- peach/store/app.js | 352 +++++++++++++-------------- peach/store/user.js | 128 ++++++++-- static/internet-empty.png | Bin 0 -> 7003 bytes 6 files changed, 620 insertions(+), 438 deletions(-) create mode 100644 pages/public/error.vue create mode 100644 static/internet-empty.png diff --git a/pages.json b/pages.json index 79e10aa..26b4e5a 100644 --- a/pages.json +++ b/pages.json @@ -63,6 +63,57 @@ } } ], + "subPackages": [ + { + "root": "pages/public", + "pages": [{ + "path": "setting", + "style": { + "navigationBarTitleText": "系统设置" + }, + "meta": { + "sync": true, + "title": "系统设置", + "group": "通用" + } + }, + { + "path": "richtext", + "style": { + "navigationBarTitleText": "富文本" + }, + "meta": { + "sync": true, + "title": "富文本", + "group": "通用" + } + }, + { + "path": "faq", + "style": { + "navigationBarTitleText": "常见问题" + }, + "meta": { + "sync": true, + "title": "常见问题", + "group": "通用" + } + }, + { + "path": "error", + "style": { + "navigationBarTitleText": "错误页面" + } + }, + { + "path": "webview", + "style": { + "navigationBarTitleText": "" + } + } + ] + } + ], "tabBar": { "list": [ { diff --git a/pages/public/error.vue b/pages/public/error.vue new file mode 100644 index 0000000..ef0ab9c --- /dev/null +++ b/pages/public/error.vue @@ -0,0 +1,39 @@ + + + + + + diff --git a/peach/request/index.js b/peach/request/index.js index dcfede9..0fba3b3 100644 --- a/peach/request/index.js +++ b/peach/request/index.js @@ -3,34 +3,34 @@ * @description api 模块管理,loading 配置,请求拦截,错误处理 */ -import Request from 'luch-request' -import { baseUrl, apiPath } from '@/peach/config' -import $store from '@/peach/store' -import { showAuthModal } from '@/peach/hooks/useModal' -import AuthUtil from '@/peach/api/member/auth' +import Request from "luch-request"; +import { baseUrl, apiPath } from "@/peach/config"; +import peach from "@/peach"; +import $store from "@/peach/store"; +import AuthUtil from "@/peach/api/member/auth"; const options = { - // 显示操作成功消息 默认不显示 - showSuccess: false, - // 成功提醒 默认使用后端返回值 - successMsg: '', - // 显示失败消息 默认显示 - showError: true, - // 失败提醒 默认使用后端返回信息 - errorMsg: '', - // 显示请求时loading模态框 默认显示 - showLoading: true, - // loading提醒文字 - loadingMsg: '加载中', - // 需要授权才能请求 默认放开 - auth: false, -} + // 显示操作成功消息 默认不显示 + showSuccess: false, + // 成功提醒 默认使用后端返回值 + successMsg: "", + // 显示失败消息 默认显示 + showError: true, + // 失败提醒 默认使用后端返回信息 + errorMsg: "", + // 显示请求时loading模态框 默认显示 + showLoading: true, + // loading提醒文字 + loadingMsg: "加载中", + // 需要授权才能请求 默认放开 + auth: false, +}; // Loading全局实例 let LoadingInstance = { - target: null, - count: 0, -} + target: null, + count: 0, +}; /** * @author Ankkaya @@ -39,21 +39,21 @@ let LoadingInstance = { * @returns {Type} */ function closeLoading() { - if (LoadingInstance.count > 0) LoadingInstance.count-- - if (LoadingInstance.count === 0) uni.hideLoading() + if (LoadingInstance.count > 0) LoadingInstance.count--; + if (LoadingInstance.count === 0) uni.hideLoading(); } // 请求实例 const http = new Request({ - baseUrl: baseUrl + apiPath, - timeout: 8000, - method: 'GET', - header: { - Accept: 'text/json', - 'Content-Type': 'application/json;charset=UTF-8', - }, - custom: options, -}) + baseUrl: baseUrl + apiPath, + timeout: 8000, + method: "GET", + header: { + Accept: "text/json", + "Content-Type": "application/json;charset=UTF-8", + }, + custom: options, +}); /** * @author Ankkaya @@ -63,39 +63,39 @@ const http = new Request({ */ http.interceptors.request.use( - (config) => { - // 自定义处理【auth 授权】:必须登录的接口,否则提示登录 - if (config.custom.auth && !$store('user').isLogin) { - // 处理登录 - showAuthModal() - return Promise.reject() - } - - // 自定义处理【loading 加载中】:如果需要显示 loading,则显示 loading - if (config.custom.showLoading) { - LoadingInstance.count++ - LoadingInstance.count === 1 && - uni.showLoading({ - title: config.custom.loadingMsg, - mask: true, - fail: () => { - uni.hideLoading() - }, - }) - } - - // 增加 token 令牌、terminal 终端、tenant 租户的请求头 - const token = getAccessToken() - if (token) { - config.header['Authorization'] = token - } - config.header['Accept'] = '*/*' - return config - }, - (error) => { - return Promise.reject(error) + (config) => { + // 自定义处理【auth 授权】:必须登录的接口,否则提示登录 + if (config.custom.auth && !$store("user").isLogin) { + // 处理登录 + peach.$router.go("/pages/index/login"); + return Promise.reject(); } -) + + // 自定义处理【loading 加载中】:如果需要显示 loading,则显示 loading + if (config.custom.showLoading) { + LoadingInstance.count++; + LoadingInstance.count === 1 && + uni.showLoading({ + title: config.custom.loadingMsg, + mask: true, + fail: () => { + uni.hideLoading(); + }, + }); + } + + // 增加 token 令牌、terminal 终端、tenant 租户的请求头 + const token = getAccessToken(); + if (token) { + config.header["Authorization"] = token; + } + config.header["Accept"] = "*/*"; + return config; + }, + (error) => { + return Promise.reject(error); + } +); /** * @author Ankkaya @@ -104,194 +104,202 @@ http.interceptors.request.use( * @returns {Type} */ http.interceptors.response.use( - (response) => { - console.log('response', response) - // 约定:如果是 /auth/ 下的 URL 地址,并且返回了 accessToken 说明是登录相关的接口,则自动设置登陆令牌 - if (response.config.url.indexOf('/member/auth/') >= 0 && response.data?.data?.accessToken) { - $store('user').setToken(response.data.data.accessToken, response.data.data.refreshToken) - } - - // 自定处理【loading 加载中】:如果需要显示 loading,则关闭 loading - response.config.custom.showLoading && closeLoading() - - // 自定义处理【error 错误提示】:如果需要显示错误提示,则显示错误提示 - if (response.data.code !== 0) { - // 特殊:如果 401 错误码,则跳转到登录页 or 刷新令牌 - if (response.data.code === 401) { - return refreshToken(response.config) - } - - // 错误提示 - if (response.config.custom.showError) { - uni.showToast({ - title: response.data.msg || '服务器开小差啦,请稍后再试~', - icon: 'none', - mask: true, - }) - return Promise.reject(false) - } - } - - // 自定义处理【showSuccess 成功提示】:如果需要显示成功提示,则显示成功提示 - if ( - response.config.custom.showSuccess && - response.config.custom.successMsg !== '' && - response.data.code === 0 - ) { - uni.showToast({ - title: response.config.custom.successMsg, - icon: 'none', - }) - } - - // 返回结果:包括 code + data + msg - return Promise.resolve(response.data) - }, - (error) => { - console.log('error', error) - const userStore = $store('user') - const isLogin = userStore.isLogin - let errorMessage = '网络请求出错' - if (error !== undefined) { - switch (error.statusCode) { - case 400: - errorMessage = '请求错误' - break - case 401: - errorMessage = isLogin ? '您的登陆已过期' : '请先登录' - // 正常情况下,后端不会返回 401 错误,所以这里不处理 handleAuthorized - break - case 403: - errorMessage = '拒绝访问' - break - case 404: - errorMessage = '请求出错' - break - case 408: - errorMessage = '请求超时' - break - case 429: - errorMessage = '请求频繁, 请稍后再访问' - break - case 500: - errorMessage = '服务器开小差啦,请稍后再试~' - break - case 501: - errorMessage = '服务未实现' - break - case 502: - errorMessage = '网络错误' - break - case 503: - errorMessage = '服务不可用' - break - case 504: - errorMessage = '网络超时' - break - case 505: - errorMessage = 'HTTP 版本不受支持' - break - } - if (error.errMsg.includes('timeout')) errorMessage = '请求超时' - // #ifdef H5 - if (error.errMsg.includes('Network')) - errorMessage = window.navigator.onLine ? '服务器异常' : '请检查您的网络连接' - // #endif - } - - if (error && error.config) { - if (error.config.custom.showError === true) { - uni.showToast({ - title: error.data?.msg || errorMessage, - icon: 'none', - mask: true, - }) - } - error.config.custom.showLoading && closeLoading() - } - - return Promise.reject(false) + (response) => { + console.log("response", response); + // 约定:如果是 /auth/ 下的 URL 地址,并且返回了 accessToken 说明是登录相关的接口,则自动设置登陆令牌 + if ( + response.config.url.indexOf("/member/auth/") >= 0 && + response.data?.data?.accessToken + ) { + $store("user").setToken( + response.data.data.accessToken, + response.data.data.refreshToken + ); } -) -let requestList = [] // 请求队列 -let isRefreshToken = false // 是否正在刷新中 + // 自定处理【loading 加载中】:如果需要显示 loading,则关闭 loading + response.config.custom.showLoading && closeLoading(); + + // 自定义处理【error 错误提示】:如果需要显示错误提示,则显示错误提示 + if (response.data.code !== 0) { + // 特殊:如果 401 错误码,则跳转到登录页 or 刷新令牌 + if (response.data.code === 401) { + return refreshToken(response.config); + } + + // 错误提示 + if (response.config.custom.showError) { + uni.showToast({ + title: response.data.msg || "服务器开小差啦,请稍后再试~", + icon: "none", + mask: true, + }); + return Promise.reject(false); + } + } + + // 自定义处理【showSuccess 成功提示】:如果需要显示成功提示,则显示成功提示 + if ( + response.config.custom.showSuccess && + response.config.custom.successMsg !== "" && + response.data.code === 0 + ) { + uni.showToast({ + title: response.config.custom.successMsg, + icon: "none", + }); + } + + // 返回结果:包括 code + data + msg + return Promise.resolve(response.data); + }, + (error) => { + console.log("error", error); + const userStore = $store("user"); + const isLogin = userStore.isLogin; + let errorMessage = "网络请求出错"; + if (error !== undefined) { + switch (error.statusCode) { + case 400: + errorMessage = "请求错误"; + break; + case 401: + errorMessage = isLogin ? "您的登陆已过期" : "请先登录"; + // 正常情况下,后端不会返回 401 错误,所以这里不处理 handleAuthorized + break; + case 403: + errorMessage = "拒绝访问"; + break; + case 404: + errorMessage = "请求出错"; + break; + case 408: + errorMessage = "请求超时"; + break; + case 429: + errorMessage = "请求频繁, 请稍后再访问"; + break; + case 500: + errorMessage = "服务器开小差啦,请稍后再试~"; + break; + case 501: + errorMessage = "服务未实现"; + break; + case 502: + errorMessage = "网络错误"; + break; + case 503: + errorMessage = "服务不可用"; + break; + case 504: + errorMessage = "网络超时"; + break; + case 505: + errorMessage = "HTTP 版本不受支持"; + break; + } + if (error.errMsg.includes("timeout")) errorMessage = "请求超时"; + // #ifdef H5 + if (error.errMsg.includes("Network")) + errorMessage = window.navigator.onLine + ? "服务器异常" + : "请检查您的网络连接"; + // #endif + } + + if (error && error.config) { + if (error.config.custom.showError === true) { + uni.showToast({ + title: error.data?.msg || errorMessage, + icon: "none", + mask: true, + }); + } + error.config.custom.showLoading && closeLoading(); + } + + return Promise.reject(false); + } +); + +let requestList = []; // 请求队列 +let isRefreshToken = false; // 是否正在刷新中 const refreshToken = async (config) => { - // 如果当前已经是 refresh-token 的 URL 地址,并且还是 401 错误,说明是刷新令牌失败了,直接返回 Promise.reject(error) - if (config.url.indexOf('/member/auth/refresh-token') >= 0) { - return Promise.reject('error') - } + // 如果当前已经是 refresh-token 的 URL 地址,并且还是 401 错误,说明是刷新令牌失败了,直接返回 Promise.reject(error) + if (config.url.indexOf("/member/auth/refresh-token") >= 0) { + return Promise.reject("error"); + } - // 如果未认证,并且未进行刷新令牌,说明可能是访问令牌过期了 - if (!isRefreshToken) { - isRefreshToken = true - // 1. 如果获取不到刷新令牌,则只能执行登出操作 - const refreshToken = getRefreshToken() - if (!refreshToken) { - return handleAuthorized() - } - // 2. 进行刷新访问令牌 - try { - const refreshTokenResult = await AuthUtil.refreshToken(refreshToken) - if (refreshTokenResult.code !== 0) { - // 如果刷新不成功,直接抛出 e 触发 2.2 的逻辑 - // noinspection ExceptionCaughtLocallyJS - throw new Error('刷新令牌失败') - } - // 2.1 刷新成功,则回放队列的请求 + 当前请求 - config.header.Authorization = 'Bearer ' + getAccessToken() - requestList.forEach((cb) => { - cb() - }) - requestList = [] - return request(config) - } catch (e) { - // 为什么需要 catch 异常呢?刷新失败时,请求因为 Promise.reject 触发异常。 - // 2.2 刷新失败,只回放队列的请求 - requestList.forEach((cb) => { - cb() - }) - // 提示是否要登出。即不回放当前请求!不然会形成递归 - return handleAuthorized() - } finally { - requestList = [] - isRefreshToken = false - } - } else { - // 添加到队列,等待刷新获取到新的令牌 - return new Promise((resolve) => { - requestList.push(() => { - config.header.Authorization = 'Bearer ' + getAccessToken() // 让每个请求携带自定义token 请根据实际情况自行修改 - resolve(request(config)) - }) - }) + // 如果未认证,并且未进行刷新令牌,说明可能是访问令牌过期了 + if (!isRefreshToken) { + isRefreshToken = true; + // 1. 如果获取不到刷新令牌,则只能执行登出操作 + const refreshToken = getRefreshToken(); + if (!refreshToken) { + return handleAuthorized(); } -} + // 2. 进行刷新访问令牌 + try { + const refreshTokenResult = await AuthUtil.refreshToken(refreshToken); + if (refreshTokenResult.code !== 0) { + // 如果刷新不成功,直接抛出 e 触发 2.2 的逻辑 + // noinspection ExceptionCaughtLocallyJS + throw new Error("刷新令牌失败"); + } + // 2.1 刷新成功,则回放队列的请求 + 当前请求 + config.header.Authorization = "Bearer " + getAccessToken(); + requestList.forEach((cb) => { + cb(); + }); + requestList = []; + return request(config); + } catch (e) { + // 为什么需要 catch 异常呢?刷新失败时,请求因为 Promise.reject 触发异常。 + // 2.2 刷新失败,只回放队列的请求 + requestList.forEach((cb) => { + cb(); + }); + // 提示是否要登出。即不回放当前请求!不然会形成递归 + return handleAuthorized(); + } finally { + requestList = []; + isRefreshToken = false; + } + } else { + // 添加到队列,等待刷新获取到新的令牌 + return new Promise((resolve) => { + requestList.push(() => { + config.header.Authorization = "Bearer " + getAccessToken(); // 让每个请求携带自定义token 请根据实际情况自行修改 + resolve(request(config)); + }); + }); + } +}; /** 处理 401 未登陆的错误 */ const handleAuthorized = () => { - const userStore = $store('user') - userStore.logout(true) - showAuthModal() - // 登录超时 - return Promise.reject({ - code: 401, - msg: userStore.isLogin ? '您的登陆已过期' : '请先登录', - }) -} + const userStore = $store("user"); + userStore.logout(true); + peach.$router.go("/pages/index/login"); + // 登录超时 + return Promise.reject({ + code: 401, + msg: userStore.isLogin ? "您的登陆已过期" : "请先登录", + }); +}; /** 获得访问令牌 */ const getAccessToken = () => { - return uni.getStorageSync('token') -} + return uni.getStorageSync("token"); +}; /** 获得刷新令牌 */ const getRefreshToken = () => { - return uni.getStorageSync('refresh-token') -} + return uni.getStorageSync("refresh-token"); +}; const request = (config) => { - return http.middleware(config) -} + return http.middleware(config); +}; -export default request +export default request; diff --git a/peach/store/app.js b/peach/store/app.js index 2b13618..0d3f507 100644 --- a/peach/store/app.js +++ b/peach/store/app.js @@ -1,181 +1,185 @@ -import { ref } from 'vue' -import { defineStore } from 'pinia' -import $platform from '@/peach/platform' -import $router from '@/peach/router' -import user from './user' -import useSysStore from './sys' +import { ref } from "vue"; +import { defineStore } from "pinia"; +import $platform from "@/peach/platform"; +import $router from "@/peach/router"; +import useUserStore from "./user"; +import useSysStore from "./sys"; const useAppStore = defineStore( - 'app', - () => { - /** - * @description 应用信息 - * @param string name 应用名称 - * @param string logo 应用logo - * @param string version 应用版本 - * @param string copyright 版权信息 - * @param string copyrightTime 版权时间 - * @param string cdnurl 静态资源域名 - * @param string filesystem 文件系统 - */ - const info = ref({ - name: '', - logo: '', - version: '', - copyright: '', - copytime: '', - cdnurl: '', - filesystem: '', - }) + "app", + () => { + /** + * @description 应用信息 + * @param string name 应用名称 + * @param string logo 应用logo + * @param string version 应用版本 + * @param string copyright 版权信息 + * @param string copyrightTime 版权时间 + * @param string cdnurl 静态资源域名 + * @param string filesystem 文件系统 + */ + const info = ref({ + name: "", + logo: "", + version: "", + copyright: "", + copytime: "", + cdnurl: "", + filesystem: "", + }); - /** - * @description 平台信息 - * @param Array share.methods 分享方式 - * @param Object share.forwardInfo 转发信息 - * @param Object share.posterInfo 海报信息 - * @param string share.linkAddress 分享链接地址 - * @param number bindMobile 绑定手机号提醒 0: 提醒 1: 不提醒 - */ - const platform = ref({ - share: { - methods: [], - forwardInfo: {}, - posterInfo: {}, - linkAddress: '', + /** + * @description 平台信息 + * @param Array share.methods 分享方式 + * @param Object share.forwardInfo 转发信息 + * @param Object share.posterInfo 海报信息 + * @param string share.linkAddress 分享链接地址 + * @param number bindMobile 绑定手机号提醒 0: 提醒 1: 不提醒 + */ + const platform = ref({ + share: { + methods: [], + forwardInfo: {}, + posterInfo: {}, + linkAddress: "", + }, + bindMobile: 0, + }); + + const chat = ref({}); + + /** + * @description 模板信息 + * @param Object basic 基础模板 + * @param Object tabbar 底部导航模板 + */ + const template = ref({ + basic: { + tabbar: { + items: [ + { + activeIconUrl: + "http://mall.yudao.iocoder.cn/static/images/1-002.png", + iconUrl: "http://mall.yudao.iocoder.cn/static/images/1-001.png", + text: "首页", + url: "/pages/index/index", }, - bindMobile: 0, - }) - - const chat = ref({}) - - /** - * @description 模板信息 - * @param Object basic 基础模板 - * @param Object tabbar 底部导航模板 - */ - const template = ref({ - basic: { - tabbar: { - items: [ - { - activeIconUrl: 'http://mall.yudao.iocoder.cn/static/images/1-002.png', - iconUrl: 'http://mall.yudao.iocoder.cn/static/images/1-001.png', - text: '首页', - url: '/pages/index/index', - }, - { - activeIconUrl: 'http://mall.yudao.iocoder.cn/static/images/2-002.png', - iconUrl: 'http://mall.yudao.iocoder.cn/static/images/2-001.png', - text: '产品', - url: '/pages/index/product', - }, - { - activeIconUrl: 'http://mall.yudao.iocoder.cn/static/images/3-002.png', - iconUrl: 'http://mall.yudao.iocoder.cn/static/images/3-001.png', - text: '订单', - url: '/pages/order/list', - }, - { - activeIconUrl: 'http://mall.yudao.iocoder.cn/static/images/4-002.png', - iconUrl: 'http://mall.yudao.iocoder.cn/static/images/4-001.png', - text: '我的', - url: '/pages/index/my', - }, - ], - style: { - activeColor: '#fc4141', - bgColor: '#fff', - bgType: 'color', - color: '#282828', - }, - theme: 'red', - }, + { + activeIconUrl: + "http://mall.yudao.iocoder.cn/static/images/2-002.png", + iconUrl: "http://mall.yudao.iocoder.cn/static/images/2-001.png", + text: "产品", + url: "/pages/index/product", }, - }) - - // 全局分享信息 - const shareInfo = ref({}) - - // 小程序发货信息管理 0: 没有 1:有 - const hasWechatTradeManaged = ref(0) - - /** - * @author Ankkaya - * @description 小程序初始化 - * @param {Type} - - * @returns {Type} - */ - async function init() { - // 检查网络 - const networkStatus = await $platform.checkNetwork() - if (!networkStatus) { - $router.error('NetworkError') - } - - if (true) { - this.info = { - name: '🍑商城', - logo: 'https://static.iocoder.cn/ruoyi-vue-pro-logo.png', - version: '1.0.0', - copyright: '全部开源,个人与企业可 100% 免费使用', - copytime: 'Copyright© 2018-2024', - - cdnurl: 'https://file.sheepjs.com', // 云存储域名 - filesystem: 'qcloud', // 云存储平台 - } - this.platform = { - share: { - methods: ['poster', 'link'], - linkAddress: 'https://shopro.sheepjs.com/#/', - posterInfo: { - user_bg: '/static/img/shop/config/user-poster-bg.png', - goods_bg: '/static/img/shop/config/goods-poster-bg.png', - groupon_bg: '/static/img/shop/config/groupon-poster-bg.png', - }, - }, - bind_mobile: 0, - } - this.chat = { - chat_domain: 'https://api.shopro.sheepjs.com/chat', - room_id: 'admin', - } - this.has_wechat_trade_managed = 0 - - // 加载主题 - const sysStore = useSysStore() - sysStore.setTheme() - - // 模拟用户登录 - const userStore = user() - if (userStore.isLogin) { - userStore.loginAfter() - } - return Promise.resolve(true) - } else { - $router.error('InitError', res.msg || '加载失败') - } - } - - return { - info, - platform, - chat, - template, - shareInfo, - hasWechatTradeManaged, - init, - } - }, - { - persist: { - enabled: true, - strategies: [ - { - key: 'app-store', - }, - ], + { + activeIconUrl: + "http://mall.yudao.iocoder.cn/static/images/3-002.png", + iconUrl: "http://mall.yudao.iocoder.cn/static/images/3-001.png", + text: "订单", + url: "/pages/order/list", + }, + { + activeIconUrl: + "http://mall.yudao.iocoder.cn/static/images/4-002.png", + iconUrl: "http://mall.yudao.iocoder.cn/static/images/4-001.png", + text: "我的", + url: "/pages/index/my", + }, + ], + style: { + activeColor: "#fc4141", + bgColor: "#fff", + bgType: "color", + color: "#282828", + }, + theme: "red", }, - } -) + }, + }); -export default useAppStore + // 全局分享信息 + const shareInfo = ref({}); + + // 小程序发货信息管理 0: 没有 1:有 + const hasWechatTradeManaged = ref(0); + + /** + * @author Ankkaya + * @description 小程序初始化 + * @param {Type} - + * @returns {Type} + */ + async function init() { + // 检查网络 + const networkStatus = await $platform.checkNetwork(); + if (!networkStatus) { + $router.error("NetworkError"); + } + + if (true) { + this.info = { + name: "🍑商城", + logo: "https://static.iocoder.cn/ruoyi-vue-pro-logo.png", + version: "1.0.0", + copyright: "全部开源,个人与企业可 100% 免费使用", + copytime: "Copyright© 2018-2024", + + cdnurl: "https://file.sheepjs.com", // 云存储域名 + filesystem: "qcloud", // 云存储平台 + }; + this.platform = { + share: { + methods: ["poster", "link"], + linkAddress: "https://shopro.sheepjs.com/#/", + posterInfo: { + user_bg: "/static/img/shop/config/user-poster-bg.png", + goods_bg: "/static/img/shop/config/goods-poster-bg.png", + groupon_bg: "/static/img/shop/config/groupon-poster-bg.png", + }, + }, + bind_mobile: 0, + }; + this.chat = { + chat_domain: "https://api.shopro.sheepjs.com/chat", + room_id: "admin", + }; + this.has_wechat_trade_managed = 0; + + // 加载主题 + const sysStore = useSysStore(); + sysStore.setTheme(); + + // 模拟用户登录 + const userStore = useUserStore(); + if (userStore.isLogin) { + userStore.loginAfter(); + } + return Promise.resolve(true); + } else { + $router.error("InitError", res.msg || "加载失败"); + } + } + + return { + info, + platform, + chat, + template, + shareInfo, + hasWechatTradeManaged, + init, + }; + }, + { + persist: { + enabled: true, + strategies: [ + { + key: "app-store", + }, + ], + }, + } +); + +export default useAppStore; diff --git a/peach/store/user.js b/peach/store/user.js index 31240a2..2197af1 100644 --- a/peach/store/user.js +++ b/peach/store/user.js @@ -1,30 +1,110 @@ -import { ref } from 'vue' -import { defineStore } from 'pinia' -import { isEmpty, cloneDeep, clone } from 'lodash' +import { ref } from "vue"; +import { defineStore } from "pinia"; +import $share from '@/peach/platform/share' +import { isEmpty, cloneDeep, clone } from "lodash"; -const useUserStore = defineStore('user', () => { - const userInfo = ref() - const isLogin = ref(!!uni.getStorageSync('token')) +// 默认用户信息 +const defaultUserInfo = { + avatar: "", // 头像 + nickname: "", // 昵称 + gender: 0, // 性别 + mobile: "", // 手机号 + point: 0, // 积分 +}; - function setToken(accessToken, refreshToken) { - if (token === '') { - isLogin.value = false - uni.removeStorageSync('token') - uni.removeStorageSync('refresh-token') - } else { - isLogin.value = true - uni.setStorageSync('token', token) - uni.setStorageSync('refresh-token', refreshToken) - // 成功后处理 - } - return isLogin.value +// 默认钱包信息 +const defaultWallet = { + balance: 0, // 余额 +}; + +// 默认订单信息 +const defaultNumData = { + unusedCouponCount: 0, + orderCount: { + allCount: 0, + unpaidCount: 0, + undeliveredCount: 0, + deliveredCount: 0, + uncommentedCount: 0, + afterSaleCount: 0, + }, +}; + +const useUserStore = defineStore( + "user", + () => { + const userInfo = ref(clone(defaultUserInfo)); + const userWallet = ref(clone(defaultWallet)); + const userNumData = ref(cloneDeep(defaultNumData)); + const isLogin = ref(!!uni.getStorageSync("token")); + const lastUpdateTime = ref(0) + + function getUserInfo() {} + + function getWallet() {} + + function getNumData() {} + + function setToken(token, refreshToken) { + if (token === "") { + isLogin.value = false; + uni.removeStorageSync("token"); + uni.removeStorageSync("refresh-token"); + } else { + isLogin.value = true; + uni.setStorageSync("token", token); + uni.setStorageSync("refresh-token", refreshToken); + // 成功后处理 + loginAfter(); + } + return isLogin.value; + } + + function resetUserData() { + setToken(""); + userInfo.value = clone(defaultUserInfo); + userWallet.value = clone(defaultWallet); + userNumData.value = cloneDeep(defaultNumData); + } + + function updateUserData() { + const nowTime = new Date().getTime() + if (lastUpdateTime.value + 5000 > nowTime) { + return + } + lastUpdateTime.value = nowTime + + await getUserInfo() + getWallet() + getNumData() + return userInfo.value + } + + function loginAfter() { + updateUserData() + $share.getShareInfo() + } + + function logOut() { + resetUserData(); + return !isLogin.value } return { - userInfo, - isLogin, - setToken, - } -}) + userInfo, + isLogin, + setToken, + logOut + }; + }, + { + persist: true, + strategies: [ + { + key: "user-store", + }, + ], + } +); -export default useUserStore +export default useUserStore; diff --git a/static/internet-empty.png b/static/internet-empty.png new file mode 100644 index 0000000000000000000000000000000000000000..55ac2f64c9d7a6480706339905a078fc1d05b7e1 GIT binary patch literal 7003 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