Compare commits
10 Commits
dd3d6b43a4
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| bc8d882104 | |||
| 253613e077 | |||
| 4c6391053d | |||
| 078b422db0 | |||
| 1d73521e17 | |||
| 7db4da5081 | |||
| f808c22a22 | |||
| ea5419dfb5 | |||
| aa879f0062 | |||
| 5270cab7e9 |
@@ -2,7 +2,8 @@
|
|||||||
export const ENV_CONFIG = {
|
export const ENV_CONFIG = {
|
||||||
// 开发环境
|
// 开发环境
|
||||||
development: {
|
development: {
|
||||||
API_BASE_URL: 'https://cms-api.websoft.top/api',
|
API_BASE_URL: 'http://127.0.0.1:9200/api',
|
||||||
|
// API_BASE_URL: 'https://cms-api.websoft.top/api',
|
||||||
APP_NAME: '开发环境',
|
APP_NAME: '开发环境',
|
||||||
DEBUG: 'true',
|
DEBUG: 'true',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -117,7 +117,7 @@ export const STATUS_COLOR_MAP = {
|
|||||||
// 申请售后
|
// 申请售后
|
||||||
export const applyAfterSale = async (params: AfterSaleApplyParams): Promise<AfterSaleDetailResponse> => {
|
export const applyAfterSale = async (params: AfterSaleApplyParams): Promise<AfterSaleDetailResponse> => {
|
||||||
try {
|
try {
|
||||||
const response = await request({
|
const response = await request<AfterSaleDetailResponse>({
|
||||||
url: '/api/after-sale/apply',
|
url: '/api/after-sale/apply',
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
data: params
|
data: params
|
||||||
@@ -136,7 +136,7 @@ export const getAfterSaleDetail = async (params: {
|
|||||||
afterSaleId?: string
|
afterSaleId?: string
|
||||||
}): Promise<AfterSaleDetailResponse> => {
|
}): Promise<AfterSaleDetailResponse> => {
|
||||||
try {
|
try {
|
||||||
const response = await request({
|
const response = await request<AfterSaleDetailResponse>({
|
||||||
url: '/api/after-sale/detail',
|
url: '/api/after-sale/detail',
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
data: params
|
data: params
|
||||||
@@ -154,7 +154,7 @@ export const getAfterSaleDetail = async (params: {
|
|||||||
// 查询售后列表
|
// 查询售后列表
|
||||||
export const getAfterSaleList = async (params: AfterSaleListParams): Promise<AfterSaleListResponse> => {
|
export const getAfterSaleList = async (params: AfterSaleListParams): Promise<AfterSaleListResponse> => {
|
||||||
try {
|
try {
|
||||||
const response = await request({
|
const response = await request<AfterSaleListResponse>({
|
||||||
url: '/api/after-sale/list',
|
url: '/api/after-sale/list',
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
data: params
|
data: params
|
||||||
@@ -170,7 +170,7 @@ export const getAfterSaleList = async (params: AfterSaleListParams): Promise<Aft
|
|||||||
// 撤销售后申请
|
// 撤销售后申请
|
||||||
export const cancelAfterSale = async (afterSaleId: string): Promise<{ success: boolean; message?: string }> => {
|
export const cancelAfterSale = async (afterSaleId: string): Promise<{ success: boolean; message?: string }> => {
|
||||||
try {
|
try {
|
||||||
const response = await request({
|
const response = await request<{ success: boolean; message?: string }>({
|
||||||
url: '/api/after-sale/cancel',
|
url: '/api/after-sale/cancel',
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
data: { afterSaleId }
|
data: { afterSaleId }
|
||||||
@@ -312,11 +312,9 @@ export const getAfterSaleSteps = (type: AfterSaleType, status: AfterSaleStatus)
|
|||||||
|
|
||||||
// 根据类型调整步骤
|
// 根据类型调整步骤
|
||||||
if (type === 'return' || type === 'exchange') {
|
if (type === 'return' || type === 'exchange') {
|
||||||
baseSteps.splice(2, 1,
|
baseSteps.splice(2, 0, { title: '等待收货', description: '等待用户寄回商品' })
|
||||||
{ title: '寄回商品', description: '请将商品寄回指定地址' },
|
baseSteps.splice(3, 0, { title: '确认收货', description: '商家确认收到退回商品' })
|
||||||
{ title: '处理中', description: '收到商品,正在处理' }
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return baseSteps
|
return baseSteps
|
||||||
}
|
}
|
||||||
@@ -207,7 +207,7 @@ export async function getByIds(params?: CmsArticleParam) {
|
|||||||
/**
|
/**
|
||||||
* 根据code查询文章
|
* 根据code查询文章
|
||||||
*/
|
*/
|
||||||
export async function getCmsArticleByCode(code: string) {
|
export async function getByCode(code: string) {
|
||||||
const res = await request.get<ApiResult<CmsArticle>>(
|
const res = await request.get<ApiResult<CmsArticle>>(
|
||||||
'/cms/cms-article/getByCode/' + code
|
'/cms/cms-article/getByCode/' + code
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -123,3 +123,16 @@ export async function getNavigationByPath(params: CmsNavigationParam) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据code查询导航
|
||||||
|
*/
|
||||||
|
export async function getByCode(code: string) {
|
||||||
|
const res = await request.get<ApiResult<CmsNavigation>>(
|
||||||
|
'/cms/cms-navigation/getByCode/' + code
|
||||||
|
);
|
||||||
|
if (res.code === 0 && res.data) {
|
||||||
|
return res.data;
|
||||||
|
}
|
||||||
|
return Promise.reject(new Error(res.message));
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -57,4 +57,7 @@ export interface Config {
|
|||||||
sysLogo?: string;
|
sysLogo?: string;
|
||||||
vipText?: string;
|
vipText?: string;
|
||||||
vipComments?: string;
|
vipComments?: string;
|
||||||
|
deliveryText?: string;
|
||||||
|
guaranteeText?: string;
|
||||||
|
openComments?: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -87,6 +87,7 @@ export default {
|
|||||||
'goodsDetail/index',
|
'goodsDetail/index',
|
||||||
'orderConfirm/index',
|
'orderConfirm/index',
|
||||||
'orderConfirmCart/index',
|
'orderConfirmCart/index',
|
||||||
|
'comments/index',
|
||||||
'search/index']
|
'search/index']
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
23
src/app.ts
23
src/app.ts
@@ -7,9 +7,11 @@ import {loginByOpenId} from "@/api/layout";
|
|||||||
import {TenantId} from "@/config/app";
|
import {TenantId} from "@/config/app";
|
||||||
import {saveStorageByLoginUser} from "@/utils/server";
|
import {saveStorageByLoginUser} from "@/utils/server";
|
||||||
import {parseInviteParams, saveInviteParams, trackInviteSource, handleInviteRelation} from "@/utils/invite";
|
import {parseInviteParams, saveInviteParams, trackInviteSource, handleInviteRelation} from "@/utils/invite";
|
||||||
import {configWebsiteField} from "@/api/cms/cmsWebsiteField";
|
import { useConfig } from "@/hooks/useConfig"; // 引入新的自定义Hook
|
||||||
|
|
||||||
function App(props: { children: any; }) {
|
function App(props: { children: any; }) {
|
||||||
|
const { refetch: handleTheme } = useConfig(); // 使用新的Hook
|
||||||
|
|
||||||
const reload = () => {
|
const reload = () => {
|
||||||
Taro.login({
|
Taro.login({
|
||||||
success: (res) => {
|
success: (res) => {
|
||||||
@@ -38,7 +40,7 @@ function App(props: { children: any; }) {
|
|||||||
};
|
};
|
||||||
// 可以使用所有的 React Hooks
|
// 可以使用所有的 React Hooks
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// 设置主题
|
// 设置主题 (现在由useConfig Hook处理)
|
||||||
handleTheme()
|
handleTheme()
|
||||||
// Taro.getSetting:获取用户的当前设置。返回值中只会出现小程序已经向用户请求过的权限。
|
// Taro.getSetting:获取用户的当前设置。返回值中只会出现小程序已经向用户请求过的权限。
|
||||||
Taro.getSetting({
|
Taro.getSetting({
|
||||||
@@ -60,7 +62,7 @@ function App(props: { children: any; }) {
|
|||||||
// 处理启动参数
|
// 处理启动参数
|
||||||
const handleLaunchOptions = (options: any) => {
|
const handleLaunchOptions = (options: any) => {
|
||||||
try {
|
try {
|
||||||
console.log('=== 小程序启动参数处理开始 ===')
|
console.log('=== 小程 序启动参数处理开始 ===')
|
||||||
console.log('完整启动参数:', JSON.stringify(options, null, 2))
|
console.log('完整启动参数:', JSON.stringify(options, null, 2))
|
||||||
|
|
||||||
// 解析邀请参数
|
// 解析邀请参数
|
||||||
@@ -76,11 +78,7 @@ function App(props: { children: any; }) {
|
|||||||
|
|
||||||
// 显示邀请提示
|
// 显示邀请提示
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
Taro.showToast({
|
console.log(`检测到邀请信息 ID:${inviteParams.inviter}`)
|
||||||
title: `检测到邀请信息 ID:${inviteParams.inviter}`,
|
|
||||||
icon: 'success',
|
|
||||||
duration: 3000
|
|
||||||
})
|
|
||||||
}, 1000)
|
}, 1000)
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@@ -93,15 +91,6 @@ function App(props: { children: any; }) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleTheme = () => {
|
|
||||||
configWebsiteField().then(data => {
|
|
||||||
// 设置主题
|
|
||||||
if(data.theme && !Taro.getStorageSync('user_theme')){
|
|
||||||
Taro.setStorageSync('user_theme', data.theme)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// 对应 onHide
|
// 对应 onHide
|
||||||
useDidHide(() => {
|
useDidHide(() => {
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
import {Image, Cell} from '@nutui/nutui-react-taro'
|
import {Image, Cell} from '@nutui/nutui-react-taro'
|
||||||
import Taro from '@tarojs/taro'
|
import Taro from '@tarojs/taro'
|
||||||
|
import {CmsArticle} from "@/api/cms/cmsArticle/model";
|
||||||
|
|
||||||
const ArticleList = (props: any) => {
|
const ArticleList = (props: any) => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className={'px-3'}>
|
<div className={'px-3'}>
|
||||||
{props.data.map((item, index) => {
|
{props.data.map((item: CmsArticle, index: number) => {
|
||||||
return (
|
return (
|
||||||
<Cell
|
<Cell
|
||||||
title={item.title}
|
title={item.title}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ function Detail() {
|
|||||||
const reload = async () => {
|
const reload = async () => {
|
||||||
const item = await getCmsArticle(Number(params.id))
|
const item = await getCmsArticle(Number(params.id))
|
||||||
|
|
||||||
if (item) {
|
if (item && item.content) {
|
||||||
item.content = wxParse(item.content)
|
item.content = wxParse(item.content)
|
||||||
setItem(item)
|
setItem(item)
|
||||||
Taro.setNavigationBarTitle({
|
Taro.setNavigationBarTitle({
|
||||||
@@ -43,6 +43,10 @@ function Detail() {
|
|||||||
<div className={'p-4 font-bold text-lg'}>{item?.title}</div>
|
<div className={'p-4 font-bold text-lg'}>{item?.title}</div>
|
||||||
<div className={'text-gray-400 text-sm px-4 '}>{item?.createTime}</div>
|
<div className={'text-gray-400 text-sm px-4 '}>{item?.createTime}</div>
|
||||||
<View className={'content p-4'}>
|
<View className={'content p-4'}>
|
||||||
|
{/*如果有视频就显示视频 视频沾满宽度*/}
|
||||||
|
{item?.video && <View className={'w-full'}>
|
||||||
|
<video src={item?.video} controls={true} width={'100%'}></video>
|
||||||
|
</View>}
|
||||||
<RichText nodes={item?.content}/>
|
<RichText nodes={item?.content}/>
|
||||||
</View>
|
</View>
|
||||||
<Line height={44}/>
|
<Line height={44}/>
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ const SimpleQRCodeModal: React.FC<SimpleQRCodeModalProps> = ({
|
|||||||
{qrContent ? (
|
{qrContent ? (
|
||||||
<View className={'flex flex-col justify-center'}>
|
<View className={'flex flex-col justify-center'}>
|
||||||
<img
|
<img
|
||||||
src={`https://cms-api.websoft.top/api/qr-code/create-encrypted-qr-image?size=300x300&expireMinutes=60&businessType=gift&data=${encodeURIComponent(qrContent)}`}
|
src={`https://mp-api.websoft.top/api/qr-code/create-encrypted-qr-image?size=300x300&expireMinutes=60&businessType=gift&data=${encodeURIComponent(qrContent)}`}
|
||||||
alt="二维码"
|
alt="二维码"
|
||||||
style={{width: '200px', height: '200px'}}
|
style={{width: '200px', height: '200px'}}
|
||||||
className="mx-auto"
|
className="mx-auto"
|
||||||
|
|||||||
50
src/hooks/useConfig.ts
Normal file
50
src/hooks/useConfig.ts
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
import Taro from '@tarojs/taro';
|
||||||
|
import { configWebsiteField } from '@/api/cms/cmsWebsiteField';
|
||||||
|
import { Config } from '@/api/cms/cmsWebsiteField/model';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自定义Hook用于获取和管理网站配置数据
|
||||||
|
* @returns {Object} 包含配置数据和加载状态的对象
|
||||||
|
*/
|
||||||
|
export const useConfig = () => {
|
||||||
|
const [config, setConfig] = useState<Config | null>(null);
|
||||||
|
const [loading, setLoading] = useState<boolean>(true);
|
||||||
|
const [error, setError] = useState<Error | null>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const fetchConfig = async () => {
|
||||||
|
try {
|
||||||
|
setLoading(true);
|
||||||
|
const data = await configWebsiteField();
|
||||||
|
setConfig(data);
|
||||||
|
Taro.setStorageSync('config', data);
|
||||||
|
|
||||||
|
// 设置主题
|
||||||
|
if (data.theme && !Taro.getStorageSync('user_theme')) {
|
||||||
|
Taro.setStorageSync('user_theme', data.theme);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
setError(err instanceof Error ? err : new Error('获取配置失败'));
|
||||||
|
console.error('获取网站配置失败:', err);
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
fetchConfig();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return { config, loading, error, refetch: () => {
|
||||||
|
setLoading(true);
|
||||||
|
setError(null);
|
||||||
|
configWebsiteField().then(data => {
|
||||||
|
setConfig(data);
|
||||||
|
Taro.setStorageSync('config', data);
|
||||||
|
setLoading(false);
|
||||||
|
}).catch(err => {
|
||||||
|
setError(err instanceof Error ? err : new Error('获取配置失败'));
|
||||||
|
setLoading(false);
|
||||||
|
});
|
||||||
|
}};
|
||||||
|
};
|
||||||
@@ -14,6 +14,10 @@ const MyPage = () => {
|
|||||||
const [hotToday, setHotToday] = useState<CmsAd>()
|
const [hotToday, setHotToday] = useState<CmsAd>()
|
||||||
const [item, setItem] = useState<CmsArticle>()
|
const [item, setItem] = useState<CmsArticle>()
|
||||||
const [loading, setLoading] = useState(true)
|
const [loading, setLoading] = useState(true)
|
||||||
|
// const [disableSwiper, setDisableSwiper] = useState(false)
|
||||||
|
|
||||||
|
// 用于记录触摸开始位置
|
||||||
|
// const touchStartRef = useRef({x: 0, y: 0})
|
||||||
|
|
||||||
// 加载数据
|
// 加载数据
|
||||||
const loadData = async () => {
|
const loadData = async () => {
|
||||||
@@ -46,8 +50,8 @@ const MyPage = () => {
|
|||||||
loadData()
|
loadData()
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
// 轮播图高度,默认200px
|
// 轮播图高度,默认300px
|
||||||
const carouselHeight = carouselData?.height || 200;
|
const carouselHeight = carouselData?.height || 300;
|
||||||
|
|
||||||
// 骨架屏组件
|
// 骨架屏组件
|
||||||
const BannerSkeleton = () => (
|
const BannerSkeleton = () => (
|
||||||
@@ -98,7 +102,10 @@ const MyPage = () => {
|
|||||||
return (
|
return (
|
||||||
<View className="flex p-2 justify-between" style={{height: `${carouselHeight}px`}}>
|
<View className="flex p-2 justify-between" style={{height: `${carouselHeight}px`}}>
|
||||||
{/* 左侧轮播图区域 */}
|
{/* 左侧轮播图区域 */}
|
||||||
<View style={{width: '50%', height: '100%'}}>
|
<View
|
||||||
|
style={{width: '50%', height: '100%'}}
|
||||||
|
className="banner-swiper-container"
|
||||||
|
>
|
||||||
<Swiper
|
<Swiper
|
||||||
defaultValue={0}
|
defaultValue={0}
|
||||||
height={carouselHeight}
|
height={carouselHeight}
|
||||||
@@ -107,11 +114,14 @@ const MyPage = () => {
|
|||||||
duration={3000}
|
duration={3000}
|
||||||
style={{
|
style={{
|
||||||
height: `${carouselHeight}px`,
|
height: `${carouselHeight}px`,
|
||||||
touchAction: 'pan-y'
|
touchAction: 'pan-y' // 关键修改:允许垂直滑动
|
||||||
}}
|
}}
|
||||||
|
disableTouch={false}
|
||||||
|
direction="horizontal"
|
||||||
|
className="custom-swiper"
|
||||||
>
|
>
|
||||||
{carouselData && carouselData?.imageList?.map((img, index) => (
|
{carouselData && carouselData?.imageList?.map((img, index) => (
|
||||||
<Swiper.Item key={index}>
|
<Swiper.Item key={index} style={{ touchAction: 'pan-x pan-y' }}>
|
||||||
<Image
|
<Image
|
||||||
width="100%"
|
width="100%"
|
||||||
height="100%"
|
height="100%"
|
||||||
@@ -121,7 +131,8 @@ const MyPage = () => {
|
|||||||
lazyLoad={false}
|
lazyLoad={false}
|
||||||
style={{
|
style={{
|
||||||
height: `${carouselHeight}px`,
|
height: `${carouselHeight}px`,
|
||||||
borderRadius: '4px'
|
borderRadius: '4px',
|
||||||
|
touchAction: 'manipulation' // 关键修改:优化触摸操作
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Swiper.Item>
|
</Swiper.Item>
|
||||||
@@ -139,7 +150,7 @@ const MyPage = () => {
|
|||||||
}}>
|
}}>
|
||||||
{
|
{
|
||||||
hotToday?.imageList?.map(item => (
|
hotToday?.imageList?.map(item => (
|
||||||
<View className={'item flex flex-col mr-4'}>
|
<View className={'item flex flex-col mr-1'} key={item.url}>
|
||||||
<Image
|
<Image
|
||||||
width={70}
|
width={70}
|
||||||
height={70}
|
height={70}
|
||||||
@@ -181,4 +192,3 @@ const MyPage = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default MyPage
|
export default MyPage
|
||||||
|
|
||||||
|
|||||||
@@ -124,6 +124,8 @@ const BestSellers = (props: {onStickyChange?: (isSticky: boolean) => void}) => {
|
|||||||
<View className={'flex text-red-500 text-xl items-baseline'}>
|
<View className={'flex text-red-500 text-xl items-baseline'}>
|
||||||
<Text className={'text-xs'}>¥</Text>
|
<Text className={'text-xs'}>¥</Text>
|
||||||
<Text className={'font-bold text-2xl'}>{item.price}</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>
|
||||||
<View className={'buy-btn'}>
|
<View className={'buy-btn'}>
|
||||||
<View className={'cart-icon items-center hidden'}>
|
<View className={'cart-icon items-center hidden'}>
|
||||||
|
|||||||
@@ -14,3 +14,10 @@
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
z-index: 0;
|
z-index: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 吸顶状态下的样式 */
|
||||||
|
.nutui-sticky--fixed {
|
||||||
|
.header-bg {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import {useEffect, useState} from "react";
|
import {useEffect, useState} from "react";
|
||||||
import Taro from '@tarojs/taro';
|
import Taro from '@tarojs/taro';
|
||||||
import {Button, Space} from '@nutui/nutui-react-taro'
|
import {Button, Space, Sticky} from '@nutui/nutui-react-taro'
|
||||||
import {TriangleDown} from '@nutui/icons-react-taro'
|
import {TriangleDown} from '@nutui/icons-react-taro'
|
||||||
import {Avatar, NavBar} from '@nutui/nutui-react-taro'
|
import {Avatar, NavBar} from '@nutui/nutui-react-taro'
|
||||||
import {getUserInfo, getWxOpenId} from "@/api/layout";
|
import {getUserInfo, getWxOpenId} from "@/api/layout";
|
||||||
@@ -13,7 +13,7 @@ import {View,Text} from '@tarojs/components'
|
|||||||
import MySearch from "./MySearch";
|
import MySearch from "./MySearch";
|
||||||
import './Header.scss';
|
import './Header.scss';
|
||||||
|
|
||||||
const Header = (props: any) => {
|
const Header = (_: any) => {
|
||||||
// 使用新的useShopInfo Hook
|
// 使用新的useShopInfo Hook
|
||||||
const {
|
const {
|
||||||
getWebsiteName,
|
getWebsiteName,
|
||||||
@@ -22,6 +22,7 @@ const Header = (props: any) => {
|
|||||||
|
|
||||||
const [IsLogin, setIsLogin] = useState<boolean>(true)
|
const [IsLogin, setIsLogin] = useState<boolean>(true)
|
||||||
const [statusBarHeight, setStatusBarHeight] = useState<number>()
|
const [statusBarHeight, setStatusBarHeight] = useState<number>()
|
||||||
|
const [stickyStatus, setStickyStatus] = useState<boolean>(false)
|
||||||
|
|
||||||
const reload = async () => {
|
const reload = async () => {
|
||||||
Taro.getSystemInfo({
|
Taro.getSystemInfo({
|
||||||
@@ -166,53 +167,76 @@ const Header = (props: any) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 处理粘性布局状态变化
|
||||||
|
const onStickyChange = (isSticky: boolean) => {
|
||||||
|
setStickyStatus(isSticky)
|
||||||
|
console.log('Header 粘性状态:', isSticky ? '已固定' : '取消固定')
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取小程序系统信息
|
||||||
|
// const getSystemInfo = () => {
|
||||||
|
// const systemInfo = Taro.getSystemInfoSync()
|
||||||
|
// // 状态栏高度 + 导航栏高度 (一般为44px)
|
||||||
|
// return (systemInfo.statusBarHeight || 0) + 44
|
||||||
|
// }
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
reload().then()
|
reload().then()
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<View className={'fixed top-0 header-bg'} style={{
|
<Sticky
|
||||||
height: !props.stickyStatus ? '180px' : `${(statusBarHeight || 0) + 44}px`,
|
threshold={0}
|
||||||
paddingBottom: !props.stickyStatus ? '12px' : '0px'
|
onChange={onStickyChange}
|
||||||
}}>
|
|
||||||
{/* 只在非吸顶状态下显示搜索框 */}
|
|
||||||
{!props.stickyStatus && <MySearch statusBarHeight={statusBarHeight} />}
|
|
||||||
</View>
|
|
||||||
<NavBar
|
|
||||||
style={{
|
style={{
|
||||||
marginTop: `${statusBarHeight}px`,
|
zIndex: 1000,
|
||||||
marginBottom: '0px',
|
backgroundColor: stickyStatus ? '#03605c' : 'transparent',
|
||||||
backgroundColor: 'transparent'
|
transition: 'background-color 0.3s ease',
|
||||||
}}
|
}}
|
||||||
onBackClick={() => {
|
>
|
||||||
}}
|
<View className={'header-bg'} style={{
|
||||||
left={
|
height: !stickyStatus ? '180px' : `${(statusBarHeight || 0) + 44}px`,
|
||||||
!IsLogin ? (
|
paddingBottom: !stickyStatus ? '12px' : '0px'
|
||||||
<View style={{display: 'flex', alignItems: 'center'}}>
|
}}>
|
||||||
<Button style={{color: '#ffffff'}} open-type="getPhoneNumber" onGetPhoneNumber={handleGetPhoneNumber}>
|
{/* 只在非吸顶状态下显示搜索框 */}
|
||||||
<Space>
|
{!stickyStatus && <MySearch statusBarHeight={statusBarHeight} />}
|
||||||
<Avatar
|
</View>
|
||||||
size="22"
|
<NavBar
|
||||||
src={getWebsiteLogo()}
|
style={{
|
||||||
/>
|
marginTop: `${statusBarHeight}px`,
|
||||||
<Text style={{color: '#ffffff'}}>{getWebsiteName()}</Text>
|
marginBottom: '0px',
|
||||||
<TriangleDown size={9} className={'text-white'}/>
|
backgroundColor: 'transparent'
|
||||||
</Space>
|
}}
|
||||||
</Button>
|
onBackClick={() => {
|
||||||
</View>
|
}}
|
||||||
) : (
|
left={
|
||||||
<View style={{display: 'flex', alignItems: 'center', gap: '8px'}}>
|
!IsLogin ? (
|
||||||
<Avatar
|
<View style={{display: 'flex', alignItems: 'center'}}>
|
||||||
size="22"
|
<Button style={{color: '#ffffff'}} open-type="getPhoneNumber" onGetPhoneNumber={handleGetPhoneNumber}>
|
||||||
src={getWebsiteLogo()}
|
<Space>
|
||||||
/>
|
<Avatar
|
||||||
<Text className={'text-white'}>{getWebsiteName()}</Text>
|
size="22"
|
||||||
<TriangleDown className={'text-white'} size={9}/>
|
src={getWebsiteLogo()}
|
||||||
</View>
|
/>
|
||||||
)}>
|
<Text style={{color: '#ffffff'}}>{getWebsiteName()}</Text>
|
||||||
{/*<QRLoginButton />*/}
|
<TriangleDown size={9} className={'text-white'}/>
|
||||||
</NavBar>
|
</Space>
|
||||||
|
</Button>
|
||||||
|
</View>
|
||||||
|
) : (
|
||||||
|
<View style={{display: 'flex', alignItems: 'center', gap: '8px'}}>
|
||||||
|
<Avatar
|
||||||
|
size="22"
|
||||||
|
src={getWebsiteLogo()}
|
||||||
|
/>
|
||||||
|
<Text className={'text-white'}>{getWebsiteName()}</Text>
|
||||||
|
<TriangleDown className={'text-white'} size={9}/>
|
||||||
|
</View>
|
||||||
|
)}>
|
||||||
|
{/*<QRLoginButton />*/}
|
||||||
|
</NavBar>
|
||||||
|
</Sticky>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,3 +18,59 @@ page {
|
|||||||
height: 70px;
|
height: 70px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 轮播图容器样式,确保支持两种滑动操作 */
|
||||||
|
.banner-swiper-container {
|
||||||
|
touch-action: pan-y !important; /* 允许垂直滑动 */
|
||||||
|
|
||||||
|
.nut-swiper {
|
||||||
|
touch-action: pan-y !important; /* 允许垂直滑动 */
|
||||||
|
|
||||||
|
.nut-swiper-item {
|
||||||
|
touch-action: pan-x pan-y !important; /* 允许水平和垂直滑动 */
|
||||||
|
|
||||||
|
image {
|
||||||
|
pointer-events: auto; /* 确保图片点击事件正常 */
|
||||||
|
touch-action: manipulation; /* 优化触摸操作 */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 为Swiper容器添加特殊处理 */
|
||||||
|
.nut-swiper--horizontal {
|
||||||
|
touch-action: pan-y !important; /* 允许垂直滑动 */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 吸顶状态下的样式 */
|
||||||
|
.nutui-sticky--fixed {
|
||||||
|
.header-bg {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 为Swiper添加更精确的触摸控制 */
|
||||||
|
.nut-swiper {
|
||||||
|
touch-action: pan-y !important;
|
||||||
|
|
||||||
|
.nut-swiper-inner {
|
||||||
|
touch-action: pan-x pan-y !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 自定义Swiper样式 */
|
||||||
|
.custom-swiper {
|
||||||
|
touch-action: pan-y !important;
|
||||||
|
|
||||||
|
.nut-swiper-item {
|
||||||
|
touch-action: pan-x pan-y !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 确保Swiper内部元素不会阻止页面滚动 */
|
||||||
|
.banner-swiper-container,
|
||||||
|
.custom-swiper,
|
||||||
|
.nut-swiper,
|
||||||
|
.nut-swiper-item {
|
||||||
|
-webkit-overflow-scrolling: touch; /* iOS平台启用硬件加速滚动 */
|
||||||
|
}
|
||||||
@@ -4,19 +4,16 @@ import Taro from '@tarojs/taro';
|
|||||||
import {useShareAppMessage} from "@tarojs/taro"
|
import {useShareAppMessage} from "@tarojs/taro"
|
||||||
import {useEffect, useState} from "react";
|
import {useEffect, useState} from "react";
|
||||||
import {getShopInfo} from "@/api/layout";
|
import {getShopInfo} from "@/api/layout";
|
||||||
import {Sticky} from '@nutui/nutui-react-taro'
|
|
||||||
import Menu from "./Menu";
|
import Menu from "./Menu";
|
||||||
import Banner from "./Banner";
|
import Banner from "./Banner";
|
||||||
import {checkAndHandleInviteRelation, hasPendingInvite} from "@/utils/invite";
|
import {checkAndHandleInviteRelation, hasPendingInvite} from "@/utils/invite";
|
||||||
import './index.scss'
|
import './index.scss'
|
||||||
|
|
||||||
// import GoodsList from "./GoodsList";
|
|
||||||
|
|
||||||
function Home() {
|
function Home() {
|
||||||
// 吸顶状态
|
// 吸顶状态
|
||||||
// const [stickyStatus, setStickyStatus] = useState<boolean>(false)
|
// const [stickyStatus, setStickyStatus] = useState<boolean>(false)
|
||||||
// Tabs粘性状态
|
// Tabs粘性状态
|
||||||
const [tabsStickyStatus, setTabsStickyStatus] = useState<boolean>(false)
|
const [_, setTabsStickyStatus] = useState<boolean>(false)
|
||||||
|
|
||||||
useShareAppMessage(() => {
|
useShareAppMessage(() => {
|
||||||
// 获取当前用户ID,用于生成邀请链接
|
// 获取当前用户ID,用于生成邀请链接
|
||||||
@@ -157,20 +154,13 @@ function Home() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{/* Header区域 - 根据Tabs粘性状态决定是否固定 */}
|
{/* Header区域 - 现在由Header组件内部处理吸顶逻辑 */}
|
||||||
{tabsStickyStatus ? (
|
<Header />
|
||||||
<Sticky threshold={0}>
|
|
||||||
<Header stickyStatus={tabsStickyStatus}/>
|
|
||||||
</Sticky>
|
|
||||||
) : (
|
|
||||||
<Header stickyStatus={tabsStickyStatus}/>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<div className={'flex flex-col mt-12'}>
|
<div className={'flex flex-col mt-12'}>
|
||||||
<Menu/>
|
<Menu/>
|
||||||
<Banner/>
|
<Banner/>
|
||||||
<BestSellers onStickyChange={handleTabsStickyChange}/>
|
<BestSellers onStickyChange={handleTabsStickyChange}/>
|
||||||
{/*<GoodsList/>*/}
|
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
// 订单页面样式
|
|
||||||
.order-page {
|
|
||||||
// 订单相关样式
|
|
||||||
}
|
|
||||||
@@ -3,25 +3,16 @@ import navTo from "@/utils/common";
|
|||||||
import {View, Text} from '@tarojs/components'
|
import {View, Text} from '@tarojs/components'
|
||||||
import {ArrowRight, Reward, Setting} from '@nutui/icons-react-taro'
|
import {ArrowRight, Reward, Setting} from '@nutui/icons-react-taro'
|
||||||
import {useUser} from '@/hooks/useUser'
|
import {useUser} from '@/hooks/useUser'
|
||||||
import {useEffect, useState} from "react";
|
|
||||||
import {useDealerUser} from "@/hooks/useDealerUser";
|
import {useDealerUser} from "@/hooks/useDealerUser";
|
||||||
import {useThemeStyles} from "@/hooks/useTheme";
|
import {useThemeStyles} from "@/hooks/useTheme";
|
||||||
import {configWebsiteField} from "@/api/cms/cmsWebsiteField";
|
import { useConfig } from "@/hooks/useConfig"; // 使用新的自定义Hook
|
||||||
import {Config} from "@/api/cms/cmsWebsiteField/model";
|
|
||||||
|
|
||||||
const IsDealer = () => {
|
const IsDealer = () => {
|
||||||
const themeStyles = useThemeStyles();
|
const themeStyles = useThemeStyles();
|
||||||
const [config, setConfig] = useState<Config>()
|
const { config } = useConfig(); // 使用新的Hook
|
||||||
const {isSuperAdmin} = useUser();
|
const {isSuperAdmin} = useUser();
|
||||||
const {dealerUser} = useDealerUser()
|
const {dealerUser} = useDealerUser()
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
configWebsiteField().then(data => {
|
|
||||||
console.log(data)
|
|
||||||
setConfig(data)
|
|
||||||
})
|
|
||||||
}, [])
|
|
||||||
console.log(dealerUser,'dealerUserdealerUserdealerUserdealerUserdealerUser')
|
|
||||||
/**
|
/**
|
||||||
* 管理中心
|
* 管理中心
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import {Avatar, Tag, Space} from '@nutui/nutui-react-taro'
|
import {Avatar, Tag, Space, Button} from '@nutui/nutui-react-taro'
|
||||||
import {View, Text} from '@tarojs/components'
|
import {View, Text} from '@tarojs/components'
|
||||||
import {getUserInfo, getWxOpenId} from '@/api/layout';
|
import {getUserInfo, getWxOpenId} from '@/api/layout';
|
||||||
import Taro from '@tarojs/taro';
|
import Taro from '@tarojs/taro';
|
||||||
@@ -179,22 +179,35 @@ const UserCard = forwardRef<any, any>((_, ref) => {
|
|||||||
className={'user-card w-full flex flex-col justify-around rounded-xl'}
|
className={'user-card w-full flex flex-col justify-around rounded-xl'}
|
||||||
>
|
>
|
||||||
<View className={'user-card-header flex w-full justify-between items-center pt-4'}>
|
<View className={'user-card-header flex w-full justify-between items-center pt-4'}>
|
||||||
<View className={'flex items-center mx-4'} onClick={handleGetPhoneNumber}>
|
<View className={'flex items-center mx-4'}>
|
||||||
<Avatar size="large"
|
{IsLogin && (
|
||||||
|
<View style={{color: '#ffffff', height: 'auto'}} onClick={() => navTo(`/user/profile/profile`)}>
|
||||||
|
<View className={'flex items-center gap-2'}>
|
||||||
|
<Avatar
|
||||||
|
size={'large'}
|
||||||
src={userInfo?.avatar || ''}
|
src={userInfo?.avatar || ''}
|
||||||
shape="round"/>
|
/>
|
||||||
<View className={'user-info flex flex-col px-2'}>
|
<View className={'flex flex-col'}>
|
||||||
<View className={'py-1 text-white font-bold'}>{getDisplayName()}</View>
|
<Text style={{color: '#ffffff'}}>{getDisplayName() || '点击登录'}</Text>
|
||||||
{IsLogin ? (
|
<View><Tag type="success">{getRoleName()}</Tag></View>
|
||||||
<View className={'grade text-xs py-1'}>
|
</View>
|
||||||
<Tag type="success" round>
|
|
||||||
<Text className={'p-1'}>
|
|
||||||
{getRoleName()}
|
|
||||||
</Text>
|
|
||||||
</Tag>
|
|
||||||
</View>
|
</View>
|
||||||
) : ''}
|
</View>
|
||||||
</View>
|
)}
|
||||||
|
{!IsLogin && (
|
||||||
|
<Button style={{color: '#ffffff', height: 'auto'}} open-type="getPhoneNumber"
|
||||||
|
onGetPhoneNumber={handleGetPhoneNumber}>
|
||||||
|
<View className={'flex items-center gap-2'}>
|
||||||
|
<Avatar
|
||||||
|
size={'large'}
|
||||||
|
src={userInfo?.avatar || ''}
|
||||||
|
/>
|
||||||
|
<View className={'flex flex-col'}>
|
||||||
|
<Text style={{color: '#ffffff'}}>{getDisplayName() || '点击登录'}</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
</View>
|
</View>
|
||||||
<Space style={{
|
<Space style={{
|
||||||
marginTop: '30px',
|
marginTop: '30px',
|
||||||
|
|||||||
@@ -1,102 +0,0 @@
|
|||||||
import {Cell} from '@nutui/nutui-react-taro'
|
|
||||||
import navTo from "@/utils/common";
|
|
||||||
import {View, Text} from '@tarojs/components'
|
|
||||||
import {ArrowRight, Reward, Setting} from '@nutui/icons-react-taro'
|
|
||||||
import {useUser} from '@/hooks/useUser'
|
|
||||||
import {useEffect, useState} from "react";
|
|
||||||
import {useDealerUser} from "@/hooks/useDealerUser";
|
|
||||||
import {configWebsiteField} from "@/api/cms/cmsWebsiteField";
|
|
||||||
import {Config} from "@/api/cms/cmsWebsiteField/model";
|
|
||||||
|
|
||||||
const UserCell = () => {
|
|
||||||
const {isSuperAdmin} = useUser();
|
|
||||||
const {dealerUser} = useDealerUser()
|
|
||||||
const [config, setConfig] = useState<Config>()
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
configWebsiteField().then(data => {
|
|
||||||
console.log(data)
|
|
||||||
setConfig(data)
|
|
||||||
})
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 管理中心
|
|
||||||
*/
|
|
||||||
if (isSuperAdmin()) {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<View className={'px-4'}>
|
|
||||||
<Cell
|
|
||||||
className="nutui-cell-clickable"
|
|
||||||
style={{
|
|
||||||
backgroundImage: 'linear-gradient(to right bottom, #e53e3e, #c53030)',
|
|
||||||
}}
|
|
||||||
title={
|
|
||||||
<View style={{display: 'inline-flex', alignItems: 'center'}}>
|
|
||||||
<Setting className={'text-white '} size={16}/>
|
|
||||||
<Text style={{fontSize: '16px'}} className={'pl-3 text-white font-medium'}>管理中心</Text>
|
|
||||||
</View>
|
|
||||||
}
|
|
||||||
extra={<ArrowRight color="#ffffff" size={18}/>}
|
|
||||||
onClick={() => navTo('/admin/index', true)}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 分销中心
|
|
||||||
*/
|
|
||||||
if (dealerUser) {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<View className={'px-4'}>
|
|
||||||
<Cell
|
|
||||||
className="nutui-cell-clickable"
|
|
||||||
style={{
|
|
||||||
backgroundImage: 'linear-gradient(to right bottom, #54a799, #177b73)',
|
|
||||||
}}
|
|
||||||
title={
|
|
||||||
<View style={{display: 'inline-flex', alignItems: 'center'}}>
|
|
||||||
<Reward className={'text-orange-100 '} size={16}/>
|
|
||||||
<Text style={{fontSize: '16px'}}
|
|
||||||
className={'pl-3 text-orange-100 font-medium'}>分销中心</Text>
|
|
||||||
{/*<Text className={'text-white opacity-80 pl-3'}>门店核销</Text>*/}
|
|
||||||
</View>
|
|
||||||
}
|
|
||||||
extra={<ArrowRight color="#cccccc" size={18}/>}
|
|
||||||
onClick={() => navTo('/dealer/index', true)}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 普通用户
|
|
||||||
*/
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<View className={'px-4'}>
|
|
||||||
<Cell
|
|
||||||
className="nutui-cell-clickable"
|
|
||||||
style={{
|
|
||||||
backgroundImage: 'linear-gradient(to right bottom, #54a799, #177b73)',
|
|
||||||
}}
|
|
||||||
title={
|
|
||||||
<View style={{display: 'inline-flex', alignItems: 'center'}}>
|
|
||||||
<Reward className={'text-orange-100 '} size={16}/>
|
|
||||||
<Text style={{fontSize: '16px'}} className={'pl-3 text-orange-100 font-medium'}>{config?.vipText}开通VIP</Text>
|
|
||||||
<Text className={'text-white opacity-80 pl-3'}>{config?.vipComments}享优惠</Text>
|
|
||||||
</View>
|
|
||||||
}
|
|
||||||
extra={<ArrowRight color="#cccccc" size={18}/>}
|
|
||||||
onClick={() => navTo('/dealer/apply/add', true)}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
export default UserCell
|
|
||||||
@@ -1,277 +0,0 @@
|
|||||||
import {Avatar, Tag, Space, Button} from '@nutui/nutui-react-taro'
|
|
||||||
import {View, Text, Image} from '@tarojs/components'
|
|
||||||
import {getUserInfo, getWxOpenId} from '@/api/layout';
|
|
||||||
import Taro from '@tarojs/taro';
|
|
||||||
import {useEffect, useState, forwardRef, useImperativeHandle} from "react";
|
|
||||||
import {User} from "@/api/system/user/model";
|
|
||||||
import navTo from "@/utils/common";
|
|
||||||
import {TenantId} from "@/config/app";
|
|
||||||
import {useUser} from "@/hooks/useUser";
|
|
||||||
import {useUserData} from "@/hooks/useUserData";
|
|
||||||
import {getStoredInviteParams} from "@/utils/invite";
|
|
||||||
import UnifiedQRButton from "@/components/UnifiedQRButton";
|
|
||||||
|
|
||||||
const UserCard = forwardRef<any, any>((_, ref) => {
|
|
||||||
const {data, refresh} = useUserData()
|
|
||||||
const {getDisplayName, getRoleName} = useUser();
|
|
||||||
const [IsLogin, setIsLogin] = useState<boolean>(false)
|
|
||||||
const [userInfo, setUserInfo] = useState<User>()
|
|
||||||
|
|
||||||
// 下拉刷新
|
|
||||||
const handleRefresh = async () => {
|
|
||||||
await refresh()
|
|
||||||
Taro.showToast({
|
|
||||||
title: '刷新成功',
|
|
||||||
icon: 'success'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// 暴露方法给父组件
|
|
||||||
useImperativeHandle(ref, () => ({
|
|
||||||
handleRefresh
|
|
||||||
}))
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
// Taro.getSetting:获取用户的当前设置。返回值中只会出现小程序已经向用户请求过的权限。
|
|
||||||
Taro.getSetting({
|
|
||||||
success: (res) => {
|
|
||||||
if (res.authSetting['scope.userInfo']) {
|
|
||||||
// 用户已经授权过,可以直接获取用户信息
|
|
||||||
console.log('用户已经授权过,可以直接获取用户信息')
|
|
||||||
reload();
|
|
||||||
} else {
|
|
||||||
// 用户未授权,需要弹出授权窗口
|
|
||||||
console.log('用户未授权,需要弹出授权窗口')
|
|
||||||
showAuthModal();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const reload = () => {
|
|
||||||
Taro.getUserInfo({
|
|
||||||
success: (res) => {
|
|
||||||
const avatar = res.userInfo.avatarUrl;
|
|
||||||
setUserInfo({
|
|
||||||
avatar,
|
|
||||||
nickname: res.userInfo.nickName,
|
|
||||||
sexName: res.userInfo.gender == 1 ? '男' : '女'
|
|
||||||
})
|
|
||||||
getUserInfo().then((data) => {
|
|
||||||
if (data) {
|
|
||||||
setUserInfo(data)
|
|
||||||
setIsLogin(true);
|
|
||||||
Taro.setStorageSync('UserId', data.userId)
|
|
||||||
|
|
||||||
// 获取openId
|
|
||||||
if (!data.openid) {
|
|
||||||
Taro.login({
|
|
||||||
success: (res) => {
|
|
||||||
getWxOpenId({code: res.code}).then(() => {
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}).catch(() => {
|
|
||||||
console.log('未登录')
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const showAuthModal = () => {
|
|
||||||
Taro.showModal({
|
|
||||||
title: '授权提示',
|
|
||||||
content: '需要获取您的用户信息',
|
|
||||||
confirmText: '去授权',
|
|
||||||
cancelText: '取消',
|
|
||||||
success: (res) => {
|
|
||||||
if (res.confirm) {
|
|
||||||
// 用户点击确认,打开授权设置页面
|
|
||||||
openSetting();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
const openSetting = () => {
|
|
||||||
// Taro.openSetting:调起客户端小程序设置界面,返回用户设置的操作结果。设置界面只会出现小程序已经向用户请求过的权限。
|
|
||||||
Taro.openSetting({
|
|
||||||
success: (res) => {
|
|
||||||
if (res.authSetting['scope.userInfo']) {
|
|
||||||
// 用户授权成功,可以获取用户信息
|
|
||||||
reload();
|
|
||||||
} else {
|
|
||||||
// 用户拒绝授权,提示授权失败
|
|
||||||
Taro.showToast({
|
|
||||||
title: '授权失败',
|
|
||||||
icon: 'none'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/* 获取用户手机号 */
|
|
||||||
const handleGetPhoneNumber = ({detail}: { detail: { code?: string, encryptedData?: string, iv?: string } }) => {
|
|
||||||
const {code, encryptedData, iv} = detail
|
|
||||||
|
|
||||||
// 获取存储的邀请参数
|
|
||||||
const inviteParams = getStoredInviteParams()
|
|
||||||
const refereeId = inviteParams?.inviter ? parseInt(inviteParams.inviter) : 0
|
|
||||||
|
|
||||||
Taro.login({
|
|
||||||
success: function () {
|
|
||||||
if (code) {
|
|
||||||
Taro.request({
|
|
||||||
url: 'https://server.websoft.top/api/wx-login/loginByMpWxPhone',
|
|
||||||
method: 'POST',
|
|
||||||
data: {
|
|
||||||
code,
|
|
||||||
encryptedData,
|
|
||||||
iv,
|
|
||||||
notVerifyPhone: true,
|
|
||||||
refereeId: refereeId, // 使用解析出的推荐人ID
|
|
||||||
sceneType: 'save_referee',
|
|
||||||
tenantId: TenantId
|
|
||||||
},
|
|
||||||
header: {
|
|
||||||
'content-type': 'application/json',
|
|
||||||
TenantId
|
|
||||||
},
|
|
||||||
success: function (res) {
|
|
||||||
if (res.data.code == 1) {
|
|
||||||
Taro.showToast({
|
|
||||||
title: res.data.message,
|
|
||||||
icon: 'error',
|
|
||||||
duration: 2000
|
|
||||||
})
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// 登录成功
|
|
||||||
Taro.setStorageSync('access_token', res.data.data.access_token)
|
|
||||||
Taro.setStorageSync('UserId', res.data.data.user.userId)
|
|
||||||
setUserInfo(res.data.data.user)
|
|
||||||
setIsLogin(true)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
console.log('登录失败!')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<View className={'header-bg pt-20'}>
|
|
||||||
<View className={'p-4'}>
|
|
||||||
{/* 使用相对定位容器,让个人资料图片可以绝对定位在右上角 */}
|
|
||||||
<View className="relative">
|
|
||||||
<View
|
|
||||||
className={'user-card w-full flex flex-col justify-around rounded-xl'}
|
|
||||||
style={{
|
|
||||||
background: 'linear-gradient(to bottom, #ffffff, #ffffff)',
|
|
||||||
height: '170px',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<View className={'user-card-header flex w-full justify-between items-center pt-4'}>
|
|
||||||
<View className={'flex items-center mx-4'}>
|
|
||||||
{
|
|
||||||
IsLogin ? (
|
|
||||||
<Avatar size="large"
|
|
||||||
src={userInfo?.avatar || 'https://oss.wsdns.cn/20250623/62f830b85edb4a7293b8948c25e6f987.jpeg'}
|
|
||||||
shape="round"/>
|
|
||||||
) : (
|
|
||||||
<Button className={'text-black'} open-type="getPhoneNumber" onGetPhoneNumber={handleGetPhoneNumber}>
|
|
||||||
<Avatar size="large"
|
|
||||||
src={userInfo?.avatar || 'https://oss.wsdns.cn/20250623/62f830b85edb4a7293b8948c25e6f987.jpeg'}
|
|
||||||
shape="round"/>
|
|
||||||
</Button>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
<View className={'user-info flex flex-col px-2'}>
|
|
||||||
<View className={'py-1 text-black font-bold'}>{getDisplayName()}</View>
|
|
||||||
{IsLogin ? (
|
|
||||||
<View className={'grade text-xs py-1'}>
|
|
||||||
<Tag type="success" round>
|
|
||||||
<Text className={'p-1'}>
|
|
||||||
{getRoleName()}
|
|
||||||
</Text>
|
|
||||||
</Tag>
|
|
||||||
</View>
|
|
||||||
) : ''}
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
<Space style={{
|
|
||||||
marginTop: '30px',
|
|
||||||
marginRight: '10px'
|
|
||||||
}}>
|
|
||||||
{/*统一扫码入口 - 支持登录和核销*/}
|
|
||||||
<UnifiedQRButton
|
|
||||||
text="扫码"
|
|
||||||
size="small"
|
|
||||||
onSuccess={(result) => {
|
|
||||||
console.log('统一扫码成功:', result);
|
|
||||||
// 根据扫码类型给出不同的提示
|
|
||||||
if (result.type === 'verification') {
|
|
||||||
// 核销成功,可以显示更多信息或跳转到详情页
|
|
||||||
Taro.showModal({
|
|
||||||
title: '核销成功',
|
|
||||||
content: `已成功核销的品类:${result.data.goodsName || '礼品卡'},面值¥${result.data.faceValue}`
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
onError={(error) => {
|
|
||||||
console.error('统一扫码失败:', error);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Space>
|
|
||||||
</View>
|
|
||||||
<View className={'flex justify-around mt-1'}>
|
|
||||||
<View className={'item flex justify-center flex-col items-center'}
|
|
||||||
onClick={() => navTo('/user/wallet/wallet', true)}>
|
|
||||||
<Text className={'text-sm text-gray-500'}>余额</Text>
|
|
||||||
<Text className={'text-xl'}>{data?.balance || '0.00'}</Text>
|
|
||||||
</View>
|
|
||||||
<View className={'item flex justify-center flex-col items-center'}>
|
|
||||||
<Text className={'text-sm text-gray-500'}>积分</Text>
|
|
||||||
<Text className={'text-xl'}>{data?.points || 0}</Text>
|
|
||||||
</View>
|
|
||||||
<View className={'item flex justify-center flex-col items-center'}
|
|
||||||
onClick={() => navTo('/user/coupon/index', true)}>
|
|
||||||
<Text className={'text-sm text-gray-500'}>优惠券</Text>
|
|
||||||
<Text className={'text-xl'}>{data?.coupons || 0}</Text>
|
|
||||||
</View>
|
|
||||||
<View className={'item flex justify-center flex-col items-center'}
|
|
||||||
onClick={() => navTo('/user/gift/index', true)}>
|
|
||||||
<Text className={'text-sm text-gray-500'}>礼品卡</Text>
|
|
||||||
<Text className={'text-xl'}>{data?.giftCards || 0}</Text>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
{/* 个人资料图片,定位在右上角 */}
|
|
||||||
<View
|
|
||||||
className="absolute top-0 right-0 overflow-hidden"
|
|
||||||
style={{
|
|
||||||
borderRadius: "0 0.75rem 0 0"
|
|
||||||
}}
|
|
||||||
onClick={() => navTo('/user/profile/profile', true)}
|
|
||||||
>
|
|
||||||
<Image
|
|
||||||
src="https://oss.wsdns.cn/20250913/7c3de38b377344b89131aba40214f63f.png"
|
|
||||||
style={{
|
|
||||||
width: "200rpx"
|
|
||||||
}}
|
|
||||||
mode="widthFix"
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
export default UserCard;
|
|
||||||
@@ -1,144 +0,0 @@
|
|||||||
import {Cell} from '@nutui/nutui-react-taro'
|
|
||||||
import navTo from "@/utils/common";
|
|
||||||
import Taro from '@tarojs/taro'
|
|
||||||
import {View, Text} from '@tarojs/components'
|
|
||||||
import {ArrowRight, ShieldCheck, LogisticsError, Location, Tips, Ask} from '@nutui/icons-react-taro'
|
|
||||||
import {useUser} from '@/hooks/useUser'
|
|
||||||
|
|
||||||
const UserCell = () => {
|
|
||||||
const {logoutUser, isCertified} = useUser();
|
|
||||||
|
|
||||||
const onLogout = () => {
|
|
||||||
Taro.showModal({
|
|
||||||
title: '提示',
|
|
||||||
content: '确定要退出登录吗?',
|
|
||||||
success: function (res) {
|
|
||||||
if (res.confirm) {
|
|
||||||
// 使用 useUser hook 的 logoutUser 方法
|
|
||||||
logoutUser();
|
|
||||||
Taro.reLaunch({
|
|
||||||
url: '/pages/index/index'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<View className={'px-4'}>
|
|
||||||
|
|
||||||
<Cell.Group divider={true} description={
|
|
||||||
<View style={{display: 'inline-flex', alignItems: 'center'}}>
|
|
||||||
<Text style={{marginTop: '12px'}}>我的服务</Text>
|
|
||||||
</View>
|
|
||||||
}>
|
|
||||||
<Cell
|
|
||||||
className="nutui-cell-clickable"
|
|
||||||
style={{
|
|
||||||
display: 'none'
|
|
||||||
}}
|
|
||||||
title={
|
|
||||||
<View style={{display: 'inline-flex', alignItems: 'center'}}>
|
|
||||||
<LogisticsError size={16}/>
|
|
||||||
<Text className={'pl-3 text-sm'}>我的钱包</Text>
|
|
||||||
</View>
|
|
||||||
}
|
|
||||||
align="center"
|
|
||||||
extra={<ArrowRight color="#cccccc" size={18}/>}
|
|
||||||
onClick={() => {
|
|
||||||
navTo('/user/wallet/index', true)
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<Cell
|
|
||||||
className="nutui-cell-clickable"
|
|
||||||
title={
|
|
||||||
<View style={{display: 'inline-flex', alignItems: 'center'}}>
|
|
||||||
<Location size={16}/>
|
|
||||||
<Text className={'pl-3 text-sm'}>收货地址</Text>
|
|
||||||
</View>
|
|
||||||
}
|
|
||||||
align="center"
|
|
||||||
extra={<ArrowRight color="#cccccc" size={18}/>}
|
|
||||||
onClick={() => {
|
|
||||||
navTo('/user/address/index', true)
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<Cell
|
|
||||||
className="nutui-cell-clickable"
|
|
||||||
title={
|
|
||||||
<View style={{display: 'inline-flex', alignItems: 'center'}}>
|
|
||||||
<ShieldCheck size={16} color={isCertified() ? '#52c41a' : '#666'}/>
|
|
||||||
<Text className={'pl-3 text-sm'}>实名认证</Text>
|
|
||||||
{isCertified() && (
|
|
||||||
<Text className={'pl-2 text-xs text-green-500'}>已认证</Text>
|
|
||||||
)}
|
|
||||||
</View>
|
|
||||||
}
|
|
||||||
align="center"
|
|
||||||
extra={<ArrowRight color="#cccccc" size={18}/>}
|
|
||||||
onClick={() => {
|
|
||||||
navTo('/user/userVerify/index', true)
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<Cell
|
|
||||||
className="nutui-cell-clickable"
|
|
||||||
title={
|
|
||||||
<View style={{display: 'inline-flex', alignItems: 'center'}}>
|
|
||||||
<Ask size={16}/>
|
|
||||||
<Text className={'pl-3 text-sm'}>常见问题</Text>
|
|
||||||
</View>
|
|
||||||
}
|
|
||||||
align="center"
|
|
||||||
extra={<ArrowRight color="#cccccc" size={18}/>}
|
|
||||||
onClick={() => {
|
|
||||||
navTo('/user/help/index')
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<Cell
|
|
||||||
className="nutui-cell-clickable"
|
|
||||||
title={
|
|
||||||
<View style={{display: 'inline-flex', alignItems: 'center'}}>
|
|
||||||
<Tips size={16}/>
|
|
||||||
<Text className={'pl-3 text-sm'}>关于我们</Text>
|
|
||||||
</View>
|
|
||||||
}
|
|
||||||
align="center"
|
|
||||||
extra={<ArrowRight color="#cccccc" size={18}/>}
|
|
||||||
onClick={() => {
|
|
||||||
navTo('/user/about/index')
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Cell.Group>
|
|
||||||
<Cell.Group divider={true} description={
|
|
||||||
<View style={{display: 'inline-flex', alignItems: 'center'}}>
|
|
||||||
<Text style={{marginTop: '12px'}}>账号管理</Text>
|
|
||||||
</View>
|
|
||||||
}>
|
|
||||||
<Cell
|
|
||||||
className="nutui-cell-clickable"
|
|
||||||
title="账号安全"
|
|
||||||
align="center"
|
|
||||||
extra={<ArrowRight color="#cccccc" size={18}/>}
|
|
||||||
onClick={() => navTo('/user/profile/profile', true)}
|
|
||||||
/>
|
|
||||||
<Cell
|
|
||||||
className="nutui-cell-clickable"
|
|
||||||
title="切换主题"
|
|
||||||
align="center"
|
|
||||||
extra={<ArrowRight color="#cccccc" size={18}/>}
|
|
||||||
onClick={() => navTo('/user/theme/index', true)}
|
|
||||||
/>
|
|
||||||
<Cell
|
|
||||||
className="nutui-cell-clickable"
|
|
||||||
title="退出登录"
|
|
||||||
align="center"
|
|
||||||
extra={<ArrowRight color="#cccccc" size={18}/>}
|
|
||||||
onClick={onLogout}
|
|
||||||
/>
|
|
||||||
</Cell.Group>
|
|
||||||
</View>
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
export default UserCell
|
|
||||||
@@ -1,102 +0,0 @@
|
|||||||
import {loginBySms} from "@/api/passport/login";
|
|
||||||
import {useState} from "react";
|
|
||||||
import Taro from '@tarojs/taro'
|
|
||||||
import {Popup} from '@nutui/nutui-react-taro'
|
|
||||||
import {UserParam} from "@/api/system/user/model";
|
|
||||||
import {Button} from '@nutui/nutui-react-taro'
|
|
||||||
import {Form, Input} from '@nutui/nutui-react-taro'
|
|
||||||
import {Copyright, Version} from "@/config/app";
|
|
||||||
const UserFooter = () => {
|
|
||||||
const [openLoginByPhone, setOpenLoginByPhone] = useState(false)
|
|
||||||
const [clickNum, setClickNum] = useState<number>(0)
|
|
||||||
const [FormData, setFormData] = useState<UserParam>(
|
|
||||||
{
|
|
||||||
phone: undefined,
|
|
||||||
password: undefined
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
const onLoginByPhone = () => {
|
|
||||||
setFormData({})
|
|
||||||
setClickNum(clickNum + 1);
|
|
||||||
if (clickNum > 10) {
|
|
||||||
setOpenLoginByPhone(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const closeLoginByPhone = () => {
|
|
||||||
setClickNum(0)
|
|
||||||
setOpenLoginByPhone(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 提交表单
|
|
||||||
const submitByPhone = (values: any) => {
|
|
||||||
loginBySms({
|
|
||||||
phone: values.phone,
|
|
||||||
code: values.code
|
|
||||||
}).then(() => {
|
|
||||||
setOpenLoginByPhone(false);
|
|
||||||
setTimeout(() => {
|
|
||||||
Taro.reLaunch({
|
|
||||||
url: '/pages/index/index'
|
|
||||||
})
|
|
||||||
},1000)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<div className={'text-center py-4 w-full text-gray-300'} onClick={onLoginByPhone}>
|
|
||||||
<div className={'text-xs text-gray-400 py-1'}>当前版本:{Version}</div>
|
|
||||||
<div className={'text-xs text-gray-400 py-1'}>Copyright © { new Date().getFullYear() } {Copyright}</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Popup
|
|
||||||
style={{width: '350px', padding: '10px'}}
|
|
||||||
visible={openLoginByPhone}
|
|
||||||
closeOnOverlayClick={false}
|
|
||||||
closeable={true}
|
|
||||||
onClose={closeLoginByPhone}
|
|
||||||
>
|
|
||||||
<Form
|
|
||||||
style={{width: '350px',padding: '10px'}}
|
|
||||||
divider
|
|
||||||
initialValues={FormData}
|
|
||||||
labelPosition="left"
|
|
||||||
onFinish={(values) => submitByPhone(values)}
|
|
||||||
footer={
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
display: 'flex',
|
|
||||||
justifyContent: 'center',
|
|
||||||
width: '100%'
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Button nativeType="submit" block style={{backgroundColor: '#000000',color: '#ffffff'}}>
|
|
||||||
提交
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<Form.Item
|
|
||||||
label={'手机号码'}
|
|
||||||
name="phone"
|
|
||||||
required
|
|
||||||
rules={[{message: '手机号码'}]}
|
|
||||||
>
|
|
||||||
<Input placeholder="请输入手机号码" maxLength={11} type="text"/>
|
|
||||||
</Form.Item>
|
|
||||||
<Form.Item
|
|
||||||
label={'短信验证码'}
|
|
||||||
name="code"
|
|
||||||
required
|
|
||||||
rules={[{message: '短信验证码'}]}
|
|
||||||
>
|
|
||||||
<Input placeholder="请输入短信验证码" maxLength={6} type="text"/>
|
|
||||||
</Form.Item>
|
|
||||||
</Form>
|
|
||||||
</Popup>
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
export default UserFooter
|
|
||||||
@@ -1,145 +0,0 @@
|
|||||||
import {Grid, ConfigProvider} from '@nutui/nutui-react-taro'
|
|
||||||
import navTo from "@/utils/common";
|
|
||||||
import Taro from '@tarojs/taro'
|
|
||||||
import {View, Button} from '@tarojs/components'
|
|
||||||
import {
|
|
||||||
ShieldCheck,
|
|
||||||
Location,
|
|
||||||
Tips,
|
|
||||||
Ask,
|
|
||||||
// Dongdong,
|
|
||||||
People,
|
|
||||||
// AfterSaleService,
|
|
||||||
Logout,
|
|
||||||
ShoppingAdd,
|
|
||||||
Service
|
|
||||||
} from '@nutui/icons-react-taro'
|
|
||||||
import {useUser} from "@/hooks/useUser";
|
|
||||||
|
|
||||||
const UserCell = () => {
|
|
||||||
const {logoutUser} = useUser();
|
|
||||||
|
|
||||||
const onLogout = () => {
|
|
||||||
Taro.showModal({
|
|
||||||
title: '提示',
|
|
||||||
content: '确定要退出登录吗?',
|
|
||||||
success: function (res) {
|
|
||||||
if (res.confirm) {
|
|
||||||
// 使用 useUser hook 的 logoutUser 方法
|
|
||||||
logoutUser();
|
|
||||||
Taro.reLaunch({
|
|
||||||
url: '/pages/index/index'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<View className="bg-white mx-4 mt-4 rounded-xl">
|
|
||||||
<View className="font-semibold text-gray-800 pt-4 pl-4">我的服务</View>
|
|
||||||
<ConfigProvider>
|
|
||||||
<Grid
|
|
||||||
columns={4}
|
|
||||||
className="no-border-grid"
|
|
||||||
style={{
|
|
||||||
'--nutui-grid-border-color': 'transparent',
|
|
||||||
'--nutui-grid-item-border-width': '0px',
|
|
||||||
border: 'none'
|
|
||||||
} as React.CSSProperties}
|
|
||||||
>
|
|
||||||
<Grid.Item text="企业采购" onClick={() => navTo('/user/poster/poster', true)}>
|
|
||||||
<View className="text-center">
|
|
||||||
<View className="w-12 h-12 bg-blue-50 rounded-xl flex items-center justify-center mx-auto mb-2">
|
|
||||||
<ShoppingAdd color="#3b82f6" size="20"/>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
</Grid.Item>
|
|
||||||
|
|
||||||
{/* 修改联系我们为微信客服 */}
|
|
||||||
<Grid.Item text="联系我们">
|
|
||||||
<Button
|
|
||||||
open-type="contact"
|
|
||||||
className="w-full h-full flex flex-col items-center justify-center p-0 bg-transparent"
|
|
||||||
hover-class="none"
|
|
||||||
style={{border: 'none'}}
|
|
||||||
>
|
|
||||||
<View className="w-12 h-12 bg-blue-50 rounded-xl flex items-center justify-center mx-auto mb-2">
|
|
||||||
<Service color="#67C23A" size="20"/>
|
|
||||||
</View>
|
|
||||||
</Button>
|
|
||||||
</Grid.Item>
|
|
||||||
|
|
||||||
<Grid.Item text="收货地址" onClick={() => navTo('/user/address/index', true)}>
|
|
||||||
<View className="text-center">
|
|
||||||
<View className="w-12 h-12 bg-emerald-50 rounded-xl flex items-center justify-center mx-auto mb-2">
|
|
||||||
<Location color="#3b82f6" size="20"/>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
</Grid.Item>
|
|
||||||
|
|
||||||
<Grid.Item text={'实名认证'} onClick={() => navTo('/user/userVerify/index', true)}>
|
|
||||||
<View className="text-center">
|
|
||||||
<View className="w-12 h-12 bg-green-50 rounded-xl flex items-center justify-center mx-auto mb-2">
|
|
||||||
<ShieldCheck color="#10b981" size="20"/>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
</Grid.Item>
|
|
||||||
|
|
||||||
<Grid.Item text={'推广邀请'} onClick={() => navTo('/dealer/team/index', true)}>
|
|
||||||
<View className="text-center">
|
|
||||||
<View className="w-12 h-12 bg-purple-50 rounded-xl flex items-center justify-center mx-auto mb-2">
|
|
||||||
<People color="#8b5cf6" size="20"/>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
</Grid.Item>
|
|
||||||
|
|
||||||
{/*<Grid.Item text={'我的邀请码'} onClick={() => navTo('/dealer/qrcode/index', true)}>*/}
|
|
||||||
{/* <View className="text-center">*/}
|
|
||||||
{/* <View className="w-12 h-12 bg-orange-50 rounded-xl flex items-center justify-center mx-auto mb-2">*/}
|
|
||||||
{/* <Dongdong color="#f59e0b" size="20"/>*/}
|
|
||||||
{/* </View>*/}
|
|
||||||
{/* </View>*/}
|
|
||||||
{/*</Grid.Item>*/}
|
|
||||||
|
|
||||||
{/*<Grid.Item text={'管理中心'} onClick={() => navTo('/admin/index', true)}>*/}
|
|
||||||
{/* <View className="text-center">*/}
|
|
||||||
{/* <View className="w-12 h-12 bg-red-50 rounded-xl flex items-center justify-center mx-auto mb-2">*/}
|
|
||||||
{/* <AfterSaleService className={'text-red-500'} size="20"/>*/}
|
|
||||||
{/* </View>*/}
|
|
||||||
{/* </View>*/}
|
|
||||||
{/*</Grid.Item>*/}
|
|
||||||
|
|
||||||
<Grid.Item text={'常见问题'} onClick={() => navTo('/user/help/index')}>
|
|
||||||
<View className="text-center">
|
|
||||||
<View className="w-12 h-12 bg-cyan-50 rounded-xl flex items-center justify-center mx-auto mb-2">
|
|
||||||
<Ask className={'text-cyan-500'} size="20"/>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
</Grid.Item>
|
|
||||||
|
|
||||||
<Grid.Item text={'关于我们'} onClick={() => navTo('/user/about/index')}>
|
|
||||||
<View className="text-center">
|
|
||||||
<View className="w-12 h-12 bg-amber-50 rounded-xl flex items-center justify-center mx-auto mb-2">
|
|
||||||
<Tips className={'text-amber-500'} size="20"/>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
</Grid.Item>
|
|
||||||
|
|
||||||
<Grid.Item text={'安全退出'} onClick={onLogout}>
|
|
||||||
<View className="text-center">
|
|
||||||
<View className="w-12 h-12 bg-pink-50 rounded-xl flex items-center justify-center mx-auto mb-2">
|
|
||||||
<Logout className={'text-pink-500'} size="20"/>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
</Grid.Item>
|
|
||||||
|
|
||||||
</Grid>
|
|
||||||
</ConfigProvider>
|
|
||||||
</View>
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
export default UserCell
|
|
||||||
|
|
||||||
@@ -1,122 +0,0 @@
|
|||||||
import navTo from "@/utils/common";
|
|
||||||
import {View, Text} from '@tarojs/components';
|
|
||||||
import {Badge} from '@nutui/nutui-react-taro';
|
|
||||||
import {ArrowRight, Wallet, Comment, Transit, Refund, Package} from '@nutui/icons-react-taro';
|
|
||||||
import {useOrderStats} from "@/hooks/useOrderStats";
|
|
||||||
|
|
||||||
function UserOrder() {
|
|
||||||
const { orderStats, refreshOrderStats } = useOrderStats();
|
|
||||||
|
|
||||||
// 处理长按刷新
|
|
||||||
const handleLongPress = () => {
|
|
||||||
refreshOrderStats();
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<View className={'px-4 pb-2'}>
|
|
||||||
<View
|
|
||||||
className={'user-card w-full flex flex-col justify-around rounded-xl shadow-sm'}
|
|
||||||
style={{
|
|
||||||
background: 'linear-gradient(to bottom, #ffffff, #ffffff)', // 这种情况建议使用类名来控制样式(引入外联样式)
|
|
||||||
// margin: '10px auto 0px auto',
|
|
||||||
height: '120px',
|
|
||||||
// paddingBottom: '3px'
|
|
||||||
// borderRadius: '22px 22px 0 0',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<View className={'title-bar flex justify-between pt-2'}>
|
|
||||||
<Text className={'title font-medium px-4'}>我的订单</Text>
|
|
||||||
<View
|
|
||||||
className={'more flex items-center px-2'}
|
|
||||||
onClick={() => navTo('/user/order/order', true)}
|
|
||||||
onLongPress={handleLongPress}
|
|
||||||
>
|
|
||||||
<Text className={'text-xs text-gray-500'}>全部订单</Text>
|
|
||||||
<ArrowRight color="#cccccc" size={12}/>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
<View className={'flex justify-around pb-1 mt-4'}>
|
|
||||||
{/* 待付款 */}
|
|
||||||
{orderStats.pending > 0 ? (
|
|
||||||
<Badge value={orderStats.pending} max={99} fill={'outline'}>
|
|
||||||
<View className={'item flex justify-center flex-col items-center'}>
|
|
||||||
<Wallet size={26} className={'font-normal text-gray-500'}
|
|
||||||
onClick={() => navTo('/user/order/order?statusFilter=0', true)}/>
|
|
||||||
<Text className={'text-sm text-gray-600 py-1'}>待付款</Text>
|
|
||||||
</View>
|
|
||||||
</Badge>
|
|
||||||
) : (
|
|
||||||
<View className={'item flex justify-center flex-col items-center'}
|
|
||||||
onClick={() => navTo('/user/order/order?statusFilter=0', true)}>
|
|
||||||
<Wallet size={26} className={'font-normal text-gray-500'}/>
|
|
||||||
<Text className={'text-sm text-gray-600 py-1'}>待付款</Text>
|
|
||||||
</View>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* 待发货 */}
|
|
||||||
{orderStats.paid > 0 ? (
|
|
||||||
<Badge value={orderStats.paid} max={99} fill={'outline'}>
|
|
||||||
<View className={'item flex justify-center flex-col items-center'}
|
|
||||||
onClick={() => navTo('/user/order/order?statusFilter=1', true)}>
|
|
||||||
<Package size={26} className={'text-gray-500 font-normal'}/>
|
|
||||||
<Text className={'text-sm text-gray-600 py-1'}>待发货</Text>
|
|
||||||
</View>
|
|
||||||
</Badge>
|
|
||||||
) : (
|
|
||||||
<View className={'item flex justify-center flex-col items-center'}
|
|
||||||
onClick={() => navTo('/user/order/order?statusFilter=1', true)}>
|
|
||||||
<Package size={26} className={'text-gray-500 font-normal'}/>
|
|
||||||
<Text className={'text-sm text-gray-600 py-1'}>待发货</Text>
|
|
||||||
</View>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* 待收货 */}
|
|
||||||
{orderStats.shipped > 0 ? (
|
|
||||||
<Badge value={orderStats.shipped} max={99} fill={'outline'}>
|
|
||||||
<View className={'item flex justify-center flex-col items-center'}
|
|
||||||
onClick={() => navTo('/user/order/order?statusFilter=3', true)}>
|
|
||||||
<Transit size={24} className={'text-gray-500 font-normal'}/>
|
|
||||||
<Text className={'text-sm text-gray-600 py-1'}>待收货</Text>
|
|
||||||
</View>
|
|
||||||
</Badge>
|
|
||||||
) : (
|
|
||||||
<View className={'item flex justify-center flex-col items-center'}
|
|
||||||
onClick={() => navTo('/user/order/order?statusFilter=3', true)}>
|
|
||||||
<Transit size={24} className={'text-gray-500 font-normal'}/>
|
|
||||||
<Text className={'text-sm text-gray-600 py-1'}>待收货</Text>
|
|
||||||
</View>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* 已完成 - 不显示badge */}
|
|
||||||
<View className={'item flex justify-center flex-col items-center'}
|
|
||||||
onClick={() => navTo('/user/order/order?statusFilter=5', true)}>
|
|
||||||
<Comment size={24} className={'text-gray-500 font-normal'}/>
|
|
||||||
<Text className={'text-sm text-gray-600 py-1'}>已完成</Text>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
{/* 退货/售后 */}
|
|
||||||
{orderStats.refund > 0 ? (
|
|
||||||
<Badge value={orderStats.refund} max={99} fill={'outline'}>
|
|
||||||
<View className={'item flex justify-center flex-col items-center'}
|
|
||||||
onClick={() => navTo('/user/order/order?statusFilter=6', true)}>
|
|
||||||
<Refund size={26} className={'font-normal text-gray-500'}/>
|
|
||||||
<Text className={'text-sm text-gray-600 py-1'}>退货/售后</Text>
|
|
||||||
</View>
|
|
||||||
</Badge>
|
|
||||||
) : (
|
|
||||||
<View className={'item flex justify-center flex-col items-center'}
|
|
||||||
onClick={() => navTo('/user/order/order?statusFilter=6', true)}>
|
|
||||||
<Refund size={26} className={'font-normal text-gray-500'}/>
|
|
||||||
<Text className={'text-sm text-gray-600 py-1'}>退货/售后</Text>
|
|
||||||
</View>
|
|
||||||
)}
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
</>
|
|
||||||
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default UserOrder;
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
export default definePageConfig({
|
|
||||||
navigationBarTitleText: '我的',
|
|
||||||
navigationStyle: 'custom',
|
|
||||||
navigationBarBackgroundColor: '#e9fff2'
|
|
||||||
})
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
.header-bg{
|
|
||||||
//background: url('https://oss.wsdns.cn/20250621/edb5d4da976b4d97ba185cb7077d2858.jpg') no-repeat top center;
|
|
||||||
background: linear-gradient(to bottom, #03605c, #18ae4f);
|
|
||||||
background-size: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.my-bg{
|
|
||||||
background: url('https://oss.wsdns.cn/20250913/5ae575a50dbb4ccaab086c3679c5e2c3.png') no-repeat top center;
|
|
||||||
}
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
import {useEffect, useRef} from 'react'
|
|
||||||
import {PullToRefresh} from '@nutui/nutui-react-taro'
|
|
||||||
import UserCard from "./components/UserCard";
|
|
||||||
import UserOrder from "./components/UserOrder";
|
|
||||||
import UserFooter from "./components/UserFooter";
|
|
||||||
import {useUserData} from "@/hooks/useUserData";
|
|
||||||
import './user.scss'
|
|
||||||
import IsDealer from "./components/IsDealer";
|
|
||||||
import UserGrid from "@/pages/user/components/UserGrid";
|
|
||||||
|
|
||||||
function User() {
|
|
||||||
|
|
||||||
const { refresh } = useUserData()
|
|
||||||
const userCardRef = useRef<any>()
|
|
||||||
|
|
||||||
// 下拉刷新处理
|
|
||||||
const handleRefresh = async () => {
|
|
||||||
await refresh()
|
|
||||||
// 如果 UserCard 组件有自己的刷新方法,也可以调用
|
|
||||||
if (userCardRef.current?.handleRefresh) {
|
|
||||||
await userCardRef.current.handleRefresh()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<PullToRefresh
|
|
||||||
onRefresh={handleRefresh}
|
|
||||||
headHeight={60}
|
|
||||||
>
|
|
||||||
<div className={'w-full'} style={{
|
|
||||||
background: 'linear-gradient(to bottom, #e9fff2, #f9fafb)'
|
|
||||||
}}>
|
|
||||||
<UserCard ref={userCardRef}/>
|
|
||||||
<UserOrder/>
|
|
||||||
<IsDealer/>
|
|
||||||
<UserGrid/>
|
|
||||||
<UserFooter/>
|
|
||||||
</div>
|
|
||||||
</PullToRefresh>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default User
|
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
import {Image} from '@nutui/nutui-react-taro'
|
import {Image} from '@nutui/nutui-react-taro'
|
||||||
import {Share} from '@nutui/icons-react-taro'
|
import {Share} from '@nutui/icons-react-taro'
|
||||||
|
import {View, Text} from '@tarojs/components'
|
||||||
import Taro from '@tarojs/taro'
|
import Taro from '@tarojs/taro'
|
||||||
import './GoodsList.scss'
|
import './GoodsList.scss'
|
||||||
|
|
||||||
@@ -8,43 +9,45 @@ const GoodsList = (props: any) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className={'py-3'}>
|
<View className={'py-3'}>
|
||||||
<div className={'flex flex-col justify-between items-center rounded-lg px-2'}>
|
<View className={'flex flex-col justify-between items-center rounded-lg px-2'}>
|
||||||
{props.data?.map((item, index) => {
|
{props.data?.map((item: any, index: number) => {
|
||||||
return (
|
return (
|
||||||
<div key={index} className={'flex flex-col rounded-lg bg-white shadow-sm w-full mb-5'}>
|
<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}
|
<Image src={item.image} mode={'aspectFit'} lazyLoad={false}
|
||||||
radius="10px 10px 0 0" height="180"
|
radius="10px 10px 0 0" height="180"
|
||||||
onClick={() => Taro.navigateTo({url: '/shop/goodsDetail/index?id=' + item.goodsId})}/>
|
onClick={() => Taro.navigateTo({url: '/shop/goodsDetail/index?id=' + item.goodsId})}/>
|
||||||
<div className={'flex flex-col p-2 rounded-lg'}>
|
<View className={'flex flex-col p-2 rounded-lg'}>
|
||||||
<div>
|
<View>
|
||||||
<div className={'car-no text-sm'}>{item.name}</div>
|
<View className={'car-no text-sm'}>{item.name}</View>
|
||||||
<div className={'flex justify-between text-xs py-1'}>
|
<View className={'flex justify-between text-xs py-1'}>
|
||||||
<span className={'text-orange-500'}>{item.comments}</span>
|
<Text className={'text-orange-500'}>{item.comments}</Text>
|
||||||
<span className={'text-gray-400'}>已售 {item.sales}</span>
|
<Text className={'text-gray-400'}>已售 {item.sales}</Text>
|
||||||
</div>
|
</View>
|
||||||
<div className={'flex justify-between items-center py-2'}>
|
<View className={'flex justify-between items-center py-2'}>
|
||||||
<div className={'flex text-red-500 text-xl items-baseline'}>
|
<View className={'flex text-red-500 text-xl items-baseline'}>
|
||||||
<span className={'text-xs'}>¥</span>
|
<Text className={'text-xs'}>¥</Text>
|
||||||
<span className={'font-bold text-2xl'}>{item.price}</span>
|
<Text className={'font-bold text-2xl'}>{item.price}</Text>
|
||||||
</div>
|
<Text className={'text-xs px-1'}>会员价</Text>
|
||||||
<div className={'buy-btn'}>
|
<Text className={'text-xs text-gray-400 line-through'}>¥{item.salePrice}</Text>
|
||||||
<div className={'cart-icon'}>
|
</View>
|
||||||
|
<View className={'buy-btn'}>
|
||||||
|
<View className={'cart-icon'}>
|
||||||
<Share size={20} className={'mx-4 mt-2'}
|
<Share size={20} className={'mx-4 mt-2'}
|
||||||
onClick={() => Taro.navigateTo({url: '/shop/goodsDetail/index?id=' + item.goodsId})}/>
|
onClick={() => Taro.navigateTo({url: '/shop/goodsDetail/index?id=' + item.goodsId})}/>
|
||||||
</div>
|
</View>
|
||||||
<div className={'text-white pl-4 pr-5'}
|
<View className={'text-white pl-4 pr-5'}
|
||||||
onClick={() => Taro.navigateTo({url: '/shop/goodsDetail/index?id=' + item.goodsId})}>购买
|
onClick={() => Taro.navigateTo({url: '/shop/goodsDetail/index?id=' + item.goodsId})}>购买
|
||||||
</div>
|
</View>
|
||||||
</div>
|
</View>
|
||||||
</div>
|
</View>
|
||||||
</div>
|
</View>
|
||||||
</div>
|
</View>
|
||||||
</div>
|
</View>
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
</div>
|
</View>
|
||||||
</div>
|
</View>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
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,3 +15,11 @@ rich-text img {
|
|||||||
.no-margin {
|
.no-margin {
|
||||||
margin: 0 !important; /* 使用 !important 来确保覆盖默认样式 */
|
margin: 0 !important; /* 使用 !important 来确保覆盖默认样式 */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 文本截断样式 */
|
||||||
|
.truncate {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
import {useEffect, useState} from "react";
|
import {useEffect, useState} from "react";
|
||||||
import {Image, Divider, Badge} from "@nutui/nutui-react-taro";
|
import {Image, Badge, Popup, CellGroup, Cell} from "@nutui/nutui-react-taro";
|
||||||
import {ArrowLeft, Headphones, Share, Cart} from "@nutui/icons-react-taro";
|
import {ArrowLeft, Headphones, Share, Cart, ArrowRight} from "@nutui/icons-react-taro";
|
||||||
import Taro, {useShareAppMessage} from "@tarojs/taro";
|
import Taro, {useShareAppMessage} from "@tarojs/taro";
|
||||||
import {RichText, View} from '@tarojs/components'
|
import {RichText, View, Text} from '@tarojs/components'
|
||||||
import {ShopGoods} from "@/api/shop/shopGoods/model";
|
import {ShopGoods} from "@/api/shop/shopGoods/model";
|
||||||
import {getShopGoods} from "@/api/shop/shopGoods";
|
import {getShopGoods} from "@/api/shop/shopGoods";
|
||||||
import {listShopGoodsSpec} from "@/api/shop/shopGoodsSpec";
|
import {listShopGoodsSpec} from "@/api/shop/shopGoodsSpec";
|
||||||
@@ -14,21 +14,30 @@ import navTo, {wxParse} from "@/utils/common";
|
|||||||
import SpecSelector from "@/components/SpecSelector";
|
import SpecSelector from "@/components/SpecSelector";
|
||||||
import "./index.scss";
|
import "./index.scss";
|
||||||
import {useCart} from "@/hooks/useCart";
|
import {useCart} from "@/hooks/useCart";
|
||||||
|
import {useConfig} from "@/hooks/useConfig";
|
||||||
|
|
||||||
const GoodsDetail = () => {
|
const GoodsDetail = () => {
|
||||||
|
const [statusBarHeight, setStatusBarHeight] = useState<number>(44);
|
||||||
|
const [windowWidth, setWindowWidth] = useState<number>(390)
|
||||||
const [goods, setGoods] = useState<ShopGoods | null>(null);
|
const [goods, setGoods] = useState<ShopGoods | null>(null);
|
||||||
const [files, setFiles] = useState<any[]>([]);
|
const [files, setFiles] = useState<any[]>([]);
|
||||||
const [specs, setSpecs] = useState<ShopGoodsSpec[]>([]);
|
const [specs, setSpecs] = useState<ShopGoodsSpec[]>([]);
|
||||||
const [skus, setSkus] = useState<ShopGoodsSku[]>([]);
|
const [skus, setSkus] = useState<ShopGoodsSku[]>([]);
|
||||||
const [showSpecSelector, setShowSpecSelector] = useState(false);
|
const [showSpecSelector, setShowSpecSelector] = useState(false);
|
||||||
const [specAction, setSpecAction] = useState<'cart' | 'buy'>('cart');
|
const [specAction, setSpecAction] = useState<'cart' | 'buy'>('cart');
|
||||||
|
const [showBottom, setShowBottom] = useState(false)
|
||||||
|
const [bottomItem, setBottomItem] = useState<any>({
|
||||||
|
title: '',
|
||||||
|
content: ''
|
||||||
|
})
|
||||||
// const [selectedSku, setSelectedSku] = useState<ShopGoodsSku | null>(null);
|
// const [selectedSku, setSelectedSku] = useState<ShopGoodsSku | null>(null);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const router = Taro.getCurrentInstance().router;
|
const router = Taro.getCurrentInstance().router;
|
||||||
const goodsId = router?.params?.id;
|
const goodsId = router?.params?.id;
|
||||||
|
|
||||||
// 使用购物车Hook
|
// 使用购物车Hook
|
||||||
const {cartCount, addToCart} = useCart();
|
const {cartCount, addToCart} = useCart()
|
||||||
|
const {config} = useConfig()
|
||||||
|
|
||||||
// 处理加入购物车
|
// 处理加入购物车
|
||||||
const handleAddToCart = () => {
|
const handleAddToCart = () => {
|
||||||
@@ -117,7 +126,21 @@ const GoodsDetail = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const openBottom = (title: string, content: string) => {
|
||||||
|
setBottomItem({
|
||||||
|
title,
|
||||||
|
content
|
||||||
|
})
|
||||||
|
setShowBottom(true)
|
||||||
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
Taro.getSystemInfo({
|
||||||
|
success: (res) => {
|
||||||
|
setWindowWidth(res.windowWidth)
|
||||||
|
setStatusBarHeight(Number(res.statusBarHeight) + 5)
|
||||||
|
},
|
||||||
|
});
|
||||||
if (goodsId) {
|
if (goodsId) {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
|
|
||||||
@@ -166,7 +189,7 @@ const GoodsDetail = () => {
|
|||||||
return {
|
return {
|
||||||
title: goods?.name || '精选商品',
|
title: goods?.name || '精选商品',
|
||||||
path: `/shop/goodsDetail/index?id=${goodsId}`,
|
path: `/shop/goodsDetail/index?id=${goodsId}`,
|
||||||
imageUrl: goods?.image, // 分享图片
|
imageUrl: goods?.image ? `${goods.image}?x-oss-process=image/resize,w_500,h_400,m_fill` : undefined, // 分享图片,调整为5:4比例
|
||||||
success: function (res: any) {
|
success: function (res: any) {
|
||||||
console.log('分享成功', res);
|
console.log('分享成功', res);
|
||||||
Taro.showToast({
|
Taro.showToast({
|
||||||
@@ -187,12 +210,12 @@ const GoodsDetail = () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (!goods || loading) {
|
if (!goods || loading) {
|
||||||
return <div>加载中...</div>;
|
return <View>加载中...</View>;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={"py-0"}>
|
<View className={"py-0"}>
|
||||||
<div
|
<View
|
||||||
className={
|
className={
|
||||||
"fixed z-10 bg-white flex justify-center items-center font-bold shadow-sm opacity-70"
|
"fixed z-10 bg-white flex justify-center items-center font-bold shadow-sm opacity-70"
|
||||||
}
|
}
|
||||||
@@ -200,36 +223,36 @@ const GoodsDetail = () => {
|
|||||||
borderRadius: "100%",
|
borderRadius: "100%",
|
||||||
width: "32px",
|
width: "32px",
|
||||||
height: "32px",
|
height: "32px",
|
||||||
top: "50px",
|
top: statusBarHeight + 'px',
|
||||||
left: "10px",
|
left: "10px",
|
||||||
}}
|
}}
|
||||||
onClick={() => Taro.navigateBack()}
|
onClick={() => Taro.navigateBack()}
|
||||||
>
|
>
|
||||||
<ArrowLeft size={14}/>
|
<ArrowLeft size={14}/>
|
||||||
</div>
|
</View>
|
||||||
<div className={
|
<View className={
|
||||||
"fixed z-10 bg-white flex justify-center items-center font-bold shadow-sm opacity-90"
|
"fixed z-10 bg-white flex justify-center items-center font-bold shadow-sm opacity-90"
|
||||||
}
|
}
|
||||||
style={{
|
style={{
|
||||||
borderRadius: "100%",
|
borderRadius: "100%",
|
||||||
width: "32px",
|
width: "32px",
|
||||||
height: "32px",
|
height: "32px",
|
||||||
top: "50px",
|
top: statusBarHeight + 'px',
|
||||||
right: "110px",
|
right: "110px",
|
||||||
}}
|
}}
|
||||||
onClick={() => Taro.switchTab({url: `/pages/cart/cart`})}>
|
onClick={() => Taro.switchTab({url: `/pages/cart/cart`})}>
|
||||||
<Badge value={cartCount} top="-2" right="2">
|
<Badge value={cartCount} top="-2" right="2">
|
||||||
<div style={{display: 'flex', alignItems: 'center'}}>
|
<View style={{display: 'flex', alignItems: 'center'}}>
|
||||||
<Cart size={16}/>
|
<Cart size={16}/>
|
||||||
</div>
|
</View>
|
||||||
</Badge>
|
</Badge>
|
||||||
</div>
|
</View>
|
||||||
{
|
{
|
||||||
files.length > 0 && (
|
files.length > 0 && (
|
||||||
<Swiper defaultValue={0} indicator height={'350px'}>
|
<Swiper defaultValue={0} indicator height={windowWidth}>
|
||||||
{files.map((item) => (
|
{files.map((item) => (
|
||||||
<Swiper.Item key={item}>
|
<Swiper.Item key={item}>
|
||||||
<Image width="100%" height={'100%'} src={item.url} mode={'scaleToFill'} lazyLoad={false}/>
|
<Image width={windowWidth} height={windowWidth} src={item.url} mode={'scaleToFill'} lazyLoad={false}/>
|
||||||
</Swiper.Item>
|
</Swiper.Item>
|
||||||
))}
|
))}
|
||||||
</Swiper>
|
</Swiper>
|
||||||
@@ -245,69 +268,118 @@ const GoodsDetail = () => {
|
|||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
<div
|
<View
|
||||||
className={"flex flex-col justify-between items-center rounded-lg px-2"}
|
className={"flex flex-col justify-between items-center"}
|
||||||
>
|
>
|
||||||
<div
|
<View
|
||||||
className={
|
className={
|
||||||
"flex flex-col rounded-lg bg-white shadow-sm w-full mt-2"
|
"flex flex-col bg-white w-full"
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<div className={"flex flex-col p-2 rounded-lg"}>
|
<View className={"flex flex-col p-3 rounded-lg"}>
|
||||||
<>
|
<>
|
||||||
<div className={'flex justify-between'}>
|
<View className={'flex justify-between'}>
|
||||||
<div className={'flex text-red-500 text-xl items-baseline'}>
|
<View className={'flex text-red-500 text-xl items-baseline'}>
|
||||||
<span className={'text-xs'}>¥</span>
|
<Text className={'text-xs'}>¥</Text>
|
||||||
<span className={'font-bold text-2xl'}>{goods.price}</span>
|
<Text className={'font-bold text-2xl'}>{goods.price}</Text>
|
||||||
</div>
|
<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>
|
<span className={"text-gray-400 text-xs"}>已售 {goods.sales}</span>
|
||||||
</div>
|
</View>
|
||||||
<div className={'flex justify-between items-center'}>
|
<View className={'flex justify-between items-center'}>
|
||||||
<div className={'goods-info'}>
|
<View className={'goods-info'}>
|
||||||
<div className={"car-no text-lg"}>
|
<View className={"car-no text-lg"}>
|
||||||
{goods.name}
|
{goods.name}
|
||||||
</div>
|
</View>
|
||||||
<div className={"flex justify-between text-xs py-1"}>
|
<View className={"flex justify-between text-xs py-1"}>
|
||||||
<span className={"text-orange-500"}>
|
<span className={"text-orange-500"}>
|
||||||
{goods.comments}
|
{goods.comments}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</View>
|
||||||
</div>
|
</View>
|
||||||
<View>
|
<View>
|
||||||
<button
|
<button
|
||||||
className={'flex flex-col justify-center items-center text-gray-500 px-1 gap-1 text-nowrap whitespace-nowrap'}
|
className={'flex flex-col justify-center items-center bg-white text-gray-500 px-1 gap-1 text-nowrap whitespace-nowrap'}
|
||||||
open-type="share"><Share
|
open-type="share">
|
||||||
size={20}/>
|
<Share size={20}/>
|
||||||
<span className={'text-xs'}>分享</span>
|
<span className={'text-xs'}>分享</span>
|
||||||
</button>
|
</button>
|
||||||
</View>
|
</View>
|
||||||
</div>
|
</View>
|
||||||
</>
|
</>
|
||||||
</div>
|
</View>
|
||||||
</div>
|
|
||||||
<div className={"mt-2 py-2"}>
|
|
||||||
<Divider>商品详情</Divider>
|
|
||||||
<RichText nodes={goods.content || '内容详情'}/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{/*底部购买按钮*/}
|
|
||||||
<div className={'fixed bg-white w-full bottom-0 left-0 pt-4 pb-10'}>
|
|
||||||
<View className={'btn-bar flex justify-between items-center'}>
|
|
||||||
<div className={'flex justify-center items-center mx-4'}>
|
|
||||||
<button open-type="contact" className={'flex items-center'}>
|
|
||||||
<Headphones size={18} style={{marginRight: '4px'}}/>咨询
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div className={'buy-btn mx-4'}>
|
|
||||||
<div className={'cart-add px-4 text-sm'}
|
|
||||||
onClick={() => handleAddToCart()}>加入购物车
|
|
||||||
</div>
|
|
||||||
<div className={'cart-buy pl-4 pr-5 text-sm'}
|
|
||||||
onClick={() => handleBuyNow()}>立即购买
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</View>
|
</View>
|
||||||
</div>
|
<View className={'w-full'}>
|
||||||
|
{
|
||||||
|
config?.deliveryText && (
|
||||||
|
<CellGroup>
|
||||||
|
<Cell title={'配送'} extra={
|
||||||
|
<View className="flex items-center">
|
||||||
|
<Text className={'truncate max-w-56 inline-block'}>{config?.deliveryText || '14:30下单,明天配送'}</Text>
|
||||||
|
<ArrowRight color="#cccccc" size={15}/>
|
||||||
|
</View>
|
||||||
|
} onClick={() => openBottom('配送', `${config?.deliveryText}`)}/>
|
||||||
|
<Cell title={'保障'} extra={
|
||||||
|
<View className="flex items-center">
|
||||||
|
<Text className={'truncate max-w-56 inline-block'}>{config?.guaranteeText || '支持7天无理由退货'}</Text>
|
||||||
|
<ArrowRight color="#cccccc" size={15}/>
|
||||||
|
</View>
|
||||||
|
} onClick={() => openBottom('保障', `${config?.guaranteeText}`)}/>
|
||||||
|
</CellGroup>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
{config?.openComments == '1' && (
|
||||||
|
<CellGroup>
|
||||||
|
<Cell title={'用户评价 (0)'} extra={
|
||||||
|
<>
|
||||||
|
<Text>查看全部</Text>
|
||||||
|
<ArrowRight color="#cccccc" size={15}/>
|
||||||
|
</>
|
||||||
|
} onClick={() => navTo(`/shop/comments/index`)}/>
|
||||||
|
<Cell className={'flex h-32 bg-white p-4'}>
|
||||||
|
暂无评价
|
||||||
|
</Cell>
|
||||||
|
</CellGroup>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
<View className={'w-full'}>
|
||||||
|
<RichText nodes={goods.content || '内容详情'}/>
|
||||||
|
<View className={'h-24'}></View>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
{/*底部弹窗*/}
|
||||||
|
<Popup
|
||||||
|
visible={showBottom}
|
||||||
|
position="bottom"
|
||||||
|
onClose={() => {
|
||||||
|
setShowBottom(false)
|
||||||
|
}}
|
||||||
|
lockScroll
|
||||||
|
>
|
||||||
|
<View className={'flex flex-col p-4'}>
|
||||||
|
<Text className={'font-bold text-sm'}>{bottomItem.title}</Text>
|
||||||
|
<Text className={'text-gray-500 my-2'}>{bottomItem.content}</Text>
|
||||||
|
</View>
|
||||||
|
</Popup>
|
||||||
|
{/*底部购买按钮*/}
|
||||||
|
<View className={'fixed bg-white w-full bottom-0 left-0 pt-4 pb-6'}>
|
||||||
|
<View className={'btn-bar flex justify-between items-center'}>
|
||||||
|
<View className={'flex justify-center items-center mx-4'}>
|
||||||
|
<button open-type="contact" className={'flex items-center text-sm py-2'}>
|
||||||
|
<Headphones size={16} style={{marginRight: '4px'}}/>咨询
|
||||||
|
</button>
|
||||||
|
</View>
|
||||||
|
<View className={'buy-btn mx-4'}>
|
||||||
|
<View className={'cart-add px-4 text-sm'}
|
||||||
|
onClick={() => handleAddToCart()}>加入购物车
|
||||||
|
</View>
|
||||||
|
<View className={'cart-buy pl-4 pr-5 text-sm'}
|
||||||
|
onClick={() => handleBuyNow()}>立即购买
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
|
||||||
{/* 规格选择器 */}
|
{/* 规格选择器 */}
|
||||||
{showSpecSelector && (
|
{showSpecSelector && (
|
||||||
@@ -320,7 +392,7 @@ const GoodsDetail = () => {
|
|||||||
onClose={() => setShowSpecSelector(false)}
|
onClose={() => setShowSpecSelector(false)}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</View>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -74,20 +74,20 @@ const OrderConfirm = () => {
|
|||||||
const getGoodsTotal = () => {
|
const getGoodsTotal = () => {
|
||||||
if (!goods) return 0
|
if (!goods) return 0
|
||||||
const price = parseFloat(goods.price || '0')
|
const price = parseFloat(goods.price || '0')
|
||||||
const total = price * quantity
|
// const total = price * quantity
|
||||||
|
|
||||||
// 🔍 详细日志,用于排查数值精度问题
|
// 🔍 详细日志,用于排查数值精度问题
|
||||||
console.log('💵 商品总价计算:', {
|
// console.log('💵 商品总价计算:', {
|
||||||
goodsPrice: goods.price,
|
// goodsPrice: goods.price,
|
||||||
goodsPriceType: typeof goods.price,
|
// goodsPriceType: typeof goods.price,
|
||||||
parsedPrice: price,
|
// parsedPrice: price,
|
||||||
quantity: quantity,
|
// quantity: quantity,
|
||||||
total: total,
|
// total: total,
|
||||||
totalFixed2: total.toFixed(2),
|
// totalFixed2: total.toFixed(2),
|
||||||
totalString: total.toString()
|
// totalString: total.toString()
|
||||||
})
|
// })
|
||||||
|
|
||||||
return total
|
return price * quantity
|
||||||
}
|
}
|
||||||
|
|
||||||
// 计算优惠券折扣
|
// 计算优惠券折扣
|
||||||
@@ -418,9 +418,9 @@ const OrderConfirm = () => {
|
|||||||
couponId: parseInt(String(bestCoupon.id), 10)
|
couponId: parseInt(String(bestCoupon.id), 10)
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
console.log('🎯 使用推荐优惠券的订单数据:', updatedOrderData);
|
console.log('🎯 使用推荐优惠券的订单数据:', updatedOrderData);
|
||||||
|
|
||||||
// 执行支付
|
// 执行支付
|
||||||
await PaymentHandler.pay(updatedOrderData, currentPaymentType);
|
await PaymentHandler.pay(updatedOrderData, currentPaymentType);
|
||||||
return; // 提前返回,避免重复执行支付
|
return; // 提前返回,避免重复执行支付
|
||||||
@@ -437,7 +437,7 @@ const OrderConfirm = () => {
|
|||||||
quantity,
|
quantity,
|
||||||
address.id,
|
address.id,
|
||||||
{
|
{
|
||||||
comments: goods.name,
|
comments: '时里院子市集',
|
||||||
deliveryType: 0,
|
deliveryType: 0,
|
||||||
buyerRemarks: orderRemark,
|
buyerRemarks: orderRemark,
|
||||||
// 🔧 确保 couponId 是正确的数字类型,且不传递 undefined
|
// 🔧 确保 couponId 是正确的数字类型,且不传递 undefined
|
||||||
|
|||||||
@@ -40,6 +40,33 @@ 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 getOrderStatusText = (order: ShopOrder) => {
|
const getOrderStatusText = (order: ShopOrder) => {
|
||||||
// 优先检查订单状态
|
// 优先检查订单状态
|
||||||
if (order.orderStatus === 2) return '已取消';
|
if (order.orderStatus === 2) return '已取消';
|
||||||
@@ -162,7 +189,7 @@ const OrderDetail = () => {
|
|||||||
<Space>
|
<Space>
|
||||||
{!order.payStatus && <Button onClick={() => console.log('取消订单')}>取消订单</Button>}
|
{!order.payStatus && <Button onClick={() => console.log('取消订单')}>取消订单</Button>}
|
||||||
{!order.payStatus && <Button type="primary" onClick={() => console.log('立即支付')}>立即支付</Button>}
|
{!order.payStatus && <Button type="primary" onClick={() => console.log('立即支付')}>立即支付</Button>}
|
||||||
{order.orderStatus === 1 && <Button onClick={() => console.log('申请退款')}>申请退款</Button>}
|
{order.orderStatus === 1 && <Button onClick={handleApplyRefund}>申请退款</Button>}
|
||||||
{order.deliveryStatus === 20 &&
|
{order.deliveryStatus === 20 &&
|
||||||
<Button type="primary" onClick={() => console.log('确认收货')}>确认收货</Button>}
|
<Button type="primary" onClick={() => console.log('确认收货')}>确认收货</Button>}
|
||||||
</Space>
|
</Space>
|
||||||
|
|||||||
@@ -9,15 +9,14 @@ import {listCmsNavigation} from "@/api/cms/cmsNavigation";
|
|||||||
import {View, RichText} from '@tarojs/components'
|
import {View, RichText} from '@tarojs/components'
|
||||||
import {listCmsDesign} from "@/api/cms/cmsDesign";
|
import {listCmsDesign} from "@/api/cms/cmsDesign";
|
||||||
import {CmsDesign} from "@/api/cms/cmsDesign/model";
|
import {CmsDesign} from "@/api/cms/cmsDesign/model";
|
||||||
import {type Config} from "@/api/cms/cmsWebsiteField/model";
|
import { useConfig } from "@/hooks/useConfig"; // 使用新的自定义Hook
|
||||||
import {configWebsiteField} from "@/api/cms/cmsWebsiteField";
|
|
||||||
|
|
||||||
|
|
||||||
const Helper = () => {
|
const Helper = () => {
|
||||||
const [nav, setNav] = useState<CmsNavigation>()
|
const [nav, setNav] = useState<CmsNavigation>()
|
||||||
const [design, setDesign] = useState<CmsDesign>()
|
const [design, setDesign] = useState<CmsDesign>()
|
||||||
const [category, setCategory] = useState<CmsNavigation[]>([])
|
const [category, setCategory] = useState<CmsNavigation[]>([])
|
||||||
const [config, setConfig] = useState<Config>()
|
const { config } = useConfig(); // 使用新的Hook
|
||||||
|
|
||||||
const reload = async () => {
|
const reload = async () => {
|
||||||
const navs = await listCmsNavigation({model: 'page', parentId: 0});
|
const navs = await listCmsNavigation({model: 'page', parentId: 0});
|
||||||
@@ -33,9 +32,7 @@ const Helper = () => {
|
|||||||
category[index].articles = await listCmsArticle({categoryId: item.navigationId});
|
category[index].articles = await listCmsArticle({categoryId: item.navigationId});
|
||||||
})
|
})
|
||||||
setCategory(category)
|
setCategory(category)
|
||||||
// 查询字段
|
// 注意:config 现在通过 useConfig Hook 获取,不再在这里调用 configWebsiteField
|
||||||
const configInfo = await configWebsiteField({})
|
|
||||||
setConfig(configInfo)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -284,7 +284,7 @@ function OrderList(props: OrderListProps) {
|
|||||||
|
|
||||||
await updateShopOrder({
|
await updateShopOrder({
|
||||||
...orderToConfirmReceive,
|
...orderToConfirmReceive,
|
||||||
deliveryStatus: 30, // 已收货
|
deliveryStatus: 20, // 已收货
|
||||||
orderStatus: 1 // 已完成
|
orderStatus: 1 // 已完成
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -316,11 +316,30 @@ function OrderList(props: OrderListProps) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 申请退款 (待发货状态)
|
// 申请退款 (待发货状态)
|
||||||
const applyRefund = (order: ShopOrder) => {
|
const applyRefund = async (order: ShopOrder) => {
|
||||||
// 跳转到退款申请页面
|
try {
|
||||||
Taro.navigateTo({
|
// 更新订单状态为"退款申请中"
|
||||||
url: `/user/order/refund/index?orderId=${order.orderId}&orderNo=${order.orderNo}`
|
await updateShopOrder({
|
||||||
});
|
orderId: order.orderId,
|
||||||
|
orderStatus: 4 // 退款申请中
|
||||||
|
});
|
||||||
|
|
||||||
|
// 更新本地状态
|
||||||
|
setDataSource(prev => prev.map(item =>
|
||||||
|
item.orderId === order.orderId ? {...item, orderStatus: 4} : item
|
||||||
|
));
|
||||||
|
|
||||||
|
// 跳转到退款申请页面
|
||||||
|
Taro.navigateTo({
|
||||||
|
url: `/user/order/refund/index?orderId=${order.orderId}&orderNo=${order.orderNo}`
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error('更新订单状态失败:', error);
|
||||||
|
Taro.showToast({
|
||||||
|
title: '操作失败,请重试',
|
||||||
|
icon: 'none'
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 查看物流 (待收货状态)
|
// 查看物流 (待收货状态)
|
||||||
@@ -738,20 +757,20 @@ function OrderList(props: OrderListProps) {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{/* 待发货状态:显示申请退款 */}
|
{/* 待发货状态:显示申请退款 */}
|
||||||
{/*{item.payStatus && item.deliveryStatus === 10 && item.orderStatus !== 2 && item.orderStatus !== 4 && (*/}
|
{item.payStatus && item.deliveryStatus === 10 && item.orderStatus !== 2 && item.orderStatus !== 4 && (
|
||||||
{/* <Button size={'small'} onClick={(e) => {*/}
|
<Button size={'small'} onClick={(e) => {
|
||||||
{/* e.stopPropagation();*/}
|
e.stopPropagation();
|
||||||
{/* applyRefund(item);*/}
|
applyRefund(item);
|
||||||
{/* }}>申请退款</Button>*/}
|
}}>申请退款</Button>
|
||||||
{/*)}*/}
|
)}
|
||||||
|
|
||||||
{/* 待收货状态:显示查看物流和确认收货 */}
|
{/* 待收货状态:显示查看物流和确认收货 */}
|
||||||
{item.deliveryStatus === 20 && item.orderStatus !== 2 && (
|
{item.deliveryStatus === 20 && item.orderStatus !== 2 && (
|
||||||
<Space>
|
<Space>
|
||||||
{/*<Button size={'small'} onClick={(e) => {*/}
|
<Button size={'small'} onClick={(e) => {
|
||||||
{/* e.stopPropagation();*/}
|
e.stopPropagation();
|
||||||
{/* viewLogistics(item);*/}
|
viewLogistics(item);
|
||||||
{/*}}>查看物流</Button>*/}
|
}}>查看物流</Button>
|
||||||
<Button size={'small'} type="primary" onClick={(e) => {
|
<Button size={'small'} type="primary" onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
confirmReceive(item);
|
confirmReceive(item);
|
||||||
@@ -770,10 +789,10 @@ function OrderList(props: OrderListProps) {
|
|||||||
{/* e.stopPropagation();*/}
|
{/* e.stopPropagation();*/}
|
||||||
{/* evaluateGoods(item);*/}
|
{/* evaluateGoods(item);*/}
|
||||||
{/*}}>评价商品</Button>*/}
|
{/*}}>评价商品</Button>*/}
|
||||||
{/*<Button size={'small'} onClick={(e) => {*/}
|
<Button size={'small'} onClick={(e) => {
|
||||||
{/* e.stopPropagation();*/}
|
e.stopPropagation();
|
||||||
{/* applyRefund(item);*/}
|
applyRefund(item);
|
||||||
{/*}}>申请退款</Button>*/}
|
}}>申请退款</Button>
|
||||||
</Space>
|
</Space>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ import {
|
|||||||
Empty,
|
Empty,
|
||||||
InputNumber
|
InputNumber
|
||||||
} from '@nutui/nutui-react-taro'
|
} from '@nutui/nutui-react-taro'
|
||||||
|
import { applyAfterSale } from '@/api/afterSale'
|
||||||
|
import { updateShopOrder } from '@/api/shop/shopOrder'
|
||||||
import './index.scss'
|
import './index.scss'
|
||||||
|
|
||||||
// 订单商品信息
|
// 订单商品信息
|
||||||
@@ -232,23 +234,55 @@ const RefundPage: React.FC = () => {
|
|||||||
|
|
||||||
setSubmitting(true)
|
setSubmitting(true)
|
||||||
|
|
||||||
// 模拟API调用
|
// 构造请求参数
|
||||||
await new Promise(resolve => setTimeout(resolve, 2000))
|
const params = {
|
||||||
|
orderId: orderId || '',
|
||||||
|
type: 'refund' as const,
|
||||||
|
reason: refundApp.refundReason,
|
||||||
|
description: refundApp.refundDescription,
|
||||||
|
amount: refundApp.refundAmount,
|
||||||
|
contactPhone: refundApp.contactPhone,
|
||||||
|
evidenceImages: refundApp.evidenceImages,
|
||||||
|
goodsItems: refundApp.refundGoods.filter(item => item.refundNum > 0).map(item => ({
|
||||||
|
goodsId: item.goodsId,
|
||||||
|
quantity: item.refundNum
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
Taro.showToast({
|
// 调用API提交退款申请
|
||||||
title: '退款申请提交成功',
|
const result = await applyAfterSale(params)
|
||||||
icon: 'success'
|
|
||||||
})
|
if (result.success) {
|
||||||
|
// 更新订单状态为"退款申请中"
|
||||||
|
if (orderId) {
|
||||||
|
try {
|
||||||
|
await updateShopOrder({
|
||||||
|
orderId: parseInt(orderId),
|
||||||
|
orderStatus: 4 // 退款申请中
|
||||||
|
})
|
||||||
|
} catch (updateError) {
|
||||||
|
console.error('更新订单状态失败:', updateError)
|
||||||
|
// 即使更新订单状态失败,也继续执行后续操作
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 延迟返回上一页
|
Taro.showToast({
|
||||||
setTimeout(() => {
|
title: '退款申请提交成功',
|
||||||
Taro.navigateBack()
|
icon: 'success'
|
||||||
}, 1500)
|
})
|
||||||
|
|
||||||
|
// 延迟返回上一页
|
||||||
|
setTimeout(() => {
|
||||||
|
Taro.navigateBack()
|
||||||
|
}, 1500)
|
||||||
|
} else {
|
||||||
|
throw new Error(result.message || '提交失败')
|
||||||
|
}
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('提交退款申请失败:', error)
|
console.error('提交退款申请失败:', error)
|
||||||
Taro.showToast({
|
Taro.showToast({
|
||||||
title: '提交失败,请重试',
|
title: error instanceof Error ? error.message : '提交失败,请重试',
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
})
|
})
|
||||||
} finally {
|
} finally {
|
||||||
@@ -420,4 +454,4 @@ const RefundPage: React.FC = () => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default RefundPage
|
export default RefundPage
|
||||||
Reference in New Issue
Block a user