-
3package.json
-
12src/api/index.ts
-
BINsrc/assets/avatar.png
-
BINsrc/assets/buy-success.png
-
BINsrc/assets/cover.png
-
BINsrc/assets/nft/dragon.jpg
-
BINsrc/assets/nft/兔.jpg
-
BINsrc/assets/nft/牛.jpg
-
BINsrc/assets/nft/狗.jpg
-
BINsrc/assets/nft/猪.jpg
-
BINsrc/assets/nft/猴.jpg
-
BINsrc/assets/nft/羊.jpg
-
BINsrc/assets/nft/虎.jpg
-
BINsrc/assets/nft/蛇.jpg
-
BINsrc/assets/nft/马.jpg
-
BINsrc/assets/nft/鸡.jpg
-
BINsrc/assets/nft/鼠.jpg
-
BINsrc/assets/personal.png
-
91src/hooks/useNotify.ts
-
37src/hooks/useWs.ts
-
27src/router/layout/Navbar.tsx
-
116src/router/layout/Notify.tsx
-
20src/router/layout/index.tsx
-
1src/styles/home.scss
-
45src/styles/layout.scss
-
10src/types/store.d.ts
Before Width: 285 | Height: 287 | Size: 86 KiB |
Before Width: 251 | Height: 294 | Size: 48 KiB After Width: 251 | Height: 294 | Size: 12 KiB |
Before Width: 307 | Height: 320 | Size: 126 KiB |
Before Width: 1080 | Height: 1528 | Size: 326 KiB |
Before Width: 1080 | Height: 1528 | Size: 290 KiB |
Before Width: 1080 | Height: 1528 | Size: 298 KiB |
Before Width: 1080 | Height: 1528 | Size: 308 KiB |
Before Width: 1080 | Height: 1528 | Size: 310 KiB |
Before Width: 1080 | Height: 1528 | Size: 282 KiB |
Before Width: 1080 | Height: 1528 | Size: 308 KiB |
Before Width: 1080 | Height: 1528 | Size: 352 KiB |
Before Width: 1080 | Height: 1528 | Size: 259 KiB |
Before Width: 1080 | Height: 1528 | Size: 281 KiB |
Before Width: 1080 | Height: 1528 | Size: 269 KiB |
Before Width: 1080 | Height: 1528 | Size: 300 KiB |
Before Width: 860 | Height: 433 | Size: 342 KiB After Width: 860 | Height: 433 | Size: 94 KiB |
@ -0,0 +1,91 @@ |
|||
import { useRef, useState } from "react"; |
|||
import { Toast } from "react-vant"; |
|||
import { clear_msg, read_all_msg } from "~/api"; |
|||
import { MessageType } from "~/types/store"; |
|||
import signGenerator from "~/utils/sign/sign"; |
|||
|
|||
const useNotify = (path: string, isNotity: boolean) => { |
|||
console.log(isNotity); |
|||
|
|||
const baseUrl = `${process.env.REACT_APP_WS_URL}/api/v1/${path}`; |
|||
const ws = useRef<any>(null); |
|||
const filterMessage = useRef([] as MessageType[]); |
|||
const [messages, setMessages] = useState([] as MessageType[]); |
|||
|
|||
const connect = (token: string) => { |
|||
let timestamp = Date.now(); |
|||
let signData = { |
|||
uri: `/api/v1/${path}`, |
|||
timestamp: timestamp, |
|||
args: "", |
|||
}; |
|||
const sign = signGenerator(signData); |
|||
ws.current = new WebSocket( |
|||
`${baseUrl}?Token=${token}&sign=${sign}×tamp=${timestamp}` |
|||
); |
|||
|
|||
ws.current.onmessage = (event: any) => { |
|||
if ( |
|||
event && |
|||
event.data && |
|||
event.origin === process.env.REACT_APP_WS_URL |
|||
) { |
|||
let message = JSON.parse(event.data) as MessageType; |
|||
let item = filterMessage.current.find((v) => v.id === message.id); |
|||
if (item) return; |
|||
filterMessage.current.push(message); |
|||
setMessages((_) => [...filterMessage.current]); |
|||
// 如果打開了消息列表,則推送直接設置為已讀
|
|||
if (isNotity) { |
|||
readAllMsg(); |
|||
} |
|||
} |
|||
}; |
|||
}; |
|||
|
|||
// 斷開連接
|
|||
const disconnect = () => { |
|||
ws.current && ws.current.close(); |
|||
ws.current = null; |
|||
resetMessages(); |
|||
}; |
|||
|
|||
// 重置消息列表
|
|||
const resetMessages = () => { |
|||
filterMessage.current = []; |
|||
setMessages([]); |
|||
}; |
|||
|
|||
// 刪除所有消息
|
|||
const deleteAllMsg = async () => { |
|||
if (messages.length <= 0) return; |
|||
const res: any = await clear_msg(); |
|||
if (res && res.code === 0) { |
|||
Toast.success("清除成功"); |
|||
resetMessages(); |
|||
} |
|||
}; |
|||
|
|||
// 設置所有消息為已讀
|
|||
const readAllMsg = async () => { |
|||
const res: any = await read_all_msg(); |
|||
if (res && res.code === 0) { |
|||
// 把消息改爲已讀
|
|||
filterMessage.current.forEach((item) => { |
|||
item.status = 2; |
|||
}); |
|||
setMessages([...filterMessage.current]); |
|||
} |
|||
}; |
|||
|
|||
return { |
|||
connect, |
|||
disconnect, |
|||
messages, |
|||
resetMessages, |
|||
readAllMsg, |
|||
deleteAllMsg, |
|||
}; |
|||
}; |
|||
|
|||
export default useNotify; |
@ -1,37 +0,0 @@ |
|||
import { useRef } from "react"; |
|||
import signGenerator from "~/utils/sign/sign"; |
|||
|
|||
const useWs = (path: string) => { |
|||
const baseUrl = `ws://14.29.101.215:30307/api/v1/${path}`; |
|||
// const baseUrl = `ws://192.168.124.52:8083/api/v1/${path}`;
|
|||
const ws = useRef<any>(null); |
|||
|
|||
const connect = (token: string) => { |
|||
let timestamp = Date.now(); |
|||
let signData = { |
|||
uri: `/api/v1/${path}`, |
|||
timestamp: timestamp, |
|||
args: "", |
|||
}; |
|||
const sign = signGenerator(signData); |
|||
ws.current = new WebSocket( |
|||
`${baseUrl}?Token=${token}&sign=${sign}×tamp=${timestamp}` |
|||
); |
|||
|
|||
ws.current.onMessage = (data: any) => { |
|||
console.log(data); |
|||
}; |
|||
}; |
|||
|
|||
const disconnect = () => { |
|||
ws.current && ws.current.close(); |
|||
ws.current = null; |
|||
}; |
|||
|
|||
return { |
|||
connect, |
|||
disconnect, |
|||
}; |
|||
}; |
|||
|
|||
export default useWs; |
@ -1,66 +1,84 @@ |
|||
import '~/styles/layout.scss' |
|||
import { Button, Divider, Popup } from "react-vant" |
|||
import { Button, Dialog, Divider, Popup } from "react-vant" |
|||
import { MessageType } from '~/types/store' |
|||
|
|||
interface NotifyProps { |
|||
visible: boolean, |
|||
setVisible: Function |
|||
setVisible: Function, |
|||
messages: MessageType[], |
|||
deleteAllMsg: Function |
|||
} |
|||
|
|||
const Notify = (props: NotifyProps) => { |
|||
|
|||
const { visible, setVisible } = props |
|||
const { visible, setVisible, messages, deleteAllMsg } = props |
|||
|
|||
const data = [ |
|||
{ title: '提醒', color: '#F96900', imgName: 'register-success', desc: '您挂单的“生肖唐彩-狗”NFT, @Miner 出价 4,153.00 USDT,您挂单的“生肖唐彩-狗”NFT, @Miner 出价 4,153.00 USDT,您挂单的“生肖唐彩-狗”NFT, @Miner 出价 4,153.00 USDT' }, |
|||
{ title: '注册成功', color: '#11C0CB', imgName: 'warn', desc: '恭喜,您已成功注册,9527NFT数字交易平台.' }, |
|||
] |
|||
const confirmDelete = async () => { |
|||
if (messages.length <= 0) return |
|||
Dialog.alert({ |
|||
showCancelButton: true, |
|||
showConfirmButton: true, |
|||
title: '提示', |
|||
message: '確定清除所有歷史消息嗎?', |
|||
confirmButtonText: '確定', |
|||
confirmButtonColor: '#0FC6D4', |
|||
onConfirm: () => deleteAllMsg() |
|||
}) |
|||
} |
|||
|
|||
return ( |
|||
<Popup |
|||
visible={visible} |
|||
onClose={() => setVisible(false)} |
|||
position='right' |
|||
style={{ |
|||
height: '100%', |
|||
width: '70%', |
|||
borderTopLeftRadius: 20, |
|||
borderBottomLeftRadius: 20, |
|||
boxShadow: '8px 8px 20px 0px rgba(0, 0, 0, 0.1)' |
|||
}} |
|||
overlayStyle={{ backgroundColor: 'rgba(0,0,0,0.05)' }} |
|||
> |
|||
<div className="p-2"> |
|||
<div className="fz-wb-550">消息提醒</div> |
|||
<Divider className="" style={{ borderColor: '#EEE' }} /> |
|||
<div> |
|||
{ |
|||
data.map((item, index) => ( |
|||
<div className="notify-box row mt-2" key={index}> |
|||
<img src={require(`~/assets/${item.imgName}.png`)} className="img" alt="" /> |
|||
<div className='ml-2'> |
|||
<div className='fz-14 fz-wb-550' style={{ color: item.color }}>{item.title}</div> |
|||
<div className='fz-12 sub-text mt-4px'>{item.desc}</div> |
|||
<> |
|||
<Popup |
|||
visible={visible} |
|||
onClose={() => setVisible(false)} |
|||
position='right' |
|||
style={{ |
|||
height: '100%', |
|||
width: '70%', |
|||
borderTopLeftRadius: 20, |
|||
borderBottomLeftRadius: 20, |
|||
boxShadow: '8px 8px 20px 0px rgba(0, 0, 0, 0.1)' |
|||
}} |
|||
overlayStyle={{ backgroundColor: 'rgba(0,0,0,0.05)' }} |
|||
> |
|||
<div className="notify"> |
|||
<div className='header plr-2'> |
|||
<div style={{ width: '100%' }}> |
|||
<div className="fz-wb-550">消息提醒</div> |
|||
</div> |
|||
</div> |
|||
<div className='notify-box'> |
|||
{ |
|||
messages.map((item) => ( |
|||
<div className="notify-item-box row mt-2" key={item.id}> |
|||
<img src={item.url} className="img" alt="" /> |
|||
<div className='ml-2'> |
|||
<div className='fz-14 fz-wb-550' style={{ color: item.color }}>{item.title}</div> |
|||
<div className='fz-12 sub-text mt-4px' style={{ wordBreak: 'break-word' }}>{item.message}</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
)) |
|||
} |
|||
</div> |
|||
<div className='mt-5 row-center'> |
|||
<Button |
|||
round |
|||
size="small" |
|||
className='fz-wb-550' |
|||
color='#EEEEEE' |
|||
> |
|||
<div className='black'>清除所有</div> |
|||
</Button> |
|||
</div> |
|||
)) |
|||
} |
|||
|
|||
<div className='close'> |
|||
<i className='iconfont icon-right-double-arrow fz-22 sub-text' onClick={() => setVisible(false)}></i> |
|||
<div className='mtb-3 row-center'> |
|||
<Button |
|||
round |
|||
size="small" |
|||
className='fz-wb-550' |
|||
color='#EEEEEE' |
|||
onClick={() => confirmDelete()} |
|||
> |
|||
<div className='black'>清除所有</div> |
|||
</Button> |
|||
</div> |
|||
</div> |
|||
<div className='close'> |
|||
<i className='iconfont icon-right-double-arrow fz-22 sub-text' onClick={() => setVisible(false)}></i> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</Popup> |
|||
</Popup> |
|||
|
|||
</> |
|||
) |
|||
} |
|||
|