feat: first commit
This commit is contained in:
54
src/components/message-chat/base/index.less
Normal file
54
src/components/message-chat/base/index.less
Normal file
@ -0,0 +1,54 @@
|
||||
@import '@/styles/common.less';
|
||||
@import '@/styles/variables.less';
|
||||
|
||||
.base-message {
|
||||
width: 100%;
|
||||
.flex-row();
|
||||
align-items: flex-start;
|
||||
margin-top: 40px;
|
||||
padding: 0 32px;
|
||||
box-sizing: border-box;
|
||||
|
||||
&.is-sender {
|
||||
flex-direction: row-reverse;
|
||||
}
|
||||
|
||||
&__avatar {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
&__content-container {
|
||||
flex: 1;
|
||||
.flex-column();
|
||||
align-items: flex-start;
|
||||
margin: 0 16px;
|
||||
|
||||
.is-sender & {
|
||||
align-items: flex-end;
|
||||
}
|
||||
}
|
||||
|
||||
&__content {
|
||||
font-size: 28px;
|
||||
line-height: 40px;
|
||||
font-weight: 400;
|
||||
color: #1D2129;
|
||||
background: #D9D9D9;
|
||||
padding: 20px 24px;
|
||||
border-radius: 20px;
|
||||
}
|
||||
|
||||
&__status {
|
||||
font-size: 20px;
|
||||
line-height: 28px;
|
||||
font-weight: 400;
|
||||
color: @blHighlightColor;
|
||||
margin-top: 8px;
|
||||
|
||||
&.done {
|
||||
color: #8D8E99;
|
||||
}
|
||||
}
|
||||
}
|
||||
66
src/components/message-chat/base/index.tsx
Normal file
66
src/components/message-chat/base/index.tsx
Normal file
@ -0,0 +1,66 @@
|
||||
import { Image } from '@tarojs/components';
|
||||
|
||||
import classNames from 'classnames';
|
||||
import { PropsWithChildren, useEffect, useState, useCallback } from 'react';
|
||||
import { MaterialViewSource } from '@/constants/material';
|
||||
|
||||
import useUserInfo from '@/hooks/use-user-info';
|
||||
import { IChatMessage } from '@/types/message';
|
||||
import { getScrollItemId } from '@/utils/common';
|
||||
import { navigateTo } from '@/utils/route';
|
||||
import { PageUrl } from '@/constants/app';
|
||||
|
||||
import './index.less';
|
||||
|
||||
export interface IBaseMessageProps {
|
||||
id: string;
|
||||
message: IChatMessage;
|
||||
}
|
||||
|
||||
export interface IUserMessageProps extends PropsWithChildren, IBaseMessageProps {
|
||||
isRead?: boolean;
|
||||
}
|
||||
|
||||
const PREFIX = 'base-message';
|
||||
|
||||
function BaseMessage(props: IUserMessageProps) {
|
||||
const { id, message, isRead: isReadProps, children } = props;
|
||||
const { userId } = useUserInfo();
|
||||
const [isRead, setIsRead] = useState(message.isRead);
|
||||
const isSender = message.senderUserId === userId;
|
||||
|
||||
// useEffect(() => {
|
||||
// if (isSender) {
|
||||
// return;
|
||||
// }
|
||||
// // 对方发的消息,拉取到消息后,后端会主动已读,这里延迟模拟下
|
||||
// const timer = setTimeout(() => setIsRead(true), 1200);
|
||||
// return () => clearTimeout(timer);
|
||||
// }, [isSender]);
|
||||
const handleClick = useCallback(
|
||||
() => navigateTo(PageUrl.MaterialView, { resumeId: message.jobId, source: MaterialViewSource.Chat }),
|
||||
[message.jobId]
|
||||
);
|
||||
useEffect(() => {
|
||||
if (isRead) {
|
||||
return;
|
||||
}
|
||||
isReadProps && setIsRead(true);
|
||||
}, [isRead, isReadProps]);
|
||||
|
||||
return (
|
||||
<div className={classNames(PREFIX, { 'is-sender': isSender })} id={getScrollItemId(id)}>
|
||||
<Image
|
||||
mode="aspectFit"
|
||||
className={`${PREFIX}__avatar`}
|
||||
src={message.senderAvatarUrl || require('@/statics/png/default_avatar.png')}
|
||||
/>
|
||||
<div className={`${PREFIX}__content-container`}>
|
||||
{children}
|
||||
<div className={classNames(`${PREFIX}__status`, { done: isRead })}>{isRead ? '已读' : '未读'}</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default BaseMessage;
|
||||
50
src/components/message-chat/contact/index.less
Normal file
50
src/components/message-chat/contact/index.less
Normal file
@ -0,0 +1,50 @@
|
||||
@import '@/styles/common.less';
|
||||
@import '@/styles/variables.less';
|
||||
|
||||
.exchange-message {
|
||||
width: 100%;
|
||||
.flex-column();
|
||||
margin-top: 40px;
|
||||
|
||||
&__content {
|
||||
padding: 24px 60px;
|
||||
background: #FFFFFF;
|
||||
border-radius: 20px;
|
||||
}
|
||||
|
||||
&__title {
|
||||
font-size: 28px;
|
||||
line-height: 40px;
|
||||
font-weight: 400;
|
||||
color: @blColor;
|
||||
}
|
||||
|
||||
&__buttons {
|
||||
.flex-row();
|
||||
justify-content: center;
|
||||
margin-top: 32px;
|
||||
}
|
||||
|
||||
&__reject {
|
||||
.button(@width: 176px; @height: 56px; @fontSize: 28px; @borderRadius: 48px);
|
||||
border: 2px solid #E0E0E0;
|
||||
color: @blColor;
|
||||
background: #FFF;
|
||||
margin-right: 24px;
|
||||
}
|
||||
|
||||
&__agree {
|
||||
.button(@width: 176px; @height: 56px; @fontSize: 28px; @borderRadius: 48px);
|
||||
}
|
||||
|
||||
&__disable-btn {
|
||||
.button(@height: 56px; @fontSize: 28px; @borderRadius: 48px);
|
||||
padding: 0 74px;
|
||||
color: #C0C0C0;
|
||||
background: #F0F0F0;
|
||||
|
||||
&:active {
|
||||
background: #F0F0F0;
|
||||
}
|
||||
}
|
||||
}
|
||||
91
src/components/message-chat/contact/index.tsx
Normal file
91
src/components/message-chat/contact/index.tsx
Normal file
@ -0,0 +1,91 @@
|
||||
import { Button } from '@tarojs/components';
|
||||
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
|
||||
import { IBaseMessageProps } from '@/components/message-chat/base';
|
||||
import { MessageActionStatus } from '@/constants/message';
|
||||
import useUserInfo from '@/hooks/use-user-info';
|
||||
import { getScrollItemId } from '@/utils/common';
|
||||
import { posConfirmAction, postAddMessageTimes, requestChatActionStatus } from '@/utils/message';
|
||||
|
||||
import './index.less';
|
||||
|
||||
interface IProps extends IBaseMessageProps {
|
||||
onClick: () => void;
|
||||
}
|
||||
|
||||
const PREFIX = 'exchange-message';
|
||||
|
||||
function ContactMessage(props: IProps) {
|
||||
const { id, message, onClick } = props;
|
||||
const { userId } = useUserInfo();
|
||||
const [status, setStatus] = useState<MessageActionStatus>();
|
||||
const isSender = message.senderUserId === userId;
|
||||
|
||||
const handleClickReject = useCallback(async () => {
|
||||
if (isSender || status !== MessageActionStatus.Send) {
|
||||
return;
|
||||
}
|
||||
postAddMessageTimes('click_reject_exchange_contact');
|
||||
await posConfirmAction({ actionId: message.actionId, status: false });
|
||||
setStatus(MessageActionStatus.Reject);
|
||||
onClick();
|
||||
}, [isSender, status, message.actionId, onClick]);
|
||||
|
||||
const handleClickAgree = useCallback(async () => {
|
||||
if (isSender || status !== MessageActionStatus.Send) {
|
||||
return;
|
||||
}
|
||||
postAddMessageTimes('click_agree_exchange_contact');
|
||||
await posConfirmAction({ actionId: message.actionId, status: true });
|
||||
setStatus(MessageActionStatus.Agree);
|
||||
onClick();
|
||||
}, [isSender, status, message.actionId, onClick]);
|
||||
|
||||
useEffect(() => {
|
||||
const init = async () => {
|
||||
const res = await requestChatActionStatus(message.actionId);
|
||||
setStatus(res);
|
||||
};
|
||||
init();
|
||||
}, [message.actionId]);
|
||||
|
||||
return (
|
||||
<div className={PREFIX} id={getScrollItemId(id)}>
|
||||
<div className={`${PREFIX}__content`}>
|
||||
<div className={`${PREFIX}__title`}>
|
||||
{isSender ? '您已向对方请求交换联系方式' : `${message.senderName}申请交换联系方式,沟通面试`}
|
||||
</div>
|
||||
<div className={`${PREFIX}__buttons`}>
|
||||
{isSender && (
|
||||
<Button className={`${PREFIX}__disable-btn`} onClick={handleClickAgree}>
|
||||
{status === MessageActionStatus.Agree
|
||||
? '对方已同意'
|
||||
: status === MessageActionStatus.Reject
|
||||
? '对方已拒绝'
|
||||
: '等待对方同意'}
|
||||
</Button>
|
||||
)}
|
||||
{!isSender && (
|
||||
<>
|
||||
{(status === MessageActionStatus.Send || !status) && (
|
||||
<>
|
||||
<Button className={`${PREFIX}__reject`} onClick={handleClickReject}>
|
||||
拒绝
|
||||
</Button>
|
||||
<Button className={`${PREFIX}__agree`} onClick={handleClickAgree}>
|
||||
同意
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
{status === MessageActionStatus.Agree && <Button className={`${PREFIX}__disable-btn`}>你已同意</Button>}
|
||||
{status === MessageActionStatus.Reject && <Button className={`${PREFIX}__disable-btn`}>你已拒绝</Button>}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default ContactMessage;
|
||||
8
src/components/message-chat/index.ts
Normal file
8
src/components/message-chat/index.ts
Normal file
@ -0,0 +1,8 @@
|
||||
import ContactMessage from './contact';
|
||||
import JobMessage from './job';
|
||||
import LocationMessage from './location';
|
||||
import MaterialMessage from './material';
|
||||
import TextMessage from './text';
|
||||
import TimeMessage from './time';
|
||||
|
||||
export { ContactMessage, JobMessage, LocationMessage, MaterialMessage, TextMessage, TimeMessage };
|
||||
29
src/components/message-chat/job/index.less
Normal file
29
src/components/message-chat/job/index.less
Normal file
@ -0,0 +1,29 @@
|
||||
@import '@/styles/common.less';
|
||||
@import '@/styles/variables.less';
|
||||
|
||||
.job-message {
|
||||
width: calc(100% - 64px);
|
||||
.flex-column();
|
||||
align-items: flex-start;
|
||||
margin: 40px 32px 0;
|
||||
padding: 20px 24px;
|
||||
background: #FFFFFF;
|
||||
border-radius: 20px;
|
||||
box-sizing: border-box;
|
||||
|
||||
&__title {
|
||||
font-size: 28px;
|
||||
line-height: 40px;
|
||||
font-weight: 500;
|
||||
color: @blColor;
|
||||
}
|
||||
|
||||
&__salary {
|
||||
font-size: 24px;
|
||||
line-height: 36px;
|
||||
font-weight: 400;
|
||||
color: @blColorG2;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
}
|
||||
38
src/components/message-chat/job/index.tsx
Normal file
38
src/components/message-chat/job/index.tsx
Normal file
@ -0,0 +1,38 @@
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import { IBaseMessageProps } from '@/components/message-chat/base';
|
||||
import { PageUrl } from '@/constants/app';
|
||||
import { IJobMessage } from '@/types/message';
|
||||
import { getScrollItemId, safeJsonParse } from '@/utils/common';
|
||||
import { getJobSalary } from '@/utils/job';
|
||||
import { navigateTo } from '@/utils/route';
|
||||
|
||||
import './index.less';
|
||||
|
||||
interface IProps extends IBaseMessageProps {}
|
||||
|
||||
const PREFIX = 'job-message';
|
||||
|
||||
function JobMessage(props: IProps) {
|
||||
const { id, message } = props;
|
||||
const data = safeJsonParse<IJobMessage>(message.actionObject, null);
|
||||
|
||||
const handleClick = useCallback(() => {
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
navigateTo(PageUrl.JobDetail, { id: data.id });
|
||||
}, [data]);
|
||||
|
||||
if (!data) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<div className={PREFIX} id={getScrollItemId(id)} onClick={handleClick}>
|
||||
<div className={`${PREFIX}__title`}>{data.title}</div>
|
||||
<div className={`${PREFIX}__salary`}>{getJobSalary(data)}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default JobMessage;
|
||||
45
src/components/message-chat/location/index.less
Normal file
45
src/components/message-chat/location/index.less
Normal file
@ -0,0 +1,45 @@
|
||||
@import '@/styles/common.less';
|
||||
@import '@/styles/variables.less';
|
||||
|
||||
.location-message {
|
||||
&__map-container {
|
||||
width: 440px;
|
||||
.flex-column();
|
||||
align-items: flex-start;
|
||||
background: #FFF;
|
||||
border-radius: 20px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
&__name {
|
||||
font-size: 28px;
|
||||
line-height: 40px;
|
||||
font-weight: 400;
|
||||
color: @blColor;
|
||||
margin: 20px 20px 0;
|
||||
.noWrap();
|
||||
}
|
||||
|
||||
&__address {
|
||||
font-size: 24px;
|
||||
line-height: 36px;
|
||||
font-weight: 400;
|
||||
color: @blColorG1;
|
||||
margin: 4px 20px 20px;
|
||||
.noWrap();
|
||||
}
|
||||
|
||||
&__map {
|
||||
width: 100%;
|
||||
height: 160px;
|
||||
}
|
||||
|
||||
&__mask {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
}
|
||||
69
src/components/message-chat/location/index.tsx
Normal file
69
src/components/message-chat/location/index.tsx
Normal file
@ -0,0 +1,69 @@
|
||||
import { Map } from '@tarojs/components';
|
||||
import Taro from '@tarojs/taro';
|
||||
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import BaseMessage, { IUserMessageProps } from '@/components/message-chat/base';
|
||||
import { ILocationMessage } from '@/types/message';
|
||||
import { safeJsonParse } from '@/utils/common';
|
||||
import Toast from '@/utils/toast';
|
||||
|
||||
import './index.less';
|
||||
|
||||
interface IProps extends IUserMessageProps {}
|
||||
|
||||
const PREFIX = 'location-message';
|
||||
|
||||
function LocationMessage(props: IProps) {
|
||||
const { message } = props;
|
||||
const data = safeJsonParse<ILocationMessage>(message.actionObject, null);
|
||||
|
||||
const handleClickMap = useCallback(
|
||||
(e: React.MouseEvent) => {
|
||||
e.stopPropagation();
|
||||
Taro.openLocation({
|
||||
name: data.name,
|
||||
address: data.address,
|
||||
longitude: Number(data.longitude),
|
||||
latitude: Number(data.latitude),
|
||||
scale: 18,
|
||||
});
|
||||
},
|
||||
[data]
|
||||
);
|
||||
|
||||
if (!data) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<BaseMessage {...props}>
|
||||
<div className={`${PREFIX}__map-container`} onClick={handleClickMap}>
|
||||
<div className={`${PREFIX}__name`}>{data.name}</div>
|
||||
<div className={`${PREFIX}__address`}>{data.address}</div>
|
||||
<Map
|
||||
scale={15}
|
||||
enableZoom={false}
|
||||
enableScroll={false}
|
||||
className={`${PREFIX}__map`}
|
||||
latitude={Number(data.latitude)}
|
||||
longitude={Number(data.longitude)}
|
||||
markers={[
|
||||
{
|
||||
id: 0,
|
||||
latitude: Number(data.latitude),
|
||||
longitude: Number(data.longitude),
|
||||
iconPath: '',
|
||||
width: 20,
|
||||
height: 28,
|
||||
},
|
||||
]}
|
||||
onError={() => Toast.error('地图加载错误')}
|
||||
/>
|
||||
<div className={`${PREFIX}__mask`} onClick={handleClickMap} />
|
||||
</div>
|
||||
</BaseMessage>
|
||||
);
|
||||
}
|
||||
|
||||
export default LocationMessage;
|
||||
30
src/components/message-chat/material/index.less
Normal file
30
src/components/message-chat/material/index.less
Normal file
@ -0,0 +1,30 @@
|
||||
@import '@/styles/common.less';
|
||||
@import '@/styles/variables.less';
|
||||
|
||||
.material-message {
|
||||
width: calc(100% - 64px);
|
||||
.flex-column();
|
||||
align-items: flex-start;
|
||||
margin: 40px 32px 0;
|
||||
padding: 20px 24px;
|
||||
background: #FFFFFF;
|
||||
border-radius: 20px;
|
||||
box-sizing: border-box;
|
||||
|
||||
&__name {
|
||||
font-size: 28px;
|
||||
line-height: 40px;
|
||||
font-weight: 500;
|
||||
color: @blColor;
|
||||
}
|
||||
|
||||
&__basic,
|
||||
&__categories {
|
||||
font-size: 24px;
|
||||
line-height: 36px;
|
||||
font-weight: 400;
|
||||
color: @blColorG2;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
}
|
||||
41
src/components/message-chat/material/index.tsx
Normal file
41
src/components/message-chat/material/index.tsx
Normal file
@ -0,0 +1,41 @@
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import { IBaseMessageProps } from '@/components/message-chat/base';
|
||||
import { PageUrl } from '@/constants/app';
|
||||
import { MaterialViewSource } from '@/constants/material';
|
||||
import { IMaterialMessage } from '@/types/message';
|
||||
import { getScrollItemId, safeJsonParse } from '@/utils/common';
|
||||
import { getBasicInfo } from '@/utils/material';
|
||||
import { navigateTo } from '@/utils/route';
|
||||
|
||||
import './index.less';
|
||||
|
||||
interface IProps extends IBaseMessageProps {}
|
||||
|
||||
const PREFIX = 'material-message';
|
||||
|
||||
function MaterialMessage(props: IProps) {
|
||||
const { id, message } = props;
|
||||
const data = safeJsonParse<IMaterialMessage>(message.actionObject, null);
|
||||
|
||||
const handleClick = useCallback(() => {
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
navigateTo(PageUrl.MaterialView, { resumeId: data.id, source: MaterialViewSource.Chat });
|
||||
}, [data]);
|
||||
|
||||
if (!data) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={PREFIX} id={getScrollItemId(id)} onClick={handleClick}>
|
||||
<div className={`${PREFIX}__name`}>{data.name}</div>
|
||||
<div className={`${PREFIX}__basic`}>{getBasicInfo(data)}</div>
|
||||
<div className={`${PREFIX}__categories`}>{`播过 ${data.workedSecCategoryStr}`}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default MaterialMessage;
|
||||
14
src/components/message-chat/text/index.less
Normal file
14
src/components/message-chat/text/index.less
Normal file
@ -0,0 +1,14 @@
|
||||
@import '@/styles/common.less';
|
||||
@import '@/styles/variables.less';
|
||||
|
||||
.text-message {
|
||||
&__content {
|
||||
font-size: 28px;
|
||||
line-height: 40px;
|
||||
font-weight: 400;
|
||||
color: #1D2129;
|
||||
background: #D9D9D9;
|
||||
padding: 20px 24px;
|
||||
border-radius: 20px;
|
||||
}
|
||||
}
|
||||
32
src/components/message-chat/text/index.tsx
Normal file
32
src/components/message-chat/text/index.tsx
Normal file
@ -0,0 +1,32 @@
|
||||
import { Text } from '@tarojs/components';
|
||||
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import BaseMessage, { IUserMessageProps } from '@/components/message-chat/base';
|
||||
import { copy } from '@/utils/common';
|
||||
import Toast from '@/utils/toast';
|
||||
|
||||
import './index.less';
|
||||
|
||||
interface IProps extends IUserMessageProps {}
|
||||
|
||||
const PREFIX = 'text-message';
|
||||
|
||||
function TextMessage(props: IProps) {
|
||||
const { message } = props;
|
||||
|
||||
const handleLongPress = useCallback(async () => {
|
||||
await copy(message.content);
|
||||
Toast.success('复制成功');
|
||||
}, [message.content]);
|
||||
|
||||
return (
|
||||
<BaseMessage {...props}>
|
||||
<Text className={`${PREFIX}__content`} onLongPress={handleLongPress}>
|
||||
{message.content}
|
||||
</Text>
|
||||
</BaseMessage>
|
||||
);
|
||||
}
|
||||
|
||||
export default TextMessage;
|
||||
12
src/components/message-chat/time/index.less
Normal file
12
src/components/message-chat/time/index.less
Normal file
@ -0,0 +1,12 @@
|
||||
@import '@/styles/common.less';
|
||||
@import '@/styles/variables.less';
|
||||
|
||||
.time-message {
|
||||
width: 100%;
|
||||
font-size: 28px;
|
||||
line-height: 40px;
|
||||
font-weight: 400;
|
||||
text-align: center;
|
||||
color: #8D8E99;
|
||||
margin-top: 40px;
|
||||
}
|
||||
20
src/components/message-chat/time/index.tsx
Normal file
20
src/components/message-chat/time/index.tsx
Normal file
@ -0,0 +1,20 @@
|
||||
import { IBaseMessageProps } from '@/components/message-chat/base';
|
||||
import { getScrollItemId } from '@/utils/common';
|
||||
import { formatTime } from '@/utils/time';
|
||||
|
||||
import './index.less';
|
||||
|
||||
interface IProps extends IBaseMessageProps {}
|
||||
|
||||
const PREFIX = 'time-message';
|
||||
|
||||
function TimeMessage(props: IProps) {
|
||||
const { id, message } = props;
|
||||
return (
|
||||
<div className={PREFIX} id={getScrollItemId(id)}>
|
||||
{formatTime(message.content, 'MM-DD HH:mm')}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default TimeMessage;
|
||||
Reference in New Issue
Block a user