Compare commits

...

2 Commits

Author SHA1 Message Date
dzq 6e49347de2 feat(支付): 重构支付方式逻辑以支持店铺模式配置
新增支付方式映射文件,支持根据店铺模式显示不同支付选项
重构结算组件,动态显示支持的支付方式并处理支付逻辑
在商品列表选择店铺时保存选中店铺信息
2025-06-21 16:33:17 +08:00
dzq 39820a036d feat(approval): 优化审批列表搜索功能并添加状态切换
- 在审批列表页面添加状态切换标签页
- 简化搜索表单为单个搜索框并添加防抖功能
- 更新搜索接口参数以支持状态筛选和模糊搜索
2025-06-21 10:43:09 +08:00
7 changed files with 137 additions and 107 deletions

View File

@ -36,6 +36,8 @@ export interface SearchApiReturnApprovalQuery {
endTime?: string endTime?: string
approvalType?: number approvalType?: number
corpid?: string corpid?: string
handleStatus?: number;
searchStr?: string;
} }
export interface ApiResponsePageData<T> { export interface ApiResponsePageData<T> {

View File

@ -0,0 +1,14 @@
export const paymentMethodOptions = [
{ label: '微信支付', value: 0, type: 'primary' },
{ label: '借呗支付', value: 1, type: 'success' },
{ label: '要呗支付', value: 2, type: 'info' },
{ label: '余额支付', value: 3, type: 'warning' },
];
export const modeToPaymentMethodMap: Record<number, number[]> = {
0: [0],
1: [0, 1],
2: [0, 1],
3: [0],
4: [2],
};

View File

@ -1,40 +1,13 @@
<template> <template>
<div class="approval-list-container"> <div class="approval-list-container">
<!-- 状态切换标签页 -->
<van-tabs v-model:active="activeTab" @change="handleTabChange">
<van-tab title="待处理"></van-tab>
<van-tab title="已处理"></van-tab>
</van-tabs>
<!-- 搜索表单 --> <!-- 搜索表单 -->
<van-form @submit="handleSearch"> <van-form @submit="handleSearch">
<van-field v-model="searchParams.approvalId" label="审批单号" type="number" placeholder="请输入审批单号" /> <van-search v-model="searchParams.searchStr" placeholder="请输入搜索内容" />
<van-field v-model="searchParams.orderId" label="订单编号" type="number" placeholder="请输入订单编号" />
<van-field v-model="searchParams.goodsId" label="商品ID" type="number" placeholder="请输入商品ID" />
<van-field name="status" label="审批状态" readonly clickable v-model="statusText" placeholder="请选择状态"
@click="showStatusPicker = true" />
<van-popup v-model:show="showStatusPicker" position="bottom">
<van-picker :columns="statusOptions" @confirm="onStatusConfirm" @cancel="showStatusPicker = false" />
</van-popup>
<!-- <van-field
readonly
clickable
name="date"
:value="dateRangeText"
label="申请时间"
placeholder="选择时间范围"
@click="showDatePicker = true"
/>
<van-popup v-model:show="showDatePicker" position="bottom">
<van-datetime-picker
type="daterange"
@confirm="onDateConfirm"
@cancel="showDatePicker = false"
/>
</van-popup> -->
<div style="margin: 16px;">
<van-button block type="primary" native-type="submit">搜索</van-button>
<van-button block plain type="primary" style="margin-top: 10px;" @click="handleReset">重置</van-button>
</div>
</van-form> </van-form>
<!-- 审批列表 --> <!-- 审批列表 -->
@ -60,14 +33,18 @@ import type { SearchApiReturnApprovalQuery, ReturnApprovalEntity } from '@/commo
import type { PickerConfirmEventParams } from 'vant/es'; import type { PickerConfirmEventParams } from 'vant/es';
import { useApprovalStore } from '@/pinia/stores/approval'; import { useApprovalStore } from '@/pinia/stores/approval';
import { useWxStore } from '@/pinia/stores/wx'; import { useWxStore } from '@/pinia/stores/wx';
import { debounce } from 'lodash-es';
const router = useRouter(); const router = useRouter();
const wxStore = useWxStore(); const wxStore = useWxStore();
// //
const activeTab = ref(0);
const searchParams = reactive<SearchApiReturnApprovalQuery>({ const searchParams = reactive<SearchApiReturnApprovalQuery>({
corpid: wxStore.corpid, corpid: wxStore.corpid,
approvalType: 0, approvalType: 0,
handleStatus: activeTab.value,
searchStr: '',
pageNum: 1, pageNum: 1,
pageSize: 10, pageSize: 10,
}) })
@ -126,6 +103,12 @@ const onStatusConfirm = (e: PickerConfirmEventParams) => {
statusText.value = String(selectedOptions[0]?.text || ''); statusText.value = String(selectedOptions[0]?.text || '');
} }
//
const handleTabChange = (tabIndex: number) => {
searchParams.handleStatus = tabIndex;
handleSearch();
};
// //
const onDateConfirm = (values: Date[]) => { const onDateConfirm = (values: Date[]) => {
const [start, end] = values const [start, end] = values
@ -137,10 +120,23 @@ const onDateConfirm = (values: Date[]) => {
// //
const handleSearch = () => { const handleSearch = () => {
list.value = [] list.value = [];
searchParams.pageNum = 1 searchParams.pageNum = 1;
onLoad() finished.value = false;
onLoad();
} }
const debouncedHandleSearch = debounce(() => {
handleSearch();
}, 500);
//
watch(() => searchParams.searchStr, (newVal) => {
debouncedHandleSearch();
});
onUnmounted(() => {
debouncedHandleSearch.cancel();
});
// //
const handleReset = () => { const handleReset = () => {

View File

@ -167,9 +167,10 @@ const handleTabChange = (tabIndex: number) => {
// //
const handleSearch = () => { const handleSearch = () => {
list.value = [] list.value = [];
searchParams.pageNum = 1 searchParams.pageNum = 1;
onLoad() finished.value = false;
onLoad();
} }
const debouncedHandleSearch = debounce(() => { const debouncedHandleSearch = debounce(() => {

View File

@ -61,6 +61,7 @@ const showAb98BindPopup = ref(false);
function handleShopSelect(selectedShopId: number) { function handleShopSelect(selectedShopId: number) {
shopId.value = selectedShopId; shopId.value = selectedShopId;
showShopList.value = false; showShopList.value = false;
productStore.setSelectedShop(shopList.value.find(shop => shop.shopId === selectedShopId)!);
productStore.getGoods(selectedShopId); productStore.getGoods(selectedShopId);
cartStore.clearCart(); cartStore.clearCart();
activeCategory.value = 0; activeCategory.value = 0;

View File

@ -1,25 +1,42 @@
<script setup lang="ts"> <script setup lang="ts">
import { useCartStore } from "@/pinia/stores/cart" import { useCartStore } from "@/pinia/stores/cart";
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 { showConfirmDialog } from "vant" import { showConfirmDialog } from "vant";
import { submitOrderApi } from "@/common/apis/shop" import { submitOrderApi } from "@/common/apis/shop";
import type { SubmitOrderRequestData, WxJsApiPreCreateResponse } from "@/common/apis/shop/type" import type { SubmitOrderRequestData, WxJsApiPreCreateResponse } from "@/common/apis/shop/type";
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router';
import { useProductStore } from "@/pinia/stores/product";
//
import { paymentMethodOptions, modeToPaymentMethodMap } from "@/common/utils/maps/payment";
const router = useRouter() const router = useRouter();
const cartStore = useCartStore() const cartStore = useCartStore();
const { cartItems, totalPrice } = storeToRefs(cartStore) const { cartItems, totalPrice } = storeToRefs(cartStore);
const wxStore = useWxStore() const wxStore = useWxStore();
const { openid, balance, corpidLogin, userid: qyUserid, name: qyName } = storeToRefs(wxStore) const { openid, balance, corpidLogin, userid: qyUserid, name: qyName } = storeToRefs(wxStore);
const ab98UserStore = useAb98UserStore() const ab98UserStore = useAb98UserStore();
const { tel, userid: ab98Userid, name } = storeToRefs(ab98UserStore) const { tel, userid: ab98Userid, name } = storeToRefs(ab98UserStore);
const selectedPayment = ref<'wechat' | 'balance' | 'approval'>('wechat'); const productStore = useProductStore();
//
const supportedPayments = computed(() => {
const shopMode = productStore.selectedShop?.mode || 0;
const allowedValues = modeToPaymentMethodMap[shopMode] || [];
//
// 1.
// 2. (0)
return paymentMethodOptions.filter(option => allowedValues.includes(option.value)
&& (option.value !== 0 || !corpidLogin.value));
});
//
const selectedPayment = ref<string>(supportedPayments.value[0]?.value.toString() || '0');
const contact = ref(""); const contact = ref("");
const applyRemark = ref(""); const applyRemark = ref("");
const submitting = ref(false); const submitting = ref(false);
@ -28,28 +45,13 @@ const isApproval = computed(() => {
return cartItems.value.some(item => item.product.belongType == 1); return cartItems.value.some(item => item.product.belongType == 1);
}); });
watch(corpidLogin, (newValue) => { // value
if (isApproval.value) { const paymentValueToType: Record<string, 'wechat' | 'balance' | 'approval'> = {
selectedPayment.value = 'approval'; '0': 'wechat',
} else { '1': 'balance',
if (newValue) { '2': 'approval',
selectedPayment.value = 'balance'; '3': 'balance'
} else { };
selectedPayment.value = 'wechat';
}
}
}, { immediate: true });
watch(isApproval, (newValue) => {
if (newValue) {
selectedPayment.value = 'approval';
} else {
if (corpidLogin.value) {
selectedPayment.value = 'balance';
} else {
selectedPayment.value = 'wechat';
}
}
})
function callWxJsApi(paymentInfo: WxJsApiPreCreateResponse) { function callWxJsApi(paymentInfo: WxJsApiPreCreateResponse) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
@ -127,7 +129,8 @@ async function handleSubmit() {
quantity: item.quantity, quantity: item.quantity,
cellId: item.product.cellId, cellId: item.product.cellId,
})), })),
paymentType: selectedPayment.value, // value
paymentType: paymentValueToType[selectedPayment.value] || 'wechat',
mobile: tel.value, mobile: tel.value,
name: isInternal === 2 ? qyName.value : name.value, name: isInternal === 2 ? qyName.value : name.value,
applyRemark: applyRemark.value, applyRemark: applyRemark.value,
@ -141,28 +144,35 @@ async function handleSubmit() {
throw new Error("订单提交失败") throw new Error("订单提交失败")
} }
if (selectedPayment.value === 'wechat') { if (selectedPayment.value == '0') { //
if (data.paymentInfo) { if (data.paymentInfo) {
await callWxJsApi(data.paymentInfo); await callWxJsApi(data.paymentInfo);
} }
} else if (selectedPayment.value === 'balance') { } else if (selectedPayment.value == '1') { //
//
wxStore.setBalance(data.newBalance || 0); wxStore.setBalance(data.newBalance || 0);
try { try {
await showConfirmDialog({ await showConfirmDialog({
title: "支付成功", title: "支付成功",
message: `余额支付成功,剩余余额:¥${data.newBalance?.toFixed(2)}` message: `借呗支付成功,剩余余额:¥${data.newBalance?.toFixed(2)}`
}) })
} catch (error) { } catch (error) {}
} } else if (selectedPayment.value == '2') { //
} else if (selectedPayment.value === 'approval') {
//
try { try {
await showConfirmDialog({ await showConfirmDialog({
title: "提交领用申请成功", title: "提交领用申请成功",
message: `请等待管理员审批` message: `请等待管理员审批`
}) })
} catch (error) {} } catch (error) {}
} else if (selectedPayment.value == '3') { //
wxStore.setBalance(data.newBalance || 0);
try {
await showConfirmDialog({
title: "支付成功",
message: `余额支付成功,剩余余额:¥${data.newBalance?.toFixed(2)}`
})
} catch (error) {}
} else { //
//
} }
router.push({ router.push({
@ -225,25 +235,24 @@ async function handleSubmit() {
<van-field v-model="applyRemark" label="领用说明" type="textarea" rows="2" autosize /> <van-field v-model="applyRemark" label="领用说明" type="textarea" rows="2" autosize />
</van-cell-group> --> </van-cell-group> -->
<!-- 支付方式 -->
<van-cell-group v-if="!isApproval" class="contact-form"> <van-cell-group v-if="!isApproval" class="contact-form">
<van-cell v-if="!corpidLogin" :class="['payment-option', { selected: selectedPayment === 'wechat' }]" <van-cell
@click="selectedPayment = 'wechat'"> v-for="method in supportedPayments"
<van-icon name="wechat" class="method-icon" /> :key="method.value"
<span class="method-label">微信支付</span> :class="['payment-option', { selected: selectedPayment === method.value.toString(), disabled: method.value === 1 && (balance < totalPrice) }]"
<div class="empty"></div> @click="selectedPayment = method.value.toString()"
<van-icon v-if="selectedPayment === 'wechat'" name="success" class="check-icon" /> >
</van-cell> <van-icon
:name="method.value === 0 ? 'wechat' : method.value === 1 ? 'balance-o' : method.value === 2 ? 'credit-card' : 'wallet'"
<van-cell v-if="balance && balance > 0" class="method-icon"
:class="['payment-option', { selected: selectedPayment === 'balance', disabled: balance < totalPrice }]" />
@click="selectedPayment = 'balance'">
<van-icon name="balance-o" class="method-icon" />
<span class="method-label"> <span class="method-label">
借呗支付 {{ method.label }}
<span class="balance-amount">当前¥{{ balance.toFixed(2) }}</span> <span v-if="method.value === 1" class="balance-amount">当前¥{{ balance.toFixed(2) }}</span>
</span> </span>
<div class="empty"></div> <div class="empty"></div>
<van-icon v-if="selectedPayment === 'balance'" name="success" class="check-icon" /> <van-icon v-if="selectedPayment === method.value.toString()" name="success" class="check-icon" />
</van-cell> </van-cell>
</van-cell-group> </van-cell-group>

View File

@ -1,3 +1,4 @@
import { ShopEntity } from "@/common/apis/shop/type"
import { pinia } from "@/pinia" import { pinia } from "@/pinia"
import { getShopGoodsApi } from "@@/apis/shop" import { getShopGoodsApi } from "@@/apis/shop"
@ -19,6 +20,11 @@ export const useProductStore = defineStore("product", () => {
const labels = ref<{ id: number, name: string }[]>([]); const labels = ref<{ id: number, name: string }[]>([]);
const categories = ref<Product[]>([]); const categories = ref<Product[]>([]);
const shopId = ref<number|null>(null); const shopId = ref<number|null>(null);
const selectedShop = ref<ShopEntity|null>(null);
const setSelectedShop = (shop: ShopEntity) => {
selectedShop.value = shop;
}
const getGoods = async (shopId_?: number) => { const getGoods = async (shopId_?: number) => {
if (shopId_ && shopId_ > 0) { if (shopId_ && shopId_ > 0) {
@ -58,7 +64,8 @@ export const useProductStore = defineStore("product", () => {
console.error("获取商品数据失败:", error) console.error("获取商品数据失败:", error)
} }
} }
return { labels, categories, shopId, getGoods } return { labels, categories, shopId, selectedShop,
getGoods, setSelectedShop }
}) })
/** /**