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,3 @@
export default definePageConfig({
navigationBarTitleText: '个人认证',
});

View File

@ -0,0 +1,79 @@
@import '@/styles/common.less';
@import '@/styles/variables.less';
.page-certification {
padding: 40px 24px;
&__id-card-container {
width: 100%;
.flex-row();
}
&__id-card {
flex: 1;
height: 178px;
.flex-column();
justify-content: center;
background: #F2F2F2;
border-radius: 12px;
margin: 24px 0;
&:first-child {
margin-right: 24px;
}
&__image {
width: 100%;
height: 100%;
}
&__icon {
width: 72px;
height: 72px;
}
&__describe {
font-size: 24px;
line-height: 32px;
font-weight: 400;
color: @blColorG1;
margin-top: 24px;
}
}
&__verify {
.flex-column();
&__input {
flex: 1;
height: 100px;
}
&__code-container {
width: 100%;
.flex-row();
}
&__send {
font-size: 32px;
line-height: 32px;
font-weight: 400;
color: @blHighlightColor;
white-space: nowrap;
}
}
&__footer {
position: fixed;
left: 24px;
right: 24px;
bottom: 0;
background: #F5F6FA;
padding-top: 30px;
}
&__submit {
.button(@width: 100%; @height: 80px);
margin-bottom: 56px;
}
}

View File

@ -0,0 +1,252 @@
import { BaseEventOrig, Button, Image, InputProps } from '@tarojs/components';
import Taro, { UploadTask } from '@tarojs/taro';
import { useCallback, useEffect, useState } from 'react';
import BlFormInput from '@/components/bl-form-input';
import BlFormItem from '@/components/bl-form-item';
import LoadingDialog from '@/components/loading-dialog';
import SafeBottomPadding from '@/components/safe-bottom-padding';
import { PageUrl } from '@/constants/app';
import { CertificationStatusType } from '@/constants/company';
import { CollectEventName, ReportEventId } from '@/constants/event';
import useUserInfo from '@/hooks/use-user-info';
import { ICertificationRequest } from '@/types/company';
import { isValidIdCard, isValidPhone, logWithPrefix } from '@/utils/common';
import { postCertification } from '@/utils/company';
import { collectEvent, reportEvent } from '@/utils/event';
import { chooseMedia } from '@/utils/material';
import { redirectTo } from '@/utils/route';
import Toast from '@/utils/toast';
import { dispatchUpdateUser, requestUserInfo } from '@/utils/user';
import { uploadVideo } from '@/utils/video';
import './index.less';
const PREFIX = 'page-certification';
const log = logWithPrefix(PREFIX);
const needIdCard = false;
const isValidCertificationInfo = (data: ICertificationRequest) => {
const {
name,
// code,
phone,
idCardNo: idNumber,
companyName: company,
// idCardSideAUrl: leftIdCardUrl,
// idCardSideBUrl: rightIdCardUrl,
} = data;
// if (!leftIdCardUrl || !rightIdCardUrl) {
// return '请上传身份证照片';
// }
if (!name) {
return '请输入姓名';
}
if (!idNumber || !isValidIdCard(idNumber)) {
return '请输入正确的身份证';
}
if (!phone || !isValidPhone(phone)) {
return '请输入正确的手机号';
}
// if (!code) {
// return '验证码不能为空';
// }
if (!company) {
return '请输入公司名称';
}
};
const uploadIdCard = async () => {
let showLoading = false;
try {
const media = await chooseMedia({
count: 1,
mediaType: ['image'],
sourceType: ['album', 'camera'],
});
if (!media) {
return;
}
const { tempFiles } = media;
const tempFile = tempFiles[0];
if (!tempFile) {
throw new Error('tempFile is not exist');
}
showLoading = true;
Taro.showLoading({ title: '上传0%' });
const onProgress: UploadTask.OnProgressUpdateCallback = res => {
log('上传视频进度', res.progress, '总长度', res.totalBytesExpectedToSend, '已上传的长度', res.totalBytesSent);
Taro.showLoading({ title: `上传${res.progress}%` });
};
const { url } = await uploadVideo(tempFile.tempFilePath, tempFile.fileType, onProgress, 'id-card');
return url;
} catch (e) {
console.error('upload fail', e);
Toast.error('上传失败');
collectEvent(CollectEventName.UPDATE_ID_CARD_FAILED, e);
} finally {
showLoading && Taro.hideLoading();
}
};
export default function Certification() {
const { phone } = useUserInfo();
const [leftIdCardUrl, setLeftIdCardUrl] = useState('');
const [rightIdCardUrl, setRightIdCardUrl] = useState('');
const [name, setName] = useState('');
const [idNumber, setIdNumber] = useState('');
// const [code, setCode] = useState('');
const [company, setCompany] = useState('');
const [open, setOpen] = useState(false);
const handleClickIdCardLeft = useCallback(async () => {
reportEvent(ReportEventId.CLICK_UPLOAD_ID_CARD, { type: 'left' });
const url = await uploadIdCard();
url && setLeftIdCardUrl(url);
}, []);
const handleClickIdCardRight = useCallback(async () => {
reportEvent(ReportEventId.CLICK_START_CERTIFICATION, { type: 'right' });
const url = await uploadIdCard();
url && setRightIdCardUrl(url);
}, []);
const handleInputName = useCallback((e: BaseEventOrig<InputProps.inputEventDetail>) => {
const value = e.detail.value || '';
setName(value);
}, []);
const handleInputIdNumber = useCallback((e: BaseEventOrig<InputProps.inputEventDetail>) => {
const value = e.detail.value || '';
setIdNumber(value);
}, []);
// const handleInputCode = useCallback((e: BaseEventOrig<InputProps.inputEventDetail>) => {
// const value = e.detail.value || '';
// setCode(value);
// }, []);
const handleInputCompany = useCallback((e: BaseEventOrig<InputProps.inputEventDetail>) => {
const value = e.detail.value || '';
setCompany(value);
}, []);
const handleSubmit = useCallback(async () => {
reportEvent(ReportEventId.CLICK_CERTIFICATION_SUBMIT);
const data: ICertificationRequest = {
name,
// code,
phone,
idCardNo: idNumber,
companyName: company,
// idCardSideAUrl: leftIdCardUrl,
// idCardSideBUrl: rightIdCardUrl,
};
const errMsg = isValidCertificationInfo(data);
if (errMsg) {
Toast.info(errMsg);
return;
}
try {
setOpen(true);
const { authSuc, msg } = await postCertification(data);
if (!authSuc) {
Toast.info(msg || '认证失败');
return;
}
dispatchUpdateUser({ bossAuthStatus: CertificationStatusType.Success });
redirectTo(PageUrl.CertificationManage);
} catch (e) {
console.error('submit error', e);
Toast.error('认证失败请重试');
collectEvent(CollectEventName.SUBMIT_CERTIFICATION_FAILED, e);
} finally {
setOpen(false);
}
}, [name, idNumber, phone, company]);
// }, [leftIdCardUrl, rightIdCardUrl, name, idNumber, phone, company]);
useEffect(() => {
if (phone) {
return;
}
const requestPhone = async () => {
collectEvent(CollectEventName.CERTIFICATION_PAGE, { info: 'start requestPhone' });
const userInfo = await requestUserInfo();
collectEvent(CollectEventName.CERTIFICATION_PAGE, { info: 'requestPhone success', phone: userInfo.phone });
};
requestPhone();
}, [phone]);
return (
<div className={PREFIX}>
{needIdCard && (
<BlFormItem title="上传身份证照片" subTitle={false} dynamicHeight>
<div className={`${PREFIX}__id-card-container`}>
<div className={`${PREFIX}__id-card`} onClick={handleClickIdCardLeft}>
{leftIdCardUrl && <Image mode="aspectFit" className={`${PREFIX}__id-card__image`} src={leftIdCardUrl} />}
{!leftIdCardUrl && (
<>
<Image
mode="aspectFit"
className={`${PREFIX}__id-card__icon`}
src={require('@/statics/svg/upload-id-card-icon.svg')}
/>
<div className={`${PREFIX}__id-card__describe`}></div>
</>
)}
</div>
<div className={`${PREFIX}__id-card`} onClick={handleClickIdCardRight}>
{rightIdCardUrl && (
<Image mode="aspectFit" className={`${PREFIX}__id-card__image`} src={rightIdCardUrl} />
)}
{!rightIdCardUrl && (
<>
<Image
mode="aspectFit"
className={`${PREFIX}__id-card__icon`}
src={require('@/statics/svg/upload-id-card-icon.svg')}
/>
<div className={`${PREFIX}__id-card__describe`}></div>
</>
)}
</div>
</div>
</BlFormItem>
)}
<BlFormItem title="姓名" subTitle={false}>
<BlFormInput value={name} onInput={handleInputName} />
</BlFormItem>
<BlFormItem title="身份证号" subTitle={false}>
<BlFormInput value={idNumber} onInput={handleInputIdNumber} type="idcard" maxlength={18} />
</BlFormItem>
<BlFormItem title="手机号" subTitle="请使用本人名下的手机号" contentClassName={`${PREFIX}__verify`} dynamicHeight>
<BlFormInput className={`${PREFIX}__verify__input`} value={phone} type="number" maxlength={11} disabled />
{/* <div className={`${PREFIX}__verify__code-container`}>
<BlFormInput
className={`${PREFIX}__verify__input`}
value={code}
onInput={handleInputCode}
type="number"
maxlength={8}
/>
<div className={`${PREFIX}__verify__send`}>获取验证码</div>
</div> */}
</BlFormItem>
<BlFormItem title="公司全称" subTitle={false}>
<BlFormInput maxlength={200} value={company} onInput={handleInputCompany} />
</BlFormItem>
<SafeBottomPadding />
<div className={`${PREFIX}__footer`}>
<Button className={`${PREFIX}__submit`} onClick={handleSubmit}>
</Button>
<SafeBottomPadding />
</div>
<div>
<LoadingDialog open={open} text="认证中" />
</div>
</div>
);
}