feat: update material card

This commit is contained in:
chashaobao
2025-09-08 23:28:17 +08:00
parent f2e7fd9d85
commit b9cd0a3e6d
4 changed files with 89 additions and 66 deletions

View File

@ -9,7 +9,7 @@ import { PageUrl } from '@/constants/app';
import { MaterialViewSource, WORK_YEAR_LABELS } from '@/constants/material'; import { MaterialViewSource, WORK_YEAR_LABELS } from '@/constants/material';
import { AnchorInfo } from '@/types/material'; import { AnchorInfo } from '@/types/material';
import { calcDistance } from '@/utils/location'; import { calcDistance } from '@/utils/location';
import { getBasicInfo } from '@/utils/material'; import { getBasicInfo, getSalary } from '@/utils/material';
import { navigateTo } from '@/utils/route'; import { navigateTo } from '@/utils/route';
import { activeDate } from '@/utils/time'; import { activeDate } from '@/utils/time';
@ -22,17 +22,6 @@ interface IProps {
} }
const PREFIX = 'anchor-card'; const PREFIX = 'anchor-card';
const getSalary = (data: AnchorInfo) => {
const { fullTimeMinPrice, fullTimeMaxPrice, partyTimeMinPrice, partyTimeMaxPrice } = data;
const prices: string[] = [];
if (fullTimeMinPrice && fullTimeMaxPrice) {
prices.push(`${fullTimeMinPrice / 1000}-${fullTimeMaxPrice / 1000}K/月`);
}
if (partyTimeMinPrice && partyTimeMaxPrice) {
prices.push(`${partyTimeMinPrice}-${partyTimeMaxPrice}/小时`);
}
return prices.filter(Boolean).join(' ');
};
function AnchorCard(props: IProps) { function AnchorCard(props: IProps) {
const { data, jobId, validator } = props; const { data, jobId, validator } = props;

View File

@ -4,7 +4,7 @@
.material-card { .material-card {
padding: 32px 24px; padding: 32px 24px;
border-radius: 16px; border-radius: 16px;
background: #FFFFFF; background: #ffffff;
box-sizing: border-box; box-sizing: border-box;
&__header { &__header {
@ -16,6 +16,10 @@
.flex-row(); .flex-row();
} }
&__right {
color: @blHighlightColor;
}
&__title { &__title {
font-size: 32px; font-size: 32px;
line-height: 40px; line-height: 40px;
@ -50,7 +54,7 @@
&__body { &__body {
width: 100%; width: 100%;
height: 156px; height: 160px;
margin-top: 24px; margin-top: 24px;
.flex-column(); .flex-column();
justify-content: center; justify-content: center;
@ -80,38 +84,44 @@
} }
} }
&__scroll-view { &__info {
position: relative; .flex-row();
gap: 24px;
width: 100%;
&-left {
width: 125px;
height: 160px;
}
&-cover {
width: 100%; width: 100%;
height: 100%; height: 100%;
.flex-row(); border-radius: 12px;
&::-webkit-scrollbar {
display: none;
} }
&-right {
.name {
font-style: normal;
font-weight: 500;
font-size: 28px;
line-height: 32px;
color: @blColor;
margin-bottom: 12px;
}
.info,
.worked {
font-weight: 400;
font-size: 24px;
line-height: 36px;
color: @blColorG2;
margin-bottom: 8px;
}
.salary {
font-weight: 500;
font-size: 24px;
line-height: 36px;
color: @blColor;
&::after {
content: '';
position: absolute;
right: 0;
width: 102px;
height: 100%;
background: linear-gradient(91.41deg, rgba(255, 255, 255, 0) 1.86%, #FFFFFF 99.47%);
} }
} }
&__cover-list {
height: 100%;
.flex-row();
} }
&__cover-image {
width: 120px;
height: 100%;
margin-right: 24px;
// 不知道为啥高度不对,可能 scroll-view 默认底部是滚动条高度?
margin-top: 38px;
border-radius: 8px;
}
} }

View File

@ -1,4 +1,4 @@
import { Image, ScrollView } from '@tarojs/components'; import { Image } from '@tarojs/components';
import Taro from '@tarojs/taro'; import Taro from '@tarojs/taro';
import { Loading } from '@taroify/core'; import { Loading } from '@taroify/core';
@ -9,11 +9,12 @@ import { useCallback, useEffect, useRef, useState } from 'react';
import LoginButton from '@/components/login-button'; import LoginButton from '@/components/login-button';
import { EventName, PageUrl } from '@/constants/app'; import { EventName, PageUrl } from '@/constants/app';
import { CollectEventName, ReportEventId } from '@/constants/event'; import { CollectEventName, ReportEventId } from '@/constants/event';
import { WORK_YEAR_LABELS } from '@/constants/material';
import useUserInfo from '@/hooks/use-user-info'; import useUserInfo from '@/hooks/use-user-info';
import { MaterialProfile } from '@/types/material'; import { MaterialProfile } from '@/types/material';
import { logWithPrefix } from '@/utils/common'; import { logWithPrefix } from '@/utils/common';
import { collectEvent, reportEvent } from '@/utils/event'; import { collectEvent, reportEvent } from '@/utils/event';
import { requestProfileDetail, sortVideos } from '@/utils/material'; import { getBasicInfo, getSalary, requestProfileDetail, sortVideos } from '@/utils/material';
import { navigateTo } from '@/utils/route'; import { navigateTo } from '@/utils/route';
import Toast from '@/utils/toast'; import Toast from '@/utils/toast';
import { isValidUserInfo } from '@/utils/user'; import { isValidUserInfo } from '@/utils/user';
@ -34,8 +35,9 @@ function MaterialCard(props: IProps) {
const userInfo = useUserInfo(); const userInfo = useUserInfo();
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
const [profile, setProfile] = useState<MaterialProfile | null>(null); const [profile, setProfile] = useState<MaterialProfile | null>(null);
const refreshRef = useRef((_f?: boolean) => { }); const refreshRef = useRef((_f?: boolean) => {});
const hasMaterial = !!profile; const hasMaterial = !!profile;
const firstCover = sortVideos(profile?.materialVideoInfoList || [])[0];
const handleGoCreateProfile = useCallback(() => { const handleGoCreateProfile = useCallback(() => {
reportEvent(ReportEventId.CLICK_GO_TO_CREATE_MATERIAL); reportEvent(ReportEventId.CLICK_GO_TO_CREATE_MATERIAL);
@ -44,7 +46,7 @@ function MaterialCard(props: IProps) {
const handleGoProfile = useCallback(() => { const handleGoProfile = useCallback(() => {
if (!hasMaterial) { if (!hasMaterial) {
realtimeLogger.info('handleGoProfile noMaterial') realtimeLogger.info('handleGoProfile noMaterial');
return; return;
} }
navigateTo(PageUrl.MaterialProfile).catch(err => { navigateTo(PageUrl.MaterialProfile).catch(err => {
@ -67,7 +69,7 @@ function MaterialCard(props: IProps) {
try { try {
const profileDetail = await requestProfileDetail(); const profileDetail = await requestProfileDetail();
if (!profileDetail) { if (!profileDetail) {
realtimeLogger.info('getProfileDetail no profileDetail') realtimeLogger.info('getProfileDetail no profileDetail');
} }
setProfile(profileDetail); setProfile(profileDetail);
} catch (e) { } catch (e) {
@ -90,8 +92,10 @@ function MaterialCard(props: IProps) {
refreshRef.current?.(true); refreshRef.current?.(true);
}; };
Taro.eventCenter.on(EventName.CREATE_PROFILE, callback); Taro.eventCenter.on(EventName.CREATE_PROFILE, callback);
Taro.eventCenter.on(EventName.UPDATE_PROFILE, callback);
return () => { return () => {
Taro.eventCenter.off(EventName.CREATE_PROFILE, callback); Taro.eventCenter.off(EventName.CREATE_PROFILE, callback);
Taro.eventCenter.on(EventName.UPDATE_PROFILE, callback);
}; };
}, [userInfo]); }, [userInfo]);
@ -100,16 +104,11 @@ function MaterialCard(props: IProps) {
<div className={`${PREFIX}__header`}> <div className={`${PREFIX}__header`}>
<div className={`${PREFIX}__header__left`}> <div className={`${PREFIX}__header__left`}>
<div className={`${PREFIX}__header__title`}></div> <div className={`${PREFIX}__header__title`}></div>
{/* {profile && (
<div
className={`${PREFIX}__header__progress`}
>{`完成度${Math.min((profile.progressBar || 0) * 100, 100)}%`}</div>
)} */}
</div> </div>
{profile && ( {profile && (
<div className={`${PREFIX}__header__right`}> <div className={`${PREFIX}__header__right`}>
{/* <div className={`${PREFIX}__header__status`}>{profile?.isOpen ? '开放中' : '关闭'}</div> */} <div></div>
<ArrowRight className={`${PREFIX}__header__icon`} /> <ArrowRight color="#6D3DF5" className={`${PREFIX}__header__icon`} />
</div> </div>
)} )}
</div> </div>
@ -123,18 +122,21 @@ function MaterialCard(props: IProps) {
</div> </div>
)} )}
{!loading && hasMaterial && ( {!loading && hasMaterial && (
<ScrollView className={`${PREFIX}__scroll-view`} showScrollbar={false} enableFlex enhanced scrollX> <div className={`${PREFIX}__info`}>
<div className={`${PREFIX}__cover-list`}> {firstCover && (
{sortVideos(profile?.materialVideoInfoList || []).map(video => ( <div className={`${PREFIX}__info-left`}>
<Image <Image className={`${PREFIX}__info-cover`} mode="aspectFit" src={firstCover.coverUrl} />
className={`${PREFIX}__cover-image`} </div>
mode="aspectFit" )}
key={video.coverUrl} <div className={`${PREFIX}__info-right`}>
src={video.coverUrl} <div className="name">{profile?.name}</div>
/> <div className="info">
))} {WORK_YEAR_LABELS[profile?.workedYear] || ''}·{getBasicInfo({ ...profile, shoeSize: null })}
</div>
<div className="worked"> {profile?.workedSecCategoryStr}</div>
<div className="salary">{getSalary(profile)}</div>
</div>
</div> </div>
</ScrollView>
)} )}
{loading && <Loading />} {loading && <Loading />}
</div> </div>

View File

@ -62,6 +62,28 @@ export const getBasicInfo = (profile: Pick<MaterialProfile, 'age' | 'height' | '
return result.join('·'); return result.join('·');
}; };
export const getSalary = (
data: Pick<MaterialProfile, 'fullTimeMaxPrice' | 'fullTimeMinPrice' | 'partyTimeMaxPrice' | 'partyTimeMinPrice'>
) => {
const { fullTimeMinPrice, fullTimeMaxPrice, partyTimeMinPrice, partyTimeMaxPrice } = data;
const prices: string[] = [];
if (fullTimeMinPrice && fullTimeMaxPrice) {
if (fullTimeMinPrice >= 50000) {
prices.push(`${fullTimeMinPrice / 1000}K以上/月`);
} else {
prices.push(`${fullTimeMinPrice / 1000}-${fullTimeMaxPrice / 1000}K/月`);
}
}
if (partyTimeMinPrice && partyTimeMaxPrice) {
if (partyTimeMinPrice >= 500) {
prices.push(`500以上/小时`);
} else {
prices.push(`${partyTimeMinPrice}-${partyTimeMaxPrice}/小时`);
}
}
return prices.filter(Boolean).join(' ');
};
export const chooseMedia = async (option: Taro.chooseMedia.Option = {}) => { export const chooseMedia = async (option: Taro.chooseMedia.Option = {}) => {
try { try {
const result = await Taro.chooseMedia({ const result = await Taro.chooseMedia({