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
approvalType?: number
corpid?: string
handleStatus?: number;
searchStr?: string;
}
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>
<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-field v-model="searchParams.approvalId" label="审批单号" type="number" 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-search v-model="searchParams.searchStr" placeholder="请输入搜索内容" />
</van-form>
<!-- 审批列表 -->
@ -60,14 +33,18 @@ import type { SearchApiReturnApprovalQuery, ReturnApprovalEntity } from '@/commo
import type { PickerConfirmEventParams } from 'vant/es';
import { useApprovalStore } from '@/pinia/stores/approval';
import { useWxStore } from '@/pinia/stores/wx';
import { debounce } from 'lodash-es';
const router = useRouter();
const wxStore = useWxStore();
//
const activeTab = ref(0);
const searchParams = reactive<SearchApiReturnApprovalQuery>({
corpid: wxStore.corpid,
approvalType: 0,
handleStatus: activeTab.value,
searchStr: '',
pageNum: 1,
pageSize: 10,
})
@ -126,6 +103,12 @@ const onStatusConfirm = (e: PickerConfirmEventParams) => {
statusText.value = String(selectedOptions[0]?.text || '');
}
//
const handleTabChange = (tabIndex: number) => {
searchParams.handleStatus = tabIndex;
handleSearch();
};
//
const onDateConfirm = (values: Date[]) => {
const [start, end] = values
@ -137,10 +120,23 @@ const onDateConfirm = (values: Date[]) => {
//
const handleSearch = () => {
list.value = []
searchParams.pageNum = 1
onLoad()
list.value = [];
searchParams.pageNum = 1;
finished.value = false;
onLoad();
}
const debouncedHandleSearch = debounce(() => {
handleSearch();
}, 500);
//
watch(() => searchParams.searchStr, (newVal) => {
debouncedHandleSearch();
});
onUnmounted(() => {
debouncedHandleSearch.cancel();
});
//
const handleReset = () => {

View File

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

View File

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

View File

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

View File

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