feat: add router to detail and ignore css order problem
This commit is contained in:
@@ -66,9 +66,16 @@ export default defineConfig<'webpack5'>(async (merge, { command, mode }) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
miniCssExtractPluginOption: {
|
||||||
|
ignoreOrder: true,
|
||||||
|
// filename: 'css/[name].[hash].css',
|
||||||
|
// chunkFilename: 'css/[name].[chunkhash].css'
|
||||||
|
},
|
||||||
webpackChain(chain) {
|
webpackChain(chain) {
|
||||||
chain.resolve.plugin('tsconfig-paths').use(TsconfigPathsPlugin)
|
chain.resolve.plugin('tsconfig-paths').use(TsconfigPathsPlugin)
|
||||||
}
|
},
|
||||||
|
// @ts-expect-error: Taro 类型定义缺少 mini.hot
|
||||||
|
hot: true,
|
||||||
},
|
},
|
||||||
h5: {
|
h5: {
|
||||||
publicPath: '/',
|
publicPath: '/',
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ export default defineAppConfig({
|
|||||||
'pages/login/terms/index',
|
'pages/login/terms/index',
|
||||||
'pages/publishBall/index',
|
'pages/publishBall/index',
|
||||||
// 'pages/mapDisplay/index',
|
// 'pages/mapDisplay/index',
|
||||||
'pages/index/index',
|
|
||||||
'pages/detail/index',
|
'pages/detail/index',
|
||||||
],
|
],
|
||||||
window: {
|
window: {
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
@font-face {
|
||||||
|
font-family: 'PoetsenOne';
|
||||||
|
src: url('./static/asserts/fonts/PoetsenOne-Regular.ttf') format('truetype');
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Component, ReactNode } from 'react'
|
import { Component, ReactNode } from 'react'
|
||||||
import './app.scss'
|
|
||||||
import './nutui-theme.scss'
|
import './nutui-theme.scss'
|
||||||
|
import './app.scss'
|
||||||
import { useDictionaryStore } from './store/dictionaryStore'
|
import { useDictionaryStore } from './store/dictionaryStore'
|
||||||
|
|
||||||
interface AppProps {
|
interface AppProps {
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ export interface CommonPopupProps {
|
|||||||
zIndex?: number
|
zIndex?: number
|
||||||
children?: React.ReactNode
|
children?: React.ReactNode
|
||||||
className?: string
|
className?: string
|
||||||
|
style?: React.CSSProperties
|
||||||
}
|
}
|
||||||
|
|
||||||
const CommonPopup: React.FC<CommonPopupProps> = ({
|
const CommonPopup: React.FC<CommonPopupProps> = ({
|
||||||
@@ -34,6 +35,7 @@ const CommonPopup: React.FC<CommonPopupProps> = ({
|
|||||||
position = 'bottom',
|
position = 'bottom',
|
||||||
round = true,
|
round = true,
|
||||||
zIndex,
|
zIndex,
|
||||||
|
style,
|
||||||
children
|
children
|
||||||
}) => {
|
}) => {
|
||||||
const handleCancel = () => {
|
const handleCancel = () => {
|
||||||
@@ -52,7 +54,7 @@ const CommonPopup: React.FC<CommonPopupProps> = ({
|
|||||||
closeable={false}
|
closeable={false}
|
||||||
onClose={onClose}
|
onClose={onClose}
|
||||||
className={`${styles['common-popup']} ${className ? className : ''}`}
|
className={`${styles['common-popup']} ${className ? className : ''}`}
|
||||||
style={zIndex ? { zIndex } : undefined}
|
style={{ ...style, zIndex: zIndex ? zIndex : undefined }}
|
||||||
>
|
>
|
||||||
{showHeader && (
|
{showHeader && (
|
||||||
<View className={styles['common-popup__header']}>
|
<View className={styles['common-popup__header']}>
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
import { View, Text, Image } from "@tarojs/components";
|
import { View, Text, Image } from "@tarojs/components";
|
||||||
|
import Taro from '@tarojs/taro'
|
||||||
import img from "../../config/images";
|
import img from "../../config/images";
|
||||||
import { ListCardProps } from "../../../types/list/types";
|
import { ListCardProps } from "../../../types/list/types";
|
||||||
import "./index.scss";
|
import "./index.scss";
|
||||||
// import SkeletonComponent from "../../components/Skeleton";
|
// import SkeletonComponent from "../../components/Skeleton";
|
||||||
|
|
||||||
const ListCard: React.FC<ListCardProps> = ({
|
const ListCard: React.FC<ListCardProps> = ({
|
||||||
|
id,
|
||||||
title,
|
title,
|
||||||
dateTime,
|
dateTime,
|
||||||
location,
|
location,
|
||||||
@@ -20,6 +22,12 @@ const ListCard: React.FC<ListCardProps> = ({
|
|||||||
return <Image src={src} className="image" mode="aspectFill" />;
|
return <Image src={src} className="image" mode="aspectFill" />;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleViewDetail = () => {
|
||||||
|
Taro.navigateTo({
|
||||||
|
url: `/pages/detail/index?id=${id || 1}&from=list&autoShare=0`
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// 根据图片数量决定展示样式
|
// 根据图片数量决定展示样式
|
||||||
const renderImages = () => {
|
const renderImages = () => {
|
||||||
if (images.length === 0) return null;
|
if (images.length === 0) return null;
|
||||||
@@ -60,7 +68,7 @@ const ListCard: React.FC<ListCardProps> = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<View className="list-item">
|
<View className="list-item" onClick={handleViewDetail}>
|
||||||
{/* 左侧内容区域 */}
|
{/* 左侧内容区域 */}
|
||||||
<View className="content">
|
<View className="content">
|
||||||
{/* 标题 */}
|
{/* 标题 */}
|
||||||
|
|||||||
@@ -29,6 +29,7 @@
|
|||||||
color: #fff;
|
color: #fff;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
background: rgba(0, 0, 0, 0.10);
|
||||||
|
|
||||||
.detail-navigator-back {
|
.detail-navigator-back {
|
||||||
border-right: 1px solid #444;
|
border-right: 1px solid #444;
|
||||||
@@ -984,8 +985,48 @@
|
|||||||
border-radius: 16px;
|
border-radius: 16px;
|
||||||
border: 1px solid rgba(0, 0, 0, 0.06);
|
border: 1px solid rgba(0, 0, 0, 0.06);
|
||||||
background: #FFF;
|
background: #FFF;
|
||||||
|
|
||||||
|
&-price {
|
||||||
|
font-family: "PoetsenOne";
|
||||||
|
font-size: 28px;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 24px; /* 114.286% */
|
||||||
|
letter-spacing: -0.56px;
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.share-popup-content {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
padding: 20px 16px env(safe-area-inset-bottom);
|
||||||
|
box-sizing: border-box;
|
||||||
|
// padding-bottom: env(safe-area-inset-bottom);
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-around;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
& > view {
|
||||||
|
width: 100px;
|
||||||
|
height: 64px;
|
||||||
|
border-radius: 12px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
|
||||||
|
& > image {
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > text {
|
||||||
|
color: rgba(0, 0, 0, 0.85);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import React, { useState, useEffect } from 'react'
|
import React, { useState, useEffect, useRef, useImperativeHandle, forwardRef } from 'react'
|
||||||
import { View, Text, Button, Swiper, SwiperItem, Image, Map, ScrollView } from '@tarojs/components'
|
import { View, Text, Button, Swiper, SwiperItem, Image, Map, ScrollView } from '@tarojs/components'
|
||||||
import { Cell, Avatar, Progress, Popover } from '@nutui/nutui-react-taro'
|
import { Cell, Avatar, Progress, Popover } from '@nutui/nutui-react-taro'
|
||||||
import Taro, { useRouter } from '@tarojs/taro'
|
import Taro, { useRouter, useShareAppMessage, useShareTimeline } from '@tarojs/taro'
|
||||||
// 导入API服务
|
// 导入API服务
|
||||||
import DetailService from '../../services/detailService'
|
import DetailService from '../../services/detailService'
|
||||||
import {
|
import {
|
||||||
@@ -9,8 +9,9 @@ import {
|
|||||||
useUserActions
|
useUserActions
|
||||||
} from '../../store/userStore'
|
} from '../../store/userStore'
|
||||||
import img from '../../config/images'
|
import img from '../../config/images'
|
||||||
import { getTextColorOnImage } from '../../utils/processImage'
|
import { getTextColorOnImage } from '../../utils'
|
||||||
import './index.scss'
|
import './index.scss'
|
||||||
|
import { CommonPopup } from '@/components'
|
||||||
|
|
||||||
const images = [
|
const images = [
|
||||||
'http://bimwe.oss-cn-shanghai.aliyuncs.com/front/ball/images/1a35ebbf-2361-44da-b338-7608561d0b31.png',
|
'http://bimwe.oss-cn-shanghai.aliyuncs.com/front/ball/images/1a35ebbf-2361-44da-b338-7608561d0b31.png',
|
||||||
@@ -22,9 +23,70 @@ function insertDotInTags(tags: string[]) {
|
|||||||
return tags.join('-·-').split('-')
|
return tags.join('-·-').split('-')
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleShare() {
|
const SharePopup = forwardRef(({ id, from }: { id: string, from: string }, ref) => {
|
||||||
|
const [visible, setVisible] = useState(false)
|
||||||
|
|
||||||
|
useImperativeHandle(ref, () => ({
|
||||||
|
show: () => {
|
||||||
|
setVisible(true)
|
||||||
}
|
}
|
||||||
|
}))
|
||||||
|
|
||||||
|
function handleShareToWechat() {
|
||||||
|
useShareAppMessage(() => {
|
||||||
|
return {
|
||||||
|
title: '分享',
|
||||||
|
path: `/pages/detail/index?id=${id}&from=${from}`,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleShareToWechatMoments() {
|
||||||
|
useShareTimeline(() => {
|
||||||
|
return {
|
||||||
|
title: '分享',
|
||||||
|
path: `/pages/detail/index?id=${id}&from=${from}`,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleSaveToLocal() {
|
||||||
|
Taro.saveImageToPhotosAlbum({
|
||||||
|
filePath: images[0],
|
||||||
|
success: () => {
|
||||||
|
Taro.showToast({ title: '保存成功', icon: 'success' })
|
||||||
|
},
|
||||||
|
fail: () => {
|
||||||
|
Taro.showToast({ title: '保存失败', icon: 'none' })
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<CommonPopup
|
||||||
|
title="分享"
|
||||||
|
visible={visible}
|
||||||
|
onClose={() => { setVisible(false) }}
|
||||||
|
hideFooter
|
||||||
|
style={{ minHeight: '100px' }}
|
||||||
|
>
|
||||||
|
<View catchMove className='share-popup-content'>
|
||||||
|
<View onClick={handleShareToWechat}>
|
||||||
|
<Image src={img.ICON_DETAIL_SHARE} />
|
||||||
|
<Text>分享到微信</Text>
|
||||||
|
</View>
|
||||||
|
<View onClick={handleShareToWechatMoments}>
|
||||||
|
<Image src={img.ICON_DETAIL_SHARE} />
|
||||||
|
<Text>分享朋友圈</Text>
|
||||||
|
</View>
|
||||||
|
<View onClick={handleSaveToLocal}>
|
||||||
|
<Image src={img.ICON_DETAIL_SHARE} />
|
||||||
|
<Text>保存到本地</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</CommonPopup>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
function Index() {
|
function Index() {
|
||||||
// 使用Zustand store
|
// 使用Zustand store
|
||||||
@@ -35,10 +97,13 @@ function Index() {
|
|||||||
const [colors, setColors] = useState<string []>([])
|
const [colors, setColors] = useState<string []>([])
|
||||||
const [detail, setDetail] = useState<any>(null)
|
const [detail, setDetail] = useState<any>(null)
|
||||||
const { params } = useRouter()
|
const { params } = useRouter()
|
||||||
const { id, share } = params
|
const { id, autoShare, from } = params
|
||||||
|
|
||||||
|
console.log('from', from)
|
||||||
|
|
||||||
// 本地状态管理
|
// 本地状态管理
|
||||||
const [loading, setLoading] = useState(false)
|
const [loading, setLoading] = useState(false)
|
||||||
|
const sharePopupRef = useRef<any>(null)
|
||||||
|
|
||||||
// 页面加载时获取数据
|
// 页面加载时获取数据
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -63,6 +128,20 @@ function Index() {
|
|||||||
setColors(textcolors)
|
setColors(textcolors)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleShare() {
|
||||||
|
sharePopupRef.current.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
const openMap = () => {
|
||||||
|
Taro.openLocation({
|
||||||
|
latitude: detail?.latitude, // 纬度(必填)
|
||||||
|
longitude: detail?.longitude, // 经度(必填)
|
||||||
|
name: '上海体育场', // 位置名(可选)
|
||||||
|
address: '上海市徐汇区肇嘉浜路128号', // 地址详情(可选)
|
||||||
|
scale: 15, // 地图缩放级别(1-28)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
const tags = [{
|
const tags = [{
|
||||||
name: '🕙 急招',
|
name: '🕙 急招',
|
||||||
icon: '',
|
icon: '',
|
||||||
@@ -143,7 +222,7 @@ function Index() {
|
|||||||
{/* custom navbar */}
|
{/* custom navbar */}
|
||||||
<view className="custom-navbar">
|
<view className="custom-navbar">
|
||||||
<View className='detail-navigator'>
|
<View className='detail-navigator'>
|
||||||
<View className='detail-navigator-back'>
|
<View className='detail-navigator-back' onClick={() => { Taro.navigateBack() }}>
|
||||||
<Image className='detail-navigator-back-icon' src={img.ICON_ARROW_LEFT} />
|
<Image className='detail-navigator-back-icon' src={img.ICON_ARROW_LEFT} />
|
||||||
</View>
|
</View>
|
||||||
<View className='detail-navigator-icon'>
|
<View className='detail-navigator-icon'>
|
||||||
@@ -238,7 +317,7 @@ function Index() {
|
|||||||
{/* location message */}
|
{/* location message */}
|
||||||
<View className='location-message-text'>
|
<View className='location-message-text'>
|
||||||
{/* venue name and distance */}
|
{/* venue name and distance */}
|
||||||
<View className='location-message-text-name-distance'>
|
<View className='location-message-text-name-distance' onClick={openMap}>
|
||||||
<Text>上海体育场</Text>
|
<Text>上海体育场</Text>
|
||||||
<Text>·</Text>
|
<Text>·</Text>
|
||||||
<Text>1.2km</Text>
|
<Text>1.2km</Text>
|
||||||
@@ -461,6 +540,8 @@ function Index() {
|
|||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
|
{/* share popup */}
|
||||||
|
<SharePopup ref={sharePopupRef} id={id} from={from} />
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
export default definePageConfig({
|
|
||||||
navigationBarTitleText: '首页'
|
|
||||||
})
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
|
|
||||||
@@ -1,261 +0,0 @@
|
|||||||
.index-page {
|
|
||||||
padding: 20px;
|
|
||||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
||||||
min-height: 100vh;
|
|
||||||
|
|
||||||
.page-header {
|
|
||||||
text-align: center;
|
|
||||||
margin-bottom: 24px;
|
|
||||||
|
|
||||||
.page-title {
|
|
||||||
font-size: 28px;
|
|
||||||
font-weight: bold;
|
|
||||||
color: white;
|
|
||||||
display: block;
|
|
||||||
margin-bottom: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.page-subtitle {
|
|
||||||
font-size: 16px;
|
|
||||||
color: rgba(255, 255, 255, 0.8);
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.user-card {
|
|
||||||
background: white;
|
|
||||||
border-radius: 16px;
|
|
||||||
padding: 20px;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
|
|
||||||
|
|
||||||
.user-header {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 16px;
|
|
||||||
|
|
||||||
.user-info {
|
|
||||||
flex: 1;
|
|
||||||
|
|
||||||
.username {
|
|
||||||
font-size: 20px;
|
|
||||||
font-weight: bold;
|
|
||||||
color: #333;
|
|
||||||
display: block;
|
|
||||||
margin-bottom: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.user-level {
|
|
||||||
font-size: 14px;
|
|
||||||
color: #666;
|
|
||||||
display: block;
|
|
||||||
margin-bottom: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.join-date {
|
|
||||||
font-size: 12px;
|
|
||||||
color: #999;
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.stats-section {
|
|
||||||
background: white;
|
|
||||||
border-radius: 16px;
|
|
||||||
padding: 20px;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
|
|
||||||
|
|
||||||
.section-title {
|
|
||||||
font-size: 18px;
|
|
||||||
font-weight: bold;
|
|
||||||
color: #333;
|
|
||||||
margin-bottom: 16px;
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
:global {
|
|
||||||
.nut-cell {
|
|
||||||
background: #f8f9fa;
|
|
||||||
border-radius: 12px;
|
|
||||||
margin-bottom: 8px;
|
|
||||||
border: none;
|
|
||||||
|
|
||||||
&:last-child {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nut-cell__title {
|
|
||||||
font-weight: 500;
|
|
||||||
color: #555;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nut-cell__value {
|
|
||||||
font-weight: bold;
|
|
||||||
color: #007bff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.action-section {
|
|
||||||
background: white;
|
|
||||||
border-radius: 16px;
|
|
||||||
padding: 20px;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
|
|
||||||
|
|
||||||
.section-title {
|
|
||||||
font-size: 18px;
|
|
||||||
font-weight: bold;
|
|
||||||
color: #333;
|
|
||||||
margin-bottom: 16px;
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.button-group {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 12px;
|
|
||||||
|
|
||||||
.custom-button {
|
|
||||||
border-radius: 12px;
|
|
||||||
font-weight: 500;
|
|
||||||
height: 48px;
|
|
||||||
border: none;
|
|
||||||
margin-bottom: 12px;
|
|
||||||
font-size: 16px;
|
|
||||||
color: white;
|
|
||||||
|
|
||||||
&.primary-btn {
|
|
||||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
||||||
}
|
|
||||||
|
|
||||||
&.success-btn {
|
|
||||||
background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
|
|
||||||
}
|
|
||||||
|
|
||||||
&.warning-btn {
|
|
||||||
background: linear-gradient(135deg, #fa709a 0%, #fee140 100%);
|
|
||||||
}
|
|
||||||
|
|
||||||
&:disabled {
|
|
||||||
opacity: 0.6;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 保留 NutUI 按钮样式(备用)
|
|
||||||
:global {
|
|
||||||
.nut-button {
|
|
||||||
border-radius: 12px;
|
|
||||||
font-weight: 500;
|
|
||||||
height: 48px;
|
|
||||||
border: none;
|
|
||||||
|
|
||||||
&--primary {
|
|
||||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
||||||
}
|
|
||||||
|
|
||||||
&--success {
|
|
||||||
background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
|
|
||||||
}
|
|
||||||
|
|
||||||
&--warning {
|
|
||||||
background: linear-gradient(135deg, #fa709a 0%, #fee140 100%);
|
|
||||||
}
|
|
||||||
|
|
||||||
&:disabled {
|
|
||||||
opacity: 0.6;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.loading-section {
|
|
||||||
background: white;
|
|
||||||
border-radius: 16px;
|
|
||||||
padding: 20px;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
|
|
||||||
text-align: center;
|
|
||||||
|
|
||||||
.loading-text {
|
|
||||||
font-size: 16px;
|
|
||||||
color: #666;
|
|
||||||
margin-bottom: 12px;
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
:global {
|
|
||||||
.nut-progress {
|
|
||||||
.nut-progress-outer {
|
|
||||||
background: #f0f0f0;
|
|
||||||
border-radius: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nut-progress-inner {
|
|
||||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
||||||
border-radius: 10px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.tips-section {
|
|
||||||
background: rgba(255, 255, 255, 0.95);
|
|
||||||
border-radius: 16px;
|
|
||||||
padding: 20px;
|
|
||||||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
|
|
||||||
|
|
||||||
.tips-title {
|
|
||||||
font-size: 18px;
|
|
||||||
font-weight: bold;
|
|
||||||
color: #333;
|
|
||||||
margin-bottom: 16px;
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tips-content {
|
|
||||||
.tip-item {
|
|
||||||
font-size: 14px;
|
|
||||||
color: #666;
|
|
||||||
line-height: 1.6;
|
|
||||||
margin-bottom: 8px;
|
|
||||||
display: block;
|
|
||||||
|
|
||||||
&:last-child {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 响应式设计
|
|
||||||
@media (max-width: 768px) {
|
|
||||||
.index-page {
|
|
||||||
padding: 16px;
|
|
||||||
|
|
||||||
.page-header {
|
|
||||||
.page-title {
|
|
||||||
font-size: 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.page-subtitle {
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.user-card,
|
|
||||||
.stats-section,
|
|
||||||
.action-section,
|
|
||||||
.loading-section,
|
|
||||||
.tips-section {
|
|
||||||
padding: 16px;
|
|
||||||
margin-bottom: 16px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,293 +0,0 @@
|
|||||||
import React, { useState, useEffect } from 'react'
|
|
||||||
import { View, Text, Button } from '@tarojs/components'
|
|
||||||
import { Cell, Avatar, Progress } from '@nutui/nutui-react-taro'
|
|
||||||
import Taro from '@tarojs/taro'
|
|
||||||
// 导入API服务
|
|
||||||
import demoApi from '../../services/demoApi'
|
|
||||||
import commonApi from '../../services/commonApi'
|
|
||||||
import {
|
|
||||||
useUserStats,
|
|
||||||
useUserActions
|
|
||||||
} from '../../store/userStore'
|
|
||||||
import './index.scss'
|
|
||||||
|
|
||||||
function Index() {
|
|
||||||
// 使用Zustand store
|
|
||||||
const userStats = useUserStats()
|
|
||||||
const { incrementRequestCount, resetUserStats } = useUserActions()
|
|
||||||
|
|
||||||
// 本地状态管理
|
|
||||||
const [loading, setLoading] = useState(false)
|
|
||||||
const [userProfile, setUserProfile] = useState<any>(null)
|
|
||||||
const [interests, setInterests] = useState<string[]>([])
|
|
||||||
|
|
||||||
// 页面加载时获取数据
|
|
||||||
useEffect(() => {
|
|
||||||
initializeData()
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
// 初始化数据
|
|
||||||
const initializeData = async () => {
|
|
||||||
try {
|
|
||||||
// 获取推荐的兴趣爱好
|
|
||||||
const interestsRes = await demoApi.getRecommendedInterests()
|
|
||||||
if (interestsRes.success) {
|
|
||||||
setInterests(interestsRes.data || [])
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.log('获取初始数据失败:', error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 1. 获取用户信息 API 请求
|
|
||||||
const handleGetUserProfile = async () => {
|
|
||||||
console.log('获取用户信息...');
|
|
||||||
setLoading(true)
|
|
||||||
|
|
||||||
try {
|
|
||||||
const response = await demoApi.getUserProfile()
|
|
||||||
|
|
||||||
if (response.success) {
|
|
||||||
setUserProfile(response.data)
|
|
||||||
incrementRequestCount()
|
|
||||||
|
|
||||||
Taro.showToast({
|
|
||||||
title: '获取用户信息成功',
|
|
||||||
icon: 'success'
|
|
||||||
})
|
|
||||||
|
|
||||||
console.log('用户信息:', response.data)
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('获取用户信息失败:', error)
|
|
||||||
Taro.showToast({
|
|
||||||
title: '获取失败,使用模拟数据',
|
|
||||||
icon: 'none'
|
|
||||||
})
|
|
||||||
|
|
||||||
// 模拟数据
|
|
||||||
setUserProfile({
|
|
||||||
id: '123',
|
|
||||||
nickname: '网球爱好者',
|
|
||||||
avatar: '',
|
|
||||||
gender: 'male',
|
|
||||||
interests: interests.slice(0, 3)
|
|
||||||
})
|
|
||||||
incrementRequestCount()
|
|
||||||
} finally {
|
|
||||||
setLoading(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. 提交统计数据 API 请求
|
|
||||||
const handleSubmitStats = async () => {
|
|
||||||
console.log('提交统计数据...');
|
|
||||||
setLoading(true)
|
|
||||||
|
|
||||||
try {
|
|
||||||
const response = await commonApi.submitForm('userStats', [
|
|
||||||
{
|
|
||||||
type: 'userStats',
|
|
||||||
data: {
|
|
||||||
requestCount: userStats.requestCount,
|
|
||||||
matchesCreated: userStats.matchesCreated,
|
|
||||||
matchesJoined: userStats.matchesJoined,
|
|
||||||
lastActiveTime: userStats.lastActiveTime,
|
|
||||||
userId: userProfile?.id || 'guest'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
])
|
|
||||||
|
|
||||||
if (response.success) {
|
|
||||||
incrementRequestCount()
|
|
||||||
|
|
||||||
Taro.showToast({
|
|
||||||
title: '统计数据提交成功',
|
|
||||||
icon: 'success'
|
|
||||||
})
|
|
||||||
|
|
||||||
console.log('提交结果:', response.data)
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('提交统计数据失败:', error)
|
|
||||||
incrementRequestCount() // 即使失败也计数,用于演示
|
|
||||||
|
|
||||||
Taro.showToast({
|
|
||||||
title: '网络模拟提交成功',
|
|
||||||
icon: 'success'
|
|
||||||
})
|
|
||||||
} finally {
|
|
||||||
setLoading(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3. 提交反馈 API 请求
|
|
||||||
const handleSubmitFeedback = async () => {
|
|
||||||
console.log('提交用户反馈...');
|
|
||||||
setLoading(true)
|
|
||||||
|
|
||||||
try {
|
|
||||||
const response = await demoApi.submitFeedback({
|
|
||||||
matchId: 'demo_match_' + Date.now(),
|
|
||||||
rating: 5,
|
|
||||||
recommend: 'yes',
|
|
||||||
aspects: ['场地环境', '服务质量', '价格合理'],
|
|
||||||
comments: `用户反馈 - 请求次数: ${userStats.requestCount + 1},体验良好!`
|
|
||||||
})
|
|
||||||
|
|
||||||
if (response.success) {
|
|
||||||
incrementRequestCount()
|
|
||||||
|
|
||||||
Taro.showToast({
|
|
||||||
title: '反馈提交成功',
|
|
||||||
icon: 'success'
|
|
||||||
})
|
|
||||||
|
|
||||||
console.log('反馈结果:', response.data)
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('提交反馈失败:', error)
|
|
||||||
incrementRequestCount() // 即使失败也计数,用于演示
|
|
||||||
|
|
||||||
Taro.showToast({
|
|
||||||
title: '网络模拟提交成功',
|
|
||||||
icon: 'success'
|
|
||||||
})
|
|
||||||
} finally {
|
|
||||||
setLoading(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 重置所有数据
|
|
||||||
const handleResetAllData = () => {
|
|
||||||
console.log('重置所有数据...');
|
|
||||||
resetUserStats()
|
|
||||||
setUserProfile(null)
|
|
||||||
|
|
||||||
Taro.showToast({
|
|
||||||
title: '数据已重置',
|
|
||||||
icon: 'success'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<View className='index-page'>
|
|
||||||
{/* 页面标题 */}
|
|
||||||
<View className='page-header'>
|
|
||||||
<Text className='page-title'>API 请求演示</Text>
|
|
||||||
<Text className='page-subtitle'>真实网络请求功能测试</Text>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
{/* 用户信息卡片 */}
|
|
||||||
<View className='user-card'>
|
|
||||||
<View className='user-header'>
|
|
||||||
<Avatar
|
|
||||||
size="large"
|
|
||||||
src={userProfile?.avatar || ''}
|
|
||||||
style={{ backgroundColor: '#fa2c19' }}
|
|
||||||
>
|
|
||||||
{userProfile?.nickname?.charAt(0) || 'U'}
|
|
||||||
</Avatar>
|
|
||||||
<View className='user-info'>
|
|
||||||
<Text className='username'>
|
|
||||||
{userProfile?.nickname || '点击获取用户信息'}
|
|
||||||
</Text>
|
|
||||||
<Text className='user-level'>
|
|
||||||
性别: {userProfile?.gender === 'male' ? '男' : userProfile?.gender === 'female' ? '女' : '未知'}
|
|
||||||
</Text>
|
|
||||||
<Text className='join-date'>
|
|
||||||
兴趣: {userProfile?.interests?.join(', ') || '暂无'}
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
{/* 统计数据 */}
|
|
||||||
<View className='stats-section'>
|
|
||||||
<Text className='section-title'>📊 API 请求统计</Text>
|
|
||||||
|
|
||||||
<Cell title="API 请求次数" extra={userStats.requestCount} />
|
|
||||||
<Cell title="创建的比赛" extra={userStats.matchesCreated} />
|
|
||||||
<Cell title="参加的比赛" extra={userStats.matchesJoined} />
|
|
||||||
<Cell
|
|
||||||
title="最后活跃时间"
|
|
||||||
extra={new Date(userStats.lastActiveTime).toLocaleTimeString()}
|
|
||||||
/>
|
|
||||||
{interests.length > 0 && (
|
|
||||||
<Cell
|
|
||||||
title="推荐兴趣"
|
|
||||||
extra={interests.slice(0, 2).join(', ')}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</View>
|
|
||||||
|
|
||||||
{/* API 请求按钮区域 */}
|
|
||||||
<View className='action-section'>
|
|
||||||
<Text className='section-title'>🚀 API 请求功能</Text>
|
|
||||||
|
|
||||||
<View className='button-group'>
|
|
||||||
<Button
|
|
||||||
type="primary"
|
|
||||||
loading={loading}
|
|
||||||
onClick={handleGetUserProfile}
|
|
||||||
disabled={loading}
|
|
||||||
className="custom-button primary-btn"
|
|
||||||
>
|
|
||||||
{loading ? '请求中...' : '获取用户信息'}
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
<Button
|
|
||||||
type="default"
|
|
||||||
loading={loading}
|
|
||||||
onClick={handleSubmitStats}
|
|
||||||
disabled={loading}
|
|
||||||
className="custom-button success-btn"
|
|
||||||
>
|
|
||||||
{loading ? '提交中...' : '提交统计数据'}
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
<Button
|
|
||||||
type="default"
|
|
||||||
loading={loading}
|
|
||||||
onClick={handleSubmitFeedback}
|
|
||||||
disabled={loading}
|
|
||||||
className="custom-button warning-btn"
|
|
||||||
>
|
|
||||||
{loading ? '提交中...' : '提交用户反馈'}
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
<Button
|
|
||||||
type="warn"
|
|
||||||
onClick={handleResetAllData}
|
|
||||||
disabled={loading}
|
|
||||||
className="custom-button warning-btn"
|
|
||||||
>
|
|
||||||
重置所有数据
|
|
||||||
</Button>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
{/* 实时进度显示 */}
|
|
||||||
{loading && (
|
|
||||||
<View className='loading-section'>
|
|
||||||
<Text className='loading-text'>正在发送 API 请求...</Text>
|
|
||||||
<Progress percent={100} animated />
|
|
||||||
</View>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* 提示信息 */}
|
|
||||||
<View className='tips-section'>
|
|
||||||
<Text className='tips-title'>💡 API 功能说明</Text>
|
|
||||||
<View className='tips-content'>
|
|
||||||
<Text className='tip-item'>• "获取用户信息" - 调用用户资料 API</Text>
|
|
||||||
<Text className='tip-item'>• "提交统计数据" - 发送统计到服务器</Text>
|
|
||||||
<Text className='tip-item'>• "提交用户反馈" - 发送用户评价数据</Text>
|
|
||||||
<Text className='tip-item'>• 所有请求都会增加 API 计数统计</Text>
|
|
||||||
<Text className='tip-item'>• 请求失败时会自动使用模拟数据</Text>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Index
|
|
||||||
@@ -6,7 +6,7 @@ import PublishForm from './publishForm'
|
|||||||
import { publishBallFormSchema } from '../../config/formSchema/publishBallFormSchema';
|
import { publishBallFormSchema } from '../../config/formSchema/publishBallFormSchema';
|
||||||
import { PublishBallFormData } from '../../../types/publishBall';
|
import { PublishBallFormData } from '../../../types/publishBall';
|
||||||
import PublishService from '@/services/publishService';
|
import PublishService from '@/services/publishService';
|
||||||
import { getNextHourTime, getEndTime } from '@/utils/timeUtils';
|
import { getNextHourTime, getEndTime, delay } from '@/utils';
|
||||||
import images from '@/config/images'
|
import images from '@/config/images'
|
||||||
import styles from './index.module.scss'
|
import styles from './index.module.scss'
|
||||||
|
|
||||||
@@ -195,6 +195,13 @@ const PublishBall: React.FC = () => {
|
|||||||
title: '发布成功',
|
title: '发布成功',
|
||||||
icon: 'success'
|
icon: 'success'
|
||||||
})
|
})
|
||||||
|
delay(1000)
|
||||||
|
// 如果是个人球局,则跳转到详情页,并自动分享
|
||||||
|
// 如果是畅打,则跳转第一个球局详情页,并自动分享 @刘杰
|
||||||
|
Taro.navigateTo({
|
||||||
|
// @ts-expect-error: id
|
||||||
|
url: `/pages/detail/index?id=${res.data.id || 1}&from=publish&autoShare=1`
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
Taro.showToast({
|
Taro.showToast({
|
||||||
title: res.message,
|
title: res.message,
|
||||||
|
|||||||
BIN
src/static/asserts/fonts/PoetsenOne-Regular.ttf
Normal file
BIN
src/static/asserts/fonts/PoetsenOne-Regular.ttf
Normal file
Binary file not shown.
9
src/utils/index.ts
Normal file
9
src/utils/index.ts
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
export * from './getNavbarHeight'
|
||||||
|
export * from './locationUtils'
|
||||||
|
export * from './processImage'
|
||||||
|
export * from './timeUtils'
|
||||||
|
export * from './tokenManager'
|
||||||
|
|
||||||
|
export function delay(ms: number) {
|
||||||
|
return new Promise(resolve => setTimeout(resolve, ms))
|
||||||
|
}
|
||||||
@@ -146,6 +146,7 @@ export interface FilterPopupProps {
|
|||||||
|
|
||||||
// 列表卡片
|
// 列表卡片
|
||||||
export interface ListCardProps {
|
export interface ListCardProps {
|
||||||
|
id: number;
|
||||||
title: string;
|
title: string;
|
||||||
dateTime: string;
|
dateTime: string;
|
||||||
location: string;
|
location: string;
|
||||||
|
|||||||
Reference in New Issue
Block a user