Compare commits

...

7 Commits

Author SHA1 Message Date
dzq 2d502e6bb1 feat(商品): 添加商品格子ID字段以支持多格子管理
在商品相关的接口、类型定义和组件中添加了`cellId`字段,以便更好地管理商品在不同格子中的分布和订单提交时的数据完整性。
2025-04-18 15:55:25 +08:00
dzq 877f3fb954 添加注释 2025-04-18 11:31:02 +08:00
dzq 6e5a076d81 fix(router): 修复导航守卫中用户存储未正确初始化的问题
在导航守卫中,`ab98UserStore` 的初始化位置被移动到需要的地方,以确保在检查登录状态时已正确初始化。此外,在 `App.vue` 中,增加了对 `token` 的非空检查,避免在 `token` 为空时执行不必要的操作。
2025-04-18 10:24:01 +08:00
dzq 55ba35230e feat: 添加用户姓名字段并实现token登录功能
在订单提交请求中添加用户姓名字段,并实现通过token进行登录的功能。同时优化了路由守卫中的登录状态检查逻辑。
2025-04-18 09:01:44 +08:00
dzq e777d1e931 feat(approval): 添加用户信息和开柜功能
在审批页面中新增了用户信息展示(姓名、手机号、用户ID),并添加了打开柜子的功能按钮。同时优化了代码结构和样式,提升了用户体验。
2025-04-17 16:40:04 +08:00
dzq 5ad9456a0f fix(ProductList): 将产品封面图片从c63.jpg更改为c63.png
修复了产品列表页面中封面图片的格式问题,确保图片显示正确
2025-04-17 09:18:11 +08:00
dzq 6a3841dd72 feat(订单页面): 添加打开柜子功能并优化支付方式选择界面
- 在订单页面添加打开柜子的功能,支持状态为1和5的订单商品
- 优化支付方式选择界面,使用更直观的单元格布局
- 在提交订单时添加手机号格式验证
2025-04-15 16:54:40 +08:00
17 changed files with 300 additions and 131 deletions

2
.env
View File

@ -7,4 +7,4 @@ VITE_APP_TITLE = 借还柜
VITE_ROUTER_HISTORY = hash VITE_ROUTER_HISTORY = hash
## 是否开启 console 调试工具 ## 是否开启 console 调试工具
VITE_CONSOLE = true VITE_CONSOLE = false

BIN
public/c63.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

BIN
public/cover.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

View File

@ -3,10 +3,14 @@ import Layout from "@/layout/index.vue"
import { useUserStore } from "@/pinia/stores/user" import { useUserStore } from "@/pinia/stores/user"
import { useDark } from "@@/composables/useDark" import { useDark } from "@@/composables/useDark"
import { useWxStore } from "@/pinia/stores/wx" import { useWxStore } from "@/pinia/stores/wx"
import { tokenLogin } from '@/common/apis/ab98'
import { useAb98UserStore } from '@/pinia/stores/ab98-user'
// const userStore = useUserStore() // const userStore = useUserStore()
const wxStore = useWxStore() const wxStore = useWxStore()
const route = useRoute() const route = useRoute()
const router = useRouter()
const ab98UserStore = useAb98UserStore()
const { isDark, initDark } = useDark() const { isDark, initDark } = useDark()
@ -31,6 +35,25 @@ onMounted(() => {
const state = urlParams.get('state') || undefined; const state = urlParams.get('state') || undefined;
const corpid = urlParams.get('corpid') || undefined; const corpid = urlParams.get('corpid') || undefined;
const isAdmin = urlParams.get('isAdmin') || undefined; const isAdmin = urlParams.get('isAdmin') || undefined;
if (state && state.indexOf('token') !== -1) {
const token = state.split('token_')[1];
if (token) {
ab98UserStore.setTokenLogin(token);
tokenLogin(token).then(res => {
if (res && res.code == 0) {
if (res.data.success) {
ab98UserStore.setTel(res.data.tel)
ab98UserStore.setUserInfo(res.data)
ab98UserStore.setIsLogin(true)
router.push('/')
}
}
})
}
}
if (isAdmin == '1') { if (isAdmin == '1') {
wxStore.setIsCabinetAdmin(true); wxStore.setIsCabinetAdmin(true);
} }

View File

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

View File

@ -61,6 +61,14 @@ export interface ReturnApprovalEntity {
goodsName: string goodsName: string
/** 封面图URL */ /** 封面图URL */
coverImg: string coverImg: string
/** 手机号 */
mobile: string
/** 用户id */
userid: string
/** 用户姓名 */
name: string
/** 是否内部用户0否 1汇邦云用户 2企业微信用户 */
isInternal: number
} }
export type SubmitApprovalResponseData = ApiResponseMsgData<{ export type SubmitApprovalResponseData = ApiResponseMsgData<{

View File

@ -4,7 +4,7 @@ import { GetOpenIdRequestParams } from './type'
/** 获取当前登录用户详情 */ /** 获取商品列表 */
export function getShopGoodsApi() { export function getShopGoodsApi() {
return request<ShopGoodsResponseData>({ return request<ShopGoodsResponseData>({
url: "shop/goods", url: "shop/goods",

View File

@ -6,7 +6,8 @@ export type Goods = {
stock: number, stock: number,
status: number, status: number,
coverImg: string, coverImg: string,
goodsDetail: string goodsDetail: string,
cellId: number
} }
export type category = { export type category = {
@ -26,6 +27,8 @@ export interface SubmitOrderRequestData {
paymentType: 'wechat' | 'balance'; paymentType: 'wechat' | 'balance';
/** 联系电话 */ /** 联系电话 */
mobile: string; mobile: string;
/** 用户姓名 */
name: string;
/** 企业微信用户ID或汇邦云用户ID */ /** 企业微信用户ID或汇邦云用户ID */
qyUserid: string; qyUserid: string;
/** 是否内部订单 0否 1汇邦云用户 2企业微信用户 */ /** 是否内部订单 0否 1汇邦云用户 2企业微信用户 */
@ -34,6 +37,7 @@ export interface SubmitOrderRequestData {
goodsList: Array<{ goodsList: Array<{
goodsId: number goodsId: number
quantity: number quantity: number
cellId: number
}> }>
} }

View File

@ -1,23 +1,10 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref } from 'vue' import { ref } from 'vue'
import { showConfirmDialog, showSuccessToast, showToast, UploaderFileListItem, Popup, Picker } from 'vant' import { showConfirmDialog, showSuccessToast, showFailToast, showToast, UploaderFileListItem, Popup, Picker } from 'vant'
const showStatusPicker = ref(false)
const showPreview = ref(false)
const currentPreviewImage = ref('')
const statusMap: { [key: number]: string } = {
1: '待审核',
2: '已通过',
3: '已驳回'
}
const statusOptions = [
{ text: '待审核', value: 1 },
{ text: '通过', value: 2 },
{ text: '驳回', value: 3 }
]
import axios from "axios" import axios from "axios"
import { handleApprovalApi } from '@/common/apis/approval' import { handleApprovalApi } from '@/common/apis/approval'
import { openCabinetApi } from '@/common/apis/shop'
import type { HandleApprovalRequestData } from '@/common/apis/approval/type' import type { HandleApprovalRequestData } from '@/common/apis/approval/type'
import { useRoute, useRouter } from 'vue-router' import { useRoute, useRouter } from 'vue-router'
import { useApprovalStore } from '@/pinia/stores/approval' import { useApprovalStore } from '@/pinia/stores/approval'
@ -38,7 +25,22 @@ const formData = ref<HandleApprovalRequestData>({
const submitting = ref(false) const submitting = ref(false)
const fileList = ref<UploaderFileListItem[]>([]) const fileList = ref<UploaderFileListItem[]>([])
const uploading = ref(false) const uploading = ref(false)
const isButtonDisabled = ref(false)
const showStatusPicker = ref(false)
const showPreview = ref(false)
const currentPreviewImage = ref('')
const statusMap: { [key: number]: string } = {
1: '待审核',
2: '已通过',
3: '已驳回'
}
const statusOptions = [
{ text: '待审核', value: 1 },
{ text: '通过', value: 2 },
{ text: '驳回', value: 3 }
]
const validateForm = () => { const validateForm = () => {
if (!formData.value.approvalId || isNaN(formData.value.approvalId)) { if (!formData.value.approvalId || isNaN(formData.value.approvalId)) {
showConfirmDialog({ title: '错误', message: '审批单ID参数错误' }) showConfirmDialog({ title: '错误', message: '审批单ID参数错误' })
@ -153,6 +155,32 @@ onMounted(() => {
} }
}) })
const handleOpenCabinet = async () => {
if (!approvalStore.currentApproval?.orderId || !approvalStore.currentApproval?.orderGoodsId) {
showFailToast('缺少订单信息')
return
}
isButtonDisabled.value = true
try {
const result = await openCabinetApi(
approvalStore.currentApproval.orderId,
approvalStore.currentApproval.orderGoodsId
)
if (result.code !== 0) {
showFailToast(result.msg || '开启失败')
return
}
showSuccessToast('柜口已开启')
} catch (error) {
showFailToast('请求失败')
} finally {
setTimeout(() => {
isButtonDisabled.value = false
}, 5000)
}
}
const handleSubmit = async () => { const handleSubmit = async () => {
if (!validateForm()) return if (!validateForm()) return
@ -192,16 +220,13 @@ const handleSubmit = async () => {
<div class="content-wrapper"> <div class="content-wrapper">
<van-cell-group> <van-cell-group>
<van-cell title="姓名" :value="approvalStore.currentApproval?.name" />
<van-cell title="手机号" :value="approvalStore.currentApproval?.mobile" />
<van-cell title="用户id" :value="approvalStore.currentApproval?.userid" />
<van-cell title="商品名称" :value="approvalStore.currentApproval?.goodsName" /> <van-cell title="商品名称" :value="approvalStore.currentApproval?.goodsName" />
<van-cell title="商品封面" v-if="approvalStore.currentApproval?.coverImg"> <van-cell title="商品封面" v-if="approvalStore.currentApproval?.coverImg">
<van-image <van-image :src="approvalStore.currentApproval.coverImg" fit="cover" width="80" height="80"
:src="approvalStore.currentApproval.coverImg" @click="previewImage(approvalStore.currentApproval.coverImg)" style="margin-top: 8px" />
fit="cover"
width="80"
height="80"
@click="previewImage(approvalStore.currentApproval.coverImg)"
style="margin-top: 8px"
/>
</van-cell> </van-cell>
<van-cell title="退还数量" :value="approvalStore.currentApproval?.returnQuantity" /> <van-cell title="退还数量" :value="approvalStore.currentApproval?.returnQuantity" />
<van-cell title="商品单价" :value="`¥${approvalStore.currentApproval?.goodsPrice}`" /> <van-cell title="商品单价" :value="`¥${approvalStore.currentApproval?.goodsPrice}`" />
@ -222,30 +247,17 @@ const handleSubmit = async () => {
<van-cell-group> <van-cell-group>
<!-- 原有表单字段保持不变 --> <!-- 原有表单字段保持不变 -->
<van-field <van-button type="primary" size="small"
v-model="formData.returnAmount" @click="handleOpenCabinet" :disabled="isButtonDisabled" style="margin-bottom: 12px">
:readonly="approvalStore.currentApproval?.status !== 1" 打开柜子
label="退款金额" </van-button>
type="number" <van-field v-model="formData.returnAmount" :readonly="approvalStore.currentApproval?.status !== 1"
class="audit-remark-field" label="退款金额" type="number" class="audit-remark-field" :min="0" />
:min="0" <van-field :model-value="statusOptions.find(opt => opt.value === formData.status)?.text || ''"
/> label="审批结果" readonly @click="showStatusPicker = true"
<van-field :disabled="approvalStore.currentApproval?.status !== 1" class="clickable-status-field" />
:model-value="statusOptions.find(opt => opt.value === formData.status)?.text || ''" <van-field v-model="formData.auditRemark" label="审核说明" type="textarea" rows="2" autosize
label="审批结果" class="audit-remark-field" />
readonly
@click="showStatusPicker = true"
:disabled="approvalStore.currentApproval?.status !== 1"
class="clickable-status-field"
/>
<van-field
v-model="formData.auditRemark"
label="审核说明"
type="textarea"
rows="2"
autosize
class="audit-remark-field"
/>
</van-cell-group> </van-cell-group>
<van-popup v-model:show="showStatusPicker" position="bottom"> <van-popup v-model:show="showStatusPicker" position="bottom">
@ -267,15 +279,8 @@ const handleSubmit = async () => {
</van-cell> </van-cell>
</van-cell-group> </van-cell-group>
<div class="submit-bar" <div class="submit-bar" v-if="approvalStore.currentApproval?.status !== 2">
v-if="approvalStore.currentApproval?.status !== 2"> <van-button type="primary" block :loading="submitting" loading-text="提交中..." @click="handleSubmit">
<van-button
type="primary"
block
:loading="submitting"
loading-text="提交中..."
@click="handleSubmit"
>
提交审批 提交审批
</van-button> </van-button>
</div> </div>

View File

@ -1,7 +1,10 @@
<script setup lang="ts"> <script setup lang="ts">
import { onMounted } from 'vue' import { onMounted } from 'vue'
import { useOrderStore } from '@/pinia/stores/order' import { OrderGoods, useOrderStore } from '@/pinia/stores/order'
import { useRoute, useRouter } from 'vue-router' import { useRoute, useRouter } from 'vue-router'
import { openCabinetApi } from '@/common/apis/shop'
import { showSuccessToast, showFailToast } from 'vant'
import { ref } from 'vue'
const orderStore = useOrderStore() const orderStore = useOrderStore()
const route = useRoute() const route = useRoute()
@ -55,6 +58,27 @@ onMounted(() => {
// //
} }
}) })
const isButtonDisabled = ref<Record<number, boolean>>({})
async function handleOpenCabinet(item: OrderGoods) {
const orderGoodsId = item.orderGoods.orderGoodsId
isButtonDisabled.value[orderGoodsId] = true
try {
const result = await openCabinetApi(orderId.value, orderGoodsId)
if (result.code !== 0) {
showFailToast(result.msg || '开启失败,请稍后重试')
return
}
showSuccessToast('柜口已成功开启')
} catch (error) {
showFailToast('开启失败,请稍后重试')
} finally {
setTimeout((currentId) => {
delete isButtonDisabled.value[currentId]
}, 5000, orderGoodsId)
}
}
</script> </script>
<template> <template>
@ -94,16 +118,26 @@ onMounted(() => {
<div class="action-row"> <div class="action-row">
<p>数量: {{ item.orderGoods.quantity }}</p> <p>数量: {{ item.orderGoods.quantity }}</p>
<p>小计: ¥{{ (item.orderGoods.price * item.orderGoods.quantity).toFixed(2) }}</p> <p>小计: ¥{{ (item.orderGoods.price * item.orderGoods.quantity).toFixed(2) }}</p>
<template v-if="item.orderGoods.status === 1"> <div class="button-group">
<van-button <van-button
v-if="[1,5].includes(item.orderGoods.status)"
type="primary" type="primary"
size="mini" size="small"
class="refund-btn" @click="handleOpenCabinet(item)"
:disabled="isButtonDisabled[item.orderGoods.orderGoodsId]"
>
打开柜子
</van-button>
<van-button
v-if="item.orderGoods.status === 1"
type="primary"
size="small"
@click="handleRefund(item)" @click="handleRefund(item)"
> >
退还 退还商品
</van-button> </van-button>
</template> </div>
</div>
<span <span
v-if="[2,5,6].includes(item.orderGoods.status)" v-if="[2,5,6].includes(item.orderGoods.status)"
class="status-text" class="status-text"
@ -112,7 +146,6 @@ onMounted(() => {
{{ getOrderGoodsStatusText(item.orderGoods.status) }} {{ getOrderGoodsStatusText(item.orderGoods.status) }}
</span> </span>
</div> </div>
</div>
</van-cell> </van-cell>
</van-cell-group> </van-cell-group>
</div> </div>
@ -183,20 +216,17 @@ goods-info {
color: #999; color: #999;
} }
.refund-btn { .button-group {
margin-left: auto; display: flex;
color: #fff; justify-content: flex-end;
background: #ee0a24; gap: 8px;
border-radius: 15px; width: 100%;
padding: 8px 20px;
font-size: 14px;
min-width: 80px;
} }
.action-row { .action-row {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 8px;
align-items: flex-end; align-items: flex-end;
gap: 4px;
} }
</style> </style>

View File

@ -123,7 +123,7 @@ function handleCheckout() {
<template> <template>
<div class="shop"> <div class="shop">
<div class="shop-header" :style="{ height: `${headerHeight}px` }"> <div class="shop-header" :style="{ height: `${headerHeight}px` }">
<van-image :src="`${publicPath}c63.jpg`" class="shop-cover" fit="cover" /> <van-image :src="`${publicPath}cover.png`" class="shop-cover" fit="cover" />
</div> </div>
<div class="product-container"> <div class="product-container">
<!-- 左侧分类导航 --> <!-- 左侧分类导航 -->

View File

@ -17,7 +17,7 @@ const wxStore = useWxStore()
const { openid, balance, corpidLogin, userid: qyUserid } = storeToRefs(wxStore) const { openid, balance, corpidLogin, userid: qyUserid } = storeToRefs(wxStore)
const ab98UserStore = useAb98UserStore() const ab98UserStore = useAb98UserStore()
const { tel, userid: ab98Userid } = storeToRefs(ab98UserStore) const { tel, userid: ab98Userid, name } = storeToRefs(ab98UserStore)
const selectedPayment = ref<'wechat' | 'balance'>('wechat') const selectedPayment = ref<'wechat' | 'balance'>('wechat')
const contact = ref("") const contact = ref("")
@ -72,7 +72,13 @@ async function handleSubmit() {
}) })
} }
// // handleSubmit
if (!/^1[3-9]\d{9}$/.test(tel.value)) {
return showConfirmDialog({
title: "格式错误",
message: "请输入有效的手机号码"
});
}
submitting.value = true submitting.value = true
try { try {
@ -91,10 +97,12 @@ async function handleSubmit() {
corpid: wxStore.corpid, corpid: wxStore.corpid,
goodsList: cartItems.value.map(item => ({ goodsList: cartItems.value.map(item => ({
goodsId: item.product.id, goodsId: item.product.id,
quantity: item.quantity quantity: item.quantity,
cellId: item.product.cellId,
})), })),
paymentType: selectedPayment.value, paymentType: selectedPayment.value,
mobile: tel.value, mobile: tel.value,
name: name.value,
qyUserid: isInternal === 2 ? qyUserid.value : ab98Userid.value, qyUserid: isInternal === 2 ? qyUserid.value : ab98Userid.value,
isInternal: isInternal isInternal: isInternal
} }
@ -165,23 +173,40 @@ async function handleSubmit() {
</div> </div>
</div> </div>
</van-cell> </van-cell>
<van-cell>
<van-field
v-model="tel"
label="手机号"
placeholder="请输入联系电话"
required
class="tel-input"
/>
</van-cell>
</van-cell-group> </van-cell-group>
<van-cell-group class="contact-form"> <van-cell-group class="contact-form">
<van-field label="支付方式" :model-value="selectedPayment" readonly> <van-cell v-if="!corpidLogin"
<template #input> :class="['payment-option', { selected: selectedPayment === 'wechat' }]"
<van-radio-group v-model="selectedPayment" direction="horizontal"> @click="selectedPayment = 'wechat'"
<van-radio name="wechat" v-if="!corpidLogin"> >
<van-icon name="wechat" class="method-icon" /> <van-icon name="wechat" class="method-icon" />
微信支付 <span class="method-label">微信支付</span>
</van-radio> <div class="empty"></div>
<van-radio name="balance" :disabled="balance < totalPrice"> <van-icon v-if="selectedPayment === 'wechat'" name="success" class="check-icon" />
</van-cell>
<van-cell
:class="['payment-option', { selected: selectedPayment === 'balance', disabled: balance < totalPrice }]"
@click="selectedPayment = 'balance'"
>
<van-icon name="balance-o" class="method-icon" /> <van-icon name="balance-o" class="method-icon" />
余额支付当前¥{{ balance.toFixed(2) }} <span class="method-label">
</van-radio> 余额支付
</van-radio-group> <span class="balance-amount">当前¥{{ balance.toFixed(2) }}</span>
</template> </span>
</van-field> <div class="empty"></div>
<van-icon v-if="selectedPayment === 'balance'" name="success" class="check-icon" />
</van-cell>
</van-cell-group> </van-cell-group>
<!-- 提交订单栏 --> <!-- 提交订单栏 -->
@ -197,7 +222,7 @@ async function handleSubmit() {
</div> </div>
</template> </template>
<style scoped> <style lang="scss" scoped>
.van-nav-bar { .van-nav-bar {
position: fixed; position: fixed;
top: 0; top: 0;
@ -253,15 +278,6 @@ async function handleSubmit() {
font-size: 13px; font-size: 13px;
} }
.method-icon {
font-size: 24px;
margin-right: 10px;
}
.method-label {
font-size: 15px;
}
.submit-bar { .submit-bar {
position: fixed; position: fixed;
bottom: 0; bottom: 0;
@ -280,4 +296,67 @@ async function handleSubmit() {
color: #e95d5d; color: #e95d5d;
font-weight: bold; font-weight: bold;
} }
.payment-option {
display: flex;
align-items: center;
justify-content: flex-start;
margin: 8px 0;
border: 1px solid #ebedf0;
border-radius: 8px;
transition: all 0.2s;
:deep(.van-cell__value) {
display: flex;
}
}
.check-icon {
font-size: 18px;
}
.payment-option.selected {
border-color: #07c160;
background-color: #f6ffed;
}
.payment-option.disabled {
opacity: 0.6;
filter: grayscale(1);
pointer-events: none;
}
.method-icon {
vertical-align: middle;
margin-right: 12px;
font-size: 24px;
}
.method-label {
vertical-align: middle;
font-size: 15px;
}
.empty {
flex-grow: 1;
margin-right: 20px;
}
.balance-amount {
font-size: 13px;
color: #666;
}
.tel-input {
background-color: #f5f5f5;
border-radius: 4px;
padding: 8px 12px;
}
.check-icon {
margin-left: auto;
color: #07c160;
font-size: 18px;
}
</style> </style>

View File

@ -36,7 +36,9 @@ export const useAb98UserStore = defineStore("ab98User", () => {
const tel = ref<string>(storedTel ? decodeURIComponent(storedTel) : "") const tel = ref<string>(storedTel ? decodeURIComponent(storedTel) : "")
// 用户认证令牌 // 用户认证令牌
const storedToken = localStorage.getItem(STORAGE_KEYS.TOKEN) const storedToken = localStorage.getItem(STORAGE_KEYS.TOKEN)
const token = ref<string>(storedToken ? decodeURIComponent(storedToken) : "") const token = ref<string>(storedToken ? decodeURIComponent(storedToken) : "");
const tokenLogin = ref<string>("");
// 用户登录状态 // 用户登录状态
const isLogin = ref<boolean>(false); const isLogin = ref<boolean>(false);
isLogin.value = tel.value ? true : false; isLogin.value = tel.value ? true : false;
@ -98,6 +100,10 @@ export const useAb98UserStore = defineStore("ab98User", () => {
isLogin.value = value; isLogin.value = value;
} }
const setTokenLogin = (value: string) => {
tokenLogin.value = value;
}
return { return {
face_img, face_img,
sex, sex,
@ -107,11 +113,13 @@ export const useAb98UserStore = defineStore("ab98User", () => {
tel, tel,
token, token,
isLogin, isLogin,
tokenLogin,
setUserInfo, setUserInfo,
setToken, setToken,
setTel, setTel,
setIsLogin, setIsLogin,
clearUserInfo clearUserInfo,
setTokenLogin
} }
}) })

View File

@ -3,10 +3,12 @@ import { getOrdersByOpenIdApi } from "@@/apis/shop"
import type { ShopOrderEntity, ShopOrderGoodsEntity, Goods } from "@@/apis/shop/type" import type { ShopOrderEntity, ShopOrderGoodsEntity, Goods } from "@@/apis/shop/type"
export interface Order extends ShopOrderEntity { export interface Order extends ShopOrderEntity {
goodsList: Array<{ goodsList: Array<OrderGoods>
}
export interface OrderGoods {
goodsInfo: Goods goodsInfo: Goods
orderGoods: ShopOrderGoodsEntity orderGoods: ShopOrderGoodsEntity
}>
} }
export const useOrderStore = defineStore("order", () => { export const useOrderStore = defineStore("order", () => {

View File

@ -9,6 +9,7 @@ export interface Product {
description: string // 商品描述 description: string // 商品描述
image: string // 商品图片URL image: string // 商品图片URL
label: number // 商品标签 label: number // 商品标签
cellId: number // 商品所在的格子ID
} }
export const useProductStore = defineStore("product", () => { export const useProductStore = defineStore("product", () => {
@ -34,7 +35,8 @@ export const useProductStore = defineStore("product", () => {
stock: g.stock, stock: g.stock,
description: g.goodsDetail || "暂无描述", description: g.goodsDetail || "暂无描述",
image: g.coverImg, image: g.coverImg,
label: g.categoryId label: g.categoryId,
cellId: g.cellId
})) }))
} catch (error) { } catch (error) {
console.error("获取商品数据失败:", error) console.error("获取商品数据失败:", error)

View File

@ -26,8 +26,9 @@ export function registerNavigationGuard(router: Router) {
return true; return true;
} }
const userStore = useAb98UserStore() // useAb98UserStore位置不能放在外面否则会导致路由守卫无法正常工作
if (!userStore.isLogin) { const ab98UserStore = useAb98UserStore();
if (!ab98UserStore.isLogin) {
// 如果在免登录的白名单中,则直接进入 // 如果在免登录的白名单中,则直接进入
if (isWhiteList(to)) return true if (isWhiteList(to)) return true
// 其他没有访问权限的页面将被重定向到登录页面 // 其他没有访问权限的页面将被重定向到登录页面

View File

@ -27,8 +27,6 @@ declare module 'vue' {
VanNavBar: typeof import('vant/es')['NavBar'] VanNavBar: typeof import('vant/es')['NavBar']
VanPicker: typeof import('vant/es')['Picker'] VanPicker: typeof import('vant/es')['Picker']
VanPopup: typeof import('vant/es')['Popup'] VanPopup: typeof import('vant/es')['Popup']
VanRadio: typeof import('vant/es')['Radio']
VanRadioGroup: typeof import('vant/es')['RadioGroup']
VanSidebar: typeof import('vant/es')['Sidebar'] VanSidebar: typeof import('vant/es')['Sidebar']
VanSidebarItem: typeof import('vant/es')['SidebarItem'] VanSidebarItem: typeof import('vant/es')['SidebarItem']
VanTabbar: typeof import('vant/es')['Tabbar'] VanTabbar: typeof import('vant/es')['Tabbar']