Compare commits

...

3 Commits

Author SHA1 Message Date
dzq 67addd582f fix: 修复登录状态判断逻辑以避免重复登录
修复了在用户已登录时重复触发登录逻辑的问题。通过引入 `isLogin` 变量,确保只有在用户未登录时才执行登录操作并跳转页面。
2025-05-13 15:33:49 +08:00
dzq e895e5619c feat(储物柜): 添加库存显示功能
在储物柜列表中新增库存显示功能,当库存为0时,图片会变为灰度显示,并在图片右下角显示库存数量。此功能帮助用户更直观地了解储物柜的库存情况。
2025-05-13 10:42:26 +08:00
dzq 401d8ac4ca feat(登录): 添加openid支持并引入登录验证码机制
为了增强登录安全性和支持微信登录,本次提交引入了openid字段,并在用户登录流程中添加了验证码机制。具体修改包括:
1. 在VerifySmsParams类型中添加openid字段
2. 在Ab98Login.vue中传递openid参数
3. 在App.vue中更新tokenLogin调用以包含openid
4. 在ab98/index.ts中修改tokenLogin接口以支持openid
5. 在ab98-user.ts中引入登录验证码逻辑,确保登录状态验证更加安全
2025-05-10 17:16:24 +08:00
7 changed files with 50 additions and 13 deletions

View File

@ -46,13 +46,16 @@ onMounted(() => {
watch(
() => wxStore.userid,
(newVal) => {
if (newVal && !ab98UserStore.isLogin) {
tokenLogin(ab98UserStore.tokenLogin, newVal).then(res => {
const isLogin = ab98UserStore.isLogin;
if (newVal) {
tokenLogin(ab98UserStore.tokenLogin, newVal, wxStore.openid).then(res => {
if (res?.code === 0 && res.data?.success) {
ab98UserStore.setTel(res.data.tel)
ab98UserStore.setUserInfo(res.data)
ab98UserStore.setIsLogin(true)
router.push('/')
if (!isLogin) {
ab98UserStore.setIsLogin(true)
router.push('/')
}
}
})
}

View File

@ -55,10 +55,10 @@ export function logoutApi(token: string) {
}
/** ab98Token登录 */
export function tokenLogin(token: string, userid: string) {
export function tokenLogin(token: string, userid: string, openid: string) {
return request<ApiResponseData<LoginData>>({
url: '/wx/login/tokenLogin',
method: 'get',
params: { token, userid }
params: { token, userid, openid }
})
}

View File

@ -57,4 +57,5 @@ export type VerifySmsParams = {
/** 验证码 */
vcode: string
userid: string
openid: string
}

View File

@ -8,6 +8,7 @@ export interface CabinetDetailDTO {
export interface CellInfoDTO {
cellId: number
pinNo: number
stock: number
product?: ProductInfoDTO
}

View File

@ -7,10 +7,15 @@
<div class="product-list">
<van-cell v-for="locker in lockerList" :key="locker.lockerId" class="product-item">
<template #icon>
<van-image width="80" height="80"
:src="locker.coverImg ? locker.coverImg : `${publicPath}` + 'img/product-image.svg'" fit="cover"
radius="4" class="product-image">
</van-image>
<div class="image-container">
<van-image width="80" height="80"
:src="locker.coverImg ? locker.coverImg : `${publicPath}` + 'img/product-image.svg'" fit="cover"
radius="4" class="product-image" :style="{ filter: locker.stock === 0 ? 'grayscale(100%)' : 'none' }">
</van-image>
<div v-if="locker.stock >= 0" class="stock-overlay">
库存: {{ locker.stock }}
</div>
</div>
<!-- <div v-else class="status-overlay">
<svg width="80" height="80" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
<rect x="5" y="5" width="90" height="90" rx="10" fill="#E8F5E9" stroke="#81C784"
@ -77,6 +82,7 @@ interface CabinetItem {
interface LockerItem {
lockerId: number
lockerNumber: number
stock: number
status: 0 | 1
statusClass: 'available' | 'occupied'
goodsName?: string
@ -109,6 +115,7 @@ const updateLockerList = (cabinet: CabinetDetailDTO) => {
lockerList.value = cabinet.cells.map(cell => ({
lockerId: cell.cellId,
lockerNumber: cell.pinNo,
stock: cell.stock,
status: cell.product ? 1 : 0,
statusClass: cell.product ? 'occupied' : 'available',
goodsName: cell.product?.goodsName,
@ -152,6 +159,24 @@ loadCabinetDetail()
</script>
<style lang="scss" scoped>
.image-container {
position: relative;
display: flex;
align-items: center;
justify-content: center;
}
.stock-overlay {
position: absolute;
right: 4px;
bottom: 4px;
background-color: rgba(0, 0, 0, 0.6);
color: white;
padding: 2px 6px;
border-radius: 4px;
font-size: 12px;
}
.cabinet-container {
display: flex;
height: calc(100vh - var(--van-tabbar-height));

View File

@ -111,7 +111,8 @@ const handleSubmit = async () => {
token: userStore.token,
tel: form.value.tel,
vcode: form.value.vcode,
userid: wxStore.userid
userid: wxStore.userid,
openid: wxStore.openid
})
if (data.success) {

View File

@ -9,7 +9,8 @@ const STORAGE_KEYS = {
USERID: 'ab98_userid',
REGISTERED: 'ab98_registered',
TEL: 'ab98_tel',
TOKEN: 'ab98_token'
TOKEN: 'ab98_token',
LOGIN_CODE: 'ab98_login_code'
}
/**
@ -39,9 +40,12 @@ export const useAb98UserStore = defineStore("ab98User", () => {
const token = ref<string>(storedToken ? decodeURIComponent(storedToken) : "");
const tokenLogin = ref<string>("");
// 登录验证码
const loginCode = '1'; // 默认验证码
// 用户登录状态
const isLogin = ref<boolean>(false);
isLogin.value = tel.value ? true : false;
const storedLoginCode = localStorage.getItem(STORAGE_KEYS.LOGIN_CODE);
isLogin.value = tel.value && storedLoginCode === String(loginCode) ? true : false;
/**
*
@ -60,6 +64,7 @@ export const useAb98UserStore = defineStore("ab98User", () => {
localStorage.setItem(STORAGE_KEYS.REGISTERED, JSON.stringify(data.registered))
tel.value = data.tel
localStorage.setItem(STORAGE_KEYS.TEL, encodeURIComponent(data.tel))
localStorage.setItem(STORAGE_KEYS.LOGIN_CODE, encodeURIComponent(loginCode))
}
/**
@ -80,6 +85,7 @@ export const useAb98UserStore = defineStore("ab98User", () => {
tel.value = ""
localStorage.removeItem(STORAGE_KEYS.TEL)
localStorage.removeItem(STORAGE_KEYS.TOKEN)
localStorage.removeItem(STORAGE_KEYS.LOGIN_CODE)
}
/**