262 lines
9.6 KiB
TypeScript
262 lines
9.6 KiB
TypeScript
import { BaseEventOrig, Image, Swiper, SwiperItem, SwiperProps } from '@tarojs/components';
|
|
import Taro from '@tarojs/taro';
|
|
|
|
import classNames from 'classnames';
|
|
import { useCallback, useState } from 'react';
|
|
|
|
import DevDiv from '@/components/dev-div';
|
|
import SafeBottomPadding from '@/components/safe-bottom-padding';
|
|
import { OpenSource, PageUrl } from '@/constants/app';
|
|
import { CITY_CODE_TO_NAME_MAP } from '@/constants/city';
|
|
import { FULL_PRICE_OPTIONS, PART_PRICE_OPTIONS } from '@/constants/job';
|
|
import { ProfileGroupType, ProfileTitleMap, WORK_YEAR_OPTIONS } from '@/constants/material';
|
|
import { MaterialProfile } from '@/types/material';
|
|
import { logWithPrefix, isDesktop } from '@/utils/common';
|
|
import { getBasicInfo, sortVideos } from '@/utils/material';
|
|
import { navigateTo } from '@/utils/route';
|
|
|
|
import './index.less';
|
|
import onChangeEventDetail = SwiperProps.onChangeEventDetail;
|
|
import { JoinGroupHint } from '@/components/join-group-hint';
|
|
|
|
interface IProps {
|
|
editable: boolean;
|
|
profile: MaterialProfile;
|
|
onDev?: () => void;
|
|
}
|
|
|
|
const PREFIX = 'profile-view-fragment';
|
|
const log = logWithPrefix(PREFIX);
|
|
const DEFAULT_TEXT = '未填写';
|
|
|
|
const getIndentCity = (codeString: string = '') => {
|
|
const codes = codeString.split('、');
|
|
const cityNames: string[] = [];
|
|
codes.forEach(code => {
|
|
const cityName = CITY_CODE_TO_NAME_MAP.get(code);
|
|
cityName && cityNames.push(cityName);
|
|
});
|
|
return cityNames.join('、');
|
|
};
|
|
|
|
const getIndentPrice = (min: number, max: number, full: boolean) => {
|
|
if (!min && !max) {
|
|
return DEFAULT_TEXT;
|
|
}
|
|
const options = full ? FULL_PRICE_OPTIONS : PART_PRICE_OPTIONS;
|
|
const option = options.find(o => o.value.minSalary === min && o.value.maxSalary === max);
|
|
if (option) {
|
|
return option.label;
|
|
}
|
|
|
|
const unit = full ? 'K' : '';
|
|
const prices: string[] = [];
|
|
min && prices.push(`${full ? Number(min) / 1000 : min}${unit}`);
|
|
max && prices.push(`${full ? Number(max) / 1000 : max}${unit}`);
|
|
return prices.join(' - ');
|
|
};
|
|
|
|
const getWorkYear = (year: number) => {
|
|
if (!year) {
|
|
return DEFAULT_TEXT;
|
|
}
|
|
const y = Math.min(year, 3);
|
|
return WORK_YEAR_OPTIONS.find(option => option.value === y)?.label || `${y}年`;
|
|
};
|
|
|
|
const getDataGroup = (profile: MaterialProfile | null) => {
|
|
if (!profile) {
|
|
return [];
|
|
}
|
|
return [
|
|
{
|
|
title: ProfileTitleMap[ProfileGroupType.Intention],
|
|
type: ProfileGroupType.Intention,
|
|
items: [
|
|
{ title: '全职薪资', value: getIndentPrice(profile.fullTimeMinPrice, profile.fullTimeMaxPrice, true) || '' },
|
|
{ title: '兼职薪资', value: getIndentPrice(profile.partyTimeMinPrice, profile.partyTimeMaxPrice, false) || '' },
|
|
{ title: '意向城市', value: getIndentCity(profile.cityCodes) || DEFAULT_TEXT },
|
|
{ title: '是否接受坐班', value: profile.acceptWorkForSit ? '是' : '否' },
|
|
],
|
|
},
|
|
{
|
|
title: ProfileTitleMap[ProfileGroupType.Experience],
|
|
type: ProfileGroupType.Experience,
|
|
items: [
|
|
{ title: '直播年限', value: getWorkYear(profile.workedYear) || DEFAULT_TEXT },
|
|
{ title: '直播过的账号', value: profile.workedAccounts || DEFAULT_TEXT },
|
|
{ title: '自然流起号经验', value: Boolean(profile.newAccountExperience) ? '有' : '无' },
|
|
{ title: '直播过的品类', value: profile.workedSecCategoryStr || DEFAULT_TEXT },
|
|
{ title: '最高GMV', value: profile.maxGmv ? `${profile.maxGmv / 10000}万` : DEFAULT_TEXT },
|
|
{ title: '最高在线人数', value: profile.maxOnline || DEFAULT_TEXT },
|
|
],
|
|
},
|
|
{
|
|
title: ProfileTitleMap[ProfileGroupType.Advantages],
|
|
type: ProfileGroupType.Advantages,
|
|
items: [{ title: '自身优势', value: profile.advantages || DEFAULT_TEXT, fullLine: true }],
|
|
},
|
|
];
|
|
};
|
|
|
|
export default function ProfileViewFragment(props: IProps) {
|
|
const { profile, editable, onDev } = props;
|
|
const [coverIndex, setCoverIndex] = useState(0);
|
|
const dataGroup = getDataGroup(profile);
|
|
const videos = sortVideos(profile?.materialVideoInfoList || []);
|
|
|
|
const handleClickVideo = useCallback(
|
|
(index: number) => {
|
|
log('handleClickVideo', index);
|
|
|
|
if (isDesktop) {
|
|
navigateTo(PageUrl.MaterialWebview, {
|
|
source: encodeURIComponent(videos[index].url),
|
|
});
|
|
} else {
|
|
Taro.previewMedia({
|
|
sources: videos.map(video => ({ url: video.url, type: video.type })),
|
|
current: index,
|
|
});
|
|
}
|
|
},
|
|
[videos]
|
|
);
|
|
|
|
const handleEditVideo = useCallback(() => {
|
|
log('handleEditBasic');
|
|
navigateTo(PageUrl.MaterialUploadVideo, { source: OpenSource.UserPage });
|
|
}, []);
|
|
|
|
const handleEditBasic = useCallback(() => {
|
|
log('handleEditBasic');
|
|
navigateTo(PageUrl.MaterialEditProfile, { type: ProfileGroupType.Basic });
|
|
}, []);
|
|
|
|
const handleEditGroupItem = useCallback((groupType: ProfileGroupType) => {
|
|
log('handleEditGroupItem', groupType);
|
|
navigateTo(PageUrl.MaterialEditProfile, { type: groupType });
|
|
}, []);
|
|
|
|
const videoLength = videos.length ? videos.length : 0;
|
|
const showSwiperButton = videoLength > 1 && isDesktop;
|
|
|
|
const handleChange = useCallback((e: BaseEventOrig<onChangeEventDetail>) => {
|
|
setCoverIndex(e.detail.current);
|
|
}, []);
|
|
|
|
const handlePrev = useCallback(() => {
|
|
setCoverIndex(coverIndex ? coverIndex - 1 : videoLength - 1);
|
|
}, [coverIndex, videoLength]);
|
|
|
|
const handleNext = useCallback(() => {
|
|
setCoverIndex(coverIndex === videoLength - 1 ? 0 : coverIndex + 1);
|
|
}, [coverIndex, videoLength]);
|
|
|
|
return (
|
|
<div className={PREFIX}>
|
|
<div className={`${PREFIX}__header`}>
|
|
<Swiper className={`${PREFIX}__header__swiper`} current={coverIndex} onChange={handleChange} circular>
|
|
{videos.map((cover, index) => (
|
|
<SwiperItem key={cover.coverUrl}>
|
|
<div className={`${PREFIX}__header__swiper-item`}>
|
|
<Image
|
|
mode="aspectFill"
|
|
src={cover.coverUrl}
|
|
className={`${PREFIX}__header__cover`}
|
|
onClick={() => handleClickVideo(index)}
|
|
/>
|
|
{cover.type === 'video' && (
|
|
<Image
|
|
className={`${PREFIX}__header__cover-preview`}
|
|
mode="aspectFit"
|
|
src={require('@/statics/svg/preview_video.svg')}
|
|
onClick={() => handleClickVideo(index)}
|
|
/>
|
|
)}
|
|
</div>
|
|
</SwiperItem>
|
|
))}
|
|
</Swiper>
|
|
{showSwiperButton && (
|
|
<div className={`${PREFIX}__header__swiper-button__prev`} onClick={handlePrev}>
|
|
<Image
|
|
className={`${PREFIX}__header__swiper-button__image`}
|
|
mode="aspectFit"
|
|
src={require('@/statics/svg/arrow-left-thin.svg')}
|
|
/>
|
|
</div>
|
|
)}
|
|
{showSwiperButton && (
|
|
<div className={`${PREFIX}__header__swiper-button__next`} onClick={handleNext}>
|
|
<Image
|
|
className={`${PREFIX}__header__swiper-button__image`}
|
|
mode="aspectFit"
|
|
src={require('@/statics/svg/arrow-right-thin.svg')}
|
|
/>
|
|
</div>
|
|
)}
|
|
{editable && (
|
|
<div className={`${PREFIX}__header__edit-video`} onClick={handleEditVideo}>
|
|
编辑录屏
|
|
</div>
|
|
)}
|
|
<div className={`${PREFIX}__header__banner`}>
|
|
<div>{videos[coverIndex]?.title || ''}</div>
|
|
<div
|
|
className={`${PREFIX}__header__video-size`}
|
|
>{`${coverIndex + 1}/${profile.materialVideoInfoList.length}`}</div>
|
|
</div>
|
|
</div>
|
|
{!editable && <JoinGroupHint />}
|
|
<div className={`${PREFIX}__body`}>
|
|
<div className={`${PREFIX}__basic-info`}>
|
|
<div className={`${PREFIX}__basic-info__name-container`}>
|
|
<DevDiv className={`${PREFIX}__basic-info__name`} OnDev={onDev}>
|
|
{profile.name}
|
|
</DevDiv>
|
|
{editable && (
|
|
<div className={`${PREFIX}__basic-info__edit`} onClick={handleEditBasic}>
|
|
编辑
|
|
</div>
|
|
)}
|
|
</div>
|
|
<div className={`${PREFIX}__basic-info__content`}>{getBasicInfo(profile)}</div>
|
|
<div className={`${PREFIX}__divider`} />
|
|
</div>
|
|
{dataGroup.map((data, index: number) => (
|
|
<div className={`${PREFIX}__info-group`} key={data.type}>
|
|
<div className={`${PREFIX}__info-group__header`}>
|
|
{index ? (
|
|
<div className={`${PREFIX}__info-group__header__title`}>{data.title}</div>
|
|
) : (
|
|
<DevDiv className={`${PREFIX}__info-group__header__title`} OnDev={onDev}>
|
|
{data.title}
|
|
</DevDiv>
|
|
)}
|
|
{editable && (
|
|
<div className={`${PREFIX}__info-group__header__edit`} onClick={() => handleEditGroupItem(data.type)}>
|
|
编辑
|
|
</div>
|
|
)}
|
|
</div>
|
|
<div className={`${PREFIX}__info-group__items`}>
|
|
{data.items.map(item => (
|
|
<div
|
|
key={String(item.value)}
|
|
className={classNames(`${PREFIX}__info-group__item`, { 'full-line': item.fullLine })}
|
|
>
|
|
<div className={`${PREFIX}__info-group__item__title`}>{item.title}</div>
|
|
<div className={`${PREFIX}__info-group__item__value`}>{item.value}</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
{index !== dataGroup.length - 1 && <div className={`${PREFIX}__divider`} />}
|
|
</div>
|
|
))}
|
|
</div>
|
|
<SafeBottomPadding />
|
|
</div>
|
|
);
|
|
}
|