Skip to content

Commit

Permalink
feat: login,admin,edit,create pages
Browse files Browse the repository at this point in the history
  • Loading branch information
BIYUEHU committed Jun 14, 2024
1 parent 99c7339 commit e52fdba
Show file tree
Hide file tree
Showing 20 changed files with 719 additions and 50 deletions.
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
"license": "GPL-3.0",
"author": "Romi <[email protected]>",
"scripts": {
"client": "pnpm --filter @moehub/client",
"common": "pnpm --filter @moehub/common",
"dev:core": "nodemon --watch",
"dev:client": "pnpm --filter @moehub/client dev",
"lint": "eslint \"packages/*/src/*.ts\" --fix",
Expand Down
8 changes: 7 additions & 1 deletion packages/client/src/components/Layout/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Flex, Layout as AntLayout } from 'antd';
import { Flex, Layout as AntLayout, Avatar, Image } from 'antd';
import { LoginOutlined } from '@ant-design/icons';
import { Link } from 'react-router-dom';
import styles from './styles.module.css';

Expand All @@ -12,9 +13,14 @@ const Layout: React.FC<{ outlet: React.ReactElement }> = ({ outlet }) => (
<Header className={styles.header}>
<h1>
<Link className={styles.headerTitle} to="/">
<Avatar style={{ marginRight: 10 }} src={<Image src="https://biyuehu.github.io/images/avatar.png" />} />
Moe Hub
</Link>
</h1>

<Link to="/admin">
<Avatar style={{ background: 'none', color: '#eee' }} icon={<LoginOutlined />} />
</Link>
</Header>
<Content className={styles.content}>{outlet}</Content>
<Footer className={styles.footer}>
Expand Down
6 changes: 6 additions & 0 deletions packages/client/src/components/Layout/styles.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,19 @@
}

.header {
display: flex;
justify-content: space-between;
color: #eee;
background-color: #227d51;
height: 64px;
padding-inline: 48px;
line-height: 64px;
}

.header a {
background: none;
}

.headerTitle {
color: #eee;
}
Expand Down
14 changes: 13 additions & 1 deletion packages/client/src/http/character.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { MoehubApiCharacter, MoehubApiCharacters } from '@moehub/common';
import { MoehubApiBase, MoehubApiCharacter, MoehubApiCharacters, MoehubDataCharacter } from '@moehub/common';
import http from './http';

export function getCharacter(id: number): Promise<MoehubApiCharacter> {
Expand All @@ -8,3 +8,15 @@ export function getCharacter(id: number): Promise<MoehubApiCharacter> {
export function getCharacters(): Promise<MoehubApiCharacters> {
return http.get('/character');
}

export function createCharacter(character: MoehubDataCharacter): Promise<MoehubApiBase<201>> {
return http.post('/character', character);
}

export function updateCharacter(id: number, character: MoehubDataCharacter): Promise<MoehubApiBase<204>> {
return http.put(`/character/${id}`, character);
}

export function deleteCharacter(id: number): Promise<MoehubApiBase<204>> {
return http.delete(`/character/${id}`);
}
9 changes: 4 additions & 5 deletions packages/client/src/http/http.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,10 @@ http.interceptors.request.use(
);

http.interceptors.response.use(
(response) =>
/* if (response.status === 200 && typeof response.data === 'object' && typeof response.data.data === 'object') {
return response.data.data;
} */
response.data,
(response) => {
if (response.data) response.config.headers['Content-Type'] = 'application/json';
return response.data;
},
(err) => {
notification.error({
message: 'Http request error',
Expand Down
26 changes: 25 additions & 1 deletion packages/client/src/router/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React, { lazy } from 'react';
import { useRoutes } from 'react-router-dom';
import Loading from '../components/loading';

/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
Expand All @@ -11,7 +12,7 @@ function lazyLoader(callback: () => Promise<any>) {
);
}

export default [
const Routes: Parameters<typeof useRoutes>[0] = [
{
path: '/',
element: lazyLoader(() => import('../views/Home'))
Expand All @@ -23,5 +24,28 @@ export default [
{
path: '/about',
element: lazyLoader(() => import('../views/About'))
},
{
path: '/admin',
children: [
{
path: '/admin',
element: lazyLoader(() => import('../views/Admin'))
},
{
path: '/admin/login',
element: lazyLoader(() => import('../views/Admin/Login'))
},
{
path: '/admin/create',
element: lazyLoader(() => import('../views/Admin/Create'))
},
{
path: '/admin/edit/:id',
element: lazyLoader(() => import('../views/Admin/Edit'))
}
]
}
];

export default Routes;
9 changes: 9 additions & 0 deletions packages/client/src/store/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export default class Store {
public static get(key: string) {
return localStorage.getItem(key);
}

public static set(key: string, value: string) {
localStorage.setItem(key, value);
}
}
41 changes: 41 additions & 0 deletions packages/client/src/styles/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,44 @@ a::selection {
border: 1px solid #00000040;
border-radius: 10px;
}

.cardButton {
height: 40px;
width: 110px;
color: #212121 !important;
font-size: 1.2rem;
margin: 10px;
border: 1px solid #00000040 !important;
border-radius: 5px;
}

.cardButton:hover {
background-color: #227d51 !important;
color: #fff !important;
}

.cardButton a:hover {
background: none;
}

.cardList a {
background: none;
}

.cardFixed {
width: 1000px;
max-width: 95vw;
margin-bottom: 14px;
}

.clean {
background: none !important;
}

.cleanAll {
background: none !important;
}

.cleanAll * {
background: none !important;
}
193 changes: 193 additions & 0 deletions packages/client/src/views/Admin/Create/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
import React from 'react';
import { Button, Card, Collapse, DatePicker, Flex, Form, Input, InputNumber, Radio, Space, notification } from 'antd';
import { MinusCircleOutlined, PlusOutlined } from '@ant-design/icons';
import { MoehubDataCharacter } from '@moehub/common';
import styles from '../styles.module.css';
import { createCharacter } from '../../../http';

const CreateView: React.FC = () => {
const [form] = Form.useForm();

const onFinish = (values: MoehubDataCharacter) => {
createCharacter(values).then(() => notification.success({ message: '角色创建成功' }));
};

return (
<div>
<h1>角色创建</h1>
<Flex justify="center" align="center" vertical>
<Card hoverable className="card cardFixed cleanAll">
<Form form={form} name="control-hooks" className={styles.form} onFinish={onFinish}>
<Form.Item name="name" label="角色名" rules={[{ required: true }]}>
<Input />
</Form.Item>
<Form.Item name="romaji" label="罗马音" rules={[{ required: true }]}>
<Input />
</Form.Item>
<Form.Item name="gender" label="性别" rules={[{ required: true }]}>
<Radio.Group>
<Radio.Button value="MALE">男性</Radio.Button>
<Radio.Button value="FEMALE">女性</Radio.Button>
<Radio.Button value="OTHER">其它/未知</Radio.Button>
</Radio.Group>
</Form.Item>
<Form.Item name="series" label="作品名" rules={[{ required: true }]}>
<Input />
</Form.Item>
<Form.Item name="seriesGenre" label="作品类型" rules={[{ required: true }]}>
<Radio.Group>
<Radio value="ANIME">动画</Radio>
<Radio value="COMIC">漫画</Radio>
<Radio value="GALGAME">Galgame</Radio>
<Radio value="GAME">游戏</Radio>
<Radio value="NOVEL">轻小说</Radio>
<Radio value="OTHER">其它</Radio>
</Radio.Group>
</Form.Item>
<hr />
<Form.List name="alias">
{(fields, { add, remove }, { errors }) => (
<>
{fields.map((field) => (
<>
<Form.Item {...field} rules={[{ required: true }]}>
<Input />
</Form.Item>
<MinusCircleOutlined onClick={() => remove(field.name)} />
</>
))}
<Form.Item>
<Button type="dashed" onClick={() => add()} icon={<PlusOutlined />}>
添加别名
</Button>
<Form.ErrorList errors={errors} />
</Form.Item>
</>
)}
</Form.List>
<Form.List name="images">
{(fields, { add, remove }, { errors }) => (
<>
{fields.map((field) => (
<>
<Form.Item {...field} rules={[{ required: true }]}>
<Input />
</Form.Item>
<MinusCircleOutlined onClick={() => remove(field.name)} />
</>
))}
<Form.Item>
<Button type="dashed" onClick={() => add()} icon={<PlusOutlined />}>
添加图片
</Button>
<Form.ErrorList errors={errors} />
</Form.Item>
</>
)}
</Form.List>
<Form.Item name="description" label="描述">
<Input />
</Form.Item>
<Form.Item name="hitokoto" label="一言">
<Input />
</Form.Item>
<Form.Item name="birthday" label="生日">
<DatePicker format="MM-DD" />
</Form.Item>
<Form.Item name="comment" label="个人评价">
<Input />
</Form.Item>
<Form.List name="tags">
{(fields, { add, remove }, { errors }) => (
<>
{fields.map((field) => (
<>
<Form.Item {...field} rules={[{ required: true }]}>
<Input />
</Form.Item>
<MinusCircleOutlined onClick={() => remove(field.name)} />
</>
))}
<Form.Item>
<Button type="dashed" onClick={() => add()} icon={<PlusOutlined />}>
添加萌点
</Button>
<Form.ErrorList errors={errors} />
</Form.Item>
</>
)}
</Form.List>
<hr />
<Collapse>
<Collapse.Panel header="其它信息" key="1">
<Form.Item name="voice" label="声优">
<Input />
</Form.Item>
<Form.Item name="age" label="年龄" rules={[{ type: 'number' }]}>
<InputNumber />
</Form.Item>
<Form.Item name="height" label="身高" rules={[{ type: 'number' }]}>
<InputNumber />
</Form.Item>
<Form.Item name="bust" label="胸围" rules={[{ type: 'number' }]}>
<InputNumber />
</Form.Item>
<Form.Item name="waist" label="腰围" rules={[{ type: 'number' }]}>
<InputNumber />
</Form.Item>
<Form.Item name="hip" label="臀围" rules={[{ type: 'number' }]}>
<InputNumber />
</Form.Item>
<Form.Item name="hairColor" label="发色">
<Input />
</Form.Item>
<Form.Item name="eyeColor" label="瞳色">
<Input />
</Form.Item>
<Form.Item name="bloodType" label="血型">
<Radio.Group>
<Radio value="A">A 型</Radio>
<Radio value="B">B 型</Radio>
<Radio value="AB">AB 型</Radio>
<Radio value="O">O 型</Radio>
</Radio.Group>
</Form.Item>

<Form.List name="url">
{(fields, { add, remove }, { errors }) => (
<>
{fields.map((field) => (
<>
<Form.Item {...field} rules={[{ required: true }]}>
<Input />
</Form.Item>
<MinusCircleOutlined onClick={() => remove(field.name)} />
</>
))}
<Form.Item>
<Button type="dashed" onClick={() => add()} icon={<PlusOutlined />}>
添加链接
</Button>
<Form.ErrorList errors={errors} />
</Form.Item>
</>
)}
</Form.List>
</Collapse.Panel>
</Collapse>
<br />
<Form.Item>
<Space>
<Button type="primary" htmlType="submit" className="cardButton">
提交
</Button>
</Space>
</Form.Item>
</Form>
</Card>
</Flex>
</div>
);
};

export default CreateView;
Loading

0 comments on commit e52fdba

Please sign in to comment.