feat: first commit
This commit is contained in:
223
src/fragments/profile/view/index.tsx
Normal file
223
src/fragments/profile/view/index.tsx
Normal file
@ -0,0 +1,223 @@
|
||||
import { Image } from '@tarojs/components';
|
||||
import Taro from '@tarojs/taro';
|
||||
|
||||
import { Swiper } from '@taroify/core';
|
||||
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';
|
||||
|
||||
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 });
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className={PREFIX}>
|
||||
<div className={`${PREFIX}__header`}>
|
||||
<Swiper className={`${PREFIX}__header__swiper`} onChange={setCoverIndex} stopPropagation={false} lazyRender>
|
||||
{videos.map((cover, index) => (
|
||||
<Swiper.Item 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>
|
||||
</Swiper.Item>
|
||||
))}
|
||||
</Swiper>
|
||||
{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>
|
||||
<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`}>
|
||||
<div className={`${PREFIX}__info-group__header__title`}>{data.title}</div>
|
||||
{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>
|
||||
);
|
||||
}
|
Reference in New Issue
Block a user