增加banneer占位图

This commit is contained in:
李瑞
2026-02-01 16:12:04 +08:00
parent d7c24ca8b3
commit 1cbec87f77
6 changed files with 184 additions and 21 deletions

View File

@@ -57,6 +57,7 @@ export default defineAppConfig({
"ntrp-evaluate/index", // NTRP评估页 "ntrp-evaluate/index", // NTRP评估页
"enable_notification/index", // 开启消息通知 "enable_notification/index", // 开启消息通知
"emptyState/index", // 空状态页面 "emptyState/index", // 空状态页面
"bannerDetail/index", // Banner 图片详情页
], ],
}, },
], ],

View File

@@ -3,6 +3,7 @@ import ListCard from "@/components/ListCard";
import ListLoadError from "@/components/ListLoadError"; import ListLoadError from "@/components/ListLoadError";
import ListCardSkeleton from "@/components/ListCardSkeleton"; import ListCardSkeleton from "@/components/ListCardSkeleton";
import { useReachBottom } from "@tarojs/taro"; import { useReachBottom } from "@tarojs/taro";
import Taro from "@tarojs/taro";
import { useUserInfo, useUserActions, useLastTestResult } from "@/store/userStore"; import { useUserInfo, useUserActions, useLastTestResult } from "@/store/userStore";
import { NTRPTestEntryCard } from "@/components"; import { NTRPTestEntryCard } from "@/components";
import { EvaluateScene } from "@/store/evaluateStore"; import { EvaluateScene } from "@/store/evaluateStore";
@@ -158,6 +159,35 @@ const ListContainer = (props) => {
[evaluateFlag, data, hasTestInLastMonth, showNumber] [evaluateFlag, data, hasTestInLastMonth, showNumber]
); );
// 渲染 banner 卡片
const renderBanner = (item, index) => {
if (!item?.banner_image_url) return null;
return (
<View
key={item.id || `banner-${index}`}
style={{
maxHeight: "122px",
overflow: "hidden",
borderRadius: "12px",
}}
>
<Image
src={item.banner_image_url}
mode="widthFix"
style={{ width: "100%", display: "block", maxHeight: "122px" }}
onClick={() => {
const target = item.banner_detail_url;
if (target) {
(Taro as any).navigateTo({
url: `/other_pages/bannerDetail/index?img=${encodeURIComponent(target)}`,
});
}
}}
/>
</View>
);
};
// 渲染列表 // 渲染列表
const renderList = () => { const renderList = () => {
// 请求数据为空 // 请求数据为空
@@ -181,6 +211,9 @@ const ListContainer = (props) => {
return ( return (
<> <>
{memoizedList.map((match, index) => { {memoizedList.map((match, index) => {
if (match.type === "banner") {
return renderBanner(match, index);
}
if (match.type === "evaluateCard") { if (match.type === "evaluateCard") {
return ( return (
<NTRPTestEntryCard key="evaluate" type={EvaluateScene.list} /> <NTRPTestEntryCard key="evaluate" type={EvaluateScene.list} />

View File

@@ -0,0 +1,8 @@
export default definePageConfig({
navigationBarTitleText: '',
navigationStyle: 'custom',
navigationBarBackgroundColor: '#FFFFFF',
backgroundColor: '#FFFFFF',
});

View File

@@ -0,0 +1,16 @@
.banner_detail_page {
min-height: 100vh;
background: #ffffff;
}
.banner_detail_content {
padding: 12px;
}
.banner_detail_image {
width: 100%;
border-radius: 12px;
display: block;
}

View File

@@ -0,0 +1,36 @@
import { useEffect, useState } from 'react';
import { View, Image } from '@tarojs/components';
import Taro from '@tarojs/taro';
import { GeneralNavbar } from '@/components';
import './index.scss';
function Index() {
const [imgUrl, setImgUrl] = useState<string>('');
useEffect(() => {
const instance = (Taro as any).getCurrentInstance?.();
const params = instance?.router?.params || {};
const url = params?.img ? decodeURIComponent(params.img) : '';
setImgUrl(url);
}, []);
return (
<View className="banner_detail_page">
<GeneralNavbar title="" showBack={true} />
<View className="banner_detail_content">
{imgUrl ? (
<Image
className="banner_detail_image"
src={imgUrl}
mode="widthFix"
showMenuByLongpress
/>
) : null}
</View>
</View>
);
}
export default Index;

View File

@@ -11,6 +11,7 @@ import {
getCityQrCode, getCityQrCode,
getDistricts, getDistricts,
} from "../services/listApi"; } from "../services/listApi";
import commonApi from "../services/commonApi";
import { import {
ListActions, ListActions,
IFilterOptions, IFilterOptions,
@@ -18,6 +19,27 @@ import {
IPayload, IPayload,
} from "../../types/list/types"; } from "../../types/list/types";
// 将 banner 按索引插入到 rows 的工具方法
function insertBannersToRows(rows: any[], dictData: any) {
if (!Array.isArray(rows) || !dictData) return rows;
// 仅单张图片与单个索引
const img = (dictData?.bannerListImage || "").trim();
const indexRaw = (dictData?.bannerListIndex || "").toString().trim();
if (!img) return rows;
// 固定采用 0 基索引
const parsed = parseInt(indexRaw, 10);
const normalized = Number.isFinite(parsed) ? parsed : 0;
const resultRows = [...rows];
const target = Math.max(0, Math.min(normalized, resultRows.length));
resultRows.splice(target, 0, {
type: "banner",
id: `banner-${target}`,
banner_image_url: img,
banner_detail_url: (dictData?.bannerDetailImage || "").trim(),
} as any);
return resultRows;
}
function translateCityData(dataTree) { function translateCityData(dataTree) {
return dataTree.map((item) => { return dataTree.map((item) => {
const { children, ...rest } = item; const { children, ...rest } = item;
@@ -296,7 +318,31 @@ export const useListStore = create<TennisStore>()((set, get) => ({
} }
} }
const resData = (await fetchFn(reqParams)) || {}; // 并发请求:列表接口 + 字典接口(仅第一页且非追加时插入 Banner
const shouldInsertBanner = (currentPageState?.pageOption?.page || 1) === 1 && !isAppend;
const keys = "bannerListImage,bannerDetailImage,bannerListIndex";
let resData: any = {};
let dictData: any = null;
if (shouldInsertBanner) {
const [listResult, dictResult] = await Promise.allSettled([
fetchFn(reqParams),
commonApi.getDictionaryManyKey(keys),
]);
// 列表接口请求成功
if (listResult.status === "fulfilled") {
resData = listResult.value || {};
} else {
throw listResult.reason || new Error("获取数据失败");
}
// 字典接口请求成功
if (dictResult.status === "fulfilled" && (dictResult.value as any)?.code === 0) {
dictData = (dictResult.value as any)?.data || null;
}
} else {
resData = (await fetchFn(reqParams)) || {};
}
const { data = {}, code } = resData; const { data = {}, code } = resData;
if (code !== 0) { if (code !== 0) {
setListData({ setListData({
@@ -308,7 +354,14 @@ export const useListStore = create<TennisStore>()((set, get) => ({
}); });
return Promise.reject(new Error('获取数据失败')); return Promise.reject(new Error('获取数据失败'));
} }
const { count, rows } = data; const { count } = data;
let { rows } = data as any;
// 将 banner 插入到指定位置(仅第一页且非追加)
if (shouldInsertBanner && Array.isArray(rows) && dictData) {
rows = insertBannersToRows(rows, dictData);
}
setListData({ setListData({
error: '', error: '',
data: rows || [], data: rows || [],
@@ -344,24 +397,30 @@ export const useListStore = create<TennisStore>()((set, get) => ({
try { try {
const searchParams = getSearchParams() || {}; const searchParams = getSearchParams() || {};
const keys = "bannerListImage,bannerDetailImage,bannerListIndex";
// 调用常规列表接口 // 并发请求:常规列表、智能排序列表、字典
const listParams = { const [listResSettled, integrateResSettled, dictSettled] = await Promise.allSettled([
...searchParams, getGamesList({
order: searchParams.order || "distance", ...searchParams,
}; order: searchParams.order || "distance",
const listRes = await getGamesList(listParams); }),
getGamesIntegrateList({
// 调用智能排序列表接口 ...searchParams,
const integrateParams = { order: "",
...searchParams, seachOption: {
order: "", ...searchParams.seachOption,
seachOption: { isRefresh: true,
...searchParams.seachOption, },
isRefresh: true, }),
}, commonApi.getDictionaryManyKey(keys),
}; ]);
const integrateRes = await getGamesIntegrateList(integrateParams);
const listRes = listResSettled.status === "fulfilled" ? listResSettled.value : null;
const integrateRes = integrateResSettled.status === "fulfilled" ? integrateResSettled.value : null;
const dictData = dictSettled.status === "fulfilled" && (dictSettled.value as any)?.code === 0
? (dictSettled.value as any)?.data
: null;
// 根据当前排序方式更新对应的数据 // 根据当前排序方式更新对应的数据
const currentPageState = state.isSearchResult ? state.searchPageState : state.listPageState; const currentPageState = state.isSearchResult ? state.searchPageState : state.listPageState;
@@ -369,7 +428,12 @@ export const useListStore = create<TennisStore>()((set, get) => ({
const isIntegrate = distanceQuickFilter?.order === "0"; const isIntegrate = distanceQuickFilter?.order === "0";
if (listRes?.code === 0 && listRes?.data) { if (listRes?.code === 0 && listRes?.data) {
const { count, rows } = listRes.data; const { count } = listRes.data;
let { rows } = listRes.data as any;
// 插入 banner当为第一页时
if ((currentPageState?.pageOption?.page || 1) === 1 && Array.isArray(rows) && dictData) {
rows = insertBannersToRows(rows, dictData);
}
if (!isIntegrate) { if (!isIntegrate) {
// 如果当前是常规排序,更新常规列表数据 // 如果当前是常规排序,更新常规列表数据
setListData({ setListData({
@@ -383,7 +447,12 @@ export const useListStore = create<TennisStore>()((set, get) => ({
} }
if (integrateRes?.code === 0 && integrateRes?.data) { if (integrateRes?.code === 0 && integrateRes?.data) {
const { count, rows, recommendList } = integrateRes.data; const { count } = integrateRes.data;
let { rows, recommendList } = integrateRes.data as any;
// 插入 banner当为第一页时
if ((currentPageState?.pageOption?.page || 1) === 1 && Array.isArray(rows) && dictData) {
rows = insertBannersToRows(rows, dictData);
}
if (isIntegrate) { if (isIntegrate) {
// 如果当前是智能排序,更新智能排序列表数据 // 如果当前是智能排序,更新智能排序列表数据
setListData({ setListData({