pull/52/head
sunface 4 years ago
parent bc63942425
commit e7a292efc5

@ -4,7 +4,7 @@ import Nav from "layouts/nav/nav"
import PageContainer from "layouts/page-container" import PageContainer from "layouts/page-container"
import Sidebar from "layouts/sidebar/sidebar" import Sidebar from "layouts/sidebar/sidebar"
import React, { useEffect, useState } from "react" import React, { useEffect, useState } from "react"
import {adminLinks, interactionLinks} from "src/data/links" import {dashboardLinks} from "src/data/links"
import { requestApi } from "utils/axios/request" import { requestApi } from "utils/axios/request"
import PageContainer1 from "layouts/page-container1" import PageContainer1 from "layouts/page-container1"
import Empty from "components/empty" import Empty from "components/empty"
@ -30,7 +30,7 @@ const FollowersPage = () => {
<> <>
<PageContainer1> <PageContainer1>
<Box display="flex"> <Box display="flex">
<Sidebar routes={interactionLinks} title="我的关注" /> <Sidebar routes={dashboardLinks} title="dashboard" />
<Card ml="4" p="6" width="100%"> <Card ml="4" p="6" width="100%">
{ {
users.length === 0 ? <Empty /> : users.length === 0 ? <Empty /> :

@ -2,7 +2,7 @@ import { Text, Box, Heading, Image, Divider, useToast, HStack, Slider, SliderTra
import Card from "components/card" import Card from "components/card"
import Sidebar from "layouts/sidebar/sidebar" import Sidebar from "layouts/sidebar/sidebar"
import React, { useEffect, useState } from "react" import React, { useEffect, useState } from "react"
import {interactionLinks} from "src/data/links" import {dashboardLinks} from "src/data/links"
import { requestApi } from "utils/axios/request" import { requestApi } from "utils/axios/request"
import { useRouter } from "next/router" import { useRouter } from "next/router"
import PageContainer1 from "layouts/page-container1" import PageContainer1 from "layouts/page-container1"
@ -42,7 +42,7 @@ const TagsPage = () => {
<> <>
<PageContainer1> <PageContainer1>
<Box display="flex"> <Box display="flex">
<Sidebar routes={interactionLinks} title="我的关注" /> <Sidebar routes={dashboardLinks} title="dashboard" />
<Card ml="4" p="6" width="100%"> <Card ml="4" p="6" width="100%">
<Text fontSize=".95rem" fontWeight="600">Adjust tag weight to modify your home feed. Higher values mean more appearances.</Text> <Text fontSize=".95rem" fontWeight="600">Adjust tag weight to modify your home feed. Higher values mean more appearances.</Text>
<Divider my="6" /> <Divider my="6" />

@ -4,7 +4,7 @@ import Nav from "layouts/nav/nav"
import PageContainer from "layouts/page-container" import PageContainer from "layouts/page-container"
import Sidebar from "layouts/sidebar/sidebar" import Sidebar from "layouts/sidebar/sidebar"
import React, { useEffect, useState } from "react" import React, { useEffect, useState } from "react"
import {interactionLinks} from "src/data/links" import {dashboardLinks} from "src/data/links"
import { requestApi } from "utils/axios/request" import { requestApi } from "utils/axios/request"
import PageContainer1 from "layouts/page-container1" import PageContainer1 from "layouts/page-container1"
import Empty from "components/empty" import Empty from "components/empty"
@ -37,7 +37,7 @@ const UsersPage = () => {
<> <>
<PageContainer1> <PageContainer1>
<Box display="flex"> <Box display="flex">
<Sidebar routes={interactionLinks} title="我的关注" /> <Sidebar routes={dashboardLinks} title="Dashboard" />
<Card ml="4" p="6" width="100%"> <Card ml="4" p="6" width="100%">
{ {
users.length === 0 ? <Empty /> : users.length === 0 ? <Empty /> :

@ -0,0 +1,109 @@
import { Text, Box, Heading, Image, Center, Button, Flex, VStack, Divider, useToast, Wrap, WrapItem, useColorModeValue, StackDivider, HStack } from "@chakra-ui/react"
import Card from "components/card"
import Nav from "layouts/nav/nav"
import PageContainer from "layouts/page-container"
import Sidebar from "layouts/sidebar/sidebar"
import React, { useEffect, useState } from "react"
import { dashboardLinks } from "src/data/links"
import { requestApi } from "utils/axios/request"
import PageContainer1 from "layouts/page-container1"
import Empty from "components/empty"
import { IDType } from "src/types/id"
import UserCard from "components/users/user-card"
import userCustomTheme from "theme/user-custom"
import { Story } from "src/types/story"
import moment from 'moment'
import { FaComment, FaEye, FaHeart, FaRegComment, FaRegEye, FaRegHeart } from "react-icons/fa"
import Link from "next/link"
const DashboardPage = () => {
const [stories, setStories]: [Story[], any] = useState([])
const [totalLikes, setTotalLikes] = useState(0)
const [totalViews, setTotalViews] = useState(0)
const [totalComments, setTotalComments] = useState(0)
const borderColor = useColorModeValue(userCustomTheme.borderColor.light, userCustomTheme.borderColor.dark)
const getStories = async () => {
const res = await requestApi.get(`/story/posts/dashboard`)
setStories(res.data)
let likes = 0
let views = 0
let comments = 0
res.data.forEach(s => {
likes += s.likes
views += s.views
comments += s.comments
})
setTotalLikes(likes)
setTotalViews(views)
setTotalComments(comments)
}
useEffect(() => {
getStories()
}, [])
return (
<>
<PageContainer1>
<Box display="flex">
<Sidebar routes={dashboardLinks} title="dashboard" />
<Box ml="4" width="100%">
<HStack alignItems="top" width="100%" spacing="3">
<Card width="33%">
<Heading size="md">{totalLikes}</Heading>
<Text layerStyle="textSecondary" mt="2">Total likes</Text>
</Card>
<Card width="33%">
<Heading size="md">{totalViews}</Heading>
<Text layerStyle="textSecondary" mt="2">Total Views</Text>
</Card>
<Card width="33%">
<Heading size="md">{totalComments}</Heading>
<Text layerStyle="textSecondary" mt="2">Total Comments</Text>
</Card>
</HStack>
<Card mt="2" p="6" width="100%">
<Heading size="sm" >Stories ({stories.length})</Heading>
<Divider my="4"/>
{
stories.map((s,i) =>
<Link key={i} href={`/${s.creator.username}/${s.id}`}>
<Flex cursor="pointer" justifyContent="space-between" alignItems="center" mb={i < stories.length-1 ? 6 : 0}>
<VStack alignItems="left">
<Heading size="sm">{s.title}</Heading>
<Text fontSize=".85rem">created {moment(s.created).fromNow()} &nbsp;updated {moment(s.updated).fromNow()} </Text>
</VStack>
<HStack layerStyle="textSecondary" spacing="4">
<HStack>
<FaRegHeart />
<Text>{s.likes}</Text>
</HStack>
<HStack>
<FaRegComment />
<Text>{s.comments}</Text>
</HStack>
<HStack>
<FaRegEye />
<Text>{s.views}</Text>
</HStack>
</HStack>
</Flex>
</Link>)
}
</Card>
</Box>
</Box>
</PageContainer1>
</>
)
}
export default DashboardPage

@ -151,6 +151,17 @@ func GetHomePosts(c *gin.Context) {
c.JSON(http.StatusOK, common.RespSuccess(posts)) c.JSON(http.StatusOK, common.RespSuccess(posts))
} }
func GetDashboardPosts(c *gin.Context) {
user := user.CurrentUser(c)
posts, err := story.DashboardPosts(user)
if err != nil {
c.JSON(err.Status, common.RespError(err.Message))
return
}
c.JSON(http.StatusOK, common.RespSuccess(posts))
}
func GetBookmarkPosts(c *gin.Context) { func GetBookmarkPosts(c *gin.Context) {
filter := c.Param("filter") filter := c.Param("filter")
user := user.CurrentUser(c) user := user.CurrentUser(c)

@ -69,6 +69,7 @@ func GetStory(c *gin.Context) {
ar.Bookmarked, _ = story.Bookmarked(u.ID, ar.ID) ar.Bookmarked, _ = story.Bookmarked(u.ID, ar.ID)
} }
story.UpdateViews(id)
c.JSON(http.StatusOK, common.RespSuccess(ar)) c.JSON(http.StatusOK, common.RespSuccess(ar))
} }

@ -77,6 +77,7 @@ func (s *Server) Start() error {
r.GET("/story/posts/org/:id", IsLogin(), api.GetOrgPosts) r.GET("/story/posts/org/:id", IsLogin(), api.GetOrgPosts)
r.GET("/story/posts/drafts", IsLogin(), api.GetEditorDrafts) r.GET("/story/posts/drafts", IsLogin(), api.GetEditorDrafts)
r.GET("/story/posts/home", api.GetHomePosts) r.GET("/story/posts/home", api.GetHomePosts)
r.GET("/story/posts/dashboard", IsLogin(), api.GetDashboardPosts)
r.POST("/story", IsLogin(), api.SubmitStory) r.POST("/story", IsLogin(), api.SubmitStory)
r.POST("/story/pin/:storyID", IsLogin(), api.PinStory) r.POST("/story/pin/:storyID", IsLogin(), api.PinStory)
r.POST("/story/series", api.GetSeries) r.POST("/story/series", api.GetSeries)

@ -82,6 +82,7 @@ var sqlTables = map[string]string{
url VARCHAR(255), url VARCHAR(255),
cover VARCHAR(255), cover VARCHAR(255),
brief TEXT, brief TEXT,
views INTEGER DEFAULT 0,
likes INTEGER DEFAULT 0, likes INTEGER DEFAULT 0,
status tinyint NOT NULL, status tinyint NOT NULL,
created DATETIME NOT NULL, created DATETIME NOT NULL,

@ -295,6 +295,10 @@ func GetPostCreator(id string) (string, *e.Error) {
return uid, nil return uid, nil
} }
func UpdateViews(storyID string) {
db.Conn.Exec("UPDATE story SET views=views+1 WHERE id=?", storyID)
}
//slug有三个规则 //slug有三个规则
// 1. 长度不能超过127 // 1. 长度不能超过127
// 2. 每次title更新都要重新生成slug // 2. 每次title更新都要重新生成slug

@ -29,6 +29,26 @@ func HomePosts(user *models.User, filter string, page int64, perPage int64) (mod
return posts, nil return posts, nil
} }
func DashboardPosts(user *models.User) ([]*models.Story, *e.Error) {
rows, err := db.Conn.Query("SELECT id,title,url,created,views,likes,updated FROM story WHERE creator=? AND status=? ORDER BY created DESC", user.ID, models.StatusPublished)
if err != nil && err != sql.ErrNoRows {
logger.Warn("get dashboard posts error", "error", err)
return nil, e.New(http.StatusInternalServerError, e.Internal)
}
stories := make([]*models.Story, 0)
for rows.Next() {
story := &models.Story{}
rows.Scan(&story.ID, &story.Title, &story.URL, &story.Created, &story.Views, &story.Likes, &story.Updated)
story.Comments = GetCommentCount(story.ID)
stories = append(stories, story)
story.Creator = &models.UserSimple{Username: user.Username}
}
return stories, nil
}
func UserPosts(tp string, user *models.User, uid string, page int64, perPage int64) (models.Stories, *e.Error) { func UserPosts(tp string, user *models.User, uid string, page int64, perPage int64) (models.Stories, *e.Error) {
var rows *sql.Rows var rows *sql.Rows
var err error var err error

@ -136,6 +136,12 @@ func UpdateUser(u *models.User) *e.Error {
} }
func NameExist(name string) (bool, *e.Error) { func NameExist(name string) (bool, *e.Error) {
for _, n := range common.ReserverURLs {
if n == "/"+name {
return true, nil
}
}
var username string var username string
err := db.Conn.QueryRow("SELECT username FROM user WHERE username=?", name).Scan(&username) err := db.Conn.QueryRow("SELECT username FROM user WHERE username=?", name).Scan(&username)
if err != nil && err != sql.ErrNoRows { if err != nil && err != sql.ErrNoRows {

@ -4,7 +4,7 @@ package common
var ReserverURLs = []string{ var ReserverURLs = []string{
"/tags", "/tags",
"/courses", "/courses",
"/interaction", "/dashboard",
"/editor", "/editor",
"/admin", "/admin",
"/bookmarks", "/bookmarks",

@ -14,7 +14,7 @@ import { Session } from "src/types/user"
import { useRouter } from "next/router" import { useRouter } from "next/router"
import storage from "utils/localStorage" import storage from "utils/localStorage"
import { ReserveUrls } from "src/data/reserve-urls" import { ReserveUrls } from "src/data/reserve-urls"
import { FaRegSun, FaUserAlt ,FaBookmark, FaSignOutAlt,FaEdit,FaStar, FaHeart} from "react-icons/fa" import { FaRegSun, FaUserAlt ,FaBookmark, FaSignOutAlt,FaEdit,FaStar, FaHeart, FaThLarge} from "react-icons/fa"
import { isAdmin, isEditor } from "utils/role" import { isAdmin, isEditor } from "utils/role"
import { logout } from "utils/session" import { logout } from "utils/session"
import Link from "next/link" import Link from "next/link"
@ -57,7 +57,7 @@ export const UserMenu = () => {
<MenuDivider /> <MenuDivider />
{isEditor(session.user.role) && <Link href={`${ReserveUrls.Editor}/posts`}><MenuItem icon={<FaEdit fontSize="16" />} ></MenuItem></Link>} {isEditor(session.user.role) && <Link href={`${ReserveUrls.Editor}/posts`}><MenuItem icon={<FaEdit fontSize="16" />} ></MenuItem></Link>}
<Link href={`${ReserveUrls.Bookmarks}`}><MenuItem icon={<FaBookmark fontSize="16" />}></MenuItem></Link> <Link href={`${ReserveUrls.Bookmarks}`}><MenuItem icon={<FaBookmark fontSize="16" />}></MenuItem></Link>
<Link href={`${ReserveUrls.Interaction}/following-tags`}><MenuItem icon={<FaHeart fontSize="16" />}></MenuItem></Link> <Link href={`${ReserveUrls.Dashboard}/stats`}><MenuItem icon={<FaThLarge fontSize="16" />}>Dashboard</MenuItem></Link>
<MenuDivider /> <MenuDivider />
{isAdmin(session.user.role) && <Link href={`${ReserveUrls.Admin}/tags`}><MenuItem icon={<FaStar fontSize="16" />} ></MenuItem></Link>} {isAdmin(session.user.role) && <Link href={`${ReserveUrls.Admin}/tags`}><MenuItem icon={<FaStar fontSize="16" />} ></MenuItem></Link>}
<Link href={`${ReserveUrls.Settings}/profile`}><MenuItem icon={<FaRegSun fontSize="16" />}></MenuItem></Link> <Link href={`${ReserveUrls.Settings}/profile`}><MenuItem icon={<FaRegSun fontSize="16" />}></MenuItem></Link>

@ -24,20 +24,25 @@ export const editorLinks: Route[] = [{
} }
] ]
export const interactionLinks: any[] = [ export const dashboardLinks: any[] = [
{
title: 'Stats',
path: `${ReserveUrls.Dashboard}/stats`,
disabled: false
},
{ {
title: 'Following tags', title: 'Following tags',
path: `${ReserveUrls.Interaction}/following-tags`, path: `${ReserveUrls.Dashboard}/following-tags`,
disabled: false disabled: false
}, },
{ {
title: 'Following users', title: 'Following users',
path: `${ReserveUrls.Interaction}/following-users`, path: `${ReserveUrls.Dashboard}/following-users`,
disabled: false disabled: false
}, },
{ {
title: 'Followers', title: 'Followers',
path: `${ReserveUrls.Interaction}/followers`, path: `${ReserveUrls.Dashboard}/followers`,
disabled: false disabled: false
}, },
] ]

@ -2,7 +2,7 @@
export enum ReserveUrls { export enum ReserveUrls {
Tags = "/tags", Tags = "/tags",
Courses = "/courses", Courses = "/courses",
Interaction = "/interaction", Dashboard = "/dashboard",
Editor = "/editor", Editor = "/editor",
Admin = "/admin", Admin = "/admin",
Bookmarks = "/bookmarks", Bookmarks = "/bookmarks",

@ -22,8 +22,10 @@ export interface Story {
cover?: string cover?: string
brief?: string brief?: string
created?: string created?: string
updated?:string
tags?: string[] tags?: string[]
rawTags?: Tag[] rawTags?: Tag[]
views?: number
likes? : number likes? : number
liked? : boolean liked? : boolean
pinned?: boolean pinned?: boolean

Loading…
Cancel
Save