This commit is contained in:
dzc committed 2026-06-10 14:29:21 +08:00
commit c8cd13b6cf
7 files changed
+174 -34

No files matched your search

+7
View File
@@ -44,6 +44,13 @@
"disableScroll": true
}
},
{
"path": "pages/root/force-change-password",
"style": {
"navigationBarTitleText": "修改密码",
"disableScroll": true
}
},
{
"path": "pages/user/address/index",
"style": {
+115
View File
@@ -0,0 +1,115 @@
<template>
<crud-layout title="修改密码" bg="/static/page/blue-bg.png">
<view class="h-30rpx" />
<view class="card p-x-30rpx p-y-40rpx">
<view class="color-grey font-size-sm m-b-30rpx">
首次登录须修改密码,请设置新密码后重新登录
</view>
<tm-form ref="applyFormRef" v-model="applyForm" :rules="applyFormRules" direction="vertical">
<tm-form-item name="username" label="用户名" :showBottom="false">
<tm-input v-model="applyForm.username" disabled placeholder="用户名" />
</tm-form-item>
<view class="h-30rpx" />
<tm-form-item name="password" label="原密码" :showBottom="false">
<tm-input password showEye v-model="applyForm.password" placeholder="请输入当前密码.." />
</tm-form-item>
<view class="h-30rpx" />
<tm-form-item name="newpassword1" label="新密码" :showBottom="false">
<tm-input password showEye v-model="applyForm.newpassword1" placeholder="请输入新密码.." />
</tm-form-item>
<view class="h-30rpx" />
<tm-form-item name="newpassword2" label="确认新密码" :showBottom="false">
<tm-input password showEye v-model="applyForm.newpassword2" placeholder="请再次输入新密码.." />
</tm-form-item>
</tm-form>
</view>
<view class="bg-blue p-y-20rpx text-center rounded-40rpx m-x-30rpx m-t-40rpx sub-text-30 color-white!" @tap="doSubmit">
确认修改
</view>
<view class="text-center m-t-30rpx">
<text class="color-blue font-size-sm" @click="router.back()">返回登录</text>
</view>
</crud-layout>
</template>
<script setup lang="ts">
import { onLoad } from "@dcloudio/uni-app"
import { reactive, ref } from "vue"
import { userApi } from "@/sheep/api"
import { router } from "@@/index"
const PASSWORD_REG = /^(?=.*[A-Za-z])(?=.*\d)[A-Za-z0-9]{8,20}$/
const applyForm = reactive({
username: "",
password: "",
newpassword1: "",
newpassword2: "",
})
const applyFormRef = ref<any>(null)
const state = reactive({
submitting: false,
})
const validateConfirmPassword = (val: string) => val === applyForm.newpassword1
const applyFormRules = reactive<any>({
username: [{ required: true, message: "用户名不能为空" }],
password: [{ required: true, message: "请输入原密码" }],
newpassword1: [
{ required: true, message: "请输入新密码" },
{ required: true, rule: PASSWORD_REG, message: "密码需为8-20位字母和数字组合" },
],
newpassword2: [
{ required: true, message: "请再次输入新密码" },
{ validator: validateConfirmPassword, message: "两次输入的新密码不一致" },
],
})
onLoad((options: any) => {
if (options?.username) {
applyForm.username = decodeURIComponent(options.username)
}
})
const doSubmit = async () => {
if (state.submitting) return
applyFormRef.value.submit()
const { isPass } = applyFormRef.value.validate()
if (!isPass) return
if (applyForm.password === applyForm.newpassword1) {
uni.showToast({ title: "新旧密码不能相同", icon: "none" })
return
}
state.submitting = true
uni.showLoading({ title: "提交中...", mask: true })
try {
const res: any = await userApi.resetUserPassword({
username: applyForm.username,
password: applyForm.password,
newpassword1: applyForm.newpassword1,
})
if (res.code !== 0) {
uni.showToast({ title: res.msg || "修改失败", icon: "none" })
return
}
uni.showToast({ title: "修改成功,请重新登录", icon: "none" })
setTimeout(() => {
router.jump("/pages/root/login", {}, 2)
}, 1500)
} finally {
state.submitting = false
uni.hideLoading()
}
}
</script>
<style lang="scss" scoped>
:deep() {
.tmFormItemLabel {
padding-bottom: 10rpx !important;
}
}
</style>
+2 -2
View File
@@ -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<any>({
],
newPassword: [
{ required: true, message: "请输入新密码" },
{ required: true, rule: PASSWORD_REG, message: "密码需为8-20位且包含大小写字母、数字和特殊字符" },
{ required: true, rule: PASSWORD_REG, message: "密码需为8-20位字母和数字组合" },
],
})
+28 -18
View File
@@ -34,6 +34,8 @@ onShow(() => {
})
const CREDENTIALS_EXPIRED = "credentials_expired"
const applyFormRef = ref<any>(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 = () => {
+11 -11
View File
@@ -93,14 +93,14 @@ const state = reactive<any>({
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)]
}
+8
View File
@@ -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({
+3 -3
View File
@@ -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)