pull/52/head
sunface 4 years ago
parent 807679a4e2
commit 3e19434047

@ -27,6 +27,7 @@ import { getUserName } from "utils/user"
import moment from 'moment'
import userCustomTheme from "theme/user-custom"
import Link from "next/link"
import Notifications from "components/notifications"
const filters = [
{icon: 'bell',label:'All',type: 0},
@ -39,26 +40,22 @@ const filters = [
const NotificationPage = () => {
const [filter, setFilter]= useState(filters[0])
const [notifications,setNotifications]: [Notification[],any] = useState([])
const stackBorderColor = useColorModeValue(userCustomTheme.borderColor.light, userCustomTheme.borderColor.dark)
useEffect(() => {
initData()
},[])
const initData = async () => {
await getNotifications()
await requestApi.post(`/notifications/unread`)
}
const getNotifications = async (f?) => {
const res = await requestApi.get(`/notifications/list/${f ? f.type : filter.type}`)
setNotifications(res.data)
const getNotifications = async (p) => {
const res = await requestApi.get(`/notifications/list/${filter.type}?page=${p}`)
return res
}
const onFilterChange = (f) => {
setFilter(f)
getNotifications(f)
}
return (
@ -88,25 +85,7 @@ const filters = [
}
</Wrap>}
<Divider mt="3" mb="5" />
{notifications.length !== 0
?
<VStack alignItems="left" px="4" spacing="5" pb="4" divider={<StackDivider borderColor={stackBorderColor} />}>
{notifications.map((p,i) =>
<HStack key={i} alignItems="top" spacing="4">
<Image src={p.user.avatar} height="45px"/>
<VStack alignItems="left" >
<HStack>
<Link href={`/${p.user.username}`}><Heading fontSize="1rem" cursor="pointer">{getUserName(p.user)}</Heading></Link>
<Text >{p.title}</Text>
</HStack>
{p.subTitle && <Link href={`/${p.user.username}/${p.storyID}`}><Heading size="sm" color="teal" cursor="pointer">{p.subTitle}</Heading></Link>}
<Text fontSize=".8rem" layerStyle="textSecondary">{moment(p.created).fromNow()} {!p.read&& <Tag size="sm" colorScheme="orange">unread</Tag>}</Text>
</VStack>
</HStack>)}
</VStack>
:
<Empty />
}
<Notifications onLoad={getNotifications} filter={filter}/>
</Card>
</VStack>
<IndexSidebar />

@ -14,7 +14,11 @@ func GetNotifications(c *gin.Context) {
tp, _ := strconv.Atoi(c.Param("type"))
u := user.CurrentUser(c)
nos, err := notification.Query(u, tp)
page, err0 := strconv.Atoi(c.Query("page"))
if err0 != nil {
page = 1
}
nos, err := notification.Query(u, tp, page)
if err != nil {
c.JSON(err.Status, common.RespError(err.Message))
return

@ -31,15 +31,17 @@ func Send(userID, orgID string, noType int, noID string, operatorID string) {
}
}
func Query(user *models.User, tp int) ([]*models.Notification, *e.Error) {
const perPage = 10
func Query(user *models.User, tp int, page int) ([]*models.Notification, *e.Error) {
var rows *sql.Rows
var err error
if tp == 0 {
rows, err = db.Conn.Query("SELECT operator_id,notifiable_type,notifiable_id,read,created FROM user_notification WHERE user_id=? ORDER BY created DESC", user.ID)
rows, err = db.Conn.Query("SELECT operator_id,notifiable_type,notifiable_id,read,created FROM user_notification WHERE user_id=? ORDER BY created DESC LIMIT ?,?", user.ID, (page-1)*perPage, page*perPage)
} else if tp == models.NotificationComment {
rows, err = db.Conn.Query("SELECT operator_id,notifiable_type,notifiable_id,read,created FROM user_notification WHERE user_id=? and notifiable_type in ('1','6') ORDER BY created DESC", user.ID)
rows, err = db.Conn.Query("SELECT operator_id,notifiable_type,notifiable_id,read,created FROM user_notification WHERE user_id=? and notifiable_type in ('1','6') ORDER BY created DESC LIMIT ?,?", user.ID, (page-1)*perPage, page*perPage)
} else {
rows, err = db.Conn.Query("SELECT operator_id,notifiable_type,notifiable_id,read,created FROM user_notification WHERE user_id=? and notifiable_type=? ORDER BY created DESC", user.ID, tp)
rows, err = db.Conn.Query("SELECT operator_id,notifiable_type,notifiable_id,read,created FROM user_notification WHERE user_id=? and notifiable_type=? ORDER BY created DESC LIMIT ?,?", user.ID, tp, (page-1)*perPage, page*perPage)
}
if err != nil {

@ -0,0 +1,98 @@
import React, { useEffect, useState } from "react"
import { Box, Center, Heading, HStack, Image, Link, StackDivider, Tag, Text, useColorModeValue, VStack } from "@chakra-ui/react"
import userCustomTheme from "theme/user-custom"
import useInfiniteScroll from 'src/hooks/use-infinite-scroll'
import { concat } from "lodash"
import Empty from "src/components/empty"
import { Notification } from "src/types/notification"
import moment from 'moment'
import { getUserName } from "utils/user"
interface Props {
onLoad?: any
filter?: any
}
export const Notifications = (props: Props) => {
const { onLoad, filter } = props
const [notifications,setNotifications]: [Notification[],any] = useState([])
const [noMore, setNoMore] = useState(false)
const [isFetching, setIsFetching] = useInfiniteScroll(fetchMoreListItems);
const [page, setPage] = useState(1)
const stackBorderColor = useColorModeValue(userCustomTheme.borderColor.light, userCustomTheme.borderColor.dark)
useEffect(() => {
setNotifications([])
setNoMore(false)
setPage(1)
onLoad(1).then(res => {
if (res.data.length < 10) {
setNoMore(true)
}
setNotifications(res.data)
})
}, [filter])
function fetchMoreListItems() {
if (page === 1 && notifications.length === 0) {
// 走到这里面说明视图逻辑出问题了,你可以这样触发
// 进入tag或者个人页面然后把文章拉到第二页
// 此时点击tag会瞬间同时加载第一页和第二页的文章
// 因为第一页的文章还没加载完毕没有更新posts第二页的文章就会覆盖掉第一页的数据
// 这样第一页的数据就丢失了
// 走到该函数意味着已经是第二页的加载逻辑了在此时posts不应该为空
//@ts-ignore
setIsFetching(false)
return
}
if (noMore) {
//@ts-ignore
setIsFetching(false)
return
}
setPage(page + 1)
onLoad(page + 1).then(res => {
if (res.data.length < 5) {
setNoMore(true)
}
setNotifications(concat(notifications, ...res.data))
}
)
//@ts-ignore
setIsFetching(false)
}
return (
<>
{notifications.length !== 0
?
<>
<VStack alignItems="left" px="4" spacing="4" pb="4" divider={<StackDivider borderColor={stackBorderColor} />}>
{notifications.map((p,i) =>
<HStack key={i} alignItems="top" spacing="4">
<Image src={p.user.avatar} height="45px"/>
<VStack alignItems="left" >
<HStack>
<Link href={`/${p.user.username}`}><Heading fontSize="1rem" cursor="pointer">{getUserName(p.user)}</Heading></Link>
<Text >{p.title}</Text>
</HStack>
{p.subTitle && <Link href={`/${p.user.username}/${p.storyID}`}><Heading size="sm" color="teal" cursor="pointer">{p.subTitle}</Heading></Link>}
<Text fontSize=".8rem" layerStyle="textSecondary">{moment(p.created).fromNow()} {!p.read&& <Tag size="sm" colorScheme="orange">unread</Tag>}</Text>
</VStack>
</HStack>)}
</VStack>
{noMore && <Center><Text layerStyle="textSecondary" fontSize="sm" py="4"></Text></Center>}
</>
:
<Empty />
}
</>
)
}
export default Notifications
Loading…
Cancel
Save