├── src ├── plugins │ ├── react-redux │ │ ├── index.ts │ │ └── provider.tsx │ └── redux │ │ ├── index.ts │ │ ├── model.ts │ │ ├── combineReducers.ts │ │ ├── applyMiddlewares.ts │ │ └── createStore.ts ├── types │ ├── chart.ts │ ├── account.ts │ ├── base.ts │ ├── dashboard.ts │ ├── demo.ts │ ├── api.ts │ ├── stock.ts │ ├── stockHistory.ts │ ├── apiError.ts │ ├── geolog.ts │ └── global.ts ├── stores │ ├── index.ts │ ├── hooks.ts │ ├── global.ts │ ├── reducer.ts │ └── actions.ts ├── assets │ ├── imgs │ │ ├── logo.png │ │ ├── moon.jpg │ │ ├── world.jpg │ │ ├── world.bd.jpg │ │ ├── starfield.jpg │ │ └── logo.svg │ └── icons │ │ └── threejs.tsx ├── pages │ ├── home │ │ ├── style.module.scss │ │ ├── components │ │ │ ├── header.module.scss │ │ │ ├── footer.tsx │ │ │ ├── siderbar.module.scss │ │ │ ├── siderbar.tsx │ │ │ └── header.tsx │ │ └── home.tsx │ ├── stocks │ │ ├── historyDetail.tsx │ │ ├── kLine │ │ │ └── index.tsx │ │ ├── detail.tsx │ │ ├── index.tsx │ │ └── history.tsx │ ├── charts │ │ ├── america │ │ │ └── index.tsx │ │ ├── china │ │ │ └── index.tsx │ │ ├── style.module.scss │ │ ├── index.tsx │ │ └── day │ │ │ └── index.tsx │ ├── threejs │ │ └── index.tsx │ ├── logs │ │ ├── style.module.scss │ │ ├── useApi.ts │ │ ├── geography │ │ │ └── useList.ts │ │ ├── useErrors.ts │ │ └── drawer.tsx │ ├── demos │ │ ├── demo.module.scss │ │ ├── components │ │ │ └── test.tsx │ │ ├── reducer.ts │ │ ├── useDemo.ts │ │ ├── demoMobx.tsx │ │ └── demoRedux.tsx │ ├── app.tsx │ ├── dashboard │ │ ├── style.module.scss │ │ ├── dashboard.tsx │ │ └── useData.ts │ ├── face │ │ └── style.module.scss │ ├── lottery │ │ ├── detail │ │ │ ├── style.module.scss │ │ │ └── useDetail.ts │ │ ├── trend │ │ │ └── useTrend.ts │ │ ├── useBallTrend.ts │ │ ├── chart │ │ │ └── index.tsx │ │ └── useBallList.ts │ ├── login │ │ ├── style.module.scss │ │ ├── wave.tsx │ │ ├── login.tsx │ │ └── index.tsx │ ├── leaveMsg │ │ ├── useDetail.ts │ │ ├── useList.ts │ │ ├── leaveMsgEdit.tsx │ │ ├── detail.tsx │ │ ├── leaveMsgList.tsx │ │ └── index.tsx │ ├── comment │ │ ├── useDetail.ts │ │ ├── useList.ts │ │ ├── detail.tsx │ │ ├── commentEdit.tsx │ │ ├── commentList.tsx │ │ └── index.tsx │ ├── tag │ │ ├── useTag.ts │ │ ├── useDetail.ts │ │ ├── tagEdit.tsx │ │ ├── tagCreate.tsx │ │ ├── detail.tsx │ │ ├── index.tsx │ │ └── tagList.tsx │ ├── articleType │ │ ├── useArticleType.ts │ │ ├── useDetail.ts │ │ ├── articleTypeEdit.tsx │ │ ├── articleTypeCreate.tsx │ │ ├── detail.tsx │ │ ├── index.tsx │ │ └── articleTypeList.tsx │ ├── user │ │ ├── useList.ts │ │ ├── detail │ │ │ └── useDetail.ts │ │ └── userEdit.tsx │ ├── article │ │ ├── useList.ts │ │ ├── useDetail.ts │ │ └── detail.tsx │ └── register │ │ └── index.tsx ├── models │ ├── tag.ts │ ├── articleType.ts │ ├── leaveMsg.ts │ ├── base.ts │ ├── comment.ts │ ├── article.ts │ ├── user.ts │ └── ball.ts ├── components │ ├── progress │ │ ├── style.module.scss │ │ └── index.tsx │ ├── datePicker │ │ └── index.tsx │ ├── jsonView.tsx │ ├── notFound.tsx │ ├── message.ts │ ├── loading.tsx │ └── editor │ │ ├── new.tsx │ │ └── index.tsx ├── utils │ ├── i18n │ │ ├── zh_CN.json │ │ ├── zh_TW.json │ │ ├── en_US.json │ │ └── index.ts │ ├── params.ts │ ├── http.ts │ ├── debounce.ts │ ├── themeConfig.ts │ └── httpHelper.ts ├── services │ ├── chart.ts │ ├── api.ts │ ├── account.ts │ ├── stock.ts │ ├── geography.ts │ ├── stockHistory.ts │ └── http.ts ├── scss │ ├── variables.scss │ ├── theme.scss │ ├── functions.scss │ └── app.scss ├── custom.d.ts ├── index.tsx ├── constants │ └── index.ts ├── index.html ├── routes │ ├── pageRoutes.tsx │ └── index.tsx └── global.d.ts ├── statics ├── favicon.ico ├── imgs │ └── favicon.ico ├── model │ ├── age_gender_model.bin │ ├── face_expression_model.bin │ ├── face_landmark_68_model.bin │ ├── face_recognition_model.bin │ ├── ssd_mobilenetv1_model.bin │ ├── tiny_face_detector_model.bin │ ├── face_landmark_68_tiny_model.bin │ └── tiny_face_detector_model-weights_manifest.json ├── manifest.json └── logo.svg ├── .gitignore ├── index.html ├── .stylelintrc.js ├── README.md ├── .babelrc.js ├── tsconfig.json ├── vite.config.ts └── .eslintrc.js /src/plugins/react-redux/index.ts: -------------------------------------------------------------------------------- 1 | export * from './provider' 2 | export * from './connect' -------------------------------------------------------------------------------- /src/types/chart.ts: -------------------------------------------------------------------------------- 1 | 2 | export interface DayChart { 3 | d: string 4 | total: number 5 | } -------------------------------------------------------------------------------- /src/stores/index.ts: -------------------------------------------------------------------------------- 1 | export * from './global' 2 | export * from './actions' 3 | export * from './reducer' -------------------------------------------------------------------------------- /statics/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xpioneer/react-typescript/HEAD/statics/favicon.ico -------------------------------------------------------------------------------- /src/assets/imgs/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xpioneer/react-typescript/HEAD/src/assets/imgs/logo.png -------------------------------------------------------------------------------- /src/assets/imgs/moon.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xpioneer/react-typescript/HEAD/src/assets/imgs/moon.jpg -------------------------------------------------------------------------------- /src/assets/imgs/world.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xpioneer/react-typescript/HEAD/src/assets/imgs/world.jpg -------------------------------------------------------------------------------- /statics/imgs/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xpioneer/react-typescript/HEAD/statics/imgs/favicon.ico -------------------------------------------------------------------------------- /src/assets/imgs/world.bd.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xpioneer/react-typescript/HEAD/src/assets/imgs/world.bd.jpg -------------------------------------------------------------------------------- /src/assets/imgs/starfield.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xpioneer/react-typescript/HEAD/src/assets/imgs/starfield.jpg -------------------------------------------------------------------------------- /src/pages/home/style.module.scss: -------------------------------------------------------------------------------- 1 | 2 | .right { 3 | height: 100vh; 4 | } 5 | 6 | .main { 7 | overflow: auto; 8 | } 9 | -------------------------------------------------------------------------------- /src/plugins/redux/index.ts: -------------------------------------------------------------------------------- 1 | export * from './model' 2 | export * from './createStore' 3 | export * from './combineReducers' -------------------------------------------------------------------------------- /statics/model/age_gender_model.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xpioneer/react-typescript/HEAD/statics/model/age_gender_model.bin -------------------------------------------------------------------------------- /src/pages/home/components/header.module.scss: -------------------------------------------------------------------------------- 1 | 2 | .header { 3 | // position: sticky; 4 | // top: 0; 5 | // z-index: 1; 6 | } 7 | -------------------------------------------------------------------------------- /statics/model/face_expression_model.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xpioneer/react-typescript/HEAD/statics/model/face_expression_model.bin -------------------------------------------------------------------------------- /statics/model/face_landmark_68_model.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xpioneer/react-typescript/HEAD/statics/model/face_landmark_68_model.bin -------------------------------------------------------------------------------- /statics/model/face_recognition_model.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xpioneer/react-typescript/HEAD/statics/model/face_recognition_model.bin -------------------------------------------------------------------------------- /statics/model/ssd_mobilenetv1_model.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xpioneer/react-typescript/HEAD/statics/model/ssd_mobilenetv1_model.bin -------------------------------------------------------------------------------- /statics/model/tiny_face_detector_model.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xpioneer/react-typescript/HEAD/statics/model/tiny_face_detector_model.bin -------------------------------------------------------------------------------- /statics/model/face_landmark_68_tiny_model.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xpioneer/react-typescript/HEAD/statics/model/face_landmark_68_tiny_model.bin -------------------------------------------------------------------------------- /src/models/tag.ts: -------------------------------------------------------------------------------- 1 | import { BaseModel } from './base' 2 | 3 | export interface Tag extends BaseModel { 4 | 5 | name: string 6 | 7 | remark: string 8 | } -------------------------------------------------------------------------------- /src/models/articleType.ts: -------------------------------------------------------------------------------- 1 | import { BaseModel } from './base' 2 | 3 | export interface ArticleType extends BaseModel { 4 | 5 | name: string 6 | 7 | remark: string 8 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | #editor 2 | .vscode 3 | .idea 4 | 5 | # dependencies 6 | /node_modules 7 | dist 8 | 9 | # mac 10 | .DS_Store 11 | 12 | npm-debug.log* 13 | yarn-debug.log* 14 | yarn-error.log* 15 | -------------------------------------------------------------------------------- /src/pages/stocks/historyDetail.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from 'react' 2 | 3 | const StockHistoryPage: React.FC = () => { 4 | return
5 | } 6 | 7 | export default StockHistoryPage -------------------------------------------------------------------------------- /src/types/account.ts: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | export interface LoginForm { 5 | username: string 6 | password: string 7 | } 8 | 9 | export interface RegisterForm extends LoginForm { 10 | confirm: string 11 | } 12 | -------------------------------------------------------------------------------- /src/components/progress/style.module.scss: -------------------------------------------------------------------------------- 1 | .progress { 2 | position: fixed; 3 | top: 0; 4 | left: 0; 5 | z-index: 1; 6 | border-top-right-radius: 2px; 7 | border-bottom-right-radius: 2px; 8 | transition: width 0.02s; 9 | } -------------------------------------------------------------------------------- /src/models/leaveMsg.ts: -------------------------------------------------------------------------------- 1 | import { BaseModel } from './base' 2 | 3 | export interface LeaveMsg extends BaseModel { 4 | 5 | description: string 6 | 7 | parentId: string 8 | 9 | ip: string 10 | 11 | client: string 12 | } -------------------------------------------------------------------------------- /src/pages/charts/america/index.tsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from 'react' 2 | 3 | 4 | 5 | export default function Chart() { 6 | 7 | return ( 8 |
9 | this is chart page. 10 |
11 | ) 12 | } 13 | -------------------------------------------------------------------------------- /src/pages/charts/china/index.tsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from 'react' 2 | 3 | 4 | 5 | export default function Chart() { 6 | 7 | return ( 8 |
9 | this is chart page. 10 |
11 | ) 12 | } 13 | -------------------------------------------------------------------------------- /src/pages/charts/style.module.scss: -------------------------------------------------------------------------------- 1 | .chartW { 2 | position: relative; 3 | 4 | h2 { 5 | text-align: center; 6 | } 7 | 8 | .chart { 9 | height: 500px; 10 | border: 1px solid #eee; 11 | margin-bottom: 20px; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/models/base.ts: -------------------------------------------------------------------------------- 1 | 2 | export class BaseModel { 3 | id: string 4 | 5 | createdAt: string 6 | 7 | createdBy?: string 8 | 9 | updatedAt?: string 10 | 11 | updatedBy?: string 12 | 13 | deletedAt?: string 14 | 15 | deletedBy?: string 16 | } -------------------------------------------------------------------------------- /src/models/comment.ts: -------------------------------------------------------------------------------- 1 | import { BaseModel } from './base' 2 | 3 | export interface Comment extends BaseModel { 4 | 5 | description: string 6 | 7 | articleId: string 8 | 9 | parentId: string 10 | 11 | ip: string 12 | 13 | client: string 14 | } -------------------------------------------------------------------------------- /src/utils/i18n/zh_CN.json: -------------------------------------------------------------------------------- 1 | { 2 | "confirm": "确认", 3 | "ok": "好的", 4 | "success": "成功", 5 | "introduction": "你好,欢迎来到我的个人技能展示项目。我是一名web应用开发者,项目使用React + Typescript开发,脚手架是自己从0到1自己写的。非常热爱编程,喜欢前端开发。完全理解并且能开发前后端所有的流程等功能,熟练使用nodejs,Python,Typescript,ES6+,mysql等技术栈。" 6 | } -------------------------------------------------------------------------------- /src/utils/i18n/zh_TW.json: -------------------------------------------------------------------------------- 1 | { 2 | "confirm": "确认", 3 | "ok": "好的", 4 | "success": "成功", 5 | "introduction": "你好,歡迎來到我的個人技能展示項目。 我是一名web應用開發者,項目使用React + Typescript開發,脚手架是自己從0到1自己寫的。 非常熱愛程式設計,喜歡前端開發。 完全理解並且能開發前後端所有的流程等功能,熟練使用nodejs,Python,Typescript,ES6+,mysql等科技棧。" 6 | } -------------------------------------------------------------------------------- /src/components/datePicker/index.tsx: -------------------------------------------------------------------------------- 1 | import dateFnsGenerateConfig from 'rc-picker/lib/generate/dateFns' 2 | import generatePicker from 'antd/es/date-picker/generatePicker' 3 | import 'antd/es/date-picker/style/index' 4 | 5 | export const DatePicker = generatePicker(dateFnsGenerateConfig) 6 | -------------------------------------------------------------------------------- /src/services/chart.ts: -------------------------------------------------------------------------------- 1 | import { DayChart } from '@/types/chart' 2 | import { useRequest } from './http' 3 | import { Method } from '@/types/demo' 4 | 5 | 6 | 7 | export const getEveryDay = () => { 8 | return useRequest('/log/geo/day', undefined, Method.GET).then(res => res.data) 9 | } -------------------------------------------------------------------------------- /src/pages/threejs/index.tsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect } from 'react' 2 | import { EarthMap } from './earth' 3 | 4 | export default function ThreeJSPage() { 5 | useEffect(() => { 6 | // 7 | }, []) 8 | return
9 | This is Threejs Demo Page 10 | 11 |
12 | } -------------------------------------------------------------------------------- /statics/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "React", 3 | "icons": [ 4 | { 5 | "src": "logo.svg", 6 | "sizes": "192x192", 7 | "type": "image/svg" 8 | } 9 | ], 10 | "theme_color": "#ffffff", 11 | "background_color": "#ffffff", 12 | "start_url": "/React-PWA/", 13 | "display": "standalone" 14 | } -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | React + Vite 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/pages/logs/style.module.scss: -------------------------------------------------------------------------------- 1 | 2 | /* row-flex */ 3 | 4 | .large { 5 | top: 80px; 6 | 7 | :global { 8 | .row { 9 | display: flex; 10 | padding-bottom: 12px; 11 | 12 | & > div { 13 | word-break: break-all; 14 | 15 | &:first-child { 16 | flex: 0 0 100px; 17 | } 18 | } 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /src/pages/charts/index.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | import DayChart from './day' 3 | import styles from './style.module.scss' 4 | 5 | export default function ChartPage() { 6 | 7 | return ( 8 |
9 |

Date Matrix and Line Graphs of Requests from Around the World

10 | 11 |
12 | ) 13 | } 14 | -------------------------------------------------------------------------------- /src/scss/variables.scss: -------------------------------------------------------------------------------- 1 | $main-color: #fff; 2 | 3 | :root { 4 | --main-bg-color: #fff; 5 | --main-txt-color: #333; 6 | --main-border-color: #eee; 7 | } 8 | 9 | @media (prefers-color-scheme: dark) { 10 | :root { 11 | --main-bg-color: #000; 12 | --main-txt-color: #ddd; 13 | } 14 | } 15 | 16 | body[theme=dark] { 17 | --main-bg-color: #000; 18 | --main-txt-color: #ddd; 19 | } -------------------------------------------------------------------------------- /src/plugins/redux/model.ts: -------------------------------------------------------------------------------- 1 | 2 | export interface IAction { 3 | type: string 4 | playload?: any 5 | } 6 | 7 | export interface IAnyObject { 8 | [key: string]: any 9 | } 10 | 11 | export interface ICreateStore { 12 | getState: () => any 13 | dispatch: (action: IAction) => void 14 | subscribe: (listener: Function) => () => void 15 | replaceReducer: (nextReducer: Function) => void 16 | } -------------------------------------------------------------------------------- /statics/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | React Logo 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/pages/demos/demo.module.scss: -------------------------------------------------------------------------------- 1 | .block { 2 | margin-bottom: 20px; 3 | padding: 12px; 4 | border-radius: 6px; 5 | box-shadow: rgba(0, 0, 0, 0.12) 0px 1px 8px, rgba(0, 0, 0, 0.12) 0px 1px 6px; 6 | } 7 | 8 | 9 | .jsonView { 10 | min-height: 200px; 11 | 12 | :global { 13 | .ant-form-item-control-input-content > div { 14 | border-radius: 6px; 15 | min-height: 400px; 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /src/assets/imgs/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | React Logo 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/pages/app.tsx: -------------------------------------------------------------------------------- 1 | import React, { useReducer } from 'react' 2 | import { AppStore, reducer, initState } from '@/stores' 3 | import { Navigation } from '@/routes/index' 4 | 5 | const App: React.FC = () => { 6 | 7 | const store = useReducer(reducer, initState) 8 | 9 | return ( 10 | 11 | 12 | 13 | ) 14 | } 15 | 16 | export default App -------------------------------------------------------------------------------- /src/scss/theme.scss: -------------------------------------------------------------------------------- 1 | 2 | /* dark mode */ 3 | @media (prefers-color-scheme: dark) { 4 | body { 5 | background-color: var(--main-bg-color); 6 | color: var(--main-txt-color); 7 | } 8 | 9 | a { 10 | color: #4e9eff; 11 | } 12 | } 13 | 14 | /* custom dark mode */ 15 | body[theme=dark] { 16 | background-color: var(--main-bg-color); 17 | color: var(--main-txt-color); 18 | 19 | a { 20 | color: #4e9eff; 21 | } 22 | } -------------------------------------------------------------------------------- /src/types/base.ts: -------------------------------------------------------------------------------- 1 | 2 | export class BaseModel { 3 | id: string 4 | createAt: number 5 | createBy: string 6 | updateAt: number 7 | updateBy: string 8 | deleteAt: number 9 | deleteBy: string 10 | } 11 | 12 | 13 | export enum DateFormat { 14 | Date = 'yyyy-MM-dd', 15 | DateDiagonal = 'yyyy/MM/dd', 16 | DateTime = 'yyyy-MM-dd HH:mm:ss', 17 | DateTimeM = 'yyyy-MM-dd HH:mm', 18 | DateTimeMS = 'yyyy-MM-dd HH:mm:SSS' 19 | } -------------------------------------------------------------------------------- /src/plugins/redux/combineReducers.ts: -------------------------------------------------------------------------------- 1 | import { IAction, IAnyObject } from './model' 2 | 3 | // 组合reducer,计算后存为单个state 4 | export const combineReducers = (reducers: IAnyObject) => { 5 | // 这里重新组合state 6 | return (state: IAnyObject = {}, action: IAction) => { 7 | let newState: IAnyObject = {} 8 | for (let key in reducers) { 9 | newState[key] = reducers[key](state[key], action) 10 | } 11 | return newState 12 | } 13 | } -------------------------------------------------------------------------------- /src/custom.d.ts: -------------------------------------------------------------------------------- 1 | import { MessageInstance } from 'antd/lib/message/interface' 2 | import { NotificationInstance } from 'antd/lib/notification/interface' 3 | import { AxiosStatic } from 'axios' 4 | 5 | declare global { 6 | 7 | const $http: AxiosStatic 8 | 9 | const $msg: MessageInstance 10 | 11 | const $notice: NotificationInstance 12 | 13 | interface ICommonProps

{ 14 | [key: string]: P 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/types/dashboard.ts: -------------------------------------------------------------------------------- 1 | 2 | type Stats = { 3 | count: number 4 | name: string 5 | } 6 | 7 | export class StatsData { 8 | statusCnt: { 9 | apiCnt: Stats[] 10 | errCnt: Stats[] 11 | } 12 | pathCnt: { 13 | apiCnt: Stats[] 14 | errCnt: Stats[] 15 | } 16 | } 17 | 18 | export type GeographicStats = { 19 | ip: string 20 | name_en: string 21 | sub_name_en: string 22 | latitude: string 23 | longitude: string 24 | total: string 25 | } -------------------------------------------------------------------------------- /src/components/jsonView.tsx: -------------------------------------------------------------------------------- 1 | import React, {} from 'react' 2 | import { JsonView, allExpanded, darkStyles, defaultStyles } from 'react-json-view-lite'; 3 | import 'react-json-view-lite/dist/index.css'; 4 | 5 | interface IProps { 6 | data: Object | any[] 7 | } 8 | 9 | export const JSONView: React.FC = ({ 10 | data 11 | }) => { 12 | return 17 | } -------------------------------------------------------------------------------- /src/stores/hooks.ts: -------------------------------------------------------------------------------- 1 | import { useAppStore } from './global' 2 | import { Action, setTheme } from './actions' 3 | import { THEME_MODE } from '@/constants' 4 | import { Theme } from '../types/global' 5 | import { storage } from '../utils/tools' 6 | 7 | /** 8 | * set app theme 9 | * @param theme enum Theme 10 | */ 11 | export const useTheme = (theme: Theme, dispatch: React.Dispatch) => { 12 | storage.set(THEME_MODE, theme) 13 | dispatch(setTheme(theme)) 14 | } -------------------------------------------------------------------------------- /src/index.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | import { createRoot } from 'react-dom/client' 3 | import App from './pages/app' 4 | import './scss/app.scss' 5 | import 'antd/dist/reset.css' 6 | import 'quill/dist/quill.snow.css' 7 | import serviceWorker from './serviceWorker' 8 | import { setRem } from '@utils/tools' 9 | import '@utils/i18n' 10 | 11 | // setRem(); 12 | 13 | const container = document.getElementById('app')! 14 | createRoot(container).render() 15 | serviceWorker() -------------------------------------------------------------------------------- /src/pages/home/components/footer.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | import { Layout, Flex, theme } from 'antd' 3 | 4 | const { Footer } = Layout 5 | 6 | export default () => { 7 | const { token: { boxShadow, paddingSM } } = theme.useToken() 8 | return

9 | 10 | Copyright by  11 | xpioneer 12 | 13 |
14 | } -------------------------------------------------------------------------------- /src/pages/dashboard/style.module.scss: -------------------------------------------------------------------------------- 1 | 2 | .dashboard { 3 | color: var(--main-txt-color); 4 | background-color: var(--main-bg-color); 5 | padding: 20px; 6 | 7 | h2 { 8 | text-align: center; 9 | padding-bottom: 8px; 10 | } 11 | 12 | .chart { 13 | position: relative; 14 | height: 400px; 15 | width: 100%; 16 | margin-bottom: 24px; 17 | border: 1px solid var(--main-border-color); 18 | 19 | :global(.amap-container) { 20 | left: 0; 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /src/models/article.ts: -------------------------------------------------------------------------------- 1 | import { BaseModel } from './base' 2 | import { ArticleType } from './articleType' 3 | import { Tag } from './tag' 4 | 5 | export interface Article extends BaseModel { 6 | title: string 7 | 8 | abstract: string 9 | 10 | description: string 11 | 12 | tag: string[] 13 | } 14 | 15 | export type ArticlesData = { 16 | articles?: IPageData
17 | article?: Article 18 | articleTypes: { 19 | list: ArticleType[] 20 | } 21 | tags: { 22 | list: Tag[] 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/pages/face/style.module.scss: -------------------------------------------------------------------------------- 1 | 2 | .face { 3 | height: 100%; 4 | 5 | img, canvas { 6 | width: 100%; 7 | display: block; 8 | margin: 0 auto; 9 | } 10 | } 11 | 12 | .wrap { 13 | height: 100%; 14 | 15 | &> div { 16 | width: 44%; 17 | height: 100%; 18 | border: 1px dashed #ccc; 19 | border-radius: 4px; 20 | display: flex; 21 | justify-content: center; 22 | align-items: center; 23 | 24 | &.result { 25 | border-color:red; 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/components/notFound.tsx: -------------------------------------------------------------------------------- 1 | import { useState } from "react" 2 | import * as React from 'react' 3 | import { Button, Result } from 'antd' 4 | import { useNavigate } from 'react-router-dom' 5 | 6 | 7 | export const NotFound: React.FC = () => { 8 | 9 | const navigate = useNavigate() 10 | 11 | return navigate('/')}>Back Home} 16 | /> 17 | } 18 | -------------------------------------------------------------------------------- /src/types/demo.ts: -------------------------------------------------------------------------------- 1 | import { object2Options } from '@utils/tools' 2 | 3 | export interface APIFormTest { 4 | url: string 5 | method: Method 6 | apiType: APIType 7 | params: string 8 | } 9 | 10 | 11 | export enum Method { 12 | GET = 'GET', 13 | POST = 'POST', 14 | PUT = 'PUT', 15 | DELETE = 'DELETE', 16 | } 17 | 18 | export const methodOpts = object2Options(Method) 19 | 20 | export enum APIType { 21 | 'RESTful' = '/api', 22 | 'Graphql' = '/graphql' 23 | } 24 | 25 | export const apiTypeOpts = object2Options(APIType) 26 | -------------------------------------------------------------------------------- /src/pages/charts/day/index.tsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from 'react' 2 | import { useChart } from './useChart' 3 | import { Spin } from 'antd' 4 | import styles from '../style.module.scss' 5 | 6 | export default function Chart() { 7 | 8 | const { 9 | loading, 10 | heatRef, 11 | chartRef, 12 | } = useChart() 13 | 14 | return ( 15 | 16 |
17 |
18 | 19 | ) 20 | } 21 | -------------------------------------------------------------------------------- /src/pages/lottery/detail/style.module.scss: -------------------------------------------------------------------------------- 1 | 2 | .ballWrap { 3 | flex-wrap: wrap; 4 | } 5 | .ball { 6 | width: 32px; 7 | height: 32px; 8 | border-radius: 100%; 9 | cursor: pointer; 10 | border: 1px solid #f54646; 11 | color: #f54646; 12 | transition: all .3s; 13 | 14 | &.active { 15 | background-color: #f54646; 16 | color: #fff; 17 | } 18 | 19 | &.blue { 20 | border-color: #39f; 21 | color: #39f; 22 | 23 | &.active { 24 | background-color: #39f; 25 | color: #fff; 26 | } 27 | } 28 | } 29 | 30 | 31 | -------------------------------------------------------------------------------- /src/utils/i18n/en_US.json: -------------------------------------------------------------------------------- 1 | { 2 | "confirm": "Confirm", 3 | "ok": "OK", 4 | "success": "Success", 5 | "introduction": "Hello, welcome to my personal skills showcase project. I am a web application developer, and my project is developed using React+Typescript. The scaffolding was written by myself from scratch. I am very passionate about programming and enjoy front-end development. Fully understand and be able to develop all front-end and back-end processes and functions, proficient in using technology stacks such as Node.js, Python, Typescript, ES6+, MySQL, etc." 6 | } -------------------------------------------------------------------------------- /src/stores/global.ts: -------------------------------------------------------------------------------- 1 | import { createContext, Dispatch, useContext, useReducer } from 'react' 2 | import { Store } from '@/types/global' 3 | import { Action, } from './actions' 4 | 5 | export const initState = new Store 6 | 7 | type AppContextProps = [Store, Dispatch] | undefined 8 | 9 | export const AppStore = createContext(undefined) 10 | 11 | export const useAppStore = () => { 12 | const store = useContext(AppStore) 13 | if (!store) { 14 | throw new Error('useAppStore must be used within a AppStore.Provider'); 15 | } 16 | return store 17 | } -------------------------------------------------------------------------------- /src/models/user.ts: -------------------------------------------------------------------------------- 1 | import { object2Options } from '@/utils/tools' 2 | import { BaseModel } from './base' 3 | 4 | export class User extends BaseModel { 5 | 6 | username: string 7 | 8 | nickName: string 9 | 10 | userType: number 11 | 12 | sex: number 13 | 14 | remark: string 15 | } 16 | 17 | export enum UserType { 18 | 超级用户 = 0, 19 | 管理员 = 1, 20 | 普通用户 = 2, 21 | 测试用户 = 9, 22 | } 23 | 24 | export const userTypeOpts = object2Options(UserType) 25 | 26 | 27 | export enum UserSex { 28 | 女 = 0, 29 | 男 = 1, 30 | } 31 | 32 | export const userSexOpts = object2Options(UserSex) -------------------------------------------------------------------------------- /src/types/api.ts: -------------------------------------------------------------------------------- 1 | 2 | export interface APILog { 3 | host: string 4 | 5 | path: string 6 | 7 | url: string 8 | 9 | params: any 10 | 11 | method: string 12 | 13 | origin: string 14 | 15 | hostname: string 16 | 17 | headers: any 18 | 19 | resHeaders: any 20 | 21 | resData: any 22 | 23 | time: number 24 | 25 | protocol: string 26 | 27 | status: number 28 | 29 | msg: string 30 | 31 | client: string 32 | } 33 | 34 | export type RequestStatus = 'default' | 'success' | 'warning' | 'error' 35 | 36 | export type APIQuery = { 37 | url: string 38 | path: string 39 | createdAt: string 40 | } -------------------------------------------------------------------------------- /src/models/ball.ts: -------------------------------------------------------------------------------- 1 | import { BaseModel } from './base' 2 | 3 | export interface Ball extends BaseModel { 4 | 5 | issue: number 6 | 7 | red1: number 8 | 9 | red2: number 10 | 11 | red3: number 12 | 13 | red4: number 14 | 15 | red5: number 16 | 17 | red6: number 18 | 19 | reds: number[] 20 | 21 | blue: number | number[] 22 | 23 | pool: number 24 | 25 | drawDate: string 26 | } 27 | 28 | export interface ChartOption { 29 | name: string 30 | value: number 31 | } 32 | 33 | export interface BallChart { 34 | reds: ChartOption[] 35 | blues: ChartOption[] 36 | redDisList: ChartOption[][] 37 | } -------------------------------------------------------------------------------- /src/constants/index.ts: -------------------------------------------------------------------------------- 1 | // jwt token key 2 | export const JWT_TOKEN = 'JWT_TOKEN' 3 | 4 | // system language key 5 | export const SYS_LANG = 'SYS_LANG' 6 | 7 | // redirect url key 8 | export const REDIRECT_URL = 'REDIRECT_URL' 9 | 10 | // graphql api modal 11 | export const GRAPHQL_API = '/graphql' 12 | 13 | export const COLOR_PRIMARY_KEY = 'COLOR_PRIMARY_KEY' 14 | 15 | export const PRIMARY_COLOR = '#087ea4' 16 | 17 | export const THEME_MODE = 'THEME_MODE' 18 | 19 | export const PREFERS_COLOR_SCHEME_DARK = '(prefers-color-scheme: dark)' 20 | 21 | export const EXCLUDE_KEYS = [ 22 | COLOR_PRIMARY_KEY, 23 | THEME_MODE, 24 | ] 25 | -------------------------------------------------------------------------------- /src/types/stock.ts: -------------------------------------------------------------------------------- 1 | 2 | 3 | export class Stock { 4 | id: number 5 | name: string 6 | code: string 7 | market: Market 8 | block: Board 9 | amount: number // 单手成交数量 10 | 11 | // 最后交易时间 12 | lastestTradeAt: number 13 | } 14 | 15 | export enum Market { 16 | 上证 = 1, 17 | 深证 18 | } 19 | 20 | export type KeyofMarket = keyof typeof Market 21 | 22 | export enum Board { 23 | 主板 = 1, 24 | 创业板, 25 | 科创板 26 | } 27 | 28 | export type KeyofBlock = keyof typeof Board 29 | 30 | 31 | export type StockQuery = Omit 32 | 33 | export type StockStats = { 34 | total: number 35 | block: Board 36 | } 37 | -------------------------------------------------------------------------------- /src/components/message.ts: -------------------------------------------------------------------------------- 1 | import { App } from 'antd' 2 | import type { MessageInstance } from 'antd/es/message/interface' 3 | import type { ModalStaticFunctions } from 'antd/es/modal/confirm' 4 | import type { NotificationInstance } from 'antd/es/notification/interface' 5 | 6 | let message: MessageInstance 7 | let notification: NotificationInstance 8 | let modal: Omit 9 | 10 | export default function useAntApp() { 11 | const app = App.useApp() 12 | message = app.message 13 | modal = app.modal 14 | notification = app.notification 15 | return { message, notification, modal } 16 | } 17 | 18 | export { message, notification, modal } -------------------------------------------------------------------------------- /.stylelintrc.js: -------------------------------------------------------------------------------- 1 | 2 | module.exports = { 3 | 'extends': 'stylelint-config-standard', 4 | 'rules': { 5 | 'selector-list-comma-newline-after': 'never-multi-line', 6 | 'value-list-comma-newline-after': 'never-multi-line', 7 | 'selector-pseudo-class-no-unknown': null, 8 | 'declaration-colon-newline-after': null, 9 | 'no-descending-specificity': null, 10 | 'max-empty-lines': 2, 11 | 'at-rule-no-unknown': [true, { 12 | ignoreAtRules: [/for|while|include/] 13 | }] 14 | }, 15 | ignoreFiles: [ 16 | 'node_modules/**/*', 17 | 'public/**/*', 18 | 'dist/**/*', 19 | '**/*.js', 20 | '**/*.jsx', 21 | '**/*.tsx', 22 | '**/*.ts' 23 | ] 24 | } -------------------------------------------------------------------------------- /src/components/loading.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | import { Spin } from 'antd' 3 | 4 | interface ILoadingProps { 5 | size?: 'small' | 'default' | 'large' 6 | } 7 | 8 | export default class Loading extends React.Component { 9 | 10 | state = { 11 | id: '123' 12 | } 13 | 14 | render () { 15 | const { size = 'default' } = this.props 16 | 17 | return ( 18 |
24 | 25 |
26 | ) 27 | } 28 | } 29 | 30 | const component = new Loading({size: 'default'}) -------------------------------------------------------------------------------- /src/services/api.ts: -------------------------------------------------------------------------------- 1 | import { pageData2Params } from '@utils/tools' 2 | import { APILog, APIQuery } from 'types/api' 3 | import { ErrorLog, ErrorQuery } from 'types/apiError' 4 | import { useRequest } from './http' 5 | import { StatsData } from '@/types/dashboard' 6 | 7 | 8 | export const getMongoLogsStats = () => { 9 | return useRequest('/log/stats').then(r => r.data) 10 | } 11 | 12 | 13 | export const getApiLogs = (params: APIQuery & IPageParams) => { 14 | return useRequest('/log-api', { params }) 15 | } 16 | 17 | 18 | export const getErrorLogs = (params: ErrorQuery & IPageParams) => { 19 | return useRequest('/log-errors', { params }) 20 | } 21 | 22 | -------------------------------------------------------------------------------- /src/types/stockHistory.ts: -------------------------------------------------------------------------------- 1 | 2 | 3 | export class StockHistory { 4 | id: number 5 | stockId: number 6 | timestamp: number 7 | volume: number 8 | open: number 9 | high: number 10 | low: number 11 | close: number 12 | chg: number 13 | percent: number 14 | turnoverrate: number 15 | amount: number 16 | volume_post: number 17 | amount_post: number 18 | pe: number 19 | pb: number 20 | ps: number 21 | pcf: number 22 | market_capital: number 23 | balance: number 24 | hold_volume_cn: number 25 | hold_ratio_cn: number 26 | net_volume_cn: number 27 | hold_volume_hk: number 28 | hold_ratio_hk: number 29 | net_volume_hk: number 30 | 31 | tradeAt: string 32 | } -------------------------------------------------------------------------------- /src/pages/home/components/siderbar.module.scss: -------------------------------------------------------------------------------- 1 | 2 | .logo { 3 | height: 64px; 4 | display: flex; 5 | align-items: center; 6 | padding-left: 20px; 7 | 8 | svg { 9 | display: block; 10 | animation: logoRotate 6s linear 0s infinite normal running none; 11 | 12 | &:hover { 13 | animation-play-state: paused; 14 | } 15 | } 16 | 17 | .title { 18 | color: #fff; 19 | margin-left: 20px; 20 | font-weight: bold; 21 | } 22 | } 23 | 24 | :global(.ant-layout-sider-collapsed) .title { 25 | display: none; 26 | } 27 | 28 | @keyframes logoRotate { 29 | from { 30 | transform: rotateZ(0); 31 | } 32 | 33 | to { 34 | transform: rotateZ(360deg); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # react-typescript 2 | 3 | ### 项目概况 4 | *** 5 | 使用Ant-Design开发的一套后台管理系统,主要用到了React、Typescript、Mobx、PWA等技术,使用webpack5打包构建,包含React18的一些新特性。 6 | 7 | ### 项目主要技术结构 8 | 9 | *** 10 | * react 11 | * typescript 12 | * antd 13 | * hooks 14 | * webpack5 15 | * react-router5 16 | * pwa 17 | 18 | ### 安装 19 | *** 20 | 在终端下操作 21 | 22 | 项目地址: (`git clone`) 23 | 24 | ``` 25 | git clone git@github.com:xpioneer/react-typescript.git 26 | ``` 27 | 28 | 安装node_modules依赖 `yarn` 29 | 30 | ``` 31 | yarn #in your command terminal 32 | ``` 33 | *** 34 | 35 | 36 | ### 运行 37 | 启动开发服务: (http://localhost:8060) 38 | 39 | ``` 40 | yarn start 41 | ``` 42 | 43 | 生产环境打包 44 | 45 | ``` 46 | yarn build 47 | ``` 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /src/pages/login/style.module.scss: -------------------------------------------------------------------------------- 1 | .login { 2 | width: 100%; 3 | height: 100vh; 4 | display: flex; 5 | justify-content: center; 6 | align-items: center; 7 | position: relative; 8 | 9 | .waveW { 10 | position: absolute; 11 | top: 0; 12 | left: 0; 13 | width: 100%; 14 | height: 100%; 15 | } 16 | 17 | .form { 18 | position: relative; 19 | z-index: 1; 20 | 21 | h2 { 22 | color: var(--main-txt-color); 23 | } 24 | 25 | :global(.ant-checkbox-wrapper) { 26 | color: var(--main-txt-color); 27 | } 28 | } 29 | } 30 | 31 | .intro { 32 | position: absolute; 33 | top: 70%; 34 | left: 0; 35 | width: 100%; 36 | z-index: 1; 37 | padding: 0 240px; 38 | } -------------------------------------------------------------------------------- /src/types/apiError.ts: -------------------------------------------------------------------------------- 1 | 2 | export interface ErrorLog { 3 | id: string 4 | 5 | host: string 6 | 7 | ip: string 8 | 9 | path: string 10 | 11 | url: string 12 | 13 | params: any 14 | 15 | method: string 16 | 17 | origin: string 18 | 19 | hostname: string 20 | 21 | headers: any 22 | 23 | resHeaders: any 24 | 25 | resData: any 26 | 27 | time: number 28 | 29 | protocol: string 30 | 31 | status: number 32 | 33 | msg: string 34 | 35 | client: string 36 | 37 | errors: string[] 38 | 39 | createdAt: string 40 | } 41 | 42 | 43 | export type ErrorQuery = { 44 | url: string 45 | path: string 46 | msg: string 47 | createdAt: string 48 | _createdAt?: [Date, Date] 49 | } -------------------------------------------------------------------------------- /src/services/account.ts: -------------------------------------------------------------------------------- 1 | import { LoginForm, RegisterForm } from "types/account" 2 | import $http from '@utils/http' 3 | import { storage } from "@/utils/tools" 4 | import { JWT_TOKEN } from "@/constants" 5 | 6 | 7 | export const onLogin = (data: LoginForm) => { 8 | return $http.post('/api/login', data).then(res => res.data) 9 | } 10 | 11 | export const onLogout = () => { 12 | return $http.post('/api/logout', {}).then((res: any) => { 13 | storage.remove(JWT_TOKEN) 14 | location.replace('/login') 15 | }, err => { 16 | // $msg.error(err.msg) 17 | }) 18 | } 19 | 20 | 21 | export const onCreate = (data: LoginForm) => { 22 | return $http.post('/api/register', data).then(res => res.data) 23 | } 24 | -------------------------------------------------------------------------------- /src/services/stock.ts: -------------------------------------------------------------------------------- 1 | import { Method } from '@/types/demo' 2 | import { pageData2Params } from '@utils/tools' 3 | import { StockStats, Stock } from 'types/stock' 4 | import { useRequest } from './http' 5 | 6 | 7 | export type StockQuery = Omit & { noPage: boolean } 8 | 9 | export const stockPageList = (params: Partial = pageData2Params()) => { 10 | return useRequest('/stocks', params) 11 | } 12 | 13 | export const getStockDetail = (id: number) => { 14 | return useRequest(`/stocks/${id}`).then(res => res.data) 15 | } 16 | 17 | 18 | export const getStockChartCount = () => { 19 | return useRequest('/stock/chartCount').then(res => res.data) 20 | } -------------------------------------------------------------------------------- /.babelrc.js: -------------------------------------------------------------------------------- 1 | 2 | module.exports = { 3 | presets: [ 4 | [ 5 | '@babel/preset-env', 6 | { 7 | targets: '> 0.25%, not dead', 8 | ignoreBrowserslistConfig: true, 9 | useBuiltIns: false, 10 | modules: false, 11 | exclude: ['transform-typeof-symbol'] 12 | } 13 | ], 14 | '@babel/preset-react', 15 | [ 16 | '@babel/preset-typescript', 17 | { 18 | isTSX: true, 19 | allExtensions: true, 20 | allowNamespaces: true, 21 | allowDeclareFields: true 22 | } 23 | ] 24 | ], 25 | plugins: [ 26 | [ 27 | '@babel/plugin-proposal-decorators', 28 | {legacy: true} 29 | ], 30 | // [ 31 | // '@babel/plugin-proposal-class-properties', 32 | // {loose: true} 33 | // ] 34 | ] 35 | } -------------------------------------------------------------------------------- /src/services/geography.ts: -------------------------------------------------------------------------------- 1 | import { useRequest } from "./http" 2 | import { SystemLog } from "@/types/geolog" 3 | import { Method } from "@/types/demo" 4 | import { GeographicStats } from "@/types/dashboard" 5 | 6 | export const getGeologs = (params: any) => { 7 | return useRequest('/log/geos', params, Method.GET) 8 | } 9 | 10 | export const getGeoGPSStats = () => { 11 | return useRequest('/log/geo/stats').then(r => r.data) 12 | } 13 | 14 | export const getGeoGPSChina = () => { 15 | return useRequest('/log/geo/china').then(r => r.data) 16 | } 17 | 18 | export const getGeoVisit = () => { 19 | return useRequest('/log/geo/visit').then(r => r.data) 20 | } 21 | 22 | export const getGeoMapStats = () => { 23 | return Promise.all([getGeoVisit(), getGeoGPSStats()]) 24 | } -------------------------------------------------------------------------------- /src/utils/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import i18n from 'i18next' 2 | import { initReactI18next } from 'react-i18next' 3 | import en_US from './en_US.json' 4 | import zh_CN from './zh_CN.json' 5 | import zh_TW from './zh_TW.json' 6 | import { getCurrentLang } from '@/types/global' 7 | 8 | const currentLang = getCurrentLang() 9 | 10 | i18n 11 | .use(initReactI18next) // passes i18n down to react-i18next 12 | .init({ 13 | resources: { 14 | en_US: { 15 | translation: en_US, 16 | }, 17 | zh_CN: { 18 | translation: zh_CN, 19 | }, 20 | zh_TW: { 21 | translation: zh_TW, 22 | }, 23 | }, 24 | lng: currentLang, 25 | fallbackLng: currentLang, 26 | interpolation: { 27 | escapeValue: false, // react already safes from xss => https://www.i18next.com/translation-function/interpolation#unescape 28 | }, 29 | }) -------------------------------------------------------------------------------- /src/pages/demos/components/test.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react' 2 | import { Flex, Space, Button, Badge } from 'antd' 3 | 4 | const useTest = () => { 5 | const [count, setCount] = useState(10) 6 | return { 7 | count, 8 | setCount, 9 | } 10 | } 11 | 12 | export const TestComponent: React.FC = () => { 13 | const { count, setCount } = useTest() 14 | return 15 | 16 | test1 17 | 18 | 19 | } 20 | 21 | 22 | export const TestComponent2: React.FC = () => { 23 | const { count, setCount } = useTest() 24 | return 25 | 26 | test2 27 | 28 | 29 | } -------------------------------------------------------------------------------- /src/pages/home/home.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | import { Layout } from 'antd' 3 | import { Outlet } from 'react-router-dom' 4 | import { HeaderComponent } from './components/header' 5 | import Footer from './components/footer' 6 | import { SiderBar } from './components/siderbar' 7 | import { useAppStore } from '@/stores/global' 8 | import classNames from 'classnames' 9 | import styles from './style.module.scss' 10 | 11 | const { Content } = Layout 12 | 13 | const HomePage: React.FC = () => { 14 | 15 | const [{ 16 | authorized 17 | }] = useAppStore() 18 | 19 | 20 | return ( 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 |