理顺框架

This commit is contained in:
LittleBoy 2023-08-21 23:45:47 +08:00
parent 62a323bdf9
commit 07347cba09
15 changed files with 174 additions and 37 deletions

View File

@ -1,3 +1,56 @@
/* http://meyerweb.com/eric/tools/css/reset/
v5.0.1 | 20191019
License: none (public domain)
*/
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,
figure, figcaption, footer, header, hgroup,
main, menu, nav, output, ruby, section, summary,
time, mark, audio, video {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure,
footer, header, hgroup, main, menu, nav, section {
display: block;
}
/* HTML5 hidden-attribute fix for newer browsers */
*[hidden] {
display: none;
}
body {
line-height: 1;
}
menu, ol, ul {
list-style: none;
}
blockquote, q {
quotes: none;
}
blockquote:before, blockquote:after,
q:before, q:after {
content: '';
content: none;
}
table {
border-collapse: collapse;
border-spacing: 0;
}
:root { :root {
--max-width: 1100px; --max-width: 1100px;
--border-radius: 12px; --border-radius: 12px;
@ -73,12 +126,6 @@
} }
} }
* {
box-sizing: border-box;
padding: 0;
margin: 0;
}
html, html,
body { body {
max-width: 100vw; max-width: 100vw;

View File

@ -85,7 +85,10 @@ export const LoginComponent = () => {
{/* </div>*/} {/* </div>*/}
{/*</div>*/} {/*</div>*/}
</Modal> </Modal>
{visible?'xxx':'0000'} {visible ? 'xxx' : '0000'}
<Button type="primary" onClick={() => setVisible(true)}></Button> <Button type="primary" onClick={() => {
setVisible(true)
// Modal.success({ title: 'This is a success message', content: 'bla bla bla...' });
}}></Button>
</div>) </div>)
} }

View File

@ -25,7 +25,6 @@ export const AppRouter = () => (<WebRouter>
<div className="page-body-content"> <div className="page-body-content">
<Routes> <Routes>
<Route path="/" element={<DefaultPage/>}/> <Route path="/" element={<DefaultPage/>}/>
<Route path="*" element={<NotFound/>}/> <Route path="*" element={<NotFound/>}/>
</Routes> </Routes>
</div> </div>

View File

@ -1,9 +1,18 @@
.index{ .index {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
height: 100vh; height: 100vh;
} }
.modal{ .title{
font-size: 20px;
font-weight: 700;
color: #333;
margin-bottom: 20px;
}
.loginWrapper {
background-color: #fff;
padding: 15px 20px;
border-radius: 6px;
width: 350px;
} }

View File

@ -1,10 +1,77 @@
import React from "react"; import React, {useRef, useState} from "react";
import {IconGithubLogo, IconWeibo} from "@douyinfe/semi-icons";
import css from './index.module.scss' import css from './index.module.scss'
import {LoginComponent} from "../../components/LoginComponent.tsx"; import {LoginComponent} from "../../components/LoginComponent.tsx";
import {useNavigate} from "react-router-dom";
import {useUserinfoStore} from "../../store/userinfoStore.ts";
import {Button, Divider, Form, Modal, Notification, Space} from "@douyinfe/semi-ui";
import {cx} from "@emotion/css";
const DefaultPage: React.FC = () => { const DefaultPage: React.FC = () => {
const [loading, setLoading] = useState(false);
const navigate = useNavigate();
const {login} = useUserinfoStore()
const onFinish = async (values: any) => {
setLoading(true);
try {
const user = await login(values)
setVisible(true);
navigate('/dashboard')
} catch (err) {
// 登录失败
console.log(err)
// 登录失败
Notification.error({
content: '登录失败,请检查用户名和密码'
})
}
setLoading(false);
};
const [visible, setVisible] = useState(false);
const hideModal = () => setVisible(false)
return (<div className={css.index}> return (<div className={css.index}>
<LoginComponent/> {/*<LoginComponent/>*/}
<div className={css.loginWrapper}>
<h2 className={cx('text-center', css.title)}></h2>
<Form
onSubmit={onFinish}
>
<Form.Input
field="account"
placeholder="请输入用户名"
noLabel
rules={[{required: true, message: '用户名不可空'}]}
/>
<Form.Input
type="password"
field="password"
placeholder="请输入登录密码"
noLabel
rules={[{required: true, message: '密码不可空'}]}
/>
<Form.Checkbox
field="remember"
value={false}
noLabel
></Form.Checkbox>
<div className='flex align-center space-between'>
<Button block type='primary' theme='solid' loading={loading} htmlType="submit"></Button>
</div>
</Form>
<div style={{padding: '30px 0 20px'}}>
<Divider>OR</Divider>
<div className="text-center" style={{marginTop: 20}}>
<Space>
<Button icon={<IconWeibo/>}>GOOGLE</Button>
<Button theme='solid' type="primary" icon={<IconGithubLogo/>}>GITHUB</Button>
</Space>
</div>
</div>
</div>
</div>); </div>);
} }
export default DefaultPage; export default DefaultPage;

View File

@ -35,7 +35,7 @@ Axios.interceptors.request.use(config => {
const token = Storage.get<string>(APP_CONFIG.LOGIN_TOKEN_KEY) const token = Storage.get<string>(APP_CONFIG.LOGIN_TOKEN_KEY)
// const {token} = useUserinfoStore() // const {token} = useUserinfoStore()
if (token) { if (token) {
config.headers['Authorization'] = `Bearer ${token}`; config.headers['Authorization'] = `${token}`; // Bearer
} }
if (config.data && config.data instanceof FormData) { if (config.data && config.data instanceof FormData) {
config.headers['Content-Type'] = 'multipart/form-data'; config.headers['Content-Type'] = 'multipart/form-data';
@ -81,7 +81,7 @@ export function request<T>(url: string, method: RequestMethod, data: any = null,
if (code == 403) { if (code == 403) {
const state = useUserinfoStore.getState() const state = useUserinfoStore.getState()
// 未登录 显示登录modal // 未登录 显示登录modal
state.showLogin(true); // state.showLogin(true);
} }
reject(new BizError(msg, code)) reject(new BizError(msg, code))
} }

View File

@ -2,8 +2,8 @@ import {get, post} from "./request.ts";
import {UserModel} from "../../model"; import {UserModel} from "../../model";
export function login(user: string, password: string) { export function login(username: string, password: string) {
return post<UserModel>('/api/user/info', {user, password}) return post<UserModel>('/api/user/login', {username, password})
} }
export function getInfo() { export function getInfo() {

View File

@ -74,8 +74,7 @@ export const useUserinfoStore = create<{
}, },
login: (data) => { login: (data) => {
return new Promise<void>((resolve, reject) => { return new Promise<void>((resolve, reject) => {
const promise = login(data.account, data.password); login(data.account, data.password).then((ret) => {
promise.then((ret) => {
const token = ret.token; const token = ret.token;
Storage.put(LOGIN_TOKEN_KEY, token) Storage.put(LOGIN_TOKEN_KEY, token)
getInfo().then(userinfo => { getInfo().then(userinfo => {

View File

@ -1,6 +1,7 @@
import { InitServerOption } from "./types"; import { InitServerOption } from "./types";
// import { createServer as createServerOrigin } from "http"; // import { createServer as createServerOrigin } from "http";
import express = require("express"); // import express = require("express");
import * as express from "express";
export function createServer(options: Partial<InitServerOption>, callback?: () => void) { export function createServer(options: Partial<InitServerOption>, callback?: () => void) {
// 创建express服务器 // 创建express服务器

View File

@ -2,7 +2,7 @@ import {Application, Request, Response} from "express";
import {RouteHandleFunction, RouteHandleFunctionParam} from "../core/types"; import {RouteHandleFunction, RouteHandleFunctionParam} from "../core/types";
import {home} from "./home"; import {home} from "./home";
import {appList, reportToServer, appEvent, eventData} from "./reportor"; import {appList, reportToServer, appEvent, eventData} from "./reportor";
import {loginHandler} from "./user.ts"; import {getUserInfo, loginHandler} from "./user.ts";
// //
function createRoute(handler: RouteHandleFunction) { function createRoute(handler: RouteHandleFunction) {
@ -28,5 +28,6 @@ export function initRoutes(app: Application) {
app.all('/api/app/list', createRoute(appList)) app.all('/api/app/list', createRoute(appList))
app.all('/api/app/event', createRoute(appEvent)) app.all('/api/app/event', createRoute(appEvent))
app.all('/api/app/event-data', createRoute(eventData)) app.all('/api/app/event-data', createRoute(eventData))
app.all('/api/login', createRoute(loginHandler)) app.all('/api/user/login', createRoute(loginHandler))
app.all('/api/user/info', createRoute(getUserInfo))
} }

View File

@ -1,5 +1,5 @@
import { createPool } from 'mysql' import {createPool} from 'mysql'
import { DB_CONFIG } from './../config'; import {DB_CONFIG} from './../config';
export const pool = createPool({ export const pool = createPool({
...DB_CONFIG, ...DB_CONFIG,
@ -30,19 +30,23 @@ export async function selectArray<T>(sql: string, params: any = null) {
// }) // })
// }); // });
} }
// 查询单个对象 // 查询单个对象
export async function selectOne<T>(sql: string, params: any = null) { export async function selectOne<T>(sql: string, params: any = null) {
// 执行查询sql并返回查询结果 // 执行查询sql并返回查询结果
const arr = await selectArray<T>(sql, params); const arr = await selectArray<T>(sql, params);
if (arr.length != 1) throw new Error("查询结果数量不等于1"); // if (arr.length != 1) throw new Error("查询结果数量不等于1");
return arr[0]; return arr.length > 0 ? arr[0] : null;
} }
// 统计数据 // 统计数据
export async function queryCount(sql: string, params: any = null) { export async function queryCount(sql: string, params: any = null) {
const obj = await selectOne<{ [key: string]: number }>(sql, params); const obj = await selectOne<{ [key: string]: number }>(sql, params);
if(!obj) return 0;
const keys = Object.keys(obj); const keys = Object.keys(obj);
return obj[keys[0]]; return obj[keys[0]];
} }
// 根据表名和条件判断数据是否存在 // 根据表名和条件判断数据是否存在
export async function isExistByTable(tableName: string, condition: any = {}) { export async function isExistByTable(tableName: string, condition: any = {}) {
let sql = `select count(*) as count from ${tableName} where 1=1`; let sql = `select count(*) as count from ${tableName} where 1=1`;
@ -54,10 +58,12 @@ export async function isExistByTable(tableName: string, condition: any = {}) {
const count = await queryCount(sql, params); const count = await queryCount(sql, params);
return count > 0; return count > 0;
} }
export async function isExist(sql: string, params: any) { export async function isExist(sql: string, params: any) {
const count = await queryCount(sql, params); const count = await queryCount(sql, params);
return count > 0; return count > 0;
} }
// 查询多条数据 // 查询多条数据
function executeSQL<T>(sql: string, params: any) { function executeSQL<T>(sql: string, params: any) {
@ -76,10 +82,12 @@ export async function execute(sql: string, params: any = null) {
const ret = await executeSQL<{ affectedRows: number }>(sql, params) const ret = await executeSQL<{ affectedRows: number }>(sql, params)
return ret.affectedRows return ret.affectedRows
} }
export async function insertAndGetInsertId(tableName: string, data: any = null) { export async function insertAndGetInsertId(tableName: string, data: any = null) {
const ret = await executeSQL<{ insertId: number }>(`insert into \`${tableName}\` set ?`, data) const ret = await executeSQL<{ insertId: number }>(`insert into \`${tableName}\` set ?`, data)
return ret.insertId return ret.insertId
} }
export default { export default {
selectArray, selectArray,
executeSQL, executeSQL,

View File

@ -1,4 +1,4 @@
import { execute, selectArray, pool, queryCount } from './../src/service/mysql' import { execute, selectArray, pool, queryCount } from './../service/service/mysql'
// 使用execute执行更新数据 // 使用execute执行更新数据
describe('Database', () => { describe('Database', () => {
@ -25,4 +25,4 @@ describe('Database', () => {
const count = await queryCount('select count(*) from user'); const count = await queryCount('select count(*) from user');
console.log('total:', count); console.log('total:', count);
}) })
}) })

View File

@ -1,5 +1,6 @@
import { Test } from 'supertest'; import {Test} from 'supertest';
import { PORT } from './../config' import {PORT} from './../service/config'
const request = require("supertest"); const request = require("supertest");
// import { createServer } from './../src/core/server' // import { createServer } from './../src/core/server'
@ -12,4 +13,4 @@ const request = require("supertest");
// initRoutes(app) // initRoutes(app)
export const createRequest = () => request(`http://localhost:${PORT}`) export const createRequest = () => request(`http://localhost:${PORT}`)
export const get = (path: string): Test => createRequest().get(path) export const get = (path: string): Test => createRequest().get(path)

View File

@ -1,8 +1,9 @@
{ {
"compilerOptions": { "compilerOptions": {
/* ESNext */
"target": "ESNext", "target": "ESNext",
"lib": ["DOM", "DOM.Iterable", "ESNext"], "lib": ["DOM", "DOM.Iterable", "ESNext"],
"module": "CommonJS", "module": "commonjs",
"skipLibCheck": true, "skipLibCheck": true,
/* Bundler mode */ /* Bundler mode */

View File

@ -12,11 +12,12 @@ export default defineConfig(({mode}) => {
'@/': '/front/' '@/': '/front/'
} }
}, },
define: { // define: {
buildVersion: JSON.stringify((new Date()).toLocaleString()), // buildVersion: JSON.stringify((new Date()).toLocaleString()),
mode:JSON.stringify(mode), // mode:JSON.stringify(mode),
}, // },
build: { build: {
outDir:'static',
// 小于10kb直接base64 // 小于10kb直接base64
assetsInlineLimit: 10240, assetsInlineLimit: 10240,
rollupOptions: { rollupOptions: {