Compare commits
No commits in common. "8cfa252d9af1d68546ddfcafa9b64797ccb82799" and "999625ccd03630f739c8fba7c5d7618d5b61f94c" have entirely different histories.
8cfa252d9a
...
999625ccd0
|
@ -1,96 +0,0 @@
|
||||||
import { request } from "@/http/axios"
|
|
||||||
import { PageDTO, ResponseData, BasePageQuery } from "../type"
|
|
||||||
|
|
||||||
export interface ShopGoodsDTO {
|
|
||||||
goodsId?: number
|
|
||||||
goodsName?: string
|
|
||||||
categoryId?: number
|
|
||||||
categoryName?: string
|
|
||||||
price?: number
|
|
||||||
stock?: number
|
|
||||||
status?: number
|
|
||||||
autoApproval?: number
|
|
||||||
coverImg?: string
|
|
||||||
creatorId?: number
|
|
||||||
creatorName?: string
|
|
||||||
createTime?: string
|
|
||||||
remark?: string
|
|
||||||
cabinetName?: string
|
|
||||||
cellNo?: number
|
|
||||||
cellNoStr?: string
|
|
||||||
totalStock?: number
|
|
||||||
usageInstruction?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface SearchShopGoodsQuery extends BasePageQuery {
|
|
||||||
goodsName?: string
|
|
||||||
categoryId?: number
|
|
||||||
status?: number
|
|
||||||
autoApproval?: number
|
|
||||||
minPrice?: number
|
|
||||||
maxPrice?: number
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 获取商品列表 */
|
|
||||||
export function getGoodsList(query: SearchShopGoodsQuery) {
|
|
||||||
return request<ResponseData<PageDTO<ShopGoodsDTO>>>({
|
|
||||||
url: "manage/goods/list",
|
|
||||||
method: "get",
|
|
||||||
params: query
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 新增商品 */
|
|
||||||
export function addGoods(data: {
|
|
||||||
goodsName: string
|
|
||||||
categoryId: number
|
|
||||||
price: number
|
|
||||||
stock: number
|
|
||||||
status: number
|
|
||||||
autoApproval: number
|
|
||||||
coverImg: string
|
|
||||||
goodsDetail?: string
|
|
||||||
usageInstruction?: string
|
|
||||||
}) {
|
|
||||||
return request<ResponseData<void>>({
|
|
||||||
url: "manage/goods",
|
|
||||||
method: "post",
|
|
||||||
data
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 删除商品 */
|
|
||||||
export function deleteGoods(goodsIds: number[]) {
|
|
||||||
return request<ResponseData<void>>({
|
|
||||||
url: `manage/goods/${goodsIds.join(',')}`,
|
|
||||||
method: "delete"
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 修改商品 */
|
|
||||||
export function updateGoods(goodsId: number, data: {
|
|
||||||
goodsName?: string
|
|
||||||
categoryId?: number
|
|
||||||
price?: number
|
|
||||||
stock?: number
|
|
||||||
status?: number
|
|
||||||
autoApproval?: number
|
|
||||||
coverImg?: string
|
|
||||||
goodsDetail?: string
|
|
||||||
usageInstruction?: string
|
|
||||||
}) {
|
|
||||||
return request<ResponseData<void>>({
|
|
||||||
url: `manage/goods/${goodsId}`,
|
|
||||||
method: "put",
|
|
||||||
data
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 获取单个商品信息 */
|
|
||||||
export function getGoodsInfo(goodsId: number) {
|
|
||||||
return request<ResponseData<ShopGoodsDTO>>({
|
|
||||||
url: "manage/goods/getGoodsInfo",
|
|
||||||
method: "get",
|
|
||||||
params: { goodsId }
|
|
||||||
})
|
|
||||||
}
|
|
|
@ -101,12 +101,7 @@ export interface GetOrdersByOpenIdDTO {
|
||||||
export interface GetBalanceResponse {
|
export interface GetBalanceResponse {
|
||||||
userid: string
|
userid: string
|
||||||
corpid: string
|
corpid: string
|
||||||
/** 剩余借呗 */
|
|
||||||
balance: number
|
balance: number
|
||||||
/** 已用借呗 */
|
|
||||||
useBalance: number
|
|
||||||
/** 借呗总额 */
|
|
||||||
balanceLimit: number
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface QyLoginDTO {
|
export interface QyLoginDTO {
|
||||||
|
|
|
@ -1,24 +0,0 @@
|
||||||
|
|
||||||
export type ResponseData<T> = {
|
|
||||||
code: number;
|
|
||||||
msg: string;
|
|
||||||
data: T;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type PageDTO<T> = {
|
|
||||||
total: number;
|
|
||||||
rows: Array<T>;
|
|
||||||
};
|
|
||||||
|
|
||||||
export interface BasePageQuery extends BaseQuery {
|
|
||||||
pageNum?: number;
|
|
||||||
pageSize?: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface BaseQuery {
|
|
||||||
beginTime?: string;
|
|
||||||
endTime?: string;
|
|
||||||
orderColumn?: string;
|
|
||||||
orderDirection?: string;
|
|
||||||
timeRangeColumn?: string;
|
|
||||||
}
|
|
|
@ -1,261 +0,0 @@
|
||||||
<script setup lang="ts">
|
|
||||||
import { ref, reactive, onMounted } from 'vue';
|
|
||||||
import { showConfirmDialog, showDialog, showSuccessToast } from 'vant';
|
|
||||||
import {
|
|
||||||
getGoodsList,
|
|
||||||
addGoods,
|
|
||||||
deleteGoods,
|
|
||||||
updateGoods,
|
|
||||||
type ShopGoodsDTO,
|
|
||||||
type SearchShopGoodsQuery
|
|
||||||
} from '@/common/apis/manage/goods';
|
|
||||||
|
|
||||||
// 商品列表数据
|
|
||||||
const goodsList = ref<ShopGoodsDTO[]>([]);
|
|
||||||
const loading = ref(false);
|
|
||||||
const finished = ref(false);
|
|
||||||
|
|
||||||
// 搜索参数
|
|
||||||
const searchParams = reactive<SearchShopGoodsQuery>({
|
|
||||||
pageNum: 1,
|
|
||||||
pageSize: 10,
|
|
||||||
goodsName: '',
|
|
||||||
status: undefined
|
|
||||||
});
|
|
||||||
|
|
||||||
// 弹窗控制
|
|
||||||
const showEditDialog = ref(false);
|
|
||||||
const currentGoods = ref<Partial<ShopGoodsDTO>>({});
|
|
||||||
const isEditMode = ref(false);
|
|
||||||
|
|
||||||
// 获取商品列表
|
|
||||||
const fetchGoodsList = async () => {
|
|
||||||
try {
|
|
||||||
const res = await getGoodsList(searchParams);
|
|
||||||
goodsList.value = res.data.rows;
|
|
||||||
} catch (e) {
|
|
||||||
showDialog({ message: '加载失败,请重试' });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 加载数据
|
|
||||||
const onLoad = async () => {
|
|
||||||
try {
|
|
||||||
const res = await getGoodsList(searchParams);
|
|
||||||
goodsList.value.push(...res.data.rows);
|
|
||||||
loading.value = false;
|
|
||||||
|
|
||||||
if (goodsList.value.length >= res.data.total) {
|
|
||||||
finished.value = true;
|
|
||||||
} else {
|
|
||||||
if (searchParams.pageNum) {
|
|
||||||
searchParams.pageNum++;
|
|
||||||
} else {
|
|
||||||
searchParams.pageNum = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('获取商品列表失败', error);
|
|
||||||
finished.value = true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 删除商品
|
|
||||||
const handleDelete = async (ids: number[]) => {
|
|
||||||
await showConfirmDialog({ message: '确认删除选中商品?' });
|
|
||||||
await deleteGoods(ids);
|
|
||||||
showSuccessToast('删除成功');
|
|
||||||
await fetchGoodsList();
|
|
||||||
};
|
|
||||||
|
|
||||||
// 提交表单
|
|
||||||
const submitForm = async () => {
|
|
||||||
try {
|
|
||||||
if (isEditMode.value) {
|
|
||||||
await updateGoods(currentGoods.value.goodsId!, currentGoods.value);
|
|
||||||
} else {
|
|
||||||
await addGoods({
|
|
||||||
goodsName: currentGoods.value.goodsName || '',
|
|
||||||
categoryId: currentGoods.value.categoryId || 0,
|
|
||||||
price: currentGoods.value.price || 0,
|
|
||||||
stock: currentGoods.value.stock || 0,
|
|
||||||
status: currentGoods.value.status || 1,
|
|
||||||
autoApproval: currentGoods.value.autoApproval || 0,
|
|
||||||
coverImg: currentGoods.value.coverImg || '',
|
|
||||||
usageInstruction: currentGoods.value.usageInstruction
|
|
||||||
});
|
|
||||||
}
|
|
||||||
showSuccessToast('操作成功');
|
|
||||||
showEditDialog.value = false;
|
|
||||||
await fetchGoodsList();
|
|
||||||
} catch (e) {
|
|
||||||
showDialog({ message: '操作失败' });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 打开编辑弹窗
|
|
||||||
const openEdit = (goods?: ShopGoodsDTO) => {
|
|
||||||
currentGoods.value = goods ? { ...goods } : { status: 1 };
|
|
||||||
isEditMode.value = !!goods;
|
|
||||||
showEditDialog.value = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
onMounted(fetchGoodsList);
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div class="goods-manage">
|
|
||||||
<!-- 搜索栏和操作按钮 -->
|
|
||||||
<div class="search-action-bar">
|
|
||||||
<van-search v-model="searchParams.goodsName" placeholder="输入商品名称搜索" @search="fetchGoodsList" />
|
|
||||||
<van-button type="primary" @click="openEdit">添加商品</van-button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 商品表格 -->
|
|
||||||
<van-list v-model:loading="loading" :finished="finished" finished-text="没有更多了" @load="onLoad">
|
|
||||||
<div class="goods-grid">
|
|
||||||
<van-cell v-for="item in goodsList" :key="item.goodsId" class="goods-card">
|
|
||||||
<template #icon>
|
|
||||||
<van-image :src="item.coverImg" width="80" height="80" class="goods-image">
|
|
||||||
<div v-if="item.stock === 0" class="sold-out-overlay">
|
|
||||||
<span class="sold-out-text">已售罄</span>
|
|
||||||
</div>
|
|
||||||
<template #error>
|
|
||||||
<div class="custom-error">
|
|
||||||
图片加载失败
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</van-image>
|
|
||||||
</template>
|
|
||||||
<div class="goods-info">
|
|
||||||
<div class="goods-name van-ellipsis">{{ item.goodsName }}</div>
|
|
||||||
<div class="goods-price">¥{{ item.price?.toFixed(2) }}</div>
|
|
||||||
<div class="action-row">
|
|
||||||
<span v-if="item.stock! > 0" class="stock-count">库存: {{ item.stock }}</span>
|
|
||||||
<div class="goods-actions">
|
|
||||||
<van-button size="mini" @click="openEdit(item)">编辑</van-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</van-cell>
|
|
||||||
</div>
|
|
||||||
</van-list>
|
|
||||||
|
|
||||||
<!-- 编辑弹窗 -->
|
|
||||||
<van-dialog v-model:show="showEditDialog" :title="isEditMode ? '编辑商品' : '新增商品'">
|
|
||||||
<van-form @submit="submitForm">
|
|
||||||
<van-cell-group inset>
|
|
||||||
<van-field v-model="currentGoods.goodsName" label="商品名称" placeholder="请输入"
|
|
||||||
:rules="[{ required: true }]" />
|
|
||||||
<van-field v-model="currentGoods.price" label="价格" type="number" placeholder="请输入" />
|
|
||||||
<van-field v-model="currentGoods.stock" label="库存" type="number" placeholder="请输入" />
|
|
||||||
</van-cell-group>
|
|
||||||
<div style="padding: 16px">
|
|
||||||
<van-button block type="primary" native-type="submit">提交</van-button>
|
|
||||||
</div>
|
|
||||||
</van-form>
|
|
||||||
</van-dialog>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.goods-manage {
|
|
||||||
padding: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-action-bar {
|
|
||||||
margin: 0;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-action-bar .van-search {
|
|
||||||
flex: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.goods-grid {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
|
|
||||||
gap: 4px;
|
|
||||||
margin: 4px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.goods-card {
|
|
||||||
margin-bottom: 10px;
|
|
||||||
padding: min(2.667vw, 20px) 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.goods-image {
|
|
||||||
margin-right: 12px;
|
|
||||||
border-radius: 4px;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.goods-info {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: space-between;
|
|
||||||
height: 80px;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.goods-name {
|
|
||||||
font-size: 14px;
|
|
||||||
color: #333;
|
|
||||||
line-height: 1.4;
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
.goods-price {
|
|
||||||
font-size: 16px;
|
|
||||||
color: #e95d5d;
|
|
||||||
font-weight: bold;
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
.action-row {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: flex-end;
|
|
||||||
margin-top: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.stock-count {
|
|
||||||
font-size: 11px;
|
|
||||||
color: #bbbbbb;
|
|
||||||
margin-right: 8px;
|
|
||||||
display: flex;
|
|
||||||
align-items: flex-end;
|
|
||||||
height: 100%;
|
|
||||||
line-height: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sold-out-overlay {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
background: rgba(255, 255, 255, 0.8);
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sold-out-text {
|
|
||||||
color: #999;
|
|
||||||
font-size: 14px;
|
|
||||||
transform: rotate(-15deg);
|
|
||||||
border: 1px solid #eee;
|
|
||||||
padding: 2px 8px;
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.custom-error {
|
|
||||||
color: #999;
|
|
||||||
font-size: 12px;
|
|
||||||
text-align: center;
|
|
||||||
padding: 10px;
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -1,17 +1,16 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useRouter, useRoute } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
import { useWxStore } from '@/pinia/stores/wx'
|
import { useWxStore } from '@/pinia/stores/wx'
|
||||||
import { useAb98UserStore } from '@/pinia/stores/ab98-user'
|
import { useAb98UserStore } from '@/pinia/stores/ab98-user'
|
||||||
import { storeToRefs } from 'pinia'
|
import { storeToRefs } from 'pinia'
|
||||||
import { publicPath } from "@/common/utils/path"
|
import { publicPath } from "@/common/utils/path"
|
||||||
import { showConfirmDialog } from 'vant';
|
import { showConfirmDialog } from 'vant';
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter()
|
||||||
const route = useRoute();
|
const wxStore = useWxStore()
|
||||||
const wxStore = useWxStore();
|
const ab98UserStore = useAb98UserStore()
|
||||||
const ab98UserStore = useAb98UserStore();
|
|
||||||
|
|
||||||
const { balance, useBalance, balanceLimit, name: qyName } = storeToRefs(wxStore);
|
const { balance, name: qyName } = storeToRefs(wxStore);
|
||||||
const { name: userName, sex: userSex, face_img } = storeToRefs(ab98UserStore);
|
const { name: userName, sex: userSex, face_img } = storeToRefs(ab98UserStore);
|
||||||
|
|
||||||
const name = computed(() => {
|
const name = computed(() => {
|
||||||
|
@ -30,129 +29,79 @@ const handleLogout = () => {
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
// 取消操作
|
// 取消操作
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
|
||||||
wxStore.refreshBalance();
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
<div un-py-16px>
|
||||||
|
<van-cell-group class="user-card">
|
||||||
|
<van-cell :border="false">
|
||||||
|
<template #title>
|
||||||
|
<div class="flex items-center p-4">
|
||||||
|
<van-image
|
||||||
|
round
|
||||||
|
width="80"
|
||||||
|
height="80"
|
||||||
|
:src="userAvatar"
|
||||||
|
class="mr-4"
|
||||||
|
@click="handleLogout"
|
||||||
|
/>
|
||||||
<div>
|
<div>
|
||||||
<div class="user-card flex items-start p-4 bg-white rounded-lg shadow-sm">
|
<div class="text-lg font-bold mb-2">{{ name }}</div>
|
||||||
<div class="flex items-center pl-2">
|
<van-tag type="primary" class="mr-2">{{ userSex }}</van-tag>
|
||||||
<van-image round width="40" height="40" :src="userAvatar" class="mr-3" @click="handleLogout" />
|
|
||||||
<div class="flex-1">
|
|
||||||
<div class="text-sm font-medium mb-1">{{ name }}</div>
|
|
||||||
<van-tag type="primary">{{ userSex }}</van-tag>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</template>
|
||||||
|
</van-cell>
|
||||||
|
</van-cell-group>
|
||||||
|
|
||||||
<!-- 功能按钮区域 -->
|
<!-- 功能按钮区域 -->
|
||||||
<div class="func-buttons flex flex-wrap justify-between">
|
<van-grid :column-num="4" :gutter="12" class="func-buttons un-mt-20px">
|
||||||
<div v-for="(item, index) in [
|
<van-grid-item
|
||||||
|
v-for="(item, index) in [
|
||||||
{ icon: 'idcard', text: '身份证', color: 'transparent' },
|
{ icon: 'idcard', text: '身份证', color: 'transparent' },
|
||||||
{ icon: 'phone-o', text: '手机号', color: 'transparent' },
|
{ icon: 'phone-o', text: '手机号', color: 'transparent' },
|
||||||
{ icon: 'wechat', text: '微信', color: 'transparent' },
|
{ icon: 'wechat', text: '微信', color: 'transparent' },
|
||||||
{ icon: 'card', text: '银行卡', color: 'transparent' }
|
{ icon: 'card', text: '银行卡', color: 'transparent' }
|
||||||
]" :key="index" class="flex flex-col items-center w-1/6 mb-12px">
|
]"
|
||||||
<van-icon :name="item.icon" size="26px" :style="{ background: item.color }"
|
:key="index"
|
||||||
class="un-p-8px un-rounded-full un-text-white" />
|
>
|
||||||
|
<van-icon
|
||||||
|
:name="item.icon"
|
||||||
|
size="28px"
|
||||||
|
:style="{ background: item.color }"
|
||||||
|
class="un-p-8px un-rounded-full un-text-white"
|
||||||
|
/>
|
||||||
<div class="un-mt-8px un-text-12px un-color-hex-666">{{ item.text }}</div>
|
<div class="un-mt-8px un-text-12px un-color-hex-666">{{ item.text }}</div>
|
||||||
</div>
|
</van-grid-item>
|
||||||
</div>
|
</van-grid>
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- 余额区域 -->
|
<!-- 余额区域 -->
|
||||||
<div class="balance-card flex flex-wrap justify-between items-center p-4 bg-white rounded-lg shadow-sm un-mt-16px">
|
<van-cell
|
||||||
<van-icon name="gold-coin" size="28px" class="un-mr-8px un-color-#ffb300! mr-2" />
|
title="账户余额"
|
||||||
<div class="flex-1 ml-1">
|
:value="`¥${balance}`"
|
||||||
<div class="text-sm text-gray-700">借呗总额</div>
|
class="un-mt-16px! un-rounded-8px!"
|
||||||
<div class="text-lg font-bold text-primary">{{ balanceLimit }}</div>
|
title-class="un-text-14px! un-color-hex-333!"
|
||||||
</div>
|
value-class="un-text-16px! un-fw-600! un-color-primary!"
|
||||||
<div class="flex-1 ml-1">
|
>
|
||||||
<div class="text-sm text-gray-700">未还借呗</div>
|
<template #icon>
|
||||||
<div class="text-lg font-bold text-primary">{{ useBalance }}</div>
|
<van-icon
|
||||||
</div>
|
name="gold-coin"
|
||||||
<div class="flex-1 ml-1">
|
size="20px"
|
||||||
<div class="text-sm text-gray-700">剩余借呗</div>
|
class="un-mr-8px un-color-#ffb300!"
|
||||||
<div class="text-lg font-bold text-primary">{{ balance }}</div>
|
/>
|
||||||
</div>
|
</template>
|
||||||
</div>
|
</van-cell>
|
||||||
|
|
||||||
<!-- 个人中心按钮 -->
|
<!-- 个人中心按钮 -->
|
||||||
<van-row gutter="12" class="button-group p-4 bg-white rounded-lg shadow-sm un-mt-16px">
|
<van-cell-group>
|
||||||
<van-col span="24">
|
<van-cell title="订单列表" is-link @click="router.push('/order-list')" />
|
||||||
<div class="section-title text-sm font-bold pb-2">个人中心</div>
|
<van-cell title="柜机管理" is-link @click="router.push('/cabinet')" v-if="wxStore.isCabinetAdmin"/>
|
||||||
</van-col>
|
<van-cell title="审批中心" is-link @click="router.push('/approval/list')" v-if="wxStore.isCabinetAdmin"/>
|
||||||
<van-col span="6">
|
</van-cell-group>
|
||||||
<div class="custom-btn" @click="router.push('/order-list')">
|
|
||||||
<van-icon name="orders-o" size="20px" />
|
|
||||||
<span>订单列表</span>
|
|
||||||
</div>
|
|
||||||
</van-col>
|
|
||||||
<van-col span="6">
|
|
||||||
<div v-if="wxStore.isCabinetAdmin" class="custom-btn" @click="router.push('/manage/goods')">
|
|
||||||
<van-icon name="comment-o" size="20px" />
|
|
||||||
<span>商品管理</span>
|
|
||||||
</div>
|
|
||||||
</van-col>
|
|
||||||
<van-col span="6">
|
|
||||||
<div v-if="wxStore.isCabinetAdmin" class="custom-btn" @click="router.push('/cabinet')">
|
|
||||||
<van-icon name="manager-o" size="20px" />
|
|
||||||
<span>柜机管理</span>
|
|
||||||
</div>
|
|
||||||
</van-col>
|
|
||||||
<van-col span="6">
|
|
||||||
<div v-if="wxStore.isCabinetAdmin" class="custom-btn" @click="router.push('/approval/list')">
|
|
||||||
<van-icon name="comment-o" size="20px" />
|
|
||||||
<span>审批中心</span>
|
|
||||||
</div>
|
|
||||||
</van-col>
|
|
||||||
</van-row>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style scoped>
|
||||||
.func-buttons {
|
/* 移除了已迁移到组件的样式 */
|
||||||
background-color: #fff;
|
|
||||||
padding: 0px;
|
|
||||||
margin-top: 12px;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.user-card {
|
|
||||||
margin: 12px;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.balance-card {
|
|
||||||
margin: 12px;
|
|
||||||
flex-direction: row;
|
|
||||||
}
|
|
||||||
|
|
||||||
.button-group {
|
|
||||||
margin: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.custom-btn {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
width: 100%;
|
|
||||||
height: 70px;
|
|
||||||
padding: 0;
|
|
||||||
margin: 0 0 12px;
|
|
||||||
background: #1989fa;
|
|
||||||
border: 1px solid #1989fa;
|
|
||||||
border-radius: 4px;
|
|
||||||
color: white;
|
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
span {
|
|
||||||
margin-top: 8px;
|
|
||||||
font-size: 12px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -21,6 +21,8 @@ const { labels, categories } = storeToRefs(productStore)
|
||||||
|
|
||||||
// 当前选中的分类索引
|
// 当前选中的分类索引
|
||||||
const activeCategory = ref(0)
|
const activeCategory = ref(0)
|
||||||
|
// 存储每个分类标题的 DOM 元素引用
|
||||||
|
const categoryRefs = ref<HTMLElement[]>([])
|
||||||
// 滚动容器引用
|
// 滚动容器引用
|
||||||
const scrollContainer = ref<HTMLElement>()
|
const scrollContainer = ref<HTMLElement>()
|
||||||
// 顶部头图高度(随滚动变化)
|
// 顶部头图高度(随滚动变化)
|
||||||
|
@ -45,10 +47,14 @@ const searchQuery = ref('')
|
||||||
// 点击分类导航
|
// 点击分类导航
|
||||||
function handleCategoryClick(index: number) {
|
function handleCategoryClick(index: number) {
|
||||||
activeCategory.value = index
|
activeCategory.value = index
|
||||||
|
categoryRefs.value[index].scrollIntoView({
|
||||||
|
behavior: "smooth",
|
||||||
|
block: "start"
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 节流的滚动位置计算(用于切换左侧导航激活状态)
|
// 节流的滚动位置计算(用于切换左侧导航激活状态)
|
||||||
/* const throttledUpdate = throttle(() => {
|
const throttledUpdate = throttle(() => {
|
||||||
if (!scrollContainer.value || !categoryRefs.value.length) return
|
if (!scrollContainer.value || !categoryRefs.value.length) return
|
||||||
|
|
||||||
// 添加数组元素存在性检查
|
// 添加数组元素存在性检查
|
||||||
|
@ -67,7 +73,7 @@ function handleCategoryClick(index: number) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// activeCategory.value = activeIndex
|
// activeCategory.value = activeIndex
|
||||||
}, 100) */
|
}, 100)
|
||||||
|
|
||||||
// 节流的头部高度计算(实现顶部图片缩放效果)
|
// 节流的头部高度计算(实现顶部图片缩放效果)
|
||||||
const throttledScroll = throttle(() => {
|
const throttledScroll = throttle(() => {
|
||||||
|
@ -111,7 +117,7 @@ const currentProducts = computed(() => {
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
productStore.getGoods();
|
productStore.getGoods();
|
||||||
scrollListener.push(scrollContainer.value?.addEventListener("scroll", throttledScroll))
|
scrollListener.push(scrollContainer.value?.addEventListener("scroll", throttledScroll))
|
||||||
// scrollListener.push(scrollContainer.value?.addEventListener("scroll", throttledUpdate))
|
scrollListener.push(scrollContainer.value?.addEventListener("scroll", throttledUpdate))
|
||||||
})
|
})
|
||||||
|
|
||||||
// 组件卸载前清理事件监听
|
// 组件卸载前清理事件监听
|
||||||
|
@ -153,7 +159,7 @@ watch(() => route.path, (newPath) => {
|
||||||
shape="round"
|
shape="round"
|
||||||
class="search-box"
|
class="search-box"
|
||||||
/>
|
/>
|
||||||
<div class="category-section">
|
<div :ref="el => categoryRefs[0] = el as HTMLElement" class="category-section">
|
||||||
<van-cell v-for="product in currentProducts" :key="product.id" class="product-item">
|
<van-cell v-for="product in currentProducts" :key="product.id" class="product-item">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<van-image :src="product.image" width="80" height="80" @click.stop="showProductDetail(product.id)"
|
<van-image :src="product.image" width="80" height="80" @click.stop="showProductDetail(product.id)"
|
||||||
|
|
|
@ -22,15 +22,7 @@ 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("")
|
||||||
const remark = ref("")
|
const remark = ref("")
|
||||||
const submitting = ref(false);
|
const submitting = ref(false)
|
||||||
|
|
||||||
watch(corpidLogin, (newValue) => {
|
|
||||||
if (newValue) {
|
|
||||||
selectedPayment.value = 'balance';
|
|
||||||
} else {
|
|
||||||
selectedPayment.value = 'wechat';
|
|
||||||
}
|
|
||||||
}, { immediate: true });
|
|
||||||
|
|
||||||
function callWxJsApi(paymentInfo: WxJsApiPreCreateResponse) {
|
function callWxJsApi(paymentInfo: WxJsApiPreCreateResponse) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
|
@ -202,7 +194,7 @@ async function handleSubmit() {
|
||||||
<van-icon v-if="selectedPayment === 'wechat'" name="success" class="check-icon" />
|
<van-icon v-if="selectedPayment === 'wechat'" name="success" class="check-icon" />
|
||||||
</van-cell>
|
</van-cell>
|
||||||
|
|
||||||
<van-cell v-if="corpidLogin"
|
<van-cell
|
||||||
:class="['payment-option', { selected: selectedPayment === 'balance', disabled: balance < totalPrice }]"
|
:class="['payment-option', { selected: selectedPayment === 'balance', disabled: balance < totalPrice }]"
|
||||||
@click="selectedPayment = 'balance'">
|
@click="selectedPayment = 'balance'">
|
||||||
<van-icon name="balance-o" class="method-icon" />
|
<van-icon name="balance-o" class="method-icon" />
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import { pinia } from "@/pinia"
|
import { pinia } from "@/pinia"
|
||||||
import { getOpenIdApi, getBalanceApi, qyLogin, getBalanceByQyUserid } from "@/common/apis/shop"
|
import { getOpenIdApi, getBalanceApi, qyLogin, getBalanceByQyUserid } from "@/common/apis/shop"
|
||||||
import { GetBalanceResponse } from "@/common/apis/shop/type"
|
|
||||||
|
|
||||||
|
|
||||||
export const useWxStore = defineStore("wx", () => {
|
export const useWxStore = defineStore("wx", () => {
|
||||||
|
@ -12,12 +11,8 @@ export const useWxStore = defineStore("wx", () => {
|
||||||
const openid = ref<string>("")
|
const openid = ref<string>("")
|
||||||
// 用户 userid
|
// 用户 userid
|
||||||
const userid = ref<string>("");
|
const userid = ref<string>("");
|
||||||
// 剩余借呗
|
// 用户余额
|
||||||
const balance = ref<number>(0);
|
const balance = ref<number>(0);
|
||||||
// 已用借呗
|
|
||||||
const useBalance = ref<number>(0);
|
|
||||||
// 借呗总额
|
|
||||||
const balanceLimit = ref<number>(0);
|
|
||||||
// 企业id
|
// 企业id
|
||||||
const corpid = ref<string>("");
|
const corpid = ref<string>("");
|
||||||
// 是否企业微信登录
|
// 是否企业微信登录
|
||||||
|
@ -40,17 +35,6 @@ export const useWxStore = defineStore("wx", () => {
|
||||||
isCabinetAdmin.value = isAdmin;
|
isCabinetAdmin.value = isAdmin;
|
||||||
}
|
}
|
||||||
|
|
||||||
const refreshBalance = async () => {
|
|
||||||
if (corpid.value && userid.value) {
|
|
||||||
const res = await getBalanceByQyUserid(corpid.value, userid.value);
|
|
||||||
if (res && res.code == 0) {
|
|
||||||
balance.value = res.data.balance;
|
|
||||||
useBalance.value = res.data.useBalance;
|
|
||||||
balanceLimit.value = res.data.balanceLimit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleWxCallback = async (params: { corpid?: string; code?: string; state?: string; }) => {
|
const handleWxCallback = async (params: { corpid?: string; code?: string; state?: string; }) => {
|
||||||
console.log('handleWxCallback:', params)
|
console.log('handleWxCallback:', params)
|
||||||
if (params.code) {
|
if (params.code) {
|
||||||
|
@ -81,7 +65,7 @@ export const useWxStore = defineStore("wx", () => {
|
||||||
|
|
||||||
if (openid.value) {
|
if (openid.value) {
|
||||||
// 获取用户余额
|
// 获取用户余额
|
||||||
let balanceRes: ApiResponseData<GetBalanceResponse> | null = null;
|
let balanceRes = null;
|
||||||
|
|
||||||
if(corpid.value) {
|
if(corpid.value) {
|
||||||
balanceRes = await getBalanceByQyUserid(corpid.value, userid.value);
|
balanceRes = await getBalanceByQyUserid(corpid.value, userid.value);
|
||||||
|
@ -90,9 +74,7 @@ export const useWxStore = defineStore("wx", () => {
|
||||||
}
|
}
|
||||||
console.log('获取余额成功:', balanceRes)
|
console.log('获取余额成功:', balanceRes)
|
||||||
if (balanceRes && balanceRes.code == 0) {
|
if (balanceRes && balanceRes.code == 0) {
|
||||||
balance.value = balanceRes.data.balance;
|
balance.value = balanceRes.data.balance
|
||||||
useBalance.value = balanceRes.data.useBalance;
|
|
||||||
balanceLimit.value = balanceRes.data.balanceLimit;
|
|
||||||
if (!userid.value) {
|
if (!userid.value) {
|
||||||
userid.value = balanceRes.data.userid;
|
userid.value = balanceRes.data.userid;
|
||||||
}
|
}
|
||||||
|
@ -108,8 +90,8 @@ export const useWxStore = defineStore("wx", () => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return { code, state, openid, corpid, userid, balance, useBalance, balanceLimit, isCabinetAdmin, corpidLogin, name,
|
return { code, state, openid, corpid, userid, balance, isCabinetAdmin, corpidLogin, name,
|
||||||
setOpenid, setBalance, handleWxCallback, setIsCabinetAdmin, refreshBalance }
|
setOpenid, setBalance, handleWxCallback, setIsCabinetAdmin }
|
||||||
})
|
})
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -25,10 +25,6 @@ export function registerNavigationGuard(router: Router) {
|
||||||
if (corpid) {
|
if (corpid) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
/* const isAdmin = urlParams.get('isAdmin') || undefined;
|
|
||||||
if (isAdmin) {
|
|
||||||
return true;
|
|
||||||
} */
|
|
||||||
|
|
||||||
// useAb98UserStore位置不能放在外面,否则会导致路由守卫无法正常工作
|
// useAb98UserStore位置不能放在外面,否则会导致路由守卫无法正常工作
|
||||||
const ab98UserStore = useAb98UserStore();
|
const ab98UserStore = useAb98UserStore();
|
||||||
|
|
|
@ -111,25 +111,6 @@ export const routes: RouteRecordRaw[] = [
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
/* {
|
|
||||||
path: '/manage/goods',
|
|
||||||
component: () => import('@/pages/manage/goods/goodsList.vue'),
|
|
||||||
name: "ManageGoods",
|
|
||||||
meta: {
|
|
||||||
title: '商品管理',
|
|
||||||
keepAlive: false,
|
|
||||||
layout: {
|
|
||||||
navBar: {
|
|
||||||
showNavBar: true,
|
|
||||||
showLeftArrow: true
|
|
||||||
},
|
|
||||||
tabbar: {
|
|
||||||
showTabbar: false,
|
|
||||||
icon: "home-o"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, */
|
|
||||||
{
|
{
|
||||||
path: "/",
|
path: "/",
|
||||||
component: () => import("@/pages/product/ProductList.vue"),
|
component: () => import("@/pages/product/ProductList.vue"),
|
||||||
|
|
|
@ -14,7 +14,6 @@ declare module 'vue' {
|
||||||
VanButton: typeof import('vant/es')['Button']
|
VanButton: typeof import('vant/es')['Button']
|
||||||
VanCell: typeof import('vant/es')['Cell']
|
VanCell: typeof import('vant/es')['Cell']
|
||||||
VanCellGroup: typeof import('vant/es')['CellGroup']
|
VanCellGroup: typeof import('vant/es')['CellGroup']
|
||||||
VanCol: typeof import('vant/es')['Col']
|
|
||||||
VanConfigProvider: typeof import('vant/es')['ConfigProvider']
|
VanConfigProvider: typeof import('vant/es')['ConfigProvider']
|
||||||
VanDivider: typeof import('vant/es')['Divider']
|
VanDivider: typeof import('vant/es')['Divider']
|
||||||
VanField: typeof import('vant/es')['Field']
|
VanField: typeof import('vant/es')['Field']
|
||||||
|
@ -28,7 +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']
|
||||||
VanRow: typeof import('vant/es')['Row']
|
|
||||||
VanSearch: typeof import('vant/es')['Search']
|
VanSearch: typeof import('vant/es')['Search']
|
||||||
VanSidebar: typeof import('vant/es')['Sidebar']
|
VanSidebar: typeof import('vant/es')['Sidebar']
|
||||||
VanSidebarItem: typeof import('vant/es')['SidebarItem']
|
VanSidebarItem: typeof import('vant/es')['SidebarItem']
|
||||||
|
|
Loading…
Reference in New Issue