refactor(doctor): 重构医生模块为经销商模块并优化相关功能
- 将 doctor 目录重命名为 dealer 目录 - 更新页面标题从'会员注册'为'注册会员' - 删除银行卡管理、患者报备和订单消息功能 - 重命名组件 AddDoctor 为 AddUserAddress - 添加用户角色管理和默认角色写入逻辑 - 优化注册成功后跳转至用户中心页面 - 更新应用配置中的页面路径和子包结构 - 添加经销商资金管理、团队管理和二维码推广功能 - 更新租户信息配置,增加租户名称和版权信息 - 优化文章列表组件的类型定义和渲染方式 - 修复广告轮播图数据加载和图片兼容性问题
This commit is contained in:
@@ -1,60 +1,54 @@
|
||||
import {Image} from '@nutui/nutui-react-taro'
|
||||
import {Share} from '@nutui/icons-react-taro'
|
||||
import {View, Text} from '@tarojs/components'
|
||||
import Taro from '@tarojs/taro'
|
||||
import {ShopGoods} from "@/api/shop/shopGoods/model"
|
||||
import {CmsNavigation} from "@/api/cms/cmsNavigation/model"
|
||||
import './GoodsList.scss'
|
||||
|
||||
interface GoodsListProps {
|
||||
data: ShopGoods[]
|
||||
nav?: CmsNavigation
|
||||
}
|
||||
|
||||
const GoodsList = (props: GoodsListProps) => {
|
||||
const GoodsList = (props: any) => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<View className={'py-3'} style={{paddingTop: '0'}}>
|
||||
<View className={'bg-gray-50'}>
|
||||
<View className={'grid grid-cols-2 gap-2 pb-2 p-2'}>
|
||||
{props.data?.map((item, index) => {
|
||||
return (
|
||||
<View key={index} className={'goods-waterfall-item bg-white'} style={{
|
||||
borderRadius: '0 0 6px 6px'
|
||||
}}>
|
||||
<View className={'goods-card'}>
|
||||
<Image
|
||||
src={item.image}
|
||||
lazyLoad={false}
|
||||
style={{
|
||||
borderRadius: '6px 6px 0 0',
|
||||
height: '180px'
|
||||
}}
|
||||
onClick={() => Taro.navigateTo({url: '/shop/goodsDetail/index?id=' + item.goodsId})}
|
||||
/>
|
||||
<View className={'goods-info p-2 flex flex-col'}>
|
||||
<View className={'goods-title text-sm font-bold'}>{item.name}</View>
|
||||
<View className={'goods-meta'}>
|
||||
<Text className={'goods-comments text-gray-400 text-xs'}>{item.comments}</Text>
|
||||
<View className={'py-3'}>
|
||||
<View className={'flex flex-col justify-between items-center rounded-lg px-2'}>
|
||||
{props.data?.map((item: any, index: number) => {
|
||||
return (
|
||||
<View key={index} className={'flex flex-col rounded-lg bg-white shadow-sm w-full mb-5'}>
|
||||
<Image src={item.image} mode={'aspectFit'} lazyLoad={false}
|
||||
radius="10px 10px 0 0" height="180"
|
||||
onClick={() => Taro.navigateTo({url: '/shop/goodsDetail/index?id=' + item.goodsId})}/>
|
||||
<View className={'flex flex-col p-2 rounded-lg'}>
|
||||
<View>
|
||||
<View className={'car-no text-sm'}>{item.name}</View>
|
||||
<View className={'flex justify-between text-xs py-1'}>
|
||||
<Text className={'text-orange-500'}>{item.comments}</Text>
|
||||
<Text className={'text-gray-400'}>已售 {item.sales}</Text>
|
||||
</View>
|
||||
<View className={'flex justify-between items-center py-2'}>
|
||||
<View className={'flex text-red-500 text-xl items-baseline'}>
|
||||
<Text className={'text-xs'}>¥</Text>
|
||||
<Text className={'font-bold text-2xl'}>{item.price}</Text>
|
||||
<Text className={'text-xs px-1'}>会员价</Text>
|
||||
<Text className={'text-xs text-gray-400 line-through'}>¥{item.salePrice}</Text>
|
||||
</View>
|
||||
<View className={'goods-price-section flex justify-between'}>
|
||||
<View className={'goods-price'}>
|
||||
<Text className={'price-unit text-orange-600 font-bold text-lg'}>¥</Text>
|
||||
<Text className={'price-number text-orange-600 font-bold text-lg'}>{item.price}</Text>
|
||||
<View className={'buy-btn'}>
|
||||
<View className={'cart-icon'}>
|
||||
<Share size={20} className={'mx-4 mt-2'}
|
||||
onClick={() => Taro.navigateTo({url: '/shop/goodsDetail/index?id=' + item.goodsId})}/>
|
||||
</View>
|
||||
<View className={'goods-actions'}>
|
||||
<Text className={'goods-sales text-gray-400 text-xs'}>已售 {item.sales}</Text>
|
||||
<View className={'text-white pl-4 pr-5'}
|
||||
onClick={() => Taro.navigateTo({url: '/shop/goodsDetail/index?id=' + item.goodsId})}>购买
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
)
|
||||
})}
|
||||
</View>
|
||||
</View>
|
||||
)
|
||||
})}
|
||||
</View>
|
||||
</View>
|
||||
</>
|
||||
)
|
||||
}
|
||||
export default GoodsList
|
||||
export default GoodsList
|
||||
|
||||
@@ -42,7 +42,7 @@ function Category() {
|
||||
|
||||
useShareAppMessage(() => {
|
||||
return {
|
||||
title: `${nav?.categoryName}_WebSoft Inc.`,
|
||||
title: `${nav?.categoryName}_桂乐淘`,
|
||||
path: `/shop/category/index?id=${categoryId}`,
|
||||
success: function () {
|
||||
console.log('分享成功');
|
||||
|
||||
4
src/shop/comments/index.config.ts
Normal file
4
src/shop/comments/index.config.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export default definePageConfig({
|
||||
navigationBarTitleText: '全部评论',
|
||||
navigationBarTextStyle: 'black'
|
||||
})
|
||||
0
src/shop/comments/index.tsx
Normal file
0
src/shop/comments/index.tsx
Normal file
@@ -15,6 +15,7 @@ import SpecSelector from "@/components/SpecSelector";
|
||||
import "./index.scss";
|
||||
import {useCart} from "@/hooks/useCart";
|
||||
import {useConfig} from "@/hooks/useConfig";
|
||||
import {parseInviteParams, saveInviteParams, trackInviteSource} from "@/utils/invite";
|
||||
|
||||
const GoodsDetail = () => {
|
||||
const [statusBarHeight, setStatusBarHeight] = useState<number>(44);
|
||||
@@ -39,6 +40,24 @@ const GoodsDetail = () => {
|
||||
const {cartCount, addToCart} = useCart()
|
||||
const {config} = useConfig()
|
||||
|
||||
// 如果从分享链接进入(携带 inviter/source/t),且当前未登录,则暂存邀请信息用于注册后绑定关系
|
||||
useEffect(() => {
|
||||
try {
|
||||
const currentUserId = Taro.getStorageSync('UserId')
|
||||
if (currentUserId) return
|
||||
|
||||
const inviteParams = parseInviteParams({query: router?.params})
|
||||
if (inviteParams?.inviter) {
|
||||
saveInviteParams(inviteParams)
|
||||
trackInviteSource(inviteParams.source || 'share', parseInt(inviteParams.inviter))
|
||||
}
|
||||
} catch (e) {
|
||||
// 邀请参数解析/存储失败不影响正常浏览商品
|
||||
console.error('商品详情页处理邀请参数失败:', e)
|
||||
}
|
||||
// router 在 Taro 中可能不稳定;这里仅在 goodsId 变化时尝试处理一次即可
|
||||
}, [goodsId])
|
||||
|
||||
// 处理加入购物车
|
||||
const handleAddToCart = () => {
|
||||
if (!goods) return;
|
||||
@@ -186,10 +205,16 @@ const GoodsDetail = () => {
|
||||
|
||||
// 分享给好友
|
||||
useShareAppMessage(() => {
|
||||
const inviter = Taro.getStorageSync('UserId')
|
||||
const sharePath =
|
||||
inviter
|
||||
? `/shop/goodsDetail/index?id=${goodsId}&inviter=${inviter}&source=goods_share&t=${Date.now()}`
|
||||
: `/shop/goodsDetail/index?id=${goodsId}`
|
||||
|
||||
return {
|
||||
title: goods?.name || '精选商品',
|
||||
path: `/shop/goodsDetail/index?id=${goodsId}`,
|
||||
imageUrl: goods?.image, // 分享图片
|
||||
path: sharePath,
|
||||
imageUrl: goods?.image ? `${goods.image}?x-oss-process=image/resize,w_500,h_400,m_fill` : undefined, // 分享图片,调整为5:4比例
|
||||
success: function (res: any) {
|
||||
console.log('分享成功', res);
|
||||
Taro.showToast({
|
||||
@@ -280,8 +305,10 @@ const GoodsDetail = () => {
|
||||
<>
|
||||
<View className={'flex justify-between'}>
|
||||
<View className={'flex text-red-500 text-xl items-baseline'}>
|
||||
<span className={'text-xs'}>¥</span>
|
||||
<span className={'font-bold text-2xl'}>{goods.price}</span>
|
||||
<Text className={'text-xs'}>¥</Text>
|
||||
<Text className={'font-bold text-2xl'}>{goods.price}</Text>
|
||||
<Text className={'text-xs px-1'}>会员价</Text>
|
||||
<Text className={'text-xs text-gray-400 line-through'}>¥{goods.salePrice}</Text>
|
||||
</View>
|
||||
<span className={"text-gray-400 text-xs"}>已售 {goods.sales}</span>
|
||||
</View>
|
||||
@@ -342,9 +369,7 @@ const GoodsDetail = () => {
|
||||
)}
|
||||
</View>
|
||||
<View className={'w-full'}>
|
||||
<View className={'p-4 bg-white leading-7 '}>
|
||||
<RichText nodes={goods.content || '内容详情'}/>
|
||||
</View>
|
||||
<RichText nodes={goods.content || '内容详情'}/>
|
||||
<View className={'h-24'}></View>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
@@ -74,20 +74,20 @@ const OrderConfirm = () => {
|
||||
const getGoodsTotal = () => {
|
||||
if (!goods) return 0
|
||||
const price = parseFloat(goods.price || '0')
|
||||
const total = price * quantity
|
||||
// const total = price * quantity
|
||||
|
||||
// 🔍 详细日志,用于排查数值精度问题
|
||||
console.log('💵 商品总价计算:', {
|
||||
goodsPrice: goods.price,
|
||||
goodsPriceType: typeof goods.price,
|
||||
parsedPrice: price,
|
||||
quantity: quantity,
|
||||
total: total,
|
||||
totalFixed2: total.toFixed(2),
|
||||
totalString: total.toString()
|
||||
})
|
||||
// console.log('💵 商品总价计算:', {
|
||||
// goodsPrice: goods.price,
|
||||
// goodsPriceType: typeof goods.price,
|
||||
// parsedPrice: price,
|
||||
// quantity: quantity,
|
||||
// total: total,
|
||||
// totalFixed2: total.toFixed(2),
|
||||
// totalString: total.toString()
|
||||
// })
|
||||
|
||||
return total
|
||||
return price * quantity
|
||||
}
|
||||
|
||||
// 计算优惠券折扣
|
||||
@@ -418,9 +418,9 @@ const OrderConfirm = () => {
|
||||
couponId: parseInt(String(bestCoupon.id), 10)
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
console.log('🎯 使用推荐优惠券的订单数据:', updatedOrderData);
|
||||
|
||||
|
||||
// 执行支付
|
||||
await PaymentHandler.pay(updatedOrderData, currentPaymentType);
|
||||
return; // 提前返回,避免重复执行支付
|
||||
@@ -437,7 +437,7 @@ const OrderConfirm = () => {
|
||||
quantity,
|
||||
address.id,
|
||||
{
|
||||
comments: goods.name,
|
||||
comments: '网宿软件',
|
||||
deliveryType: 0,
|
||||
buyerRemarks: orderRemark,
|
||||
// 🔧 确保 couponId 是正确的数字类型,且不传递 undefined
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {useEffect, useState} from "react";
|
||||
import {Cell, CellGroup, Image, Space, Button} from '@nutui/nutui-react-taro'
|
||||
import {Cell, CellGroup, Image, Space, Button, Dialog} from '@nutui/nutui-react-taro'
|
||||
import Taro from '@tarojs/taro'
|
||||
import {View} from '@tarojs/components'
|
||||
import {ShopOrder} from "@/api/shop/shopOrder/model";
|
||||
@@ -13,6 +13,7 @@ import './index.scss'
|
||||
const OrderDetail = () => {
|
||||
const [order, setOrder] = useState<ShopOrder | null>(null);
|
||||
const [orderGoodsList, setOrderGoodsList] = useState<ShopOrderGoods[]>([]);
|
||||
const [confirmReceiveDialogVisible, setConfirmReceiveDialogVisible] = useState(false)
|
||||
const router = Taro.getCurrentInstance().router;
|
||||
const orderId = router?.params?.orderId;
|
||||
|
||||
@@ -40,6 +41,52 @@ const OrderDetail = () => {
|
||||
}
|
||||
};
|
||||
|
||||
// 申请退款
|
||||
const handleApplyRefund = async () => {
|
||||
if (order) {
|
||||
try {
|
||||
// 更新订单状态为"退款申请中"
|
||||
await updateShopOrder({
|
||||
orderId: order.orderId,
|
||||
orderStatus: 4 // 退款申请中
|
||||
});
|
||||
|
||||
// 更新本地状态
|
||||
setOrder(prev => prev ? {...prev, orderStatus: 4} : null);
|
||||
|
||||
// 跳转到退款申请页面
|
||||
Taro.navigateTo({
|
||||
url: `/user/order/refund/index?orderId=${order.orderId}&orderNo=${order.orderNo}`
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('更新订单状态失败:', error);
|
||||
Taro.showToast({
|
||||
title: '操作失败,请重试',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 确认收货(客户)
|
||||
const handleConfirmReceive = async () => {
|
||||
if (!order?.orderId) return
|
||||
try {
|
||||
setConfirmReceiveDialogVisible(false)
|
||||
await updateShopOrder({
|
||||
orderId: order.orderId,
|
||||
deliveryStatus: order.deliveryStatus, // 10未发货 20已发货 30部分发货
|
||||
orderStatus: 1 // 已完成
|
||||
})
|
||||
Taro.showToast({title: '确认收货成功', icon: 'success'})
|
||||
setOrder(prev => (prev ? {...prev, orderStatus: 1} : prev))
|
||||
} catch (e) {
|
||||
console.error('确认收货失败:', e)
|
||||
Taro.showToast({title: '确认收货失败', icon: 'none'})
|
||||
setConfirmReceiveDialogVisible(true)
|
||||
}
|
||||
}
|
||||
|
||||
const getOrderStatusText = (order: ShopOrder) => {
|
||||
// 优先检查订单状态
|
||||
if (order.orderStatus === 2) return '已取消';
|
||||
@@ -54,8 +101,15 @@ const OrderDetail = () => {
|
||||
|
||||
// 已付款后检查发货状态
|
||||
if (order.deliveryStatus === 10) return '待发货';
|
||||
if (order.deliveryStatus === 20) return '待收货';
|
||||
if (order.deliveryStatus === 30) return '已收货';
|
||||
if (order.deliveryStatus === 20) {
|
||||
// 若订单有配送员,则以配送员送达时间作为“可确认收货”的依据
|
||||
if (order.riderId) {
|
||||
if (order.sendEndTime && order.orderStatus !== 1) return '待确认收货';
|
||||
return '配送中';
|
||||
}
|
||||
return '待收货';
|
||||
}
|
||||
if (order.deliveryStatus === 30) return '部分发货';
|
||||
|
||||
// 最后检查订单完成状态
|
||||
if (order.orderStatus === 1) return '已完成';
|
||||
@@ -106,6 +160,15 @@ const OrderDetail = () => {
|
||||
return <div>加载中...</div>;
|
||||
}
|
||||
|
||||
const currentUserId = Number(Taro.getStorageSync('UserId'))
|
||||
const isOwner = !!currentUserId && currentUserId === order.userId
|
||||
const canConfirmReceive =
|
||||
isOwner &&
|
||||
order.payStatus &&
|
||||
order.orderStatus !== 1 &&
|
||||
order.deliveryStatus === 20 &&
|
||||
(!order.riderId || !!order.sendEndTime)
|
||||
|
||||
return (
|
||||
<div className={'order-detail-page'}>
|
||||
{/* 支付倒计时显示 - 详情页实时更新 */}
|
||||
@@ -162,12 +225,26 @@ const OrderDetail = () => {
|
||||
<Space>
|
||||
{!order.payStatus && <Button onClick={() => console.log('取消订单')}>取消订单</Button>}
|
||||
{!order.payStatus && <Button type="primary" onClick={() => console.log('立即支付')}>立即支付</Button>}
|
||||
{order.orderStatus === 1 && <Button onClick={() => console.log('申请退款')}>申请退款</Button>}
|
||||
{order.deliveryStatus === 20 &&
|
||||
<Button type="primary" onClick={() => console.log('确认收货')}>确认收货</Button>}
|
||||
{order.orderStatus === 1 && <Button onClick={handleApplyRefund}>申请退款</Button>}
|
||||
{canConfirmReceive && (
|
||||
<Button type="primary" onClick={() => setConfirmReceiveDialogVisible(true)}>
|
||||
确认收货
|
||||
</Button>
|
||||
)}
|
||||
</Space>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<Dialog
|
||||
title="确认收货"
|
||||
visible={confirmReceiveDialogVisible}
|
||||
confirmText="确认收货"
|
||||
cancelText="我再想想"
|
||||
onConfirm={handleConfirmReceive}
|
||||
onCancel={() => setConfirmReceiveDialogVisible(false)}
|
||||
>
|
||||
确定已经收到商品了吗?确认后订单将完成。
|
||||
</Dialog>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user