feat: first commit

This commit is contained in:
eleanor.mao
2025-03-31 22:34:22 +08:00
commit d25187c9c8
390 changed files with 57031 additions and 0 deletions

View File

@ -0,0 +1,117 @@
@import '@/styles/common.less';
@import '@/styles/variables.less';
.material-card {
padding: 32px 24px;
border-radius: 16px;
background: #FFFFFF;
box-sizing: border-box;
&__header {
.flex-row();
justify-content: space-between;
&__left,
&__right {
.flex-row();
}
&__title {
font-size: 32px;
line-height: 40px;
font-weight: 400;
color: @blColor;
}
&__progress {
font-size: 28px;
line-height: 32px;
font-weight: 400;
color: @blHighlightColor;
margin-left: 8px;
}
&__status {
font-size: 28px;
line-height: 32px;
font-weight: 400;
color: @blColorG1;
margin-right: 4px;
}
&__icon {
.flex-row();
height: 48px;
font-size: 32px;
line-height: 48px;
color: #969799;
}
}
&__body {
width: 100%;
height: 156px;
margin-top: 24px;
.flex-column();
justify-content: center;
}
&__placeholder {
height: 100%;
.flex-column();
justify-content: center;
&__tips {
font-size: 28px;
line-height: 32px;
font-weight: 400;
color: @blColorG1;
}
&__create-button {
.button();
font-size: 28px;
line-height: 32px;
font-weight: 400;
color: @blHighlightColor;
margin-top: 22px;
background: transparent;
border-radius: 0;
}
}
&__scroll-view {
position: relative;
width: 100%;
height: 100%;
.flex-row();
&::-webkit-scrollbar {
display: none;
}
&::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

@ -0,0 +1,145 @@
import { Image, ScrollView } from '@tarojs/components';
import Taro from '@tarojs/taro';
import { Loading } from '@taroify/core';
import { ArrowRight } from '@taroify/icons';
import classNames from 'classnames';
import { useCallback, useEffect, useRef, useState } from 'react';
import LoginButton from '@/components/login-button';
import { EventName, PageUrl } from '@/constants/app';
import { CollectEventName, ReportEventId } from '@/constants/event';
import useUserInfo from '@/hooks/use-user-info';
import { MaterialProfile } from '@/types/material';
import { logWithPrefix } from '@/utils/common';
import { collectEvent, reportEvent } from '@/utils/event';
import { requestProfileDetail, sortVideos } from '@/utils/material';
import { navigateTo } from '@/utils/route';
import Toast from '@/utils/toast';
import { isValidUserInfo } from '@/utils/user';
import './index.less';
interface IProps {
className?: string;
}
const PREFIX = 'material-card';
const log = logWithPrefix(PREFIX);
const realtimeLogger = Taro.getRealtimeLogManager();
realtimeLogger.tag(PREFIX);
function MaterialCard(props: IProps) {
const { className } = props;
const userInfo = useUserInfo();
const [loading, setLoading] = useState(true);
const [profile, setProfile] = useState<MaterialProfile | null>(null);
const refreshRef = useRef((_f?: boolean) => { });
const hasMaterial = !!profile;
const handleGoCreateProfile = useCallback(() => {
reportEvent(ReportEventId.CLICK_GO_TO_CREATE_MATERIAL);
navigateTo(PageUrl.MaterialUploadVideo);
}, []);
const handleGoProfile = useCallback(() => {
if (!hasMaterial) {
realtimeLogger.info('handleGoProfile noMaterial')
return;
}
navigateTo(PageUrl.MaterialProfile).catch(err => {
realtimeLogger.error('handleGoProfile Failed', err);
});
}, [hasMaterial]);
useEffect(() => {
refreshRef.current = async (force: boolean = false) => {
collectEvent(CollectEventName.MATERIAL_CARD_VIEW, {
status: 'refresh',
info: { force, isCreateResume: userInfo.isCreateResume },
});
setLoading(true);
if (!userInfo.isCreateResume && !force) {
log('refresh break by is not create resume');
setLoading(false);
return;
}
try {
const profileDetail = await requestProfileDetail();
if (!profileDetail) {
realtimeLogger.info('getProfileDetail no profileDetail')
}
setProfile(profileDetail);
} catch (e) {
realtimeLogger.error('getProfileDetail Failed', e);
Toast.error('加载失败');
}
setLoading(false);
};
}, [userInfo]);
useEffect(() => {
if (!isValidUserInfo(userInfo)) {
return;
}
refreshRef.current?.(true);
}, [userInfo]);
useEffect(() => {
const callback = async () => {
refreshRef.current?.(true);
};
Taro.eventCenter.on(EventName.CREATE_PROFILE, callback);
return () => {
Taro.eventCenter.off(EventName.CREATE_PROFILE, callback);
};
}, [userInfo]);
return (
<div className={classNames(PREFIX, className)} onClick={handleGoProfile}>
<div className={`${PREFIX}__header`}>
<div className={`${PREFIX}__header__left`}>
<div className={`${PREFIX}__header__title`}></div>
{/* {profile && (
<div
className={`${PREFIX}__header__progress`}
>{`完成度${Math.min((profile.progressBar || 0) * 100, 100)}%`}</div>
)} */}
</div>
{profile && (
<div className={`${PREFIX}__header__right`}>
{/* <div className={`${PREFIX}__header__status`}>{profile?.isOpen ? '开放中' : '关闭'}</div> */}
<ArrowRight className={`${PREFIX}__header__icon`} />
</div>
)}
</div>
<div className={`${PREFIX}__body`}>
{!loading && !hasMaterial && (
<div className={`${PREFIX}__placeholder`}>
<div className={`${PREFIX}__placeholder__tips`}></div>
<LoginButton className={`${PREFIX}__placeholder__create-button`} onClick={handleGoCreateProfile}>
</LoginButton>
</div>
)}
{!loading && hasMaterial && (
<ScrollView className={`${PREFIX}__scroll-view`} showScrollbar={false} enableFlex enhanced scrollX>
<div className={`${PREFIX}__cover-list`}>
{sortVideos(profile?.materialVideoInfoList || []).map(video => (
<Image
className={`${PREFIX}__cover-image`}
mode="aspectFit"
key={video.coverUrl}
src={video.coverUrl}
/>
))}
</div>
</ScrollView>
)}
{loading && <Loading />}
</div>
</div>
);
}
export default MaterialCard;