refactor(passport): 移除统一扫码页面中的核销功能
- 移除扫码页面中的核销类型相关代码 - 移除核销成功后的提示弹窗逻辑 - 移除核销相关的标签显示 - 更新页面描述文案,移除核销相关内容 - 移除核销类型的历史记录展示逻辑 - 简化扫码结果处理流程 - 移除大量已删除的工具函数和组件文件 - 恢复开发环境API配置为本地地址 - 移除支付类型枚举和支付处理器类 - 移除订单商品数据标准化工具函数 - 移除商品列表和订单列表组件 - 移除优惠券数据转换和计算相关工具函数 - 移除支付方式API接口和模型定义 - 移除规格选择器组件
This commit is contained in:
@@ -1,81 +0,0 @@
|
||||
import {useState, useEffect, useCallback} from 'react'
|
||||
import Taro from '@tarojs/taro'
|
||||
import {getShopDealerApply} from '@/api/shop/shopDealerApply'
|
||||
import type {ShopDealerApply} from '@/api/shop/shopDealerApply/model'
|
||||
|
||||
// Hook 返回值接口
|
||||
export interface UseDealerApplyReturn {
|
||||
// 经销商用户信息
|
||||
dealerApply: ShopDealerApply | null
|
||||
// 加载状态
|
||||
loading: boolean
|
||||
// 错误信息
|
||||
error: string | null
|
||||
// 刷新数据
|
||||
refresh: () => Promise<void>
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 经销商用户 Hook - 简化版本
|
||||
* 只查询经销商用户信息和判断是否存在
|
||||
*/
|
||||
export const useDealerApply = (): UseDealerApplyReturn => {
|
||||
const [dealerApply, setDealerApply] = useState<ShopDealerApply | null>(null)
|
||||
const [loading, setLoading] = useState(false)
|
||||
const [error, setError] = useState<string | null>(null)
|
||||
|
||||
const userId = Taro.getStorageSync('UserId');
|
||||
|
||||
// 获取经销商用户数据
|
||||
const fetchDealerData = useCallback(async () => {
|
||||
|
||||
if (!userId) {
|
||||
console.log('🔍 用户未登录,提前返回')
|
||||
setDealerApply(null)
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
setLoading(true)
|
||||
setError(null)
|
||||
|
||||
// 查询当前用户的经销商信息
|
||||
const dealer = await getShopDealerApply(userId)
|
||||
|
||||
if (dealer) {
|
||||
setDealerApply(dealer)
|
||||
} else {
|
||||
setDealerApply(null)
|
||||
}
|
||||
} catch (err) {
|
||||
const errorMessage = err instanceof Error ? err.message : '获取经销商信息失败'
|
||||
setError(errorMessage)
|
||||
setDealerApply(null)
|
||||
} finally {
|
||||
setLoading(false)
|
||||
}
|
||||
}, [userId])
|
||||
|
||||
// 刷新数据
|
||||
const refresh = useCallback(async () => {
|
||||
await fetchDealerData()
|
||||
}, [fetchDealerData])
|
||||
|
||||
// 初始化加载数据
|
||||
useEffect(() => {
|
||||
if (userId) {
|
||||
console.log('🔍 调用 fetchDealerData')
|
||||
fetchDealerData()
|
||||
} else {
|
||||
console.log('🔍 用户ID不存在,不调用 fetchDealerData')
|
||||
}
|
||||
}, [fetchDealerData, userId])
|
||||
|
||||
return {
|
||||
dealerApply,
|
||||
loading,
|
||||
error,
|
||||
refresh
|
||||
}
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
import {useState, useEffect, useCallback} from 'react'
|
||||
import Taro, { useDidShow } from '@tarojs/taro'
|
||||
import {getShopDealerUser} from '@/api/shop/shopDealerUser'
|
||||
import type {ShopDealerUser} from '@/api/shop/shopDealerUser/model'
|
||||
|
||||
// Hook 返回值接口
|
||||
export interface UseDealerUserReturn {
|
||||
// 经销商用户信息
|
||||
dealerUser: ShopDealerUser | null
|
||||
// 加载状态
|
||||
loading: boolean
|
||||
// 错误信息
|
||||
error: string | null
|
||||
// 刷新数据
|
||||
refresh: () => Promise<void>
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 经销商用户 Hook - 简化版本
|
||||
* 只查询经销商用户信息和判断是否存在
|
||||
*/
|
||||
export const useDealerUser = (): UseDealerUserReturn => {
|
||||
const [dealerUser, setDealerUser] = useState<ShopDealerUser | null>(null)
|
||||
const rawUserId = Taro.getStorageSync('UserId')
|
||||
const userId = Number(rawUserId)
|
||||
const hasUser = Number.isFinite(userId) && userId > 0
|
||||
|
||||
// If user is logged in, start in loading state to avoid "click too fast" mis-routing.
|
||||
const [loading, setLoading] = useState<boolean>(hasUser)
|
||||
const [error, setError] = useState<string | null>(null)
|
||||
|
||||
// 获取经销商用户数据
|
||||
const fetchDealerData = useCallback(async () => {
|
||||
|
||||
if (!hasUser) {
|
||||
setDealerUser(null)
|
||||
setLoading(false)
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
setLoading(true)
|
||||
setError(null)
|
||||
|
||||
// 查询当前用户的经销商信息
|
||||
const dealer = await getShopDealerUser(userId)
|
||||
|
||||
if (dealer) {
|
||||
setDealerUser(dealer)
|
||||
} else {
|
||||
setDealerUser(null)
|
||||
}
|
||||
} catch (err) {
|
||||
const errorMessage = err instanceof Error ? err.message : '获取经销商信息失败'
|
||||
setError(errorMessage)
|
||||
setDealerUser(null)
|
||||
} finally {
|
||||
setLoading(false)
|
||||
}
|
||||
}, [hasUser, userId])
|
||||
|
||||
// 刷新数据
|
||||
const refresh = useCallback(async () => {
|
||||
await fetchDealerData()
|
||||
}, [fetchDealerData])
|
||||
|
||||
// 初始化加载数据
|
||||
useEffect(() => {
|
||||
if (hasUser) {
|
||||
fetchDealerData()
|
||||
} else {
|
||||
setDealerUser(null)
|
||||
setError(null)
|
||||
setLoading(false)
|
||||
}
|
||||
}, [fetchDealerData, hasUser])
|
||||
|
||||
// 页面返回/切换到前台时刷新一次,避免“注册成为经销商后,页面不更新”
|
||||
useDidShow(() => {
|
||||
fetchDealerData()
|
||||
})
|
||||
|
||||
// 允许业务侧通过事件主动触发刷新(例如:注册成功后触发)
|
||||
useEffect(() => {
|
||||
const handler = () => {
|
||||
fetchDealerData()
|
||||
}
|
||||
// 事件名尽量语义化;后续可在注册成功处 trigger
|
||||
Taro.eventCenter.on('dealerUser:changed', handler)
|
||||
return () => {
|
||||
Taro.eventCenter.off('dealerUser:changed', handler)
|
||||
}
|
||||
}, [fetchDealerData])
|
||||
|
||||
return {
|
||||
dealerUser,
|
||||
loading,
|
||||
error,
|
||||
refresh
|
||||
}
|
||||
}
|
||||
@@ -4,11 +4,6 @@ import {
|
||||
confirmWechatQRLogin,
|
||||
parseQRContent
|
||||
} from '@/api/passport/qr-login';
|
||||
import { getShopGiftByCode, updateShopGift, decryptQrData } from "@/api/shop/shopGift";
|
||||
import { getGltUserTicket, updateGltUserTicket } from '@/api/glt/gltUserTicket';
|
||||
import { useUser } from "@/hooks/useUser";
|
||||
import { isValidJSON } from "@/utils/jsonUtils";
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
/**
|
||||
* 统一扫码状态
|
||||
@@ -26,19 +21,9 @@ export enum UnifiedScanState {
|
||||
*/
|
||||
export enum ScanType {
|
||||
LOGIN = 'login', // 登录二维码
|
||||
VERIFICATION = 'verification', // 核销二维码
|
||||
UNKNOWN = 'unknown' // 未知类型
|
||||
}
|
||||
|
||||
type VerificationBusinessType = 'gift' | 'ticket';
|
||||
|
||||
interface TicketVerificationPayload {
|
||||
userTicketId: number;
|
||||
qty?: number;
|
||||
userId?: number;
|
||||
t?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* 统一扫码结果
|
||||
*/
|
||||
@@ -50,10 +35,9 @@ export interface UnifiedScanResult {
|
||||
|
||||
/**
|
||||
* 统一扫码Hook
|
||||
* 可以处理登录和核销两种类型的二维码
|
||||
* 用于处理登录二维码
|
||||
*/
|
||||
export function useUnifiedQRScan() {
|
||||
const { isAdmin } = useUser();
|
||||
const [state, setState] = useState<UnifiedScanState>(UnifiedScanState.IDLE);
|
||||
const [error, setError] = useState<string>('');
|
||||
const [result, setResult] = useState<UnifiedScanResult | null>(null);
|
||||
@@ -80,29 +64,12 @@ export function useUnifiedQRScan() {
|
||||
*/
|
||||
const detectScanType = useCallback((scanResult: string): ScanType => {
|
||||
try {
|
||||
// 1. 检查是否为JSON格式(核销二维码)
|
||||
if (isValidJSON(scanResult)) {
|
||||
const json = JSON.parse(scanResult);
|
||||
if ((json.businessType === 'gift' || json.businessType === 'ticket') && json.token && json.data) {
|
||||
return ScanType.VERIFICATION;
|
||||
}
|
||||
// Allow plaintext (non-encrypted) ticket verification payload for debugging/internal use.
|
||||
if (json.userTicketId) {
|
||||
return ScanType.VERIFICATION;
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 检查是否为登录二维码
|
||||
// 检查是否为登录二维码
|
||||
const loginToken = parseQRContent(scanResult);
|
||||
if (loginToken) {
|
||||
return ScanType.LOGIN;
|
||||
}
|
||||
|
||||
// 3. 检查是否为纯文本核销码(6位数字)
|
||||
if (/^\d{6}$/.test(scanResult.trim())) {
|
||||
return ScanType.VERIFICATION;
|
||||
}
|
||||
|
||||
return ScanType.UNKNOWN;
|
||||
} catch (error) {
|
||||
console.error('检测二维码类型失败:', error);
|
||||
@@ -136,120 +103,6 @@ export function useUnifiedQRScan() {
|
||||
}
|
||||
}, []);
|
||||
|
||||
/**
|
||||
* 处理核销二维码
|
||||
*/
|
||||
const handleVerificationQR = useCallback(async (scanResult: string): Promise<UnifiedScanResult> => {
|
||||
if (!isAdmin()) {
|
||||
throw new Error('您没有核销权限');
|
||||
}
|
||||
|
||||
let businessType: VerificationBusinessType = 'gift';
|
||||
let decryptedOrRaw = '';
|
||||
|
||||
// 判断是否为加密的JSON格式
|
||||
if (isValidJSON(scanResult)) {
|
||||
const json = JSON.parse(scanResult);
|
||||
if ((json.businessType === 'gift' || json.businessType === 'ticket') && json.token && json.data) {
|
||||
businessType = json.businessType;
|
||||
// 解密获取核销内容
|
||||
const decryptedData = await decryptQrData({
|
||||
token: json.token,
|
||||
encryptedData: json.data
|
||||
});
|
||||
|
||||
if (decryptedData) {
|
||||
decryptedOrRaw = decryptedData.toString();
|
||||
} else {
|
||||
throw new Error('解密失败');
|
||||
}
|
||||
} else if (json.userTicketId) {
|
||||
businessType = 'ticket';
|
||||
decryptedOrRaw = scanResult.trim();
|
||||
}
|
||||
} else {
|
||||
// 直接使用扫码结果作为核销内容
|
||||
decryptedOrRaw = scanResult.trim();
|
||||
}
|
||||
|
||||
if (!decryptedOrRaw) {
|
||||
throw new Error('无法获取有效的核销码');
|
||||
}
|
||||
|
||||
if (businessType === 'ticket') {
|
||||
if (!isValidJSON(decryptedOrRaw)) {
|
||||
throw new Error('水票核销信息格式错误');
|
||||
}
|
||||
const payload = JSON.parse(decryptedOrRaw) as TicketVerificationPayload;
|
||||
const userTicketId = Number(payload.userTicketId);
|
||||
const qty = Math.max(1, Number(payload.qty || 1));
|
||||
if (!Number.isFinite(userTicketId) || userTicketId <= 0) {
|
||||
throw new Error('水票核销信息无效');
|
||||
}
|
||||
|
||||
const ticket = await getGltUserTicket(userTicketId);
|
||||
if (!ticket) throw new Error('水票不存在');
|
||||
if (ticket.status === 1) throw new Error('该水票已冻结');
|
||||
const available = Number(ticket.availableQty || 0);
|
||||
const used = Number(ticket.usedQty || 0);
|
||||
if (available < qty) throw new Error('水票可用次数不足');
|
||||
|
||||
await updateGltUserTicket({
|
||||
...ticket,
|
||||
availableQty: available - qty,
|
||||
usedQty: used + qty
|
||||
});
|
||||
|
||||
return {
|
||||
type: ScanType.VERIFICATION,
|
||||
data: {
|
||||
businessType: 'ticket',
|
||||
ticket: {
|
||||
...ticket,
|
||||
availableQty: available - qty,
|
||||
usedQty: used + qty
|
||||
},
|
||||
qty
|
||||
},
|
||||
message: `核销成功(已使用${qty}次)`
|
||||
};
|
||||
}
|
||||
|
||||
// 验证礼品卡核销码
|
||||
const gift = await getShopGiftByCode(decryptedOrRaw);
|
||||
|
||||
if (!gift) {
|
||||
throw new Error('核销码无效');
|
||||
}
|
||||
|
||||
if (gift.status === 1) {
|
||||
throw new Error('此礼品码已使用');
|
||||
}
|
||||
|
||||
if (gift.status === 2) {
|
||||
throw new Error('此礼品码已失效');
|
||||
}
|
||||
|
||||
if (gift.userId === 0) {
|
||||
throw new Error('此礼品码未认领');
|
||||
}
|
||||
|
||||
// 执行核销
|
||||
await updateShopGift({
|
||||
...gift,
|
||||
status: 1,
|
||||
operatorUserId: Number(Taro.getStorageSync('UserId')) || 0,
|
||||
takeTime: dayjs().format('YYYY-MM-DD HH:mm:ss'),
|
||||
verificationTime: dayjs().format('YYYY-MM-DD HH:mm:ss')
|
||||
});
|
||||
|
||||
return {
|
||||
type: ScanType.VERIFICATION,
|
||||
data: { businessType: 'gift', gift },
|
||||
message: '核销成功'
|
||||
};
|
||||
}, [isAdmin]);
|
||||
|
||||
/**
|
||||
* 开始扫码
|
||||
*/
|
||||
@@ -306,9 +159,6 @@ export function useUnifiedQRScan() {
|
||||
case ScanType.LOGIN:
|
||||
result = await handleLoginQR(scanResult);
|
||||
break;
|
||||
case ScanType.VERIFICATION:
|
||||
result = await handleVerificationQR(scanResult);
|
||||
break;
|
||||
default:
|
||||
throw new Error('未知的扫码类型');
|
||||
}
|
||||
@@ -351,7 +201,7 @@ export function useUnifiedQRScan() {
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
}, [reset, detectScanType, handleLoginQR, handleVerificationQR]);
|
||||
}, [reset, detectScanType, handleLoginQR]);
|
||||
|
||||
/**
|
||||
* 取消扫码
|
||||
|
||||
Reference in New Issue
Block a user