diff --git a/src/pages.json b/src/pages.json index 42016ac..1cfba8e 100644 --- a/src/pages.json +++ b/src/pages.json @@ -44,6 +44,13 @@ "disableScroll": true } }, + { + "path": "pages/root/force-change-password", + "style": { + "navigationBarTitleText": "修改密码", + "disableScroll": true + } + }, { "path": "pages/user/address/index", "style": { diff --git a/src/pages/root/force-change-password.vue b/src/pages/root/force-change-password.vue new file mode 100644 index 0000000..9ec2021 --- /dev/null +++ b/src/pages/root/force-change-password.vue @@ -0,0 +1,115 @@ + + + + + diff --git a/src/pages/root/forgot-password.vue b/src/pages/root/forgot-password.vue index 488a3d6..d8fcf05 100644 --- a/src/pages/root/forgot-password.vue +++ b/src/pages/root/forgot-password.vue @@ -39,7 +39,7 @@ import { router } from "@@/index" const MOBILE_REG = /^[1](([3][0-9])|([4][0,1,4-9])|([5][0-3,5-9])|([6][2,5,6,7])|([7][0-8])|([8][0-9])|([9][0-3,5-9]))[0-9]{8}$/ const SMS_CODE_REG = /^\d{6}$/ -const PASSWORD_REG = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[^A-Za-z0-9]).{8,20}$/ +const PASSWORD_REG = /^(?=.*[A-Za-z])(?=.*\d)[A-Za-z0-9]{8,20}$/ const applyForm = reactive({ mobile: "", @@ -65,7 +65,7 @@ const applyFormRules = reactive({ ], newPassword: [ { required: true, message: "请输入新密码" }, - { required: true, rule: PASSWORD_REG, message: "密码需为8-20位且包含大小写字母、数字和特殊字符" }, + { required: true, rule: PASSWORD_REG, message: "密码需为8-20位字母和数字组合" }, ], }) diff --git a/src/pages/root/login.vue b/src/pages/root/login.vue index 0ef6bed..74fb417 100644 --- a/src/pages/root/login.vue +++ b/src/pages/root/login.vue @@ -34,6 +34,8 @@ onShow(() => { }) +const CREDENTIALS_EXPIRED = "credentials_expired" + const applyFormRef = ref(null) const doSubmit = async () => { applyFormRef.value.submit() @@ -44,25 +46,33 @@ const doSubmit = async () => { const rememberUser = constant.storageConstant.REMEMBER_USER uni.removeStorageSync(tokenKey) uni.showLoading({ title: "登录中...", mask: true }) - const res: any = await userApi.login({ - ...applyForm, - grant_type: "password", - scope: "server", - }) - if (res.code != 0) { - uni.showToast({ title: res.msg + ",登录失败,请重新登录", icon: "error" }) - return + try { + const res: any = await userApi.login({ + ...applyForm, + grant_type: "password", + scope: "server", + }) + if (res.code != 0) { + if (res.data === CREDENTIALS_EXPIRED) { + uni.showToast({ title: "请先修改密码", icon: "none" }) + router.jump("/pages/root/force-change-password", { username: applyForm.username }) + return + } + uni.showToast({ title: (res.msg || "登录失败") + ",请重新登录", icon: "error" }) + return + } + uni.setStorageSync(tokenKey, res.data) + const { data: userData } = await userApi.userInfo() + uni.setStorageSync(userInfoKey, userData) + uni.setStorageSync(rememberUser, { + username: applyForm.username, + password: applyForm.password, + } as GlobalSetting.RememberUser) + uni.showToast({ title: "登录成功", icon: "none" }) + router.jump("/pages/tabbar/my") + } finally { + uni.hideLoading() } - uni.setStorageSync(tokenKey, res.data) - const { data: userData } = await userApi.userInfo() - uni.setStorageSync(userInfoKey, userData) - uni.setStorageSync(rememberUser, { - username: applyForm.username, - password: applyForm.password, - } as GlobalSetting.RememberUser) - uni.hideLoading() - uni.showToast({ title: "登录成功", icon: "none" }) - router.jump("/pages/tabbar/my") } const disposeLogin = () => { diff --git a/src/pages/tabbar/my.vue b/src/pages/tabbar/my.vue index c35528f..daba787 100644 --- a/src/pages/tabbar/my.vue +++ b/src/pages/tabbar/my.vue @@ -93,14 +93,14 @@ const state = reactive({ menuList: [ { text: "地址", icon: "/static/icon/scan.png", path: "/pages/user/map-address/index" }, { text: "扫一扫", icon: "/static/icon/scan.png", path: "" }, - { text: "钱包", icon: "/static/icon/service_3.png", path: "/pages/wallet/list" }, - { text: "喜好", icon: "/static/icon/service_4.png", path: "/pages/tabbar/canteenAnalyse" }, - { text: "记录", icon: "/static/icon/service_1.png", path: "/pages/ordering-food/records" }, + { text: "钱包管理", icon: "/static/icon/service_3.png", path: "/pages/wallet/list" }, + { text: "喜好分析", icon: "/static/icon/service_4.png", path: "/pages/tabbar/canteenAnalyse" }, + { text: "报餐记录", icon: "/static/icon/service_1.png", path: "/pages/ordering-food/records" }, // { text: "测试通知", icon: "/static/icon/service_1.png", path: "" }, // { text: "外卖配送录入", icon: "/static/icon/service_1.png", path: "/pages/delivery/rider" }, // { text: "外卖查询", icon: "/static/icon/service_6.png", path: "/pages/delivery/query" }, // { text: "我的人脸", icon: "/static/icon/service_5.png", path: "/pages/human-face/list" }, - { text: "兑换", icon: "/static/icon/service_7.png", path: "/pages/ad/make-money" }, + { text: "积分兑换", icon: "/static/icon/service_7.png", path: "/pages/ad/make-money" }, // { text: "车辆管理", icon: "/static/icon/service_6.png", path: "/pages/car/user-car/list" }, ], appInfo: "", @@ -341,7 +341,7 @@ const onTabMenu = async (item: any) => { case "扫一扫": await appScanCode() break - case "商品": + case "商品管理": await gotoOnlineDishManage() break default: @@ -401,19 +401,19 @@ onShow(async () => { appHotUpdateRef.value?.checkUpdate() }) -/** 按角色在「钱包 / 喜好」之后插入:商品、订单管理、骑手配送、报餐统计 */ +/** 按角色在「钱包管理 / 喜好分析」之后插入:商品管理、商家订单、骑手配送、报餐统计 */ const syncRoleMenus = async () => { await refreshUserRoleCodes() - const roleLabels = new Set(["商品", "商家", "配送", "统计"]) + const roleLabels = new Set(["商品管理", "商家订单", "骑手配送", "报餐统计"]) const base = (state.menuList || []).filter((x: any) => !roleLabels.has(x?.text)) const roleEntries: any[] = [] if (hasRoleCode(ROLE_ONLINE_CANTEEN_MCH)) { - roleEntries.push({ text: "商品", icon: "/static/icon/service_12.png", path: "/pages/merchant/online-dish-manage" }) - roleEntries.push({ text: "商家", icon: "/static/icon/service_13.png", path: "/pages/canteen-delivery/mch-list" }) - roleEntries.push({ text: "统计", icon: "/static/icon/service_6.png", path: "/pages/ordering-food/stats" }) + roleEntries.push({ text: "商品管理", icon: "/static/icon/service_12.png", path: "/pages/merchant/online-dish-manage" }) + roleEntries.push({ text: "商家订单", icon: "/static/icon/service_13.png", path: "/pages/canteen-delivery/mch-list" }) + roleEntries.push({ text: "报餐统计", icon: "/static/icon/service_6.png", path: "/pages/ordering-food/stats" }) } if (hasRoleCode(ROLE_CANTEEN_RIDER)) { - roleEntries.push({ text: "配送", icon: "/static/icon/service_11.png", path: "/pages/canteen-delivery/list" }) + roleEntries.push({ text: "骑手配送", icon: "/static/icon/service_11.png", path: "/pages/canteen-delivery/list" }) } state.menuList = [...base.slice(0, 2), ...roleEntries, ...base.slice(2)] } diff --git a/src/sheep/api/user.ts b/src/sheep/api/user.ts index 86551c9..a6ce610 100644 --- a/src/sheep/api/user.ts +++ b/src/sheep/api/user.ts @@ -106,6 +106,14 @@ export default { data, }), + // 首次登录/密码过期强制改密(无需登录) + resetUserPassword: (data: { username: string; password: string; newpassword1: string }) => + request({ + url: "/admin/register/password", + method: "POST", + data, + }), + // 设备认证 verifyDevice: (data: { mobilePhone: string; code: string }) => request({ diff --git a/src/sheep/utils/request.ts b/src/sheep/utils/request.ts index 0a11a48..2941907 100644 --- a/src/sheep/utils/request.ts +++ b/src/sheep/utils/request.ts @@ -9,7 +9,7 @@ import { APPENV } from "../constant" const TOKEN_KEY = constant.storageConstant.TOKEN const USER_INFO_KEY = constant.storageConstant.USERINFO -const SKIP_AUTH_URLS = ["/thirdparty/thirdPartyOAth2", "/sys/auth/refresh-token", "/auth/oauth2/token", "/admin/user/forgot-password", "/admin/stats/access/track"] +const SKIP_AUTH_URLS = ["/thirdparty/thirdPartyOAth2", "/sys/auth/refresh-token", "/auth/oauth2/token", "/admin/user/forgot-password", "/admin/register/password", "/admin/stats/access/track"] const SKIP_REFRESH_TOKEN = ["/sys/auth/refresh-token", "/auth/token/check_token"] let refreshTokenLock = true @@ -91,8 +91,8 @@ https.interceptors.response.use( uni.showToast({ title: "登录已过期,请重新登录", icon: "none" }) router.jump("/pages/root/login") } - // 显示错误信息 - else if (error?.data?.msg) { + // 登录错误由登录页自行处理 + else if (error?.data?.msg && error.config?.url !== "/auth/oauth2/token") { uni.showToast({ title: error.data.msg, icon: "none", mask: true }) } return Promise.resolve(error.data)