Skip to content

Commit

Permalink
feat(ui): Add discuss list page
Browse files Browse the repository at this point in the history
  • Loading branch information
GoForceX committed Sep 3, 2023
1 parent 34bbdbd commit c3c9255
Show file tree
Hide file tree
Showing 6 changed files with 223 additions and 9 deletions.
21 changes: 17 additions & 4 deletions packages/core/handler/discuss.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {perm} from '../declare/perm';
import {DefaultType} from '../declare/type';
import {Handler, Route} from '../handle';
import {DiscussSchema, RespondProps, discuss} from '../model/discuss';
import {DiscussSchema, RespondProps, discuss, DiscussListElementSchema} from '../model/discuss';
import {param} from '../utils/decorate';
import {token as tokenModel} from '../model/token';
import {CommentSchema, comment} from '../model/comment';
Expand Down Expand Up @@ -263,12 +263,25 @@ class DiscussHandler extends Handler {
@param('page', DefaultType.Number)
async postHotDiscussList(limit: string, page: string) {
try {
// const requester = await tokenModel.stripId(token);
const data: DiscussListElementSchema[] = await discuss.getRecentHotDiscuss(parseInt(limit), parseInt(page));
const respData: (DiscussListElementSchema & CommentSchemaExtra)[] = []

const count = await discuss.count();

for (const datum of data) {
const author = await user.getbyId(datum.author);
const respDatum: DiscussListElementSchema & CommentSchemaExtra = {
...datum,
authorName: author.username,
authorAvatar: author.gravatarLink,
};
respData.push(respDatum);
}

const data = await discuss.getRecentHotDiscuss(parseInt(limit), parseInt(page));
this.ctx.body = {
status: 'success',
data,
count,
data: respData,
};
} catch (err) {
this.ctx.body = {
Expand Down
16 changes: 14 additions & 2 deletions packages/core/model/discuss.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ export class RespondProps {

type DiscussUpdatedSchema = Omit<Partial<DiscussSchema>, 'did'>;

export type DiscussListElementSchema = Omit<Omit<DiscussSchema, 'deleted'>, 'responds'> & {
recentCommentCount: number;
};

export class DiscussModel {
async genDId() {
const newID = (await db.getone('count', {type: 'discussId'}))?.count + 1 || 1;
Expand Down Expand Up @@ -233,8 +237,8 @@ export class DiscussModel {
],);
}

async getRecentHotDiscuss(limit: number, page: number): Promise<Document[]> {
return await db.aggregate('discuss', [
async getRecentHotDiscuss(limit: number, page: number): Promise<DiscussListElementSchema[]> {
return await db.aggregate<DiscussListElementSchema>('discuss', [
{$match: {deleted: false}},
{
$lookup: {
Expand Down Expand Up @@ -264,6 +268,14 @@ export class DiscussModel {
{$limit: limit},
],);
}

async count(): Promise<number> {
const count = await db.aggregate<{count: number}>('discuss', [
{$match: {deleted: false}},
{$count: 'count'},
],);
return count[0].count;
}
}

export const discuss = new DiscussModel();
Expand Down
4 changes: 2 additions & 2 deletions packages/core/service/db.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,11 @@ class dbClass {
return res;
}

async aggregate(model: string, pipeline: object[], options: AggregateOptions = {}) {
async aggregate<T>(model: string, pipeline: object[], options: AggregateOptions = {}) {
const client = new MongoClient(this.url);
const database = client.db(this.dbname);
const coll = database.collection(model);
const res = await coll.aggregate(pipeline, options).toArray();
const res = await coll.aggregate<T>(pipeline, options).toArray();
client.close();
return res;
}
Expand Down
2 changes: 2 additions & 0 deletions packages/ui/src/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import * as Direct from './interfaces/interface';
import DiscussPage from './pages/discuss';
import './app.css';
import { DiscussCreatePage } from './pages/discussCreate';
import DiscussListPage from './pages/discussList';

const myCache = createEmotionCache({ key: 'school-hub' });

Expand Down Expand Up @@ -83,6 +84,7 @@ function App() {
<Route path='' element={<Root type='route' onThemeChange={onThemeChange} />}>
<Route path='' element={<HomePage></HomePage>} />
<Route path='login' element={<LoginPage></LoginPage>} />
<Route path='discuss' element={<DiscussListPage></DiscussListPage>} />
<Route path='discuss/:id' element={<DiscussPage></DiscussPage>} />
<Route path='discuss/create' element={<DiscussCreatePage></DiscussCreatePage>} />
</Route>
Expand Down
39 changes: 38 additions & 1 deletion packages/ui/src/handlers/discussHandler.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { fetch } from '../interfaces/data';
import {fetch} from '../interfaces/data';

interface CreateProp {
token: string;
Expand Down Expand Up @@ -30,6 +30,12 @@ interface FetchRespondProp {
did: number;
}

interface FetchDiscussListProp {
limit: number;
page: number;
token: string;
}

interface Response {
status: 'success' | 'error';
msg?: string;
Expand Down Expand Up @@ -76,6 +82,15 @@ interface FetchRespondResponse extends Response {
param?: string;
}

interface FetchDiscussListResponse extends Response {
status: 'success' | 'error';
msg?: string;
data?: DiscussListElementSchema[];
count?: number;
type?: string;
param?: string;
}

export interface CommentSchema {
cid: number;
did: number;
Expand Down Expand Up @@ -115,6 +130,23 @@ export interface DiscussSchema {
parsedResponds: RespondProps[];
}

export interface DiscussListElementSchema {
did?: number;
author: number;
topic: string;
tags: Array<string>;
title: string;
content: string;
createdTime: number;
lastModified: number;
official: boolean;
officialNotice: string;
authorName: string;
authorAvatar: string;
commentCount: number;
recentCommentCount: number;
}

interface InfoResponse extends Response {
status: 'success' | 'error';
msg?: string;
Expand Down Expand Up @@ -172,3 +204,8 @@ export async function handleFetchResponds(fetchRespondData: FetchRespondProp): P
const data = await fetch('discuss', 'fetchResponds', fetchRespondData);
return data;
}

export async function handleFetchDiscussList(fetchDiscussListData: FetchDiscussListProp): Promise<FetchDiscussListResponse> {
const data = await fetch('discuss', 'hotDiscussList', fetchDiscussListData);
return data;
}
150 changes: 150 additions & 0 deletions packages/ui/src/pages/discussList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
import {
Alert,
Avatar, Badge,
Card, Center,
Container,
createStyles, Divider, Flex, Menu, Pagination, Popover, Space, Text,
} from '@mantine/core';
import React, {useEffect, useState} from 'react';
import {useParams} from 'react-router-dom';
import {
DiscussListElementSchema,
fetchDiscussError,
handleFetchDiscussList,
} from '../handlers/discussHandler';
import {NoStyleCard} from '../components/card';
import moment from 'moment/moment';
import {IconEye, IconInfoCircle, IconMessage} from '@tabler/icons-react';

const useStyles = createStyles((theme) => ({
discussTitle: {
fontWeight: 600,
fontSize: 16,
}
}));

function DiscussSingle({data}: { data: DiscussListElementSchema }) {
const {theme, classes} = useStyles();
return (
<>
<Card.Section
withBorder
p={6}
pt={8}
pb={12}
px={10}
ta={'left'}
style={{
borderTop: 'none',
}}
onClick={() => {
window.location.href = `/discuss/${data.did}`;
}}
>
<Flex direction="row">
<Flex align="center" ml={2} mr={16}>
<Avatar color="pink" src={data.authorAvatar} size={40}
radius="xl"></Avatar>
</Flex>
<div>
<Flex direction="row" align="center">
<Text size={12.5} color="dimmed">
{data.authorName} · {moment(data.createdTime * 1000).format('YYYY-MM-DD HH:mm:ss')}
</Text>
<Space w={2}></Space>
</Flex>
<Text
pt={1}
className={classes.discussTitle}>{data.title}</Text>
<Flex direction="row" align="center" pt={1.5}>
<IconEye size={12.5}
color={theme.colors.gray[5]}>
</IconEye>
<Space w={4}></Space>
<Text size={12.5}
color={theme.colors.gray[5]}>{data.commentCount}</Text>
<Space w={8}></Space>
<Text size={12.5} color="dimmed"> · </Text>
<Space w={8}></Space>
<IconMessage size={12.5}
color={theme.colors.gray[5]}>
</IconMessage>
<Space w={4}></Space>
<Text size={12.5}
color={theme.colors.gray[5]}>{data.commentCount}</Text>
</Flex>
</div>
</Flex>
</Card.Section>
</>
)
}

export default function DiscussListPage() {
const {theme, classes} = useStyles();

const [loaded, setLoaded] = useState(false);
const [status, setStatus] = useState(false);
const [errorMsg, setErrorMsg] = useState('');

const param = useParams();

const [discussList, setDiscussList] = useState<DiscussListElementSchema[]>([]);
const [discussCount, setDiscussCount] = useState(0);

const [nowPage, setNowPage] = useState(1);
useEffect(() => {
handleFetchDiscussList({
token: localStorage.getItem('token') || '',
limit: 5,
page: nowPage
}).then((response) => {
if (response.status === 'success') {
if (response.data) {
setDiscussList(response.data);
setDiscussCount(response.count || 0);
setLoaded(true);
setStatus(true);
}
} else {
setLoaded(true);
setStatus(false);
setErrorMsg(response.type ? fetchDiscussError[response.type] || '后端未知错误' : '后端未知错误');
}
});
}, [nowPage]);

return (
<>
<Container>
<Card.Section>
<Alert icon={<IconInfoCircle></IconInfoCircle>} radius={0} title="欢迎来到 灌水区" color="blue">
<Text size={12.5} color={theme.colors.blue[4]}>
规定什么的都不重要的吧,随便灌水就好了(
</Text>
</Alert>
</Card.Section>
<Space h={10}></Space>
{loaded ? (
status ? (
<>
<NoStyleCard py={0}>
{discussList.map((element) => {
return (
<DiscussSingle key={element.did} data={element}></DiscussSingle>
);
})}
<Center><Pagination py="md" value={nowPage} onChange={setNowPage}
total={Math.ceil(discussCount / 5)}/></Center>
</NoStyleCard>
</>
) : (
<div>{errorMsg}</div>
)
) : (
<div>加载中……</div>
)}
</Container>
</>
);
}

0 comments on commit c3c9255

Please sign in to comment.