commit
a43f7c8f5d
@ -0,0 +1,25 @@ |
|||||||
|
# Logs |
||||||
|
logs |
||||||
|
*.log |
||||||
|
npm-debug.log* |
||||||
|
yarn-debug.log* |
||||||
|
yarn-error.log* |
||||||
|
pnpm-debug.log* |
||||||
|
lerna-debug.log* |
||||||
|
|
||||||
|
node_modules |
||||||
|
dist |
||||||
|
dist.* |
||||||
|
dist-ssr |
||||||
|
*.local |
||||||
|
|
||||||
|
# Editor directories and files |
||||||
|
.vscode/* |
||||||
|
!.vscode/extensions.json |
||||||
|
.idea |
||||||
|
.DS_Store |
||||||
|
*.suo |
||||||
|
*.ntvs* |
||||||
|
*.njsproj |
||||||
|
*.sln |
||||||
|
*.sw? |
@ -0,0 +1,3 @@ |
|||||||
|
# userSys |
||||||
|
|
||||||
|
用户系统 |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,66 @@ |
|||||||
|
CREATE TABLE `sys22_user`.`user_authority` ( |
||||||
|
`id` int NOT NULL AUTO_INCREMENT COMMENT '自增ID', |
||||||
|
`authority_name` varchar(32) NOT NULL COMMENT '权限名称', |
||||||
|
`type` int(2) NOT NULL COMMENT '权限类型', |
||||||
|
`grade` int(2) NOT NULL COMMENT '权限等级', |
||||||
|
`sequence` int(3) NOT NULL COMMENT '序列', |
||||||
|
`authority_remarks` varchar(255) NOT NULL COMMENT '权限备注', |
||||||
|
PRIMARY KEY (`id`) |
||||||
|
); |
||||||
|
|
||||||
|
CREATE TABLE `sys22_user`.`user_info` ( |
||||||
|
`uuid` char(32) NOT NULL COMMENT '唯一id', |
||||||
|
`username` varchar(255) NULL COMMENT '用户名', |
||||||
|
`email` varchar(255) NULL COMMENT '电子邮箱', |
||||||
|
`phone` int(11) NULL COMMENT '手机号码', |
||||||
|
`person` varchar(18) NULL COMMENT '身份证', |
||||||
|
`status` int(1) NOT NULL DEFAULT 0 COMMENT '使用状态', |
||||||
|
`createtime` bigint(13) NOT NULL COMMENT '创建时间', |
||||||
|
PRIMARY KEY (`uuid`) |
||||||
|
); |
||||||
|
|
||||||
|
CREATE TABLE `sys22_user`.`user_info_other` ( |
||||||
|
`uuid` char(32) NOT NULL COMMENT '用户唯一ID', |
||||||
|
`address` varchar(255) NULL COMMENT '住址', |
||||||
|
`country` varchar(255) NULL COMMENT '国家地区', |
||||||
|
`sex` int(1) NULL COMMENT '性别', |
||||||
|
`birthady` int(8) NULL COMMENT '生日', |
||||||
|
`nickname` varchar(64) NULL COMMENT '昵称', |
||||||
|
`personal` varchar(255) NULL COMMENT '个人简介', |
||||||
|
`slogn` varchar(64) NULL COMMENT '标语', |
||||||
|
`avatar` varchar(64) NULL COMMENT '头像', |
||||||
|
`background` varchar(64) NULL COMMENT '背景', |
||||||
|
`updateTime` bigint(13) NOT NULL COMMENT '修改时间', |
||||||
|
PRIMARY KEY (`uuid`) |
||||||
|
); |
||||||
|
|
||||||
|
CREATE TABLE `sys22_user`.`user_login` ( |
||||||
|
`id` int NOT NULL AUTO_INCREMENT COMMENT '自增id', |
||||||
|
`uuid` char(32) NOT NULL COMMENT '用户唯一ID', |
||||||
|
`password` varchar(255) NOT NULL COMMENT '加密密码', |
||||||
|
`createtime` bigint(13) NOT NULL COMMENT '密码创建时间', |
||||||
|
`status` int(1) NOT NULL DEFAULT 0 COMMENT '密码使用状态', |
||||||
|
PRIMARY KEY (`id`) |
||||||
|
); |
||||||
|
|
||||||
|
CREATE TABLE `sys22_user`.`user_relation_authority` ( |
||||||
|
`id` int NOT NULL AUTO_INCREMENT COMMENT '自增ID', |
||||||
|
`role_id` int NOT NULL COMMENT '角色ID', |
||||||
|
`authority_id` int NOT NULL COMMENT '权限ID', |
||||||
|
PRIMARY KEY (`id`) |
||||||
|
); |
||||||
|
|
||||||
|
CREATE TABLE `sys22_user`.`user_relation_role` ( |
||||||
|
`id` int NOT NULL COMMENT '自增ID', |
||||||
|
`uuid` char(32) NOT NULL COMMENT '用户标识', |
||||||
|
`role_id` int NOT NULL DEFAULT 0 COMMENT '角色ID', |
||||||
|
PRIMARY KEY (`id`) |
||||||
|
); |
||||||
|
|
||||||
|
CREATE TABLE `sys22_user`.`user_role` ( |
||||||
|
`id` int NOT NULL AUTO_INCREMENT COMMENT '唯一ID', |
||||||
|
`role_name` varchar(32) NOT NULL COMMENT '角色名称', |
||||||
|
`role_remarks` varchar(255) NOT NULL COMMENT '角色备注', |
||||||
|
PRIMARY KEY (`id`) |
||||||
|
); |
||||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,12 @@ |
|||||||
|
# userSys设计-需求分析 |
||||||
|
|
||||||
|
# 一、提供的服务 |
||||||
|
|
||||||
|
1. 记录用户信息 |
||||||
|
2. 设置用户角色 |
||||||
|
3. 控制角色权限 |
||||||
|
4. 对外提供接口 |
||||||
|
5. 记录系统权限 |
||||||
|
6. 稳定、高可用、可拓展、可迭代 |
||||||
|
7. 安全与保密性 |
||||||
|
8. 高性能 |
@ -0,0 +1,7 @@ |
|||||||
|
# userSys |
||||||
|
|
||||||
|
## run |
||||||
|
|
||||||
|
```bash |
||||||
|
npm start |
||||||
|
``` |
@ -0,0 +1,118 @@ |
|||||||
|
// koa-router:提供全面的路由功能,比如类似Express的app.get/post/put的写法,URL命名参数、路由命名、嵌套路由、支持加载多个中间件
|
||||||
|
// koa-bodyparser:post提交数据中间件,解析请求体时需要加载的中间件,支持x-www-form-urlencoded, application/json等格式的请求体,不支持form-data的请求体
|
||||||
|
// koa-views:对进行视图模板渲染,支持ejs, nunjucks等模板引擎
|
||||||
|
// koa-static:静态资源中间件,用作类似Nginx的静态文件服务,在本地开发时可用于加载前端文件或后端Fake数据
|
||||||
|
// koa-session:session验证,支持将会话信息存储在本地Cookie或Redis, MongoDB
|
||||||
|
// koa-jwt:token验证,路由权限控制功能,Session Base转为用Token Base
|
||||||
|
// koa-helmet:网络安全,增加Strict-Transport-Security, X-Frame-Options, X-Frame-Options等HTTP头,提高应用程序的安全性
|
||||||
|
// koa-compress:当响应体较大时,启用类似Gzip的压缩技术减少传输内容
|
||||||
|
// koa-logger:输出请求日志的功能,包括请求的url、状态码、响应时间、响应体大小等信息
|
||||||
|
// koa-convert:基于Promise的中间件和基于Generate的中间件相互转换
|
||||||
|
// koa-nunjucks-2:轻量级 Nunjucks 中间件,可以用作模板引擎,为koa应用提供页面渲染功能
|
||||||
|
// koa-favicon:页面logo加载
|
||||||
|
// koa-json:get提交数据的中间件
|
||||||
|
// koa-onerror:在服务器产生错误(throw 抛出等)后自动重定义到指定路径
|
||||||
|
// koa-respond:在Koa上下文中添加了常用的方法
|
||||||
|
|
||||||
|
/** |
||||||
|
* 添加依赖 |
||||||
|
* */ |
||||||
|
const Koa = require('koa')// 主依赖 Koa2
|
||||||
|
, logger = require('koa-logger')// 日志
|
||||||
|
// , bodyparser = require('koa-bodyparser')// 获取body的参数,post,支持x-www-form-urlencoded, application/json等格式的请求体,不支持form-data的请求体
|
||||||
|
, koaBody = require('koa-body')// 支持form-data,支持文件,不支持x-www-form-urlencoded,不可同时使用,
|
||||||
|
|
||||||
|
|
||||||
|
global.path = __dirname |
||||||
|
|
||||||
|
/** |
||||||
|
* 路由 |
||||||
|
* */ |
||||||
|
const router = require('./src/Routes/index') |
||||||
|
/** |
||||||
|
* 创建应用程序 |
||||||
|
* */ |
||||||
|
const app = new Koa(); |
||||||
|
// 数据库操作
|
||||||
|
// databaseOperation()
|
||||||
|
|
||||||
|
// 请求日志
|
||||||
|
app.use(logger()); |
||||||
|
// 时间
|
||||||
|
app.use(printMethod()); |
||||||
|
// ctx.request.body body参数
|
||||||
|
// 已过时,被koa-body替代
|
||||||
|
// app.use(bodyparser({
|
||||||
|
// enableTypes: ['json', 'form', 'text']
|
||||||
|
// }))
|
||||||
|
app.use(koaBody({ |
||||||
|
multipart:true, // 支持文件上传
|
||||||
|
encoding:'gzip', |
||||||
|
strict:false,// 参数:如果启用,则不解析GET,HEAD,DELETE请求,默认为true
|
||||||
|
formidable:{ |
||||||
|
// uploadDir:path.join(__dirname,'public/upload/'), // 设置文件上传目录
|
||||||
|
keepExtensions: true, // 保持文件的后缀
|
||||||
|
maxFieldsSize:2 * 1024 * 1024, // 文件上传大小
|
||||||
|
// onFileBegin:(name,file) => { // 文件上传前的设置
|
||||||
|
// // console.log(`name: ${name}`);
|
||||||
|
// // console.log(file);
|
||||||
|
// },
|
||||||
|
} |
||||||
|
})); |
||||||
|
|
||||||
|
// token
|
||||||
|
app.use(verToken()) |
||||||
|
|
||||||
|
|
||||||
|
// 路由
|
||||||
|
app.use(router.routes(), router.allowedMethods({ |
||||||
|
// throw: true, // 抛出错误,代替设置响应头状态
|
||||||
|
// notImplemented: () => '不支持当前请求所需要的功能',
|
||||||
|
// methodNotAllowed: () => '不支持的请求方式'
|
||||||
|
})); |
||||||
|
|
||||||
|
// veriToken
|
||||||
|
function verToken(){ |
||||||
|
return async function(ctx, next){ |
||||||
|
// 请求地址判断
|
||||||
|
if(ctx.req.url.indexOf('/api/user/will') == 0 || true){ |
||||||
|
await next() |
||||||
|
}else{ |
||||||
|
const token = ctx.request.header.authorization |
||||||
|
const result2 = global.token.decrypt(token) |
||||||
|
// 判断此Token有没有过期
|
||||||
|
if(result2.token){ |
||||||
|
const result = await global.Redis.getToken(token) |
||||||
|
// 判断Redis是否有此token
|
||||||
|
if(result){ |
||||||
|
ctx.uuid = result2.id.uuid |
||||||
|
ctx.token = token |
||||||
|
await next() |
||||||
|
}else{ |
||||||
|
ctx.body = global.msg.failed({}, '账户令牌失效!', true) |
||||||
|
} |
||||||
|
|
||||||
|
}else{ |
||||||
|
ctx.body = global.msg.failed({}, '账户令牌失效。', true) |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// 打印时间
|
||||||
|
function printMethod() { |
||||||
|
return async function (ctx, next) { |
||||||
|
const start = new Date() |
||||||
|
await next() |
||||||
|
const ms = new Date() - start |
||||||
|
console.info(`Method ${ctx.method} ${ctx.url} - ${ms}ms`) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
setTimeout(other) |
||||||
|
function other(){ |
||||||
|
console.w('other test') |
||||||
|
console.w(global.path) |
||||||
|
} |
||||||
|
module.exports = app; |
@ -0,0 +1,86 @@ |
|||||||
|
/** |
||||||
|
* 引入依赖 |
||||||
|
* */ |
||||||
|
|
||||||
|
const initConsole = require('../tools/console/index') |
||||||
|
, {getSystem} = require('../tools/getEnv') |
||||||
|
, app = require('../app') |
||||||
|
, http = require('http') |
||||||
|
, config = require('../config/default.config') |
||||||
|
, {createDatabase, createTables} = require('../src/Database/initDatabase') |
||||||
|
, initRedisJSON = require('../tools/redisJSON') |
||||||
|
, getStr = require('../tools/RandomString') |
||||||
|
, makeUUID = require('../tools/uuid') |
||||||
|
, mail = require('../tools/mail') |
||||||
|
, {HASH} = require('../tools/user/encryptionString') |
||||||
|
, token = require('../tools/user/token') |
||||||
|
|
||||||
|
async function run() { |
||||||
|
// 初始化console
|
||||||
|
console.time('> Web Start Use'); |
||||||
|
initConsole(); |
||||||
|
// console.clear();
|
||||||
|
/** |
||||||
|
* 环境探测 |
||||||
|
* */ |
||||||
|
const sysEnv = getSystem(); |
||||||
|
console.dev(sysEnv); |
||||||
|
/** |
||||||
|
* 初始化数据库 |
||||||
|
* */ |
||||||
|
try { |
||||||
|
let result = await createDatabase(); |
||||||
|
console.s('> ' + result.message); |
||||||
|
result = await createTables(); |
||||||
|
console.s('> ' + result.message); |
||||||
|
} catch (e) { |
||||||
|
console.dev(e); |
||||||
|
throw new Error(e) |
||||||
|
} |
||||||
|
/** |
||||||
|
* 初始化Redis |
||||||
|
* */ |
||||||
|
try { |
||||||
|
global.Redis = await initRedisJSON() |
||||||
|
} catch (e) { |
||||||
|
throw new Error(e) |
||||||
|
} |
||||||
|
/** |
||||||
|
* 加载工具 |
||||||
|
* */ |
||||||
|
console.dev('> 加载工具类。') |
||||||
|
global.cfg = config |
||||||
|
global.getStr = getStr |
||||||
|
global.makeUUID = makeUUID |
||||||
|
global.mail = mail |
||||||
|
global.HASH = HASH |
||||||
|
global.token = token |
||||||
|
// 统一消息回复
|
||||||
|
global.msg = { |
||||||
|
success: (data, message = "success") => ({data, message, status:true}), |
||||||
|
failed: (data, message = "failed", reStart = false) => ({data, message, reStart, status:false}) |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 启动服务 |
||||||
|
* */ |
||||||
|
const server = http.createServer(app.callback()); |
||||||
|
server.listen(config.PORT) |
||||||
|
// 启动
|
||||||
|
server.on("listening", function onListening(port) { |
||||||
|
console.info(`> Web System Name: ${config.PROJECT_NAME}`) |
||||||
|
console.info(`> httpServer listening in http://localhost:${config.PORT}`); |
||||||
|
console.timeEnd('> Web Start Use') |
||||||
|
}) |
||||||
|
// 出错
|
||||||
|
server.on("error", function onError(error) { |
||||||
|
console.error('> httpServer Error!'); |
||||||
|
console.error(error); |
||||||
|
process.exit(1); |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
run() |
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,66 @@ |
|||||||
|
CREATE TABLE IF NOT EXISTS `sys22_user`.`user_authority` ( |
||||||
|
`id` int NOT NULL AUTO_INCREMENT COMMENT '自增ID', |
||||||
|
`authority_name` varchar(32) NOT NULL COMMENT '权限名称', |
||||||
|
`type` int(2) NOT NULL COMMENT '权限类型', |
||||||
|
`grade` int(2) NOT NULL COMMENT '权限等级', |
||||||
|
`sequence` int(3) NOT NULL COMMENT '序列', |
||||||
|
`authority_remarks` varchar(255) NOT NULL COMMENT '权限备注', |
||||||
|
PRIMARY KEY (`id`) |
||||||
|
); |
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS `sys22_user`.`user_info` ( |
||||||
|
`uuid` char(32) NOT NULL COMMENT '唯一id', |
||||||
|
`username` varchar(255) NULL COMMENT '用户名', |
||||||
|
`email` varchar(255) NULL COMMENT '电子邮箱', |
||||||
|
`phone` bigint(11) NULL COMMENT '手机号码', |
||||||
|
`person` varchar(18) NULL COMMENT '身份证', |
||||||
|
`status` int(1) NOT NULL DEFAULT 1 COMMENT '使用状态', |
||||||
|
`createtime` bigint(13) NOT NULL COMMENT '创建时间', |
||||||
|
PRIMARY KEY (`uuid`) |
||||||
|
); |
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS `sys22_user`.`user_info_other` ( |
||||||
|
`uuid` char(32) NOT NULL COMMENT '用户唯一ID', |
||||||
|
`address` varchar(255) NULL COMMENT '住址', |
||||||
|
`country` varchar(255) NULL COMMENT '国家地区', |
||||||
|
`sex` int(1) NULL COMMENT '性别', |
||||||
|
`birthday` int(8) NULL COMMENT '生日', |
||||||
|
`nickname` varchar(64) NULL COMMENT '昵称', |
||||||
|
`personal` varchar(255) NULL COMMENT '个人简介', |
||||||
|
`slogan` varchar(64) NULL COMMENT '标语', |
||||||
|
`avatar` varchar(64) NULL COMMENT '头像', |
||||||
|
`background` varchar(64) NULL COMMENT '背景', |
||||||
|
`updateTime` bigint(13) NOT NULL COMMENT '修改时间', |
||||||
|
PRIMARY KEY (`uuid`) |
||||||
|
); |
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS `sys22_user`.`user_login` ( |
||||||
|
`id` int NOT NULL AUTO_INCREMENT COMMENT '自增id', |
||||||
|
`uuid` char(32) NOT NULL COMMENT '用户唯一ID', |
||||||
|
`password` char(128) NOT NULL COMMENT '加密密码', |
||||||
|
`createtime` bigint(13) NOT NULL COMMENT '密码创建时间', |
||||||
|
`status` int(1) NOT NULL DEFAULT 0 COMMENT '密码使用状态', |
||||||
|
PRIMARY KEY (`id`) |
||||||
|
); |
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS `sys22_user`.`user_relation_authority` ( |
||||||
|
`id` int NOT NULL AUTO_INCREMENT COMMENT '自增ID', |
||||||
|
`role_id` int NOT NULL COMMENT '角色ID', |
||||||
|
`authority_id` int NOT NULL COMMENT '权限ID', |
||||||
|
PRIMARY KEY (`id`) |
||||||
|
); |
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS `sys22_user`.`user_relation_role` ( |
||||||
|
`id` int NOT NULL AUTO_INCREMENT COMMENT '自增ID', |
||||||
|
`uuid` char(32) NOT NULL COMMENT '用户标识', |
||||||
|
`role_id` int NOT NULL DEFAULT 0 COMMENT '角色ID', |
||||||
|
PRIMARY KEY (`id`) |
||||||
|
); |
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS `sys22_user`.`user_role` ( |
||||||
|
`id` int NOT NULL AUTO_INCREMENT COMMENT '唯一ID', |
||||||
|
`role_name` varchar(32) NOT NULL COMMENT '角色名称', |
||||||
|
`role_remarks` varchar(255) NOT NULL COMMENT '角色备注', |
||||||
|
PRIMARY KEY (`id`) |
||||||
|
); |
||||||
|
|
@ -0,0 +1,52 @@ |
|||||||
|
module.exports = { |
||||||
|
// 配置文件路径
|
||||||
|
CONFIG_PATH:__dirname, |
||||||
|
SYSTEM_NAME:'ANTO-G', |
||||||
|
PROJECT_NAME:'sys22 userSys', |
||||||
|
PORT:'3000', |
||||||
|
KEY:'expressgy', |
||||||
|
DATABASE_INIT:{ |
||||||
|
host: 'localhost', |
||||||
|
user: 'root', |
||||||
|
password:'Hxl1314521', |
||||||
|
database: "sys22_user", |
||||||
|
port: 3306, |
||||||
|
sqlFile:__dirname + "/database/sys22_user.sql" |
||||||
|
}, |
||||||
|
// 加密
|
||||||
|
encryption:{ |
||||||
|
salt:'время,вперёд!',// 盐
|
||||||
|
secretKey:"быть всегда готовым!",// 密钥
|
||||||
|
}, |
||||||
|
// 用户系统
|
||||||
|
user:{ |
||||||
|
// 注册
|
||||||
|
sign:{ |
||||||
|
mailVerf: false,// 邮箱验证注册
|
||||||
|
phoneVerf:false,// 手机验证注册
|
||||||
|
length:4,// 验证码长度
|
||||||
|
}, |
||||||
|
// 登录
|
||||||
|
login:{ |
||||||
|
timeLimit:1000 * 60 * 60 * 24 * 14 ,// token时常
|
||||||
|
} |
||||||
|
}, |
||||||
|
// 邮件服务
|
||||||
|
EMAILCONFIG : { |
||||||
|
HOST:'smtp.qq.com', |
||||||
|
USER:'togy.gc@qq.com', |
||||||
|
PASS:'qnpjbbeyunysdhac' |
||||||
|
}, |
||||||
|
// redis
|
||||||
|
RedisJSON:{ |
||||||
|
host:'172.17.162.197', |
||||||
|
port:6379, |
||||||
|
timeout:5 * 60 * 1000, |
||||||
|
// timeout:5 * 1000,
|
||||||
|
startClear: false, |
||||||
|
pool:0, |
||||||
|
clearTime:1000 * 60 * 60 * 6 |
||||||
|
}, |
||||||
|
// 一个用户的同时在线终端数量
|
||||||
|
maxClientOnline:6 |
||||||
|
} |
@ -0,0 +1,34 @@ |
|||||||
|
{ |
||||||
|
"name": "realization", |
||||||
|
"version": "1.0.0", |
||||||
|
"description": "", |
||||||
|
"main": "index.js", |
||||||
|
"scripts": { |
||||||
|
"test": "echo \"Error: no test specified\" && exit 1", |
||||||
|
"start": "node bin/www.js", |
||||||
|
"dev": "node_modules\\.bin\\nodemon bin\\www.js", |
||||||
|
"prd": "pm2 start bin/www" |
||||||
|
}, |
||||||
|
"keywords": [], |
||||||
|
"author": "", |
||||||
|
"license": "ISC", |
||||||
|
"dependencies": { |
||||||
|
"crypto": "^1.0.1", |
||||||
|
"jsonwebtoken": "^8.5.1", |
||||||
|
"koa": "^2.13.4", |
||||||
|
"koa-body": "^5.0.0", |
||||||
|
"koa-bodyparser": "^4.3.0", |
||||||
|
"koa-logger": "^3.2.1", |
||||||
|
"koa-router": "^12.0.0", |
||||||
|
"mysql": "^2.18.1", |
||||||
|
"mysqls": "^1.2.2", |
||||||
|
"nodemailer": "^6.8.0", |
||||||
|
"redis": "^4.3.1", |
||||||
|
"uuid": "^8.3.2" |
||||||
|
}, |
||||||
|
"devDependencies": { |
||||||
|
"axios": "^0.27.2", |
||||||
|
"mysql-import": "^5.0.21", |
||||||
|
"nodemon": "^2.0.19" |
||||||
|
} |
||||||
|
} |
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,73 @@ |
|||||||
|
const { createConnectionNull, createConnectionDatabase } = require('../../tools/database/createConnection') |
||||||
|
, config = require('../../config/default.config') |
||||||
|
, Importer = require('mysql-import') |
||||||
|
|
||||||
|
// 创建数据库
|
||||||
|
function createDatabase(){ |
||||||
|
return new Promise(async (rec, rej) => { |
||||||
|
try { |
||||||
|
const result = await createConnectionNull() |
||||||
|
try{ |
||||||
|
const SQL = `Create Database If Not Exists ?? Character Set UTF8;` |
||||||
|
const params = config.DATABASE_INIT.database |
||||||
|
result.connect.query(SQL, params,async (err,data) => { |
||||||
|
if(err){ |
||||||
|
rej({ |
||||||
|
status:false, |
||||||
|
message:'数据库创建失败。', |
||||||
|
code:err.code, |
||||||
|
errno:err.errno, |
||||||
|
sqlMessage:err.sqlMessage |
||||||
|
}) |
||||||
|
}else{ |
||||||
|
result.connect.destroy() |
||||||
|
rec({ |
||||||
|
status:true, |
||||||
|
message:'数据库创建成功。', |
||||||
|
// data
|
||||||
|
}) |
||||||
|
} |
||||||
|
}) |
||||||
|
}catch (e){ |
||||||
|
rej(e) |
||||||
|
} |
||||||
|
}catch (e){ |
||||||
|
rej(e) |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
// 创建表,这里使用的是SQL文件导入
|
||||||
|
function createTables(){ |
||||||
|
return new Promise(async (rec, rej) => { |
||||||
|
const importer = new Importer({ |
||||||
|
host: config.DATABASE_INIT.host, |
||||||
|
user: config.DATABASE_INIT.user, |
||||||
|
password: config.DATABASE_INIT.password, |
||||||
|
database: config.DATABASE_INIT.database |
||||||
|
}); |
||||||
|
importer.import(config.DATABASE_INIT.sqlFile).then(()=>{ |
||||||
|
const files_imported = importer.getImported(); |
||||||
|
rec({ |
||||||
|
status: true, |
||||||
|
message: '数据表创建成功。', |
||||||
|
SQLfile:files_imported |
||||||
|
}) |
||||||
|
}).catch(err=>{ |
||||||
|
console.error(err); |
||||||
|
rej({ |
||||||
|
status: false, |
||||||
|
message: '数据表创建失败。', |
||||||
|
code: err.code, |
||||||
|
errno: err.errno, |
||||||
|
sqlMessage: err.sqlMessage |
||||||
|
}) |
||||||
|
}); |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
module.exports = { |
||||||
|
createDatabase, |
||||||
|
createTables |
||||||
|
} |
@ -0,0 +1,135 @@ |
|||||||
|
/** |
||||||
|
* 数据操作的方法封装 |
||||||
|
* */ |
||||||
|
const {init, exec, sql, transaction} = require('mysqls') |
||||||
|
const config = require("../../config/default.config"); |
||||||
|
|
||||||
|
init({ |
||||||
|
host: config.DATABASE_INIT.host, |
||||||
|
user: config.DATABASE_INIT.user, |
||||||
|
password: config.DATABASE_INIT.password, |
||||||
|
database: config.DATABASE_INIT.database, |
||||||
|
port: config.DATABASE_INIT.port, |
||||||
|
}) |
||||||
|
|
||||||
|
|
||||||
|
function INSERT(table, data) { |
||||||
|
return sql |
||||||
|
.table(table) |
||||||
|
.data(data) |
||||||
|
.insert() |
||||||
|
} |
||||||
|
|
||||||
|
function DELETE(table, data) { |
||||||
|
return sql |
||||||
|
.table(table) |
||||||
|
.where(data) |
||||||
|
.delet(); |
||||||
|
} |
||||||
|
|
||||||
|
function UPDATE(table, data, where) { |
||||||
|
return sql |
||||||
|
.table(table) |
||||||
|
.data(data) |
||||||
|
.where(where) |
||||||
|
.update() |
||||||
|
} |
||||||
|
|
||||||
|
function SELECT(table, field, where) { |
||||||
|
return sql |
||||||
|
.table(table) |
||||||
|
.field(field) |
||||||
|
.where(where) |
||||||
|
.select() |
||||||
|
} |
||||||
|
|
||||||
|
function ORDER(table, field, where, order){ |
||||||
|
return sql |
||||||
|
.table(table) |
||||||
|
.field(field) |
||||||
|
.where(where) |
||||||
|
.order(order) |
||||||
|
.select() |
||||||
|
} |
||||||
|
|
||||||
|
function LIMIT(table, field, limit, where){ |
||||||
|
return sql |
||||||
|
.table(table) |
||||||
|
.field(field) |
||||||
|
.limit(limit) |
||||||
|
.where(where) |
||||||
|
.select() |
||||||
|
} |
||||||
|
|
||||||
|
function COUNT(table,count, where){ |
||||||
|
return sql |
||||||
|
.count(count) |
||||||
|
.table(table) |
||||||
|
.where(where) |
||||||
|
.select() |
||||||
|
} |
||||||
|
|
||||||
|
const table = { |
||||||
|
userInfo:'user_info', |
||||||
|
userInfoOther:'user_info_other', |
||||||
|
userLogin:'user_login', |
||||||
|
userRole:'user_role', |
||||||
|
userAuthority:'user_authority', |
||||||
|
userRelationRole:'user_relation_role', |
||||||
|
userRelationAuthority:'user_relation_authority' |
||||||
|
} |
||||||
|
|
||||||
|
const DB = { |
||||||
|
SQL:{ |
||||||
|
exec, sql |
||||||
|
} |
||||||
|
} |
||||||
|
for(let i in table){ |
||||||
|
DB[i] = (() => { |
||||||
|
return { |
||||||
|
INSERT(data){ |
||||||
|
const SQL = INSERT(table[i],data) |
||||||
|
console.e(SQL); |
||||||
|
return exec(SQL) |
||||||
|
}, |
||||||
|
DELETE(data){ |
||||||
|
const SQL = DELETE(table[i],data) |
||||||
|
console.e(SQL); |
||||||
|
return exec(SQL) |
||||||
|
}, |
||||||
|
// 批量删除ID关键段
|
||||||
|
DELETEINID(data){ |
||||||
|
const SQL = `DELETE FROM ${table[i]} WHERE id in (${data})` |
||||||
|
console.e(SQL); |
||||||
|
return exec(SQL) |
||||||
|
}, |
||||||
|
UPDATE(data, where){ |
||||||
|
const SQL = UPDATE(table[i], data, where) |
||||||
|
console.e(SQL); |
||||||
|
return exec(SQL) |
||||||
|
}, |
||||||
|
SELECT(field, where){ |
||||||
|
const SQL = SELECT(table[i], field, where) |
||||||
|
console.e(SQL); |
||||||
|
return exec(SQL) |
||||||
|
}, |
||||||
|
ORDER(field, where, order){ |
||||||
|
const SQL = ORDER(table[i], field, where, order) |
||||||
|
console.e(SQL) |
||||||
|
return exec(SQL) |
||||||
|
}, |
||||||
|
LIMIT(field, limit, where){ |
||||||
|
const SQL = LIMIT(table[i], field, limit, where) |
||||||
|
console.e(SQL) |
||||||
|
return exec(SQL) |
||||||
|
}, |
||||||
|
COUNT(count, where){ |
||||||
|
const SQL = COUNT(table[i], count, where) |
||||||
|
console.e(SQL) |
||||||
|
return exec(SQL) |
||||||
|
} |
||||||
|
} |
||||||
|
})() |
||||||
|
} |
||||||
|
|
||||||
|
module.exports = DB |
@ -0,0 +1,41 @@ |
|||||||
|
// 用户登陆表
|
||||||
|
const router = require('koa-router')(); |
||||||
|
|
||||||
|
// 全局路由
|
||||||
|
router.prefix('/api') |
||||||
|
|
||||||
|
router.use( |
||||||
|
// 用户系统
|
||||||
|
require('./user/index'), |
||||||
|
// 测试系统
|
||||||
|
require('./test/index'), |
||||||
|
) |
||||||
|
router.get('/', async ctx => { |
||||||
|
ctx.body = 'sys22_userSys API!' |
||||||
|
}) |
||||||
|
|
||||||
|
module.exports = router |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
router.get('/', async ctx => { |
||||||
|
console.log('query'.green, ctx.query) |
||||||
|
// console.log('body'.green, ctx.request.body)
|
||||||
|
// Get请求只能传Query参数,POST可以传Query和Body(常用)两种形式的参数。
|
||||||
|
ctx.body = 'Hello World'; |
||||||
|
}) |
||||||
|
router.post('/', async ctx => { |
||||||
|
console.log('query'.green, ctx.query) |
||||||
|
console.log('body'.green, ctx.request.body) |
||||||
|
ctx.body = 'Hello World'; |
||||||
|
}) |
||||||
|
|
||||||
|
// 调用router.routes()来组装匹配好的路由,返回一个合并好的中间件
|
||||||
|
// 调用router.allowedMethods()获得一个中间件,当发送了不符合的请求时,会返回 `405 Method Not Allowed` 或 `501 Not Implemented`
|
||||||
|
app.use(router.routes()); |
||||||
|
app.use(router.allowedMethods({ |
||||||
|
// throw: true, // 抛出错误,代替设置响应头状态
|
||||||
|
// notImplemented: () => '不支持当前请求所需要的功能',
|
||||||
|
// methodNotAllowed: () => '不支持的请求方式'
|
||||||
|
})); |
||||||
|
* */ |
@ -0,0 +1,18 @@ |
|||||||
|
const router = require('koa-router')(); |
||||||
|
|
||||||
|
router.prefix('/test') |
||||||
|
|
||||||
|
router.get('/', function (ctx, next) { |
||||||
|
ctx.body = 'this is a testes response!' |
||||||
|
}) |
||||||
|
router.post('/', function (ctx, next) { |
||||||
|
console.log(ctx.request.body) |
||||||
|
ctx.body = 'this is a testes response!' |
||||||
|
}) |
||||||
|
|
||||||
|
router.get('/bar', function (ctx, next) { |
||||||
|
ctx.body = 'this is a testes/bar response' |
||||||
|
}) |
||||||
|
|
||||||
|
// 这里必须要使用router.routes(),多层嵌套
|
||||||
|
module.exports = router.routes() |
@ -0,0 +1,27 @@ |
|||||||
|
/** |
||||||
|
* 登陆后操作 |
||||||
|
* */ |
||||||
|
|
||||||
|
const router = require('koa-router')(); |
||||||
|
const api = require('../../API/index') |
||||||
|
|
||||||
|
router.prefix('/authority') |
||||||
|
|
||||||
|
// 创建权限
|
||||||
|
router.post('/createAuthority', api.createAuthority) |
||||||
|
// 删除权限
|
||||||
|
router.del('/romveAuthority', api.romveAuthority) |
||||||
|
// 修改权限信息
|
||||||
|
router.put('/editAuthority', api.editAuthority) |
||||||
|
// 获取所有权限
|
||||||
|
router.get('/getAllAuthority', api.getAllAuthority) |
||||||
|
// 添加角色权限关系
|
||||||
|
router.post('/relation/addAuthorityAndRoleRelation', api.addAuthorityAndRoleRelation) |
||||||
|
// 删除角色权限关联
|
||||||
|
router.post('/relation/removeAuthorityAndRoleRelation', api.removeAuthorityAndRoleRelation) |
||||||
|
// 清空当前权限的所有使用角色
|
||||||
|
router.post('/relation/clearAuthorityRole', api.clearAuthorityRole) |
||||||
|
// 获取角色权限
|
||||||
|
router.get('/getRoleAuthority', api.getRoleAuthority) |
||||||
|
|
||||||
|
module.exports = router.routes() |
@ -0,0 +1,20 @@ |
|||||||
|
const router = require('koa-router')(); |
||||||
|
|
||||||
|
router.prefix('/user') |
||||||
|
|
||||||
|
router.get('/', async ctx => { |
||||||
|
ctx.body = '/API/user' |
||||||
|
}) |
||||||
|
router.use( |
||||||
|
// 登陆前操作
|
||||||
|
require('./will'), |
||||||
|
// // 账户操作
|
||||||
|
require('./signed'), |
||||||
|
// // 角色
|
||||||
|
require('./role'), |
||||||
|
// // 权限
|
||||||
|
require('./authority') |
||||||
|
) |
||||||
|
|
||||||
|
// 这里必须要使用router.routes(),多层嵌套
|
||||||
|
module.exports = router.routes() |
@ -0,0 +1,25 @@ |
|||||||
|
/** |
||||||
|
* 登陆后操作 |
||||||
|
* */ |
||||||
|
|
||||||
|
const router = require('koa-router')(); |
||||||
|
const api = require('../../API/index') |
||||||
|
|
||||||
|
router.prefix('/role') |
||||||
|
|
||||||
|
// 创建角色
|
||||||
|
router.post('/createRole', api.createRole) |
||||||
|
// 删除角色
|
||||||
|
router.del('/deleteRoleList', api.deleteRoleList) |
||||||
|
// 修改角色信息
|
||||||
|
router.put('/editRole', api.editRole) |
||||||
|
// 获取全部角色列表
|
||||||
|
router.get('/getAllRoleList', api.getAllRoleList) |
||||||
|
// 获取个人角色列表
|
||||||
|
router.get('/getPersonalRoleIdList', api.getPersonalRoleIdList) |
||||||
|
// 添加用户角色关联
|
||||||
|
router.post('/relation/addRoleAndUserRelation', api.addRoleAndUserRelation) |
||||||
|
// 删除用户角色关联
|
||||||
|
router.post('/realtion/romoveRoleAndUserRelation', api.romoveRoleAndUserRelation) |
||||||
|
|
||||||
|
module.exports = router.routes() |
@ -0,0 +1,21 @@ |
|||||||
|
/** |
||||||
|
* 登陆后操作 |
||||||
|
* */ |
||||||
|
|
||||||
|
const router = require('koa-router')(); |
||||||
|
const api = require('../../API/index') |
||||||
|
|
||||||
|
router.prefix('/signed') |
||||||
|
|
||||||
|
// 退出登录
|
||||||
|
router.get('/signOut', api.signOut) |
||||||
|
// 修改用户信息
|
||||||
|
router.put('/editUserinfo', api.editUserinfo) |
||||||
|
// 修改密码
|
||||||
|
router.put('/editPassword', api.editPassword) |
||||||
|
// 注销用户
|
||||||
|
router.post('/writeoff', api.writeoff) |
||||||
|
// 获取用户信息
|
||||||
|
router.get('/getuserInfo', api.getuserInfo) |
||||||
|
|
||||||
|
module.exports = router.routes() |
@ -0,0 +1,20 @@ |
|||||||
|
/** |
||||||
|
* 登录前操作 |
||||||
|
* */ |
||||||
|
const router = require('koa-router')(); |
||||||
|
const api = require('../../API/index') |
||||||
|
|
||||||
|
router.prefix('/will') |
||||||
|
|
||||||
|
// 注册
|
||||||
|
router.post('/signUp', api.signUp) |
||||||
|
// 登录
|
||||||
|
router.post('/signIn', api.signIn) |
||||||
|
// 找回密码
|
||||||
|
router.post('/reset', api.reset) |
||||||
|
// 用户名查重
|
||||||
|
router.get('/checkOnly', api.checkOnly) |
||||||
|
// 发送验证码
|
||||||
|
router.get('/sendCode', api.sendCode) |
||||||
|
|
||||||
|
module.exports = router.routes() |
@ -0,0 +1,31 @@ |
|||||||
|
const { createClient } = require('redis'); |
||||||
|
|
||||||
|
async function redisJSONDemo() { |
||||||
|
try { |
||||||
|
const TEST_KEY = 'test_node'; |
||||||
|
|
||||||
|
const client = createClient({ |
||||||
|
url: 'redis://uair.cc:6379' |
||||||
|
}); |
||||||
|
await client.connect(); |
||||||
|
|
||||||
|
await client.json.set('signUpCode','$',{}) |
||||||
|
await client.json.set('signUpCode','expressgy',{code:'9527',time:new Date().getTime()}) |
||||||
|
await client.json.set('signUpCode','expressnie',{code:'9527',time:new Date().getTime()}) |
||||||
|
await client.json.set('signUpCode','admin',{code:'9527',time:new Date().getTime(),name:"何夕"}) |
||||||
|
await client.json.set('signUpCode','张良',{code:'9527',time:new Date().getTime(),name:"何夕"}) |
||||||
|
const value = await client.json.get('signUpCode'); |
||||||
|
// , {
|
||||||
|
// // JSON Path: .node = the element called 'node' at root level.
|
||||||
|
// path: 'pets[0].name',
|
||||||
|
// }
|
||||||
|
|
||||||
|
console.log(value); |
||||||
|
|
||||||
|
await client.quit(); |
||||||
|
} catch (e) { |
||||||
|
console.error(e); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
redisJSONDemo(); |
@ -0,0 +1,22 @@ |
|||||||
|
const { createClient } = require('redis'); |
||||||
|
|
||||||
|
async function redisJSONDemo() { |
||||||
|
try { |
||||||
|
const TEST_KEY = 'test_node'; |
||||||
|
|
||||||
|
const client = createClient({ |
||||||
|
url: 'redis://uair.cc:6379' |
||||||
|
}); |
||||||
|
await client.connect(); |
||||||
|
|
||||||
|
await client.set('4afcef91d5b45a965bcd4ffbd15b3af3','$') |
||||||
|
console.log(await client.get('4afcef91d5b45a965bcd4ffbd15b3af3')) |
||||||
|
console.log(await client.del('a76cb34121b5d327ae28ec56469ef6df9b2c16392bee476a4ea69314d57d36403b568654f53e89b473f631b547c2dd4ddb7d721a2f1192d999010a1fe214422dc67f4d1d5248dd86b3cc0acdeba15a89f8a60063d9e20e8d1f2f5b3777cebda3969e1d5f0cc7d7d920b1ac58617f4d832bf58311d9fd077aa16648f4b17f86bb50a37eefe369bf07d1f8cd624bd1ed6fa8dfb6c732a1487b1dbcd98541e8ce0922ace0050a485a3194d5fa823f3e43a2214ccac8c34362006ef90eae0afa89b9efba3e6902e22bd9a9071d79d46429e5be0fae3c381ff14728665c6435cf3b0d')) |
||||||
|
|
||||||
|
await client.quit(); |
||||||
|
} catch (e) { |
||||||
|
console.error(e); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
redisJSONDemo(); |
@ -0,0 +1,35 @@ |
|||||||
|
// ===============================================UUID && Token========================================================
|
||||||
|
//
|
||||||
|
// async function test() {
|
||||||
|
// const R = await Redis()
|
||||||
|
// await R.setLogin('uuid1', 'token11')
|
||||||
|
// await R.setLogin('uuid1', 'token12')
|
||||||
|
// await R.setLogin('uuid1', 'token13')
|
||||||
|
// await R.setLogin('uuid1', 'token14')
|
||||||
|
// await R.setLogin('uuid1', 'token15')
|
||||||
|
// console.log(await R.getLogin('uuid1'))
|
||||||
|
// await R.delLogin('uuid1', 'token15')
|
||||||
|
// console.log(await R.getLogin('uuid1'))
|
||||||
|
// // await R.setLogin('uuid1', 'token16')
|
||||||
|
// // await R.setLogin('uuid1', 'token17')
|
||||||
|
// // await R.setLogin('uuid1', 'token18')
|
||||||
|
// // await R.setLogin('uuid1', 'token19')
|
||||||
|
// // await R.setLogin('uuid1', 'token10')
|
||||||
|
// // await R.setLogin('uuid2', 'token21')
|
||||||
|
// // await R.setLogin('uuid2', 'token22')
|
||||||
|
// // await R.setLogin('uuid2', 'token273')
|
||||||
|
// // await R.setLogin('uuid2', 'token23')
|
||||||
|
// // await R.setLogin('uuid2', 'token24')
|
||||||
|
// // await R.setLogin('uuid2', 'token25')
|
||||||
|
// // await R.setLogin('uuid2', 'token26')
|
||||||
|
// // await R.setLogin('uuid2', 'token27')
|
||||||
|
// // await R.setLogin('uuid2', 'token28')
|
||||||
|
// // await R.clearLoginArr()
|
||||||
|
// // console.log(await R.getToken('token21'));
|
||||||
|
// // console.log(await R.getLogin('uuid1'));
|
||||||
|
// // console.log(await R.getLogin('uuid2'));
|
||||||
|
// // console.log('end')
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
// test()
|
@ -0,0 +1,13 @@ |
|||||||
|
|
||||||
|
console.time(0) |
||||||
|
var timestamp = timestamp=new Date() |
||||||
|
console.timeEnd(0) |
||||||
|
|
||||||
|
|
||||||
|
console.time(1) |
||||||
|
var timestamp1 = timestamp.valueOf(); |
||||||
|
console.timeEnd(1) |
||||||
|
|
||||||
|
console.time(2) |
||||||
|
var timestamp2 = timestamp.getTime(); |
||||||
|
console.timeEnd(2) |
@ -0,0 +1,11 @@ |
|||||||
|
const token = require('../tools/user/token') |
||||||
|
|
||||||
|
const a = token.encrypt({user:'xsxsxs'}, 3) |
||||||
|
|
||||||
|
console.log(a) |
||||||
|
|
||||||
|
setTimeout(() => { |
||||||
|
const b = token.decrypt(a) |
||||||
|
|
||||||
|
console.log(b) |
||||||
|
},2000) |
@ -0,0 +1,3 @@ |
|||||||
|
const a = " asxasxas " |
||||||
|
console.log(a); |
||||||
|
console.log(a.trim()); |
@ -0,0 +1,21 @@ |
|||||||
|
/** |
||||||
|
* 数据操作的方法封装 |
||||||
|
* */ |
||||||
|
const {init, exec, sql, transaction} = require('mysqls') |
||||||
|
const config = require("../config/default.config"); |
||||||
|
|
||||||
|
init({ |
||||||
|
host: config.DATABASE_INIT.host, |
||||||
|
user: config.DATABASE_INIT.user, |
||||||
|
password: config.DATABASE_INIT.password, |
||||||
|
database: config.DATABASE_INIT.database, |
||||||
|
port: config.DATABASE_INIT.port, |
||||||
|
}) |
||||||
|
|
||||||
|
|
||||||
|
let sqlstring = sql.field('authority_id').table('user_relation_authority').where({role_id:4}).select() |
||||||
|
let SQQ = sql.query(`SELECT * from user_authority where id in (${sqlstring})`) |
||||||
|
console.log(SQQ) |
||||||
|
exec(SQQ).then(res => { |
||||||
|
console.log(res) |
||||||
|
}) |
@ -0,0 +1,10 @@ |
|||||||
|
function getStr(len, size='big'){ |
||||||
|
if(size == 'big'){ |
||||||
|
return Math.random().toString(36).slice(-len).toString().toUpperCase(); |
||||||
|
}else{ |
||||||
|
return Math.random().toString(36).slice(-len).toString().toLowerCase(); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
module.exports = getStr |
@ -0,0 +1,70 @@ |
|||||||
|
const styles = { |
||||||
|
// style: [ style code, reset code ]
|
||||||
|
'bold' : ['\x1B[1m', '\x1B[22m'], |
||||||
|
'italic' : ['\x1B[3m', '\x1B[23m'], |
||||||
|
'underline' : ['\x1B[4m', '\x1B[24m'], |
||||||
|
'inverse' : ['\x1B[7m', '\x1B[27m'], |
||||||
|
'strikethrough' : ['\x1B[9m', '\x1B[29m'], |
||||||
|
'white' : ['\x1B[37m', '\x1B[39m'], |
||||||
|
'grey' : ['\x1B[90m', '\x1B[39m'], |
||||||
|
'black' : ['\x1B[30m', '\x1B[39m'], |
||||||
|
'blue' : ['\x1B[34m', '\x1B[39m'], |
||||||
|
'cyan' : ['\x1B[36m', '\x1B[39m'], |
||||||
|
'green' : ['\x1B[32m', '\x1B[39m'], |
||||||
|
'magenta' : ['\x1B[35m', '\x1B[39m'], |
||||||
|
'red' : ['\x1B[31m', '\x1B[39m'], |
||||||
|
'yellow' : ['\x1B[33m', '\x1B[39m'], |
||||||
|
'whiteBG' : ['\x1B[47m', '\x1B[49m'], |
||||||
|
'greyBG' : ['\x1B[49;5;8m', '\x1B[49m'], |
||||||
|
'blackBG' : ['\x1B[40m', '\x1B[49m'], |
||||||
|
'blueBG' : ['\x1B[44m', '\x1B[49m'], |
||||||
|
'cyanBG' : ['\x1B[46m', '\x1B[49m'], |
||||||
|
'greenBG' : ['\x1B[42m', '\x1B[49m'], |
||||||
|
'magentaBG' : ['\x1B[45m', '\x1B[49m'], |
||||||
|
'redBG' : ['\x1B[41m', '\x1B[49m'], |
||||||
|
'yellowBG' : ['\x1B[43m', '\x1B[49m'] |
||||||
|
}; |
||||||
|
function initConsole() { |
||||||
|
// 斜体
|
||||||
|
console.__proto__.i = function () { |
||||||
|
console.log(`\x1B[3m${Array.from(arguments).join(',')}\x1B[0m`) |
||||||
|
} |
||||||
|
// 粗体
|
||||||
|
console.__proto__.b = function () { |
||||||
|
console.log(`\x1B[1m${Array.from(arguments).join(',')}\x1B[0m`) |
||||||
|
} |
||||||
|
// 下划线
|
||||||
|
console.__proto__.u = function () { |
||||||
|
console.log(`\x1B[4m${Array.from(arguments).join(',')}\x1B[0m`) |
||||||
|
} |
||||||
|
// 错误
|
||||||
|
console.__proto__.e = console.__proto__.err = function () { |
||||||
|
console.error(`\x1B[31m${Array.from(arguments).join(',')}\x1B[0m`) |
||||||
|
} |
||||||
|
// 成功
|
||||||
|
console.__proto__.s = console.__proto__.success = function () { |
||||||
|
console.log(`\x1B[32m${Array.from(arguments).join(',')}\x1B[0m`) |
||||||
|
} |
||||||
|
// 警告
|
||||||
|
console.__proto__.w = console.__proto__.warning = function () { |
||||||
|
console.warn(`\x1B[33m${Array.from(arguments).join(',')}\x1B[0m`) |
||||||
|
} |
||||||
|
// 一般提示
|
||||||
|
console.__proto__.i = console.__proto__.info = function () { |
||||||
|
console.log(`\x1B[34m${Array.from(arguments).join(',')}\x1B[0m`) |
||||||
|
} |
||||||
|
// 青色
|
||||||
|
console.__proto__.a = function () { |
||||||
|
console.log(`\x1B[36m${Array.from(arguments).join(',')}\x1B[0m`) |
||||||
|
} |
||||||
|
|
||||||
|
// dev
|
||||||
|
console.__proto__.dev = console.log |
||||||
|
|
||||||
|
for(let i in styles){ |
||||||
|
console.__proto__[i] = function (){ |
||||||
|
console.log(`${styles[i][0]}${Array.from(arguments).join(',')}${styles[i][1]}`) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
module.exports = initConsole |
@ -0,0 +1,65 @@ |
|||||||
|
/** |
||||||
|
* 创建数据库连接 |
||||||
|
* */ |
||||||
|
const mysql = require("mysql"); |
||||||
|
const config = require("../../config/default.config"); |
||||||
|
|
||||||
|
function createConnectionNull() { |
||||||
|
return new Promise((rec, rej) => { |
||||||
|
const db = mysql.createConnection({ |
||||||
|
host: config.DATABASE_INIT.host, |
||||||
|
user: config.DATABASE_INIT.user, |
||||||
|
password: config.DATABASE_INIT.password, |
||||||
|
}); |
||||||
|
db.connect(err => { |
||||||
|
if (err) { |
||||||
|
rej({ |
||||||
|
status: false, |
||||||
|
message: '数据库连接失败。', |
||||||
|
code: err.code, |
||||||
|
errno: err.errno, |
||||||
|
sqlMessage: err.sqlMessage |
||||||
|
}) |
||||||
|
} else { |
||||||
|
rec({ |
||||||
|
status: true, |
||||||
|
message: '数据库连接成功。', |
||||||
|
connect: db |
||||||
|
}) |
||||||
|
} |
||||||
|
}) |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
function createConnectionDatabase() { |
||||||
|
return new Promise((rec, rej) => { |
||||||
|
const db = mysql.createConnection({ |
||||||
|
host: config.DATABASE_INIT.host, |
||||||
|
user: config.DATABASE_INIT.user, |
||||||
|
password: config.DATABASE_INIT.password, |
||||||
|
database: config.DATABASE_INIT.database |
||||||
|
}); |
||||||
|
db.connect(err => { |
||||||
|
if (err) { |
||||||
|
rej({ |
||||||
|
status: false, |
||||||
|
message: '数据库连接失败。', |
||||||
|
code: err.code, |
||||||
|
errno: err.errno, |
||||||
|
sqlMessage: err.sqlMessage |
||||||
|
}) |
||||||
|
} else { |
||||||
|
rec({ |
||||||
|
status: true, |
||||||
|
message: '数据库连接成功。', |
||||||
|
connect: db |
||||||
|
}) |
||||||
|
} |
||||||
|
}) |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
module.exports = { |
||||||
|
createConnectionNull, |
||||||
|
createConnectionDatabase |
||||||
|
} |
@ -0,0 +1,14 @@ |
|||||||
|
/** |
||||||
|
* 格式化SQL语句 |
||||||
|
* */ |
||||||
|
|
||||||
|
function formatSQL(tableStruct){ |
||||||
|
let field = '' |
||||||
|
for(let i of tableStruct.field){ |
||||||
|
field += `${i.name} ${i.type} ${i.attribute.join(' ')} comment "${i.comment}",` |
||||||
|
} |
||||||
|
field = field.slice(0, field.length - 1) |
||||||
|
return `Create Table If Not Exists ${tableStruct.tableName} (${field})comment = "${tableStruct.comment}";` |
||||||
|
} |
||||||
|
|
||||||
|
module.exports = formatSQL |
@ -0,0 +1,17 @@ |
|||||||
|
/** |
||||||
|
* 环境探测 |
||||||
|
* */ |
||||||
|
|
||||||
|
const os = require('os') |
||||||
|
|
||||||
|
// 获取系统信息
|
||||||
|
function getSystem(){ |
||||||
|
return { |
||||||
|
hostname:os.hostname(), |
||||||
|
os:os.type() + os.arch() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
module.exports = { |
||||||
|
getSystem |
||||||
|
} |
@ -0,0 +1,75 @@ |
|||||||
|
const nodemailer = require('nodemailer'); //引入模块
|
||||||
|
|
||||||
|
|
||||||
|
const reg = /^[a-zA-Z0-9]+([-_.][A-Za-zd]+)*@([a-zA-Z0-9]+[-.])+[A-Za-zd]{2,5}$/ |
||||||
|
|
||||||
|
const { EMAILCONFIG,SYSTEM_NAME } = require('../config/default.config') |
||||||
|
|
||||||
|
const transporter = nodemailer.createTransport({ |
||||||
|
//node_modules/nodemailer/lib/well-known/services.json 查看相关的配置,如果使用qq邮箱,就查看qq邮箱的相关配置
|
||||||
|
host:EMAILCONFIG.HOST, |
||||||
|
// secureConnection:true,
|
||||||
|
service: 'qq', //类型qq邮箱
|
||||||
|
// port: 465,
|
||||||
|
secure: true, // true for 465, false for other ports
|
||||||
|
auth: { |
||||||
|
user: EMAILCONFIG.USER, // 发送方的邮箱
|
||||||
|
pass:EMAILCONFIG.PASS// smtp 的授权码
|
||||||
|
} |
||||||
|
//pass 不是邮箱账户的密码而是stmp的授权码(必须是相应邮箱的stmp授权码)
|
||||||
|
//邮箱---设置--账户--POP3/SMTP服务---开启---获取stmp授权码
|
||||||
|
}); |
||||||
|
const typeList = { |
||||||
|
signUp:'账户注册', |
||||||
|
signIn:'登录', |
||||||
|
reset:'重置密码', |
||||||
|
writeoff:'注销账户' |
||||||
|
} |
||||||
|
|
||||||
|
function sendMail(mail, code, type) { |
||||||
|
console.log(mail, code) |
||||||
|
return new Promise((rec,rej) => { |
||||||
|
if(!checkEmail(mail)){ |
||||||
|
rej('邮箱格式错误!') |
||||||
|
} |
||||||
|
// 发送的配置项
|
||||||
|
const mailOptions = { |
||||||
|
from: '"TOGY.GC" <togy.gc@qq.com>', // 发送方
|
||||||
|
to: mail, //接收者邮箱,多个邮箱用逗号间隔
|
||||||
|
subject: `${SYSTEM_NAME}!`, // 标题
|
||||||
|
text: 'Hello world?', // 文本内容
|
||||||
|
html: `<div style="position: relative;height: 300px;width: 100%">
|
||||||
|
<div><h1 style="text-align: center;line-height: 70px">欢迎使用 ${SYSTEM_NAME} </h1><p style="text-align: center">您在某些地方请求了邮箱的验证码,如果不是自己操作请修改账户的密码。</p></div> |
||||||
|
<div style="width: 100%;position:relative;height: 200px;display: flex;align-items: center;justify-content: center"><div style="line-height: 80px;padding: 1em;font-size: 24px;color:red;font-weight: bold;text-align: centerline-height: 1em">此验证码用于 ${typeList[type]}。 </div><p style="text-align: center"></p></div> |
||||||
|
<div style="width: 100%;position:relative;height: 200px;display: flex;align-items: center;justify-content: center"> |
||||||
|
<div style="background: #333333;height: 80px;line-height: 80px;padding: 1em;font-size: 32px;color:#FEFEFE;font-weight: bold;text-align: center">${code}</div> |
||||||
|
</div> |
||||||
|
</div>`, //页面内容 |
||||||
|
// attachments: [{//发送文件
|
||||||
|
// filename: 'index.html', //文件名字
|
||||||
|
// path: './index.html' //文件路径
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// filename: 'sendEmail.js', //文件名字
|
||||||
|
// content: 'sendEmail.js' //文件路径
|
||||||
|
// }
|
||||||
|
// ]
|
||||||
|
}; |
||||||
|
//发送函数
|
||||||
|
transporter.sendMail(mailOptions, (error, info) => { |
||||||
|
if (error) { |
||||||
|
rej(error,info) |
||||||
|
} else { |
||||||
|
rec(info) //因为是异步 所有需要回调函数通知成功结果
|
||||||
|
} |
||||||
|
}); |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
function checkEmail(email){ |
||||||
|
return reg.test(email) |
||||||
|
} |
||||||
|
module.exports = { |
||||||
|
sendMail, |
||||||
|
checkEmail |
||||||
|
} |
@ -0,0 +1,308 @@ |
|||||||
|
const {createClient} = require('redis') |
||||||
|
, {RedisJSON, maxClientOnline, user} = require('../config/default.config') |
||||||
|
,{HASH} = require('../tools/user/encryptionString') |
||||||
|
|
||||||
|
function initRedisJSON() { |
||||||
|
return new Promise(async (res, rej) => { |
||||||
|
const client = createClient({ |
||||||
|
// https://github.com/redis/node-redis
|
||||||
|
url: `redis://default:Hxl1314521@${RedisJSON.host}:${RedisJSON.port}` |
||||||
|
}); |
||||||
|
try { |
||||||
|
await client.connect() |
||||||
|
RedisJSON.startClear ? client.flushAll() : '' |
||||||
|
client.select(RedisJSON.pool) |
||||||
|
res(client) |
||||||
|
} catch (e) { |
||||||
|
rej(e) |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
const codeList = ['signUp', 'signIn', 'reset', 'writeoff'] |
||||||
|
|
||||||
|
function Redis() { |
||||||
|
return new Promise(async (res, rej) => { |
||||||
|
try { |
||||||
|
const client = await initRedisJSON() |
||||||
|
|
||||||
|
// 初始化RedisJSON池
|
||||||
|
// 同类的
|
||||||
|
for(let codeType of codeList){ |
||||||
|
await client.json.set(codeType, '$', {}, {NX: true}); |
||||||
|
} |
||||||
|
// 特殊的
|
||||||
|
await client.json.set('login', '$', {}, {NX: true}); |
||||||
|
// 执行清理程序
|
||||||
|
setInterval(async () => { |
||||||
|
clearAllCode(client) |
||||||
|
}, RedisJSON.clearTime) |
||||||
|
|
||||||
|
// 生成对外程序
|
||||||
|
const codeMethods = {} |
||||||
|
for(let codeType of codeList){ |
||||||
|
const nowCodeType = codeType.replace(codeType[0],codeType.split("")[0].toUpperCase()) |
||||||
|
codeMethods['set' + nowCodeType + 'Code'] = (emailOrUsername, code) => setCode(client, codeType, emailOrUsername, code) |
||||||
|
codeMethods['get' + nowCodeType + 'Code'] = (emailOrUsername) => getCode(client, codeType, emailOrUsername) |
||||||
|
codeMethods['del' + nowCodeType + 'Code'] = (emailOrUsername) => delCode(client, codeType, emailOrUsername) |
||||||
|
// codeMethods['clear' + nowCodeType + 'Code'] = () => clearCode(client, codeType)
|
||||||
|
} |
||||||
|
const RJ = { |
||||||
|
client, |
||||||
|
// uuid和Token
|
||||||
|
setLogin: (uuid, token) => setLogin(client, uuid, token), |
||||||
|
getLogin: (uuid) => getLogin(client, uuid), |
||||||
|
delLogin: (uuid, token) => delLogin(client, uuid, token), |
||||||
|
getToken: (token) => getToken(client, token), |
||||||
|
// 'signUp', 'signIn', 'reset' Code
|
||||||
|
...codeMethods |
||||||
|
} |
||||||
|
res(RJ) |
||||||
|
} catch (e) { |
||||||
|
rej(e) |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
// $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$统一清理程序$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
|
||||||
|
function clearAllCode(client){ |
||||||
|
return new Promise(async (res, rej) => { |
||||||
|
// 清理signUpCOde
|
||||||
|
try{ |
||||||
|
await clearCode(client, 'signUp') |
||||||
|
}catch (e) { |
||||||
|
console.e('清理注册Code发生异常', e) |
||||||
|
} |
||||||
|
// 清理登录Code
|
||||||
|
try{ |
||||||
|
await clearCode(client, 'signIn') |
||||||
|
}catch (e) { |
||||||
|
console.e('清理登录Code发生异常', e) |
||||||
|
} |
||||||
|
|
||||||
|
// 清理找回密码Code
|
||||||
|
try{ |
||||||
|
await clearCode(client, 'reset') |
||||||
|
}catch (e) { |
||||||
|
console.e('清理找回密码Code发生异常', e) |
||||||
|
} |
||||||
|
res() |
||||||
|
|
||||||
|
// 清理UUID
|
||||||
|
try { |
||||||
|
await clearLoginArr(client) |
||||||
|
console.dev('清理UUID成功') |
||||||
|
} catch (e) { |
||||||
|
console.dev('清理UUID发生异常', e) |
||||||
|
} |
||||||
|
|
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
// ===============================================UUID && Token========================================================
|
||||||
|
// login,用于同账号的登陆数量,获取UUID下的TokenList
|
||||||
|
function getLogin(client, uuid) { |
||||||
|
return new Promise(async (res, rej) => { |
||||||
|
try { |
||||||
|
const result = await client.json.get('login', {path: uuid}) |
||||||
|
res(result) |
||||||
|
} catch (e) { |
||||||
|
if (e.toString().indexOf('not exist') > -1) { |
||||||
|
res([]) |
||||||
|
} else { |
||||||
|
rej(e) |
||||||
|
} |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
// 添加UUID下的Token
|
||||||
|
function setLogin(client, uuid, token) { |
||||||
|
return new Promise(async (res, rej) => { |
||||||
|
try { |
||||||
|
const nowTime = new Date().getTime() |
||||||
|
const result = await getLogin(client, uuid) |
||||||
|
if(result == null){ |
||||||
|
console.e('需要重启服务,Redis被清空,没有根节点。') |
||||||
|
throw new Error('需要重启服务,Redis被清空,没有根节点。') |
||||||
|
} |
||||||
|
if (result.length == 0) { |
||||||
|
await client.json.set('login', uuid, [{token, time: nowTime}]) |
||||||
|
await setToken(client, token, uuid) |
||||||
|
res() |
||||||
|
} else if (result.length < maxClientOnline) { |
||||||
|
await client.json.ARRAPPEND('login', uuid, {token, time: nowTime}) |
||||||
|
await setToken(client, token, uuid) |
||||||
|
res() |
||||||
|
} else { |
||||||
|
// 已经达到最大值了
|
||||||
|
for (let i = result.length - 1; i >= 0; i--) { |
||||||
|
if (nowTime - result[i].time > user.login.timeLimit) { |
||||||
|
await delLoginArr(client, uuid, i, result[i].token) |
||||||
|
} |
||||||
|
} |
||||||
|
const result2 = await getLogin(client, uuid) |
||||||
|
if(result2.length == maxClientOnline){ |
||||||
|
await delLoginArr(client, uuid, 0, result[0].token) |
||||||
|
} |
||||||
|
await client.json.ARRAPPEND('login', uuid, {token, time: nowTime}) |
||||||
|
await setToken(client, token, uuid) |
||||||
|
res() |
||||||
|
} |
||||||
|
} catch (e) { |
||||||
|
console.log(e); |
||||||
|
rej(e) |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
// 删除UUID List中的占用的Token
|
||||||
|
function delLoginArr(client, uuid, index, token) { |
||||||
|
return new Promise(async (res, rej) => { |
||||||
|
try { |
||||||
|
await client.json.ARRPOP('login', uuid, index) |
||||||
|
await delToken(client, token) |
||||||
|
res() |
||||||
|
} catch (e) { |
||||||
|
rej(e) |
||||||
|
} |
||||||
|
|
||||||
|
}) |
||||||
|
} |
||||||
|
// 退出登录时删除UUID下的Token
|
||||||
|
function delLogin(client, uuid, token){ |
||||||
|
return new Promise(async (res, rej) => { |
||||||
|
try{ |
||||||
|
const result = await getLogin(client, uuid) |
||||||
|
for(let i = result.length - 1; i >= 0 ; i--){ |
||||||
|
if(result[i].token == token){ |
||||||
|
await delLoginArr(client, uuid, i, token) |
||||||
|
} |
||||||
|
} |
||||||
|
res() |
||||||
|
}catch (e) { |
||||||
|
rej(e) |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
// 清理过期的UUID下的Token
|
||||||
|
function clearLoginArr(client) { |
||||||
|
return new Promise(async (res, rej) => { |
||||||
|
const result = await client.json.get('login') |
||||||
|
const nowTime = new Date().getTime() |
||||||
|
try { |
||||||
|
for (let i in result) { |
||||||
|
const list = result[i]; |
||||||
|
for (let j = list.length - 1; j >= 0; j--) { |
||||||
|
if (nowTime - list[j].time > user.login.timeLimit) { |
||||||
|
await delLoginArr(client, i, j, list[j].token) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
res() |
||||||
|
} catch (e) { |
||||||
|
rej(e) |
||||||
|
} |
||||||
|
|
||||||
|
}) |
||||||
|
} |
||||||
|
// 获取Token的UUID
|
||||||
|
function getToken(client, token) { |
||||||
|
return new Promise(async (res, rej) => { |
||||||
|
try { |
||||||
|
const result = await client.get(token) |
||||||
|
res(result) |
||||||
|
} catch (e) { |
||||||
|
if (e.toString().indexOf('not exist') > -1) { |
||||||
|
res([]) |
||||||
|
} else { |
||||||
|
rej(e) |
||||||
|
} |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
// 添加Token键值对,在添加UUID时,同步添加
|
||||||
|
function setToken(client, token, uuid) { |
||||||
|
return new Promise(async (res, rej) => { |
||||||
|
try { |
||||||
|
await client.set(token, uuid) |
||||||
|
res() |
||||||
|
}catch (e) { |
||||||
|
rej() |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
// 删除Token键值对,在删除UUID时,同步删除
|
||||||
|
function delToken(client, token) { |
||||||
|
return new Promise(async (res, rej) => { |
||||||
|
try{ |
||||||
|
const a = await client.del(token) |
||||||
|
if(a != 1){ |
||||||
|
rej('删除token指定的UUID失败') |
||||||
|
console.e('删除token指定的UUID失败') |
||||||
|
}else{ |
||||||
|
console.dev('删除成功', a) |
||||||
|
} |
||||||
|
res() |
||||||
|
}catch (e) { |
||||||
|
rej(e) |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>UUID && Token>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||||
|
|
||||||
|
// 通用设置Code
|
||||||
|
function setCode(client, type, emailOrUsername, code){ |
||||||
|
return new Promise(async (res, rej) => { |
||||||
|
try{ |
||||||
|
console.log('设置登陆吗') |
||||||
|
// 这里不能设置特殊符号
|
||||||
|
emailOrUsername = HASH(emailOrUsername,'md5') |
||||||
|
const time = new Date().getTime() |
||||||
|
const a = await client.json.set(type, emailOrUsername, {code, time}, {NX:true}) |
||||||
|
console.log(a) |
||||||
|
res() |
||||||
|
}catch (e) { |
||||||
|
console.log(e) |
||||||
|
rej(e) |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
function getCode(client, type, emailOrUsername){ |
||||||
|
return new Promise(async (res, rej) => { |
||||||
|
try{ |
||||||
|
emailOrUsername = HASH(emailOrUsername,'md5') |
||||||
|
const result = await client.json.get(type, {path: emailOrUsername}) |
||||||
|
res(result) |
||||||
|
}catch (e) { |
||||||
|
rej(e) |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
function delCode(client, type, emailOrUsername){ |
||||||
|
return new Promise(async (res, rej) => { |
||||||
|
try{ |
||||||
|
emailOrUsername = HASH(emailOrUsername,'md5') |
||||||
|
const result = await client.json.del(type, emailOrUsername) |
||||||
|
res(result) |
||||||
|
}catch (e) { |
||||||
|
rej(e) |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
function clearCode(client, type){ |
||||||
|
return new Promise(async (res, rej) => { |
||||||
|
try{ |
||||||
|
const nowTime = new Date().getTime() |
||||||
|
const result = await client.json.get(type) |
||||||
|
for(let i in result){ |
||||||
|
if(nowTime - result[i].time > RedisJSON.timeout){ |
||||||
|
await delResetCode(client, type, i) |
||||||
|
} |
||||||
|
} |
||||||
|
res() |
||||||
|
}catch (e) { |
||||||
|
rej(e) |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
module.exports = Redis |
@ -0,0 +1,136 @@ |
|||||||
|
/** |
||||||
|
* 加密 |
||||||
|
* */ |
||||||
|
const crypto = require('crypto'); |
||||||
|
|
||||||
|
/** |
||||||
|
* 配置文件 |
||||||
|
* */ |
||||||
|
const CFG = global.cfg ? global.cfg.encryption : require('../../config/default.config') |
||||||
|
/** |
||||||
|
* 加密算法 |
||||||
|
* */ |
||||||
|
|
||||||
|
// 不可逆加密
|
||||||
|
const MD5 = "md5" // 32位
|
||||||
|
, SHA256 = 'sha256' // 64位
|
||||||
|
, SHA512 = 'sha512' // 128位
|
||||||
|
// 可逆加密
|
||||||
|
const AES128 = 'aes-128-cbc' |
||||||
|
, AES256 = 'aes-256-gcm' |
||||||
|
|
||||||
|
// vi
|
||||||
|
// ase-128-cbc 加密算法要求key和iv长度都为16
|
||||||
|
// const key = Buffer.from('9vApxLk5G3PAsJrM', 'utf8');
|
||||||
|
// const iv = Buffer.from('FnJL7EDzjqWjcaY9', 'utf8');
|
||||||
|
|
||||||
|
// const key = crypto.randomBytes(32); // 256 位的共享密钥
|
||||||
|
// const iv = crypto.randomBytes(16); // 初始向量,16 字节
|
||||||
|
const key = Buffer.from(HASH(CFG.encryption.secretKey, MD5).slice(0, 16), 'utf8'); |
||||||
|
const iv = Buffer.from(HASH(CFG.encryption.salt, MD5).slice(0, 16), 'utf8'); |
||||||
|
|
||||||
|
/** |
||||||
|
* 不可逆加密 |
||||||
|
* */ |
||||||
|
function HASH(plaintext, algorithm = SHA512) { |
||||||
|
const sha512 = crypto.createHash(algorithm) |
||||||
|
const sha512Sum = sha512.update(plaintext + CFG.encryption.salt) |
||||||
|
const ciphertext = sha512Sum.digest('hex') |
||||||
|
return ciphertext |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 可逆加密 |
||||||
|
* */ |
||||||
|
// 加密
|
||||||
|
|
||||||
|
// 加密
|
||||||
|
function encrypt(plaintext, algorithm = AES128) { |
||||||
|
const cipher = crypto.createCipheriv(algorithm, key, iv); // 初始化加密算法
|
||||||
|
let ciphertext = cipher.update(plaintext, 'utf8', 'hex'); |
||||||
|
ciphertext += cipher.final('hex'); |
||||||
|
// return {
|
||||||
|
// ciphertext,
|
||||||
|
// tag : cipher.getAuthTag()
|
||||||
|
// };
|
||||||
|
return ciphertext |
||||||
|
} |
||||||
|
|
||||||
|
// 解密
|
||||||
|
function decrypt(ciphertext, algorithm = AES128) { |
||||||
|
let plaintext = ''; |
||||||
|
const cipher = crypto.createDecipheriv(algorithm, key, iv); |
||||||
|
plaintext += cipher.update(ciphertext, 'hex', 'utf8'); |
||||||
|
plaintext += cipher.final('utf8'); |
||||||
|
return plaintext; |
||||||
|
} |
||||||
|
|
||||||
|
// const a = 'i love u!'
|
||||||
|
// const b = encrypt(a)
|
||||||
|
// const c = decrypt(b)
|
||||||
|
// console.log(a, b, c);
|
||||||
|
// aes128()
|
||||||
|
// aes256()
|
||||||
|
|
||||||
|
function aes256(){ |
||||||
|
'use strict'; |
||||||
|
|
||||||
|
const crypto = require('crypto'); |
||||||
|
|
||||||
|
// 初始化参数
|
||||||
|
const text = 'Encryption Testing AES GCM mode'; // 要加密和解密的数据
|
||||||
|
const key = crypto.randomBytes(32); // 256 位的共享密钥
|
||||||
|
const iv = crypto.randomBytes(16); // 初始向量,16 字节
|
||||||
|
const algorithm = 'aes-256-gcm'; // 加密算法和操作模式
|
||||||
|
|
||||||
|
// 加密
|
||||||
|
const cipher = crypto.createCipheriv(algorithm, key, iv); // 初始化加密算法
|
||||||
|
let encrypted = cipher.update(text, 'utf8', 'hex'); |
||||||
|
encrypted += cipher.final('hex'); |
||||||
|
const tag = cipher.getAuthTag(); // 生成标签,用于验证密文的来源
|
||||||
|
|
||||||
|
// 解密
|
||||||
|
const decipher = crypto.createDecipheriv(algorithm, key, iv); // 初始化解密算法
|
||||||
|
decipher.setAuthTag(tag); // 传入验证标签,验证密文的来源
|
||||||
|
let decrypted = decipher.update(encrypted, 'hex', 'utf8'); |
||||||
|
decrypted += decipher.final('utf8'); |
||||||
|
|
||||||
|
console.log(decrypted); // Encryption Testing AES GCM mode
|
||||||
|
|
||||||
|
} |
||||||
|
function aes128(){ |
||||||
|
// 加密
|
||||||
|
function genSign(src, key, iv) { |
||||||
|
let sign = ''; |
||||||
|
const cipher = crypto.createCipheriv('aes-128-cbc', key, iv); |
||||||
|
sign += cipher.update(src, 'utf8', 'hex'); |
||||||
|
sign += cipher.final('hex'); |
||||||
|
return sign; |
||||||
|
} |
||||||
|
|
||||||
|
// 解密
|
||||||
|
function deSign(sign, key, iv) { |
||||||
|
let src = ''; |
||||||
|
const cipher = crypto.createDecipheriv('aes-128-cbc', key, iv); |
||||||
|
src += cipher.update(sign, 'hex', 'utf8'); |
||||||
|
src += cipher.final('utf8'); |
||||||
|
return src; |
||||||
|
} |
||||||
|
|
||||||
|
// ase-128-cbc 加密算法要求key和iv长度都为16
|
||||||
|
const key = Buffer.from('9vApxLk5G3PAsJrM', 'utf8'); |
||||||
|
const iv = Buffer.from('FnJL7EDzjqWjcaY9', 'utf8'); |
||||||
|
const sign = genSign('hello world', key, iv); |
||||||
|
console.log(sign); // 764a669609b0c9b041faeec0d572fd7a
|
||||||
|
|
||||||
|
|
||||||
|
// 解密
|
||||||
|
const src=deSign('764a669609b0c9b041faeec0d572fd7a', key, iv); |
||||||
|
console.log(src); // hello world
|
||||||
|
} |
||||||
|
|
||||||
|
module.exports = { |
||||||
|
HASH, |
||||||
|
encrypt, |
||||||
|
decrypt |
||||||
|
} |
@ -0,0 +1,3 @@ |
|||||||
|
/** |
||||||
|
* 发送验证码 |
||||||
|
* */ |
@ -0,0 +1,34 @@ |
|||||||
|
/** |
||||||
|
* 生成和验证jwt |
||||||
|
* */ |
||||||
|
const jwt = require('jsonwebtoken'); |
||||||
|
const { encrypt, decrypt } = require('./encryptionString') |
||||||
|
|
||||||
|
// authorization
|
||||||
|
// Token.decrypt(ctx.header.authorization); // 获取其中的令牌
|
||||||
|
|
||||||
|
const CFG = global.cfg ? global.cfg.encryption : require('../../config/default.config') |
||||||
|
|
||||||
|
module.exports = { |
||||||
|
// 加密
|
||||||
|
encrypt: (token, time = CFG.user.login.timeLimit) => { |
||||||
|
// 需要设置超时时间
|
||||||
|
return encrypt(jwt.sign(token, CFG.encryption.secretKey, {expiresIn: time / 1000})) |
||||||
|
}, |
||||||
|
// 解密
|
||||||
|
decrypt: (token) => { |
||||||
|
try { |
||||||
|
token = decrypt(token) |
||||||
|
let data = jwt.verify(token, CFG.encryption.secretKey); |
||||||
|
return { |
||||||
|
token:true, |
||||||
|
id:data |
||||||
|
}; |
||||||
|
} catch (e) { |
||||||
|
return { |
||||||
|
token:false, |
||||||
|
data:e |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,11 @@ |
|||||||
|
/** |
||||||
|
* 生成uuid |
||||||
|
* */ |
||||||
|
const { v4: uuidv4 } = require('uuid'); |
||||||
|
// 需要去重- 然后转换成字符串
|
||||||
|
|
||||||
|
function makeUUID(){ |
||||||
|
return uuidv4().split('-').join("") |
||||||
|
} |
||||||
|
|
||||||
|
module.exports = makeUUID |
@ -0,0 +1,24 @@ |
|||||||
|
# Logs |
||||||
|
logs |
||||||
|
*.log |
||||||
|
npm-debug.log* |
||||||
|
yarn-debug.log* |
||||||
|
yarn-error.log* |
||||||
|
pnpm-debug.log* |
||||||
|
lerna-debug.log* |
||||||
|
|
||||||
|
node_modules |
||||||
|
dist |
||||||
|
dist-ssr |
||||||
|
*.local |
||||||
|
|
||||||
|
# Editor directories and files |
||||||
|
.vscode/* |
||||||
|
!.vscode/extensions.json |
||||||
|
.idea |
||||||
|
.DS_Store |
||||||
|
*.suo |
||||||
|
*.ntvs* |
||||||
|
*.njsproj |
||||||
|
*.sln |
||||||
|
*.sw? |
@ -0,0 +1,14 @@ |
|||||||
|
<!DOCTYPE html> |
||||||
|
<html lang="zh"> |
||||||
|
<head> |
||||||
|
<meta charset="UTF-8"/> |
||||||
|
<link rel="icon" type="image/svg+xml" href="/vite.svg"/> |
||||||
|
<!-- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css"/>--> |
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"/> |
||||||
|
<title>sys22</title> |
||||||
|
</head> |
||||||
|
<body> |
||||||
|
<div id="root"></div> |
||||||
|
<script type="module" src="/src/main.jsx"></script> |
||||||
|
</body> |
||||||
|
</html> |
@ -0,0 +1,25 @@ |
|||||||
|
{ |
||||||
|
"name": "vision", |
||||||
|
"private": true, |
||||||
|
"version": "0.0.0", |
||||||
|
"type": "module", |
||||||
|
"scripts": { |
||||||
|
"start": "vite", |
||||||
|
"build": "vite build", |
||||||
|
"preview": "vite preview" |
||||||
|
}, |
||||||
|
"dependencies": { |
||||||
|
"animate.css": "^4.1.1", |
||||||
|
"mobx": "^6.6.2", |
||||||
|
"react": "^18.2.0", |
||||||
|
"react-dom": "^18.2.0", |
||||||
|
"react-router-dom": "^6.4.2" |
||||||
|
}, |
||||||
|
"devDependencies": { |
||||||
|
"@types/react": "^18.0.17", |
||||||
|
"@types/react-dom": "^18.0.6", |
||||||
|
"@vitejs/plugin-react": "^2.1.0", |
||||||
|
"sass": "^1.55.0", |
||||||
|
"vite": "^3.1.0" |
||||||
|
} |
||||||
|
} |
File diff suppressed because it is too large
Load Diff
After Width: | Height: | Size: 1.5 KiB |
@ -0,0 +1,14 @@ |
|||||||
|
import {useState} from 'react' |
||||||
|
import { useRoutes } from 'react-router-dom' |
||||||
|
import indexRouterList from "@/router" |
||||||
|
|
||||||
|
|
||||||
|
export default function App() { |
||||||
|
const indexRoute = useRoutes(indexRouterList) |
||||||
|
return ( |
||||||
|
<div className="App"> |
||||||
|
{indexRoute} |
||||||
|
</div> |
||||||
|
) |
||||||
|
} |
||||||
|
|
@ -0,0 +1,87 @@ |
|||||||
|
class Net { |
||||||
|
constructor(option = {}) { |
||||||
|
this.baseUrl = option.baseUrl ? option.baseUrl.slice(-1) != '/' ? option.baseUrl + '/' : option.baseUrl : '' |
||||||
|
} |
||||||
|
|
||||||
|
get(url, data = null, option = null) { |
||||||
|
return new Promise((res, rej) => { |
||||||
|
let URL |
||||||
|
if (url[0] != '/') { |
||||||
|
URL = this.baseUrl + url |
||||||
|
} else { |
||||||
|
URL = this.baseUrl + url.slice(1) |
||||||
|
} |
||||||
|
URL = URL + JSON.stringify(data).replace(/:/g, '=').replace(/,/g, '&').replace(/{/g, '?').replace(/}/g, '').replace(/"/g, '') |
||||||
|
|
||||||
|
fetch(URL, { |
||||||
|
method: 'GET', |
||||||
|
headers: new Headers({ |
||||||
|
'Content-Type': 'application/json' |
||||||
|
}), |
||||||
|
}).then( |
||||||
|
response => { |
||||||
|
if (response.status >= 200 && response.status < 300) { |
||||||
|
response.json().then( |
||||||
|
json => { |
||||||
|
res(json) |
||||||
|
} |
||||||
|
).catch( |
||||||
|
e => rej(e) |
||||||
|
) |
||||||
|
} else { |
||||||
|
rej(response.statusText) |
||||||
|
} |
||||||
|
} |
||||||
|
).catch( |
||||||
|
e => { |
||||||
|
rej(e) |
||||||
|
} |
||||||
|
) |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
post(url, data = null, option = null) { |
||||||
|
return new Promise((res, rej) => { |
||||||
|
let URL |
||||||
|
if (url[0] != '/') { |
||||||
|
URL = this.baseUrl + url |
||||||
|
} else { |
||||||
|
URL = this.baseUrl + url.slice(1) |
||||||
|
} |
||||||
|
const form = new FormData(); |
||||||
|
for (let i in data) { |
||||||
|
form.append(i, data[i]); |
||||||
|
} |
||||||
|
fetch(URL, { |
||||||
|
method: 'POST', |
||||||
|
body: form |
||||||
|
}).then( |
||||||
|
response => { |
||||||
|
if (response.status >= 200 && response.status < 300) { |
||||||
|
response.json().then( |
||||||
|
json => { |
||||||
|
res(json) |
||||||
|
} |
||||||
|
).catch( |
||||||
|
e => rej(e) |
||||||
|
) |
||||||
|
} else { |
||||||
|
rej(response.statusText) |
||||||
|
} |
||||||
|
} |
||||||
|
).catch( |
||||||
|
e => { |
||||||
|
rej(e) |
||||||
|
} |
||||||
|
) |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
request(option) { |
||||||
|
|
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
export const net = new Net({ |
||||||
|
baseUrl: 'api/user' |
||||||
|
}) |
@ -0,0 +1,111 @@ |
|||||||
|
:root { |
||||||
|
font-family: Inter, Avenir, Helvetica, Arial, sans-serif; |
||||||
|
font-size: 16px; |
||||||
|
line-height: 24px; |
||||||
|
font-weight: 400; |
||||||
|
|
||||||
|
color-scheme: light dark; |
||||||
|
color: rgba(255, 255, 255, 0.87); |
||||||
|
background-color: #242424; |
||||||
|
|
||||||
|
font-synthesis: none; |
||||||
|
text-rendering: optimizeLegibility; |
||||||
|
-webkit-font-smoothing: antialiased; |
||||||
|
-moz-osx-font-smoothing: grayscale; |
||||||
|
-webkit-text-size-adjust: 100%; |
||||||
|
|
||||||
|
--animate-duration: 900ms; |
||||||
|
--animate-delay: 0.9s; |
||||||
|
} |
||||||
|
|
||||||
|
a { |
||||||
|
font-weight: 500; |
||||||
|
color: #646cff; |
||||||
|
text-decoration: inherit; |
||||||
|
} |
||||||
|
a:hover { |
||||||
|
color: #535bf2; |
||||||
|
} |
||||||
|
|
||||||
|
html,body{ |
||||||
|
height: 100% !important; |
||||||
|
width: 100% !important; |
||||||
|
overflow: hidden; |
||||||
|
} |
||||||
|
#root,.App{ |
||||||
|
height: 100%; |
||||||
|
width: 100%; |
||||||
|
overflow: hidden; |
||||||
|
} |
||||||
|
|
||||||
|
body { |
||||||
|
margin: 0; |
||||||
|
} |
||||||
|
|
||||||
|
h1 { |
||||||
|
font-size: 3.2em; |
||||||
|
line-height: 1.1; |
||||||
|
} |
||||||
|
|
||||||
|
button { |
||||||
|
border-radius: 8px; |
||||||
|
border: 1px solid transparent; |
||||||
|
padding: 0.6em 1.2em; |
||||||
|
font-size: 1em; |
||||||
|
font-weight: 500; |
||||||
|
font-family: inherit; |
||||||
|
background-color: #1a1a1a; |
||||||
|
cursor: pointer; |
||||||
|
transition: border-color 0.25s; |
||||||
|
} |
||||||
|
button:hover { |
||||||
|
border-color: #646cff; |
||||||
|
} |
||||||
|
button:focus, |
||||||
|
button:focus-visible { |
||||||
|
outline: 4px auto -webkit-focus-ring-color; |
||||||
|
} |
||||||
|
|
||||||
|
@media (prefers-color-scheme: light) { |
||||||
|
:root { |
||||||
|
color: #213547; |
||||||
|
background-color: #ffffff; |
||||||
|
} |
||||||
|
a:hover { |
||||||
|
color: #747bff; |
||||||
|
} |
||||||
|
button { |
||||||
|
background-color: #f9f9f9; |
||||||
|
} |
||||||
|
} |
||||||
|
#modalRoot{ |
||||||
|
position: absolute; |
||||||
|
height: 100%; |
||||||
|
width: 100%; |
||||||
|
overflow: hidden; |
||||||
|
top:0; |
||||||
|
left: 0; |
||||||
|
align-items: center; |
||||||
|
justify-content: center; |
||||||
|
display: none; |
||||||
|
backdrop-filter: blur(50px); |
||||||
|
animation: modalRootShow ease-in-out 500ms forwards; |
||||||
|
} |
||||||
|
@keyframes modalRootShow { |
||||||
|
from{ |
||||||
|
background: #33333300; |
||||||
|
} |
||||||
|
to{ |
||||||
|
background: #66666633; |
||||||
|
} |
||||||
|
} |
||||||
|
@keyframes modalRootHide { |
||||||
|
from{ |
||||||
|
background: #33333333; |
||||||
|
} |
||||||
|
to{ |
||||||
|
background: #66666600; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
fieldset, img,input,button { border:none; padding:0;margin:0;outline-style:none; } |
After Width: | Height: | Size: 4.0 KiB |
@ -0,0 +1,53 @@ |
|||||||
|
import BPEMR from './index.module.scss' |
||||||
|
import {useState, useEffect} from "react"; |
||||||
|
|
||||||
|
export default function Button(props) { |
||||||
|
// console.log(props) |
||||||
|
|
||||||
|
const [size, setSize] = useState(props.size) |
||||||
|
const [type, setType] = useState(props.type) |
||||||
|
const [loading, setLoading] = useState(props.loading) |
||||||
|
const [disable, setDisable] = useState(props.disable) |
||||||
|
if (props.onClick && typeof props.onClick === 'function') { |
||||||
|
|
||||||
|
} else { |
||||||
|
if (props.onClick) { |
||||||
|
throw new Error('onClick必须位函数') |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
useEffect(() => { |
||||||
|
setSize(props.size ? props.size : 'default') |
||||||
|
setType(props.type ? props.type : 'default') |
||||||
|
setLoading(props.loading ? BPEMR.loading : '') |
||||||
|
setDisable(props.disable ? BPEMR.disable : '') |
||||||
|
}, [props.size, props.type, props.disable, props.loading, props.onClick]) |
||||||
|
|
||||||
|
const sizeOp = { |
||||||
|
default: BPEMR.defaultsize, |
||||||
|
undersize: BPEMR.undersize, |
||||||
|
oversize: BPEMR.oversize, |
||||||
|
} |
||||||
|
const typeOp = { |
||||||
|
default: BPEMR.defaultColor, |
||||||
|
|
||||||
|
error: BPEMR.eColor, |
||||||
|
error2: BPEMR.e2Color, |
||||||
|
error3: BPEMR.e3Color, |
||||||
|
|
||||||
|
success: BPEMR.sColor, |
||||||
|
success2: BPEMR.s3Color, |
||||||
|
success3: BPEMR.s2Color, |
||||||
|
|
||||||
|
warning: BPEMR.wColor, |
||||||
|
warning1: BPEMR.w2Color, |
||||||
|
warning3: BPEMR.w3Color, |
||||||
|
} |
||||||
|
const classname = [BPEMR.BPEMR_button, loading, disable, sizeOp[size], typeOp[type]].join(' ') |
||||||
|
return ( |
||||||
|
<div className={BPEMR.BPEMR_button_box}> |
||||||
|
<div className={classname} style={props.style} title={props.disable ? '当前不可用!' : ''} onClick={!props.disable ? props.onClick : () => { |
||||||
|
}}>{props.children}</div> |
||||||
|
</div> |
||||||
|
) |
||||||
|
} |
@ -0,0 +1,162 @@ |
|||||||
|
.BPEMR_button_box{ |
||||||
|
position: relative; |
||||||
|
width: fit-content; |
||||||
|
width: -webkit-fit-content; |
||||||
|
width: -moz-fit-content; |
||||||
|
padding: 5px 0; |
||||||
|
} |
||||||
|
.BPEMR_button { |
||||||
|
position: relative; |
||||||
|
width: fit-content; |
||||||
|
width: -webkit-fit-content; |
||||||
|
width: -moz-fit-content; |
||||||
|
line-height: 2em; |
||||||
|
padding: 0 1em; |
||||||
|
margin: 0.5em 0; |
||||||
|
user-select: none; |
||||||
|
cursor: pointer; |
||||||
|
border-radius: 5px; |
||||||
|
transition: all ease-in-out 200ms; |
||||||
|
color: #fefefe; |
||||||
|
} |
||||||
|
.BPEMR_button.loading{ |
||||||
|
$jump : jump; |
||||||
|
animation: jump .4s ease-in-out infinite alternate; |
||||||
|
@keyframes jump { |
||||||
|
0%{top:0px} |
||||||
|
33%{top:-2px} |
||||||
|
66%{top:-8px} |
||||||
|
100%{top:-10px} |
||||||
|
} |
||||||
|
&{ |
||||||
|
box-shadow: 0 5px 20px -10px #33333399; |
||||||
|
} |
||||||
|
} |
||||||
|
.BPEMR_button.disable{ |
||||||
|
cursor: no-drop; |
||||||
|
&:hover{ |
||||||
|
box-shadow: none !important; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.BPEMR_button.defaultsize { |
||||||
|
font-size: 1rem; |
||||||
|
|
||||||
|
&:hover { |
||||||
|
box-shadow: 0px 0 5px 0px #33333399; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.BPEMR_button.oversize { |
||||||
|
font-size: 1.2rem; |
||||||
|
|
||||||
|
&:hover { |
||||||
|
box-shadow: 0px 0 7px 0px #33333399; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.BPEMR_button.undersize { |
||||||
|
font-size: 0.8rem; |
||||||
|
|
||||||
|
&:hover { |
||||||
|
box-shadow: 0px 0 3px 1px #99999999; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
.BPEMR_button.defaultColor { |
||||||
|
color: #222831; |
||||||
|
background: #fefefe; |
||||||
|
border: 1px solid #bcbcbc; |
||||||
|
|
||||||
|
&:active { |
||||||
|
background: #fff !important; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.BPEMR_button.eColor { |
||||||
|
background: #E84545; |
||||||
|
background: #ff4d4f; |
||||||
|
border: 1px solid #ff4d4f; |
||||||
|
|
||||||
|
&:active { |
||||||
|
background: #ff4d4fcc !important; |
||||||
|
border: 1px solid #ff4d4fcc !important; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.BPEMR_button.e2Color { |
||||||
|
background: #F6416C; |
||||||
|
border: 1px solid #F6416C; |
||||||
|
&:active { |
||||||
|
background: #F6416Ccc !important; |
||||||
|
border: 1px solid #F6416Ccc !important; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.BPEMR_button.e3Color { |
||||||
|
background: #FF165D; |
||||||
|
border: 1px solid #FF165D; |
||||||
|
&:active { |
||||||
|
background: #E84545ee !important; |
||||||
|
border: 1px solid #E84545cc !important; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.BPEMR_button.sColor { |
||||||
|
background: #17B978; |
||||||
|
border: 1px solid #17B978; |
||||||
|
&:active { |
||||||
|
background: #17B978cc !important; |
||||||
|
border: 1px solid #17B978cc !important; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.BPEMR_button.s2Color { |
||||||
|
background: #3EC1D3; |
||||||
|
border: 1px solid #3EC1D3; |
||||||
|
&:active { |
||||||
|
background: #3EC1D3cc !important; |
||||||
|
border: 1px solid #3EC1D3cc !important; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.BPEMR_button.s3Color { |
||||||
|
background: #00ADB5; |
||||||
|
border: 1px solid #00ADB5; |
||||||
|
&:active { |
||||||
|
background: #00ADB5cc !important; |
||||||
|
border: 1px solid #00ADB5cc !important; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.BPEMR_button.wColor { |
||||||
|
background: #FF9A00; |
||||||
|
border: 1px solid #FF9A00; |
||||||
|
&:active { |
||||||
|
background: #FF9A00cc !important; |
||||||
|
border: 1px solid #FF9A00cc !important; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.BPEMR_button.w2Color { |
||||||
|
background: #FF6F3C; |
||||||
|
border: 1px solid #FF6F3C; |
||||||
|
&:active { |
||||||
|
background: #FF6F3Ccc !important; |
||||||
|
border: 1px solid #FF6F3Ccc !important; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.BPEMR_button.w3Color { |
||||||
|
background: #FFC93C; |
||||||
|
border: 1px solid #FFC93C; |
||||||
|
&:active { |
||||||
|
background: #FFC93Ccc !important; |
||||||
|
border: 1px solid #FFC93Ccc !important; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
After Width: | Height: | Size: 817 B |
@ -0,0 +1,68 @@ |
|||||||
|
import React, { useEffect, useState } from "react"; |
||||||
|
import { createPortal } from "react-dom"; |
||||||
|
import BPEMR from './index.module.scss'; |
||||||
|
import closeSvg from './close.svg' |
||||||
|
|
||||||
|
export default function Dialog(props){ |
||||||
|
const modalRoot = document.body.querySelector('#modalRoot') |
||||||
|
let node = window.document.createElement("div"); |
||||||
|
if(modalRoot){ |
||||||
|
node = modalRoot; |
||||||
|
}else{ |
||||||
|
node.id='modalRoot' |
||||||
|
window.document.body.appendChild(node) |
||||||
|
} |
||||||
|
|
||||||
|
const [state, setState] = useState(props.state) |
||||||
|
if(typeof props.width === 'number' || Number(props.width) != 'NaN'){ |
||||||
|
|
||||||
|
}else{ |
||||||
|
throw new Error('width必须为数字') |
||||||
|
} |
||||||
|
const [width, setWidth] = useState(Number(props.width)) |
||||||
|
|
||||||
|
const [temCloseAnimation, settemCloseAnimation] = useState(BPEMR.temModalShow) |
||||||
|
|
||||||
|
useEffect(() => { |
||||||
|
setState(props.state) |
||||||
|
setWidth(props.width) |
||||||
|
if(state){ |
||||||
|
modalRoot.style.animation = '' |
||||||
|
modalRoot.style.display = 'flex' |
||||||
|
}else{ |
||||||
|
modalRoot.style.display = 'none' |
||||||
|
settemCloseAnimation(BPEMR.temModalShow) |
||||||
|
} |
||||||
|
}) |
||||||
|
|
||||||
|
useEffect(() => { |
||||||
|
modalRoot.style.animation = 'modalRootHide ease-in-out 500ms forwards' |
||||||
|
},[temCloseAnimation]) |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if(!props.close){ |
||||||
|
throw new Error('缺少弹窗关闭参数。') |
||||||
|
}else if(typeof props.close != 'function'){ |
||||||
|
throw new Error('弹窗必须返回关闭程序。') |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function close(){ |
||||||
|
settemCloseAnimation(BPEMR.temModalHide) |
||||||
|
setTimeout(() => { |
||||||
|
props.close(false) |
||||||
|
}, 500) |
||||||
|
} |
||||||
|
|
||||||
|
const className = [BPEMR.BPEMR_Dialog_Tem, temCloseAnimation].join(' ') |
||||||
|
|
||||||
|
return createPortal( |
||||||
|
<div className={className} style={{width:width + 'px', height:width * 0.618 + 'px'}}> |
||||||
|
<div className={BPEMR.close} onClick={close}><img src={closeSvg} alt=""/></div> |
||||||
|
<div>{props.children}</div> |
||||||
|
</div>, |
||||||
|
node |
||||||
|
); |
||||||
|
} |
@ -0,0 +1,64 @@ |
|||||||
|
|
||||||
|
$modalShow:modalShow; |
||||||
|
$modalHide:modalHide; |
||||||
|
|
||||||
|
.BPEMR_Dialog_Tem{ |
||||||
|
position:relative; |
||||||
|
background: #fefefe; |
||||||
|
min-width: 10em !important; |
||||||
|
max-width: 90vw !important; |
||||||
|
border-radius: 5px; |
||||||
|
padding: 1.5em; |
||||||
|
box-sizing: border-box; |
||||||
|
overflow: overlay; |
||||||
|
& > .close{ |
||||||
|
position: absolute; |
||||||
|
top:0.5em; |
||||||
|
right: 0.5em; |
||||||
|
width: 1.5em; |
||||||
|
height: 1.5em; |
||||||
|
border-radius: 1.5em; |
||||||
|
cursor: pointer; |
||||||
|
box-shadow: 0px 1px 10px -1px #33333333; |
||||||
|
transition: box-shadow ease-in-out 300ms; |
||||||
|
& > img { |
||||||
|
height: 1.5em; |
||||||
|
} |
||||||
|
&:hover{ |
||||||
|
box-shadow: 1px 1px 10px -3px #333; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
.temModalShow{ |
||||||
|
animation: modalShow ease-in-out 300ms forwards; |
||||||
|
} |
||||||
|
.temModalHide{ |
||||||
|
animation: modalHide ease-in-out 300ms forwards; |
||||||
|
} |
||||||
|
|
||||||
|
@keyframes modalShow { |
||||||
|
0%{ |
||||||
|
transform: scale(0.3); |
||||||
|
box-shadow: 5px 10px 30px -10px #33333300; |
||||||
|
} |
||||||
|
80%{ |
||||||
|
transform: scale(1.1); |
||||||
|
} |
||||||
|
100%{ |
||||||
|
transform: scale(1); |
||||||
|
box-shadow: 5px 10px 30px -10px #333333aa; |
||||||
|
} |
||||||
|
} |
||||||
|
@keyframes modalHide { |
||||||
|
0%{ |
||||||
|
transform: scale(1); |
||||||
|
box-shadow: 5px 10px 30px -10px #333333aa; |
||||||
|
} |
||||||
|
20%{ |
||||||
|
transform: scale(1.1); |
||||||
|
} |
||||||
|
100%{ |
||||||
|
transform: scale(0); |
||||||
|
box-shadow: 5px 10px 30px -10px #33333300; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,15 @@ |
|||||||
|
import {useNavigate, useLocation} from "react-router-dom"; |
||||||
|
import {useEffect} from "react"; |
||||||
|
|
||||||
|
export default function RouterAuth(props){ |
||||||
|
const navigate = useNavigate(); |
||||||
|
const location = useLocation(); |
||||||
|
useEffect(() => { |
||||||
|
const path = window.location.pathname |
||||||
|
// console.log(location) |
||||||
|
if(path == '/home'){ |
||||||
|
navigate('/home/login') |
||||||
|
} |
||||||
|
}) |
||||||
|
return props.children |
||||||
|
} |
@ -0,0 +1,5 @@ |
|||||||
|
import icon from '../assets/react.svg' |
||||||
|
export const config = { |
||||||
|
projectName:'sys_22', |
||||||
|
icon, |
||||||
|
} |
@ -0,0 +1,38 @@ |
|||||||
|
import React from 'react' |
||||||
|
import ReactDOM from 'react-dom/client' |
||||||
|
import {BrowserRouter} from "react-router-dom"; |
||||||
|
import App from './App' |
||||||
|
import '@/assets/index.css' |
||||||
|
import RouterAuth from "./components/RouterAuth"; |
||||||
|
|
||||||
|
import {config} from "./config/sys22"; |
||||||
|
|
||||||
|
// console.log(config) |
||||||
|
|
||||||
|
document.title = config.projectName |
||||||
|
changeFavicon(config.icon) |
||||||
|
|
||||||
|
ReactDOM.createRoot(document.getElementById('root')).render( |
||||||
|
<React.StrictMode> |
||||||
|
<BrowserRouter> |
||||||
|
<RouterAuth> |
||||||
|
<App/> |
||||||
|
</RouterAuth> |
||||||
|
</BrowserRouter> |
||||||
|
</React.StrictMode> |
||||||
|
) |
||||||
|
|
||||||
|
function changeFavicon(link){ |
||||||
|
let $favicon = document.querySelector('link[rel="icon"]'); |
||||||
|
// If a <link rel="icon"> element already exists, |
||||||
|
// change its href to the given link. |
||||||
|
if ($favicon !== null) { |
||||||
|
$favicon.href = link; |
||||||
|
// Otherwise, create a new element and append it to <head>. |
||||||
|
} else { |
||||||
|
$favicon = document.createElement("link"); |
||||||
|
$favicon.rel = "icon"; |
||||||
|
$favicon.href = link; |
||||||
|
document.head.appendChild($favicon); |
||||||
|
} |
||||||
|
}; |
@ -0,0 +1,31 @@ |
|||||||
|
import { Navigate } from 'react-router-dom' |
||||||
|
|
||||||
|
import Home from '@/view/Home' |
||||||
|
import Login from '@/view/Login' |
||||||
|
import Index from '@/view/Index' |
||||||
|
|
||||||
|
export default [ |
||||||
|
// 路由表 |
||||||
|
{ |
||||||
|
path:'/', |
||||||
|
element: <Index /> |
||||||
|
}, |
||||||
|
{ |
||||||
|
path:'/login', |
||||||
|
element: <Login /> |
||||||
|
}, |
||||||
|
{ |
||||||
|
path: '/home', |
||||||
|
element: <Home />, |
||||||
|
children:[ |
||||||
|
{ |
||||||
|
path: 'login', |
||||||
|
element: <Login />, |
||||||
|
} |
||||||
|
] |
||||||
|
}, |
||||||
|
{ |
||||||
|
path: "", |
||||||
|
element: <Navigate to="home" replace /> |
||||||
|
} |
||||||
|
] |
@ -0,0 +1,5 @@ |
|||||||
|
import UserStore from './userStore' |
||||||
|
import NetStore from "./netStore"; |
||||||
|
|
||||||
|
export const userStore = new UserStore() |
||||||
|
export const netStore = new NetStore() |
@ -0,0 +1,92 @@ |
|||||||
|
import {observable, action, computed, makeObservable} from "mobx"; |
||||||
|
import {config} from "@/config/sys22"; |
||||||
|
import {userStore} from "./index"; |
||||||
|
|
||||||
|
import {net} from "@/api"; |
||||||
|
|
||||||
|
|
||||||
|
class NetStore { |
||||||
|
// 系统配置
|
||||||
|
// config = config;
|
||||||
|
|
||||||
|
constructor() { |
||||||
|
// mobx6 和以前版本这是最大的区别
|
||||||
|
makeObservable(this, { |
||||||
|
// config: observable,
|
||||||
|
// name: observable,
|
||||||
|
// sex: observable,
|
||||||
|
// userObj: observable,
|
||||||
|
// setName: action,
|
||||||
|
// titleName: computed
|
||||||
|
}); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
// 用户名查重
|
||||||
|
checkOnly(data) { |
||||||
|
return new Promise(res => { |
||||||
|
net.get('/will/checkOnly', data).then( |
||||||
|
response => { |
||||||
|
console.log(response) |
||||||
|
res(response.status) |
||||||
|
}, |
||||||
|
e => { |
||||||
|
console.log(e) |
||||||
|
} |
||||||
|
) |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
// 登录
|
||||||
|
signIn(data) { |
||||||
|
return new Promise(res => { |
||||||
|
net.post('/will/signIn', data).then( |
||||||
|
response => { |
||||||
|
console.log(response) |
||||||
|
res(response.status) |
||||||
|
if (response.status) { |
||||||
|
userStore.setToken(response.data.token) |
||||||
|
} |
||||||
|
}, |
||||||
|
e => { |
||||||
|
console.log(e) |
||||||
|
} |
||||||
|
) |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
// 发送验证码
|
||||||
|
sendCode(data, type = 'signIn') { |
||||||
|
return new Promise(res => { |
||||||
|
net.get('/will/sendCode', { |
||||||
|
...data, |
||||||
|
type |
||||||
|
}).then( |
||||||
|
response => { |
||||||
|
console.log(response) |
||||||
|
res(response.status) |
||||||
|
}, |
||||||
|
e => { |
||||||
|
console.log(e) |
||||||
|
} |
||||||
|
) |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
// setName(v) {
|
||||||
|
// console.log('触发action');
|
||||||
|
// this.name = v;
|
||||||
|
// }
|
||||||
|
// setUserObj(obj) {
|
||||||
|
// this.userObj = obj;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// get titleName(){
|
||||||
|
// return this.name+'___111';
|
||||||
|
// }
|
||||||
|
// get userObject() {
|
||||||
|
// return this.userObj;
|
||||||
|
// }
|
||||||
|
} |
||||||
|
|
||||||
|
export default NetStore |
@ -0,0 +1,63 @@ |
|||||||
|
import { observable, action, computed, makeObservable} from "mobx"; |
||||||
|
import {config} from "@/config/sys22"; |
||||||
|
|
||||||
|
|
||||||
|
class UserStore { |
||||||
|
// 系统配置
|
||||||
|
config = config; |
||||||
|
token = ''; |
||||||
|
name = 'kangkang000'; |
||||||
|
sex = '男'; |
||||||
|
userObj = { |
||||||
|
name: 'kangkang000', |
||||||
|
age: 23, |
||||||
|
token: '12345689' |
||||||
|
} |
||||||
|
|
||||||
|
constructor() { |
||||||
|
// mobx6 和以前版本这是最大的区别
|
||||||
|
makeObservable(this, { |
||||||
|
config: observable, |
||||||
|
token:observable, |
||||||
|
|
||||||
|
name: observable, |
||||||
|
sex: observable, |
||||||
|
userObj: observable, |
||||||
|
setName: action, |
||||||
|
titleName: computed |
||||||
|
}); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
setToken(token){ |
||||||
|
window.localStorage.setItem('token',token) |
||||||
|
this.token = token |
||||||
|
} |
||||||
|
get token(){ |
||||||
|
if(!this.token){ |
||||||
|
this.token = window.localStorage.getItem('token') |
||||||
|
return this.token |
||||||
|
}else{ |
||||||
|
return this.token |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
setName(v) { |
||||||
|
console.log('触发action'); |
||||||
|
this.name = v; |
||||||
|
} |
||||||
|
setUserObj(obj) { |
||||||
|
this.userObj = obj; |
||||||
|
} |
||||||
|
|
||||||
|
get titleName(){ |
||||||
|
return this.name+'___111'; |
||||||
|
} |
||||||
|
get userObject() { |
||||||
|
return this.userObj; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
export default UserStore |
@ -0,0 +1,9 @@ |
|||||||
|
import {Outlet} from 'react-router-dom' |
||||||
|
export default function Home(){ |
||||||
|
return( |
||||||
|
<div> |
||||||
|
<div>Home</div> |
||||||
|
<Outlet/> |
||||||
|
</div> |
||||||
|
) |
||||||
|
} |
After Width: | Height: | Size: 233 KiB |
@ -0,0 +1,23 @@ |
|||||||
|
import css from './index.module.scss' |
||||||
|
import background from './background.jpg' |
||||||
|
import { useNavigate } from "react-router-dom"; |
||||||
|
import 'animate.css' |
||||||
|
import {useState} from "react"; |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export default function Index(){ |
||||||
|
const navigate = useNavigate(); |
||||||
|
const [goOutAnimate, setGoOutAnimate] = useState('animate__fadeInDown') |
||||||
|
function go(){ |
||||||
|
setGoOutAnimate('animate__fadeOutUp'); |
||||||
|
setTimeout(() => { |
||||||
|
navigate('/login') |
||||||
|
},900) |
||||||
|
} |
||||||
|
return (<div className={[css.Index, 'animate__animated', goOutAnimate].join(' ')} onClick={go} > |
||||||
|
<div> |
||||||
|
<div className={css.title}>幽意</div> |
||||||
|
</div> |
||||||
|
</div>) |
||||||
|
} |
@ -0,0 +1,28 @@ |
|||||||
|
.Index{ |
||||||
|
position: relative; |
||||||
|
height: 100%; |
||||||
|
width: 100%; |
||||||
|
background-image: url("./background.jpg"); |
||||||
|
background-position: center 100%; |
||||||
|
background-repeat: no-repeat; |
||||||
|
background-size:cover; |
||||||
|
-moz-user-select:none; |
||||||
|
-webkit-user-select:none; |
||||||
|
user-select:none; |
||||||
|
cursor: pointer; |
||||||
|
& > div{ |
||||||
|
position: relative; |
||||||
|
height: 100%; |
||||||
|
width: 100%; |
||||||
|
backdrop-filter: blur(15px); |
||||||
|
background: #33333333; |
||||||
|
display: flex; |
||||||
|
align-items: center; |
||||||
|
justify-content: center; |
||||||
|
& >div.title{ |
||||||
|
font-size: 2.5rem; |
||||||
|
color:#fefefe; |
||||||
|
letter-spacing: 20px; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,236 @@ |
|||||||
|
import css from './index.module.scss' |
||||||
|
import {userStore, netStore} from "@/store"; |
||||||
|
import {useEffect, useRef, useState} from "react"; |
||||||
|
import next from './next.svg'; |
||||||
|
import Button from "@/components/Button"; |
||||||
|
import {useNavigate} from "react-router-dom"; |
||||||
|
|
||||||
|
|
||||||
|
export default function Login(){ |
||||||
|
// 用户信息 |
||||||
|
const [userInfo, setUserInfo] = useState('') |
||||||
|
// 用户输入长度确认 |
||||||
|
const [userInfoState, setUserInfoState] = useState('') |
||||||
|
// 登录容器样式 |
||||||
|
const [loginStyle, setLoginStyle] = useState(['animate__zoomIn', 'animate__animated', 'animate__faster'].join(' ')) |
||||||
|
// 当前页 |
||||||
|
const [pageNum, setPageNum] = useState(1) |
||||||
|
// 第一屏样式 |
||||||
|
const [page1Style, setPage1Style] = useState(css.page1) |
||||||
|
// 第二屏样式 |
||||||
|
const [page2Style, setPage2Style] = useState(css.page2) |
||||||
|
// 登录或者注册 |
||||||
|
const [signInOrOut, setSignInOrOut] = useState(true) |
||||||
|
// 请求用户信息存在的状态 |
||||||
|
const [checkUserInfoState, setCheckUserInfoState] = useState(true) |
||||||
|
// 登陆方式 |
||||||
|
const [loginMethod, setLoginMethod] = useState('') |
||||||
|
// 密码 |
||||||
|
const [password, setPassword] = useState('') |
||||||
|
// 验证码 |
||||||
|
const [verfCode, setVerfCode] = useState('') |
||||||
|
// 发送验证码按钮状态 |
||||||
|
const [sendBut, setSendBut] = useState(false) |
||||||
|
// 路由跳转 |
||||||
|
const navigate = useNavigate(); |
||||||
|
|
||||||
|
|
||||||
|
// input |
||||||
|
const input1 = useRef() |
||||||
|
const input2 = useRef() |
||||||
|
const input3 = useRef() |
||||||
|
|
||||||
|
|
||||||
|
useEffect(() => { |
||||||
|
if(pageNum == 1){ |
||||||
|
input1.current.focus() |
||||||
|
} |
||||||
|
if(!signInOrOut){ |
||||||
|
setTimeout(() => { |
||||||
|
if(loginMethod == ''){ |
||||||
|
input2.current.focus() |
||||||
|
}else{ |
||||||
|
input3.current.focus() |
||||||
|
} |
||||||
|
},800) |
||||||
|
} |
||||||
|
}, [pageNum,signInOrOut]) |
||||||
|
|
||||||
|
// 用户信息输入 |
||||||
|
const userInfoInput = event => { |
||||||
|
if(event.target.value.length >= 8){ |
||||||
|
setUserInfoState(css.temNextShow) |
||||||
|
}else if(event.target.value.length < 8){ |
||||||
|
if(userInfo.length >= 8){ |
||||||
|
setUserInfoState(css.temNextHide) |
||||||
|
}else{ |
||||||
|
setUserInfoState('') |
||||||
|
} |
||||||
|
} |
||||||
|
setUserInfo(event.target.value) |
||||||
|
} |
||||||
|
const handleUserInfoKeyDown = event => { |
||||||
|
// console.log(event) |
||||||
|
switch (event.code){ |
||||||
|
case 'Enter': |
||||||
|
checkUserInfo() |
||||||
|
break; |
||||||
|
case 'Tab': |
||||||
|
checkUserInfo() |
||||||
|
event.preventDefault() |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
// 密码输入 |
||||||
|
const passwordInput = event => { |
||||||
|
setPassword(event.target.value) |
||||||
|
} |
||||||
|
const handlePasswordKeyDown = event => { |
||||||
|
if(event.code == 'Enter'){ |
||||||
|
signIn() |
||||||
|
} |
||||||
|
} |
||||||
|
// 验证码输入 |
||||||
|
const verfCodeInput = event => { |
||||||
|
setVerfCode(event.target.value) |
||||||
|
} |
||||||
|
|
||||||
|
// 点击下一步,检验用户信息是否存在 |
||||||
|
async function checkUserInfo(){ |
||||||
|
if(!userInfoState && checkUserInfoState){ |
||||||
|
return |
||||||
|
} |
||||||
|
setCheckUserInfoState(false) |
||||||
|
const state = await netStore.checkOnly({username: userInfo}) |
||||||
|
setPage1Style([css.page1, css.temSlideOutLeft].join(' ')) |
||||||
|
setPage2Style([css.page2, css.temSlideOutLeft].join(' ')) |
||||||
|
setSignInOrOut(state) |
||||||
|
|
||||||
|
|
||||||
|
} |
||||||
|
// 返回按钮的状态控制,300ms内不允许点击 |
||||||
|
let goBackPage1State = true |
||||||
|
// 返回第一页 |
||||||
|
function goBackPage1(){ |
||||||
|
if(goBackPage1State){ |
||||||
|
goBackPage1State = false |
||||||
|
setTimeout(() => { |
||||||
|
goBackPage1State = true |
||||||
|
},300) |
||||||
|
}else{ |
||||||
|
return |
||||||
|
} |
||||||
|
setSignInOrOut(true) |
||||||
|
setCheckUserInfoState(true) |
||||||
|
setPage1Style([css.page1, css.temSlideInLeft].join(' ')) |
||||||
|
setPage2Style([css.page2, css.temSlideInLeft].join(' ')) |
||||||
|
} |
||||||
|
// 切换登陆方式 |
||||||
|
function changeLoginMethod(){ |
||||||
|
loginMethod == '' ? setLoginMethod(css.left) : setLoginMethod('') |
||||||
|
loginMethod != '' ? input2.current.focus() : input3.current.focus() |
||||||
|
} |
||||||
|
// 发送验证码 |
||||||
|
async function sendEmail(){ |
||||||
|
setSendBut(true) |
||||||
|
let status = 60 |
||||||
|
const sendEmailInterval = setInterval(() => { |
||||||
|
status-- |
||||||
|
if(status == 0){ |
||||||
|
setSendBut(false) |
||||||
|
clearInterval(sendEmailInterval) |
||||||
|
} |
||||||
|
},1000) |
||||||
|
const state = await netStore.sendCode({username:userInfo}) |
||||||
|
console.log(state) |
||||||
|
} |
||||||
|
// 登录 |
||||||
|
let signInState = true |
||||||
|
async function signIn(){ |
||||||
|
console.log('点击登录') |
||||||
|
if(!signInState){ |
||||||
|
return |
||||||
|
} |
||||||
|
setTimeout(() => { |
||||||
|
signInState = true |
||||||
|
},3000) |
||||||
|
const data = { |
||||||
|
username:userInfo |
||||||
|
} |
||||||
|
if(loginMethod == ''){ |
||||||
|
// 密码登录 |
||||||
|
data.password = password; |
||||||
|
if(password.length < 8){ |
||||||
|
alert('密码长度不正确') |
||||||
|
return |
||||||
|
} |
||||||
|
}else{ |
||||||
|
// 验证码登录 |
||||||
|
if(password.length != 4){ |
||||||
|
alert('验证码格式错误') |
||||||
|
return |
||||||
|
} |
||||||
|
data.code = verfCode; |
||||||
|
} |
||||||
|
const state = await netStore.signIn(data) |
||||||
|
signInState = true |
||||||
|
if(state){ |
||||||
|
setLoginStyle(['animate__zoomOut', 'animate__animated', 'animate__faster'].join(' ')) |
||||||
|
setTimeout(() => { |
||||||
|
navigate('/') |
||||||
|
},500) |
||||||
|
}else{ |
||||||
|
alert('登陆失败') |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return( |
||||||
|
<div className={css.login}> |
||||||
|
<div className={loginStyle}> |
||||||
|
<div className={css.title}>{userStore.config.projectName}</div> |
||||||
|
<div className={css.icon}><img src={userStore.config.icon} alt=""/></div> |
||||||
|
<div> |
||||||
|
{!signInOrOut && <div onClick={changeLoginMethod}> |
||||||
|
<div className={loginMethod}></div> |
||||||
|
<div>密<span style={{width:'1rem',display:'inline-block'}}></span>码</div> |
||||||
|
<div>验证码</div> |
||||||
|
</div>} |
||||||
|
</div> |
||||||
|
{/*登录页第一屏,输入用户信息*/} |
||||||
|
<div className={css.loginBox}> |
||||||
|
<div className={page1Style}> |
||||||
|
<div><input ref={input1} type="text" onChange={userInfoInput} onKeyDown={handleUserInfoKeyDown} value={userInfo} spellCheck ="false" placeholder={'请输入账户信息'}/></div> |
||||||
|
<div className={userInfoState}> |
||||||
|
<div onClick={checkUserInfo}> |
||||||
|
<img src={next} alt=""/> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
{/*登录页第二屏,输入验证信息或前往注册*/} |
||||||
|
<div className={page2Style}> |
||||||
|
{!signInOrOut && |
||||||
|
<div className={css.input}> |
||||||
|
<div className={loginMethod == '' ? css.temTdShow : css.temTdHide}> |
||||||
|
<div><input ref={input2} type="password" onChange={passwordInput} onKeyDown={handlePasswordKeyDown} value={password} spellCheck ="false" placeholder={'请输入密码'}/></div> |
||||||
|
</div> |
||||||
|
<div className={loginMethod != '' ? css.temTdShow2 : css.temTdHide2}> |
||||||
|
<div> |
||||||
|
<div><input ref={input3} type="text" onChange={verfCodeInput} onKeyDown={handlePasswordKeyDown} value={verfCode} spellCheck ="false" placeholder={'请输入验证码'}/></div> |
||||||
|
<div><Button size='undersize' type='warning1' onClick={() => { |
||||||
|
sendEmail()}} disable={sendBut != 0}>发送验证码</Button></div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div>} |
||||||
|
<div className={css.button}> |
||||||
|
<div onClick={goBackPage1}>返回</div> |
||||||
|
<div> |
||||||
|
{!signInOrOut && <div onClick={signIn}>登录</div>} |
||||||
|
{signInOrOut && <div>注册</div>} |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
) |
||||||
|
} |
@ -0,0 +1,433 @@ |
|||||||
|
.login { |
||||||
|
position: relative; |
||||||
|
height: 100%; |
||||||
|
width: 100%; |
||||||
|
|
||||||
|
background-image: linear-gradient(to bottom, transparent 75%, #ffffff 100%), radial-gradient(at 0% 0%, hsla(154, 4%, 50%, 0.25) 0, transparent 50%), radial-gradient(at 0% 50%, hsla(120, 5%, 50%, 0.23) 0, transparent 50%), radial-gradient(at 40% 40%, hsla(120, 4%, 50%, 0.21) 0, transparent 50%), radial-gradient(at 80% 0%, #ffffff 0, transparent 50%), radial-gradient(at 80% 50%, #ffffff 0, transparent 50%), radial-gradient(at 80% 50%, #ffffff 0, transparent 50%), linear-gradient(to bottom, transparent 75%, #ffffff 100%); |
||||||
|
background-position: center; |
||||||
|
background-size: cover; |
||||||
|
background-repeat: no-repeat; |
||||||
|
|
||||||
|
display: flex; |
||||||
|
align-items: center; |
||||||
|
justify-content: center; |
||||||
|
|
||||||
|
user-select: none; |
||||||
|
|
||||||
|
& > div { |
||||||
|
position: relative; |
||||||
|
width: 18rem; |
||||||
|
height: 25rem; |
||||||
|
backdrop-filter: blur(20px); |
||||||
|
|
||||||
|
display: flex; |
||||||
|
flex-direction: column; |
||||||
|
|
||||||
|
overflow: hidden; |
||||||
|
|
||||||
|
background: #00ADB5; |
||||||
|
border-radius: 1rem; |
||||||
|
padding: 1rem; |
||||||
|
box-sizing: border-box; |
||||||
|
|
||||||
|
& > div.title { |
||||||
|
position: relative; |
||||||
|
font-size: 2rem; |
||||||
|
line-height: 4rem; |
||||||
|
text-align: center; |
||||||
|
flex-shrink: 0; |
||||||
|
} |
||||||
|
|
||||||
|
& > div.icon { |
||||||
|
position: relative; |
||||||
|
text-align: center; |
||||||
|
height: 4rem; |
||||||
|
display: flex; |
||||||
|
align-items: center; |
||||||
|
justify-content: center; |
||||||
|
flex-shrink: 0; |
||||||
|
|
||||||
|
& > img { |
||||||
|
width: 2rem; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
& > div:nth-child(3) { |
||||||
|
position: relative; |
||||||
|
flex-shrink: 0; |
||||||
|
height: 1.5rem; |
||||||
|
|
||||||
|
& > div { |
||||||
|
position: relative; |
||||||
|
width: 7rem; |
||||||
|
border-radius: 2rem; |
||||||
|
border: 1px solid #fefefe; |
||||||
|
display: flex; |
||||||
|
font-size: 0.8rem; |
||||||
|
line-height: 1.3rem; |
||||||
|
margin: 0 auto; |
||||||
|
|
||||||
|
& > div { |
||||||
|
position: relative; |
||||||
|
flex: 1; |
||||||
|
text-align: center; |
||||||
|
cursor: pointer; |
||||||
|
color: #fefefe; |
||||||
|
} |
||||||
|
|
||||||
|
& > div:nth-child(1) { |
||||||
|
border-radius: 2rem; |
||||||
|
position: absolute; |
||||||
|
width: 50%; |
||||||
|
left: 0; |
||||||
|
background: #535bf2; |
||||||
|
height: 100%; |
||||||
|
transition: left ease-in-out 300ms; |
||||||
|
} |
||||||
|
|
||||||
|
& > div:nth-child(1).left { |
||||||
|
left: 50%; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
& > div.loginBox { |
||||||
|
position: relative; |
||||||
|
flex: 1; |
||||||
|
height: 100%; |
||||||
|
width: 100%; |
||||||
|
padding: 1rem; |
||||||
|
box-sizing: border-box; |
||||||
|
overflow: hidden; |
||||||
|
display: flex; |
||||||
|
//flex-wrap: wrap; |
||||||
|
|
||||||
|
& > div.page1 { |
||||||
|
position: relative; |
||||||
|
height: 100%; |
||||||
|
width: 100%; |
||||||
|
display: flex; |
||||||
|
flex-shrink: 0; |
||||||
|
flex-direction: column; |
||||||
|
|
||||||
|
& > div { |
||||||
|
position: relative; |
||||||
|
|
||||||
|
display: flex; |
||||||
|
align-items: center; |
||||||
|
justify-content: center; |
||||||
|
} |
||||||
|
|
||||||
|
& > div:nth-child(1) { |
||||||
|
flex: 1; |
||||||
|
|
||||||
|
& > input { |
||||||
|
width: 100%; |
||||||
|
border-radius: 5px; |
||||||
|
font-size: 1rem; |
||||||
|
line-height: 1.5rem; |
||||||
|
padding: 0.5rem; |
||||||
|
box-sizing: border-box; |
||||||
|
text-align: center; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
& > div:nth-child(2) { |
||||||
|
height: 0; |
||||||
|
overflow: hidden; |
||||||
|
|
||||||
|
& > div { |
||||||
|
position: relative; |
||||||
|
background: #535bf2; |
||||||
|
height: 3.5rem; |
||||||
|
width: 3.5rem; |
||||||
|
margin: 0 auto; |
||||||
|
cursor: pointer; |
||||||
|
border-radius: 1.8rem; |
||||||
|
display: flex; |
||||||
|
align-items: center; |
||||||
|
justify-content: center; |
||||||
|
|
||||||
|
transition: box-shadow ease-in-out 300ms; |
||||||
|
|
||||||
|
&:hover { |
||||||
|
box-shadow: 0px 0px 10px -1px #33333399; |
||||||
|
} |
||||||
|
|
||||||
|
& > img { |
||||||
|
width: 2rem; |
||||||
|
padding: 0.8rem; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
& > div.page2 { |
||||||
|
position: relative; |
||||||
|
height: 100%; |
||||||
|
width: 100%; |
||||||
|
display: flex; |
||||||
|
flex-shrink: 0; |
||||||
|
flex-direction: column; |
||||||
|
margin-left: 2rem; |
||||||
|
|
||||||
|
& > div { |
||||||
|
position: relative; |
||||||
|
flex: 1; |
||||||
|
display: flex; |
||||||
|
align-items: center; |
||||||
|
justify-content: center; |
||||||
|
} |
||||||
|
|
||||||
|
& > div.input { |
||||||
|
position: relative; |
||||||
|
display: block; |
||||||
|
|
||||||
|
& > div { |
||||||
|
position: absolute; |
||||||
|
left: 0; |
||||||
|
right: 0; |
||||||
|
height: 100%; |
||||||
|
width: 100%; |
||||||
|
display: flex; |
||||||
|
align-items: center; |
||||||
|
justify-content: center; |
||||||
|
|
||||||
|
& input { |
||||||
|
width: 100%; |
||||||
|
border-radius: 5px; |
||||||
|
font-size: 1rem; |
||||||
|
line-height: 1.5rem; |
||||||
|
padding: 0.5rem; |
||||||
|
box-sizing: border-box; |
||||||
|
text-align: center; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
& > div:nth-child(1) { |
||||||
|
} |
||||||
|
|
||||||
|
& > div:nth-child(2) { |
||||||
|
position: relative; |
||||||
|
width: 100%; |
||||||
|
|
||||||
|
& > div { |
||||||
|
display: flex; |
||||||
|
width: 100%; |
||||||
|
overflow: hidden; |
||||||
|
& > input { |
||||||
|
display: block; |
||||||
|
flex: 1; |
||||||
|
} |
||||||
|
|
||||||
|
& > div:nth-child(2) { |
||||||
|
position: relative; |
||||||
|
flex-shrink: 0; |
||||||
|
width: 6rem; |
||||||
|
//margin-left: 0.5rem; |
||||||
|
font-size: 0.8px; |
||||||
|
display: flex; |
||||||
|
align-items: center; |
||||||
|
justify-content: center; |
||||||
|
& > div{ |
||||||
|
padding: 0; |
||||||
|
margin: 0; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// 登陆方式切换动画 |
||||||
|
$tdShow: tdShow; |
||||||
|
$tdHide: tdHide; |
||||||
|
@keyframes tdHide { |
||||||
|
0% { |
||||||
|
transform: rotateX(0deg); |
||||||
|
opacity: 1; |
||||||
|
} |
||||||
|
100% { |
||||||
|
transform: rotateX(90deg); |
||||||
|
opacity: 0; |
||||||
|
display: none; |
||||||
|
overflow: hidden; |
||||||
|
} |
||||||
|
} |
||||||
|
@keyframes tdShow { |
||||||
|
0% { |
||||||
|
transform: rotateX(90deg); |
||||||
|
opacity: 0; |
||||||
|
display: none; |
||||||
|
overflow: hidden; |
||||||
|
} |
||||||
|
100% { |
||||||
|
transform: rotateX(0deg); |
||||||
|
opacity: 1; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.temTdHide { |
||||||
|
animation: tdHide ease-in-out 500ms forwards; |
||||||
|
} |
||||||
|
|
||||||
|
.temTdShow { |
||||||
|
animation: tdShow ease-in-out 500ms forwards; |
||||||
|
} |
||||||
|
|
||||||
|
$tdShow2: tdShow2; |
||||||
|
$tdHide2: tdHide2; |
||||||
|
@keyframes tdHide2 { |
||||||
|
0% { |
||||||
|
transform: rotateX(0deg); |
||||||
|
opacity: 1; |
||||||
|
} |
||||||
|
100% { |
||||||
|
transform: rotateX(90deg); |
||||||
|
opacity: 0; |
||||||
|
display: none; |
||||||
|
overflow: hidden; |
||||||
|
} |
||||||
|
} |
||||||
|
@keyframes tdShow2 { |
||||||
|
0% { |
||||||
|
transform: rotateX(-90deg); |
||||||
|
opacity: 0; |
||||||
|
display: none; |
||||||
|
overflow: hidden; |
||||||
|
} |
||||||
|
100% { |
||||||
|
transform: rotateX(0deg); |
||||||
|
opacity: 1; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.temTdHide2 { |
||||||
|
animation: tdHide2 ease-in-out 500ms forwards; |
||||||
|
} |
||||||
|
|
||||||
|
.temTdShow2 { |
||||||
|
animation: tdShow2 ease-in-out 500ms forwards; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
& > div.button { |
||||||
|
position: relative; |
||||||
|
overflow: hidden; |
||||||
|
display: flex; |
||||||
|
|
||||||
|
& > div { |
||||||
|
position: relative; |
||||||
|
display: flex; |
||||||
|
align-items: center; |
||||||
|
justify-content: center; |
||||||
|
height: 2.5rem; |
||||||
|
background: #535bf2; |
||||||
|
border-radius: 5px; |
||||||
|
color: #fefefe; |
||||||
|
cursor: pointer; |
||||||
|
} |
||||||
|
|
||||||
|
& > div:nth-child(1) { |
||||||
|
width: 4.5rem; |
||||||
|
transition: width ease-in-out 300ms; |
||||||
|
|
||||||
|
&:hover { |
||||||
|
width: 8rem; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
& > div:nth-child(2) { |
||||||
|
flex: 1; |
||||||
|
margin-left: 1rem; |
||||||
|
text-align: center; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
$nextShow: nextShow; |
||||||
|
$nextHide: nextHide; |
||||||
|
@keyframes nextShow { |
||||||
|
0% { |
||||||
|
height: 0; |
||||||
|
} |
||||||
|
100% { |
||||||
|
height: 50%; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@keyframes nextHide { |
||||||
|
0% { |
||||||
|
height: 50%; |
||||||
|
} |
||||||
|
100% { |
||||||
|
height: 0; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.temNextShow { |
||||||
|
animation: nextShow ease-in-out 300ms forwards; |
||||||
|
} |
||||||
|
|
||||||
|
.temNextHide { |
||||||
|
animation: nextHide ease-in-out 300ms forwards; |
||||||
|
} |
||||||
|
|
||||||
|
$slideOutLeft: slideOutLeft; |
||||||
|
$slideOutRight: slideOutRight; |
||||||
|
$slideInLeft: slideInLeft; |
||||||
|
$slideInRight: slideInRight; |
||||||
|
|
||||||
|
@keyframes slideOutLeft { |
||||||
|
from { |
||||||
|
left: 0; |
||||||
|
} |
||||||
|
to { |
||||||
|
left: calc(-100% - 2rem); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@keyframes slideOutRight { |
||||||
|
from { |
||||||
|
left: 0; |
||||||
|
} |
||||||
|
to { |
||||||
|
left: calc(100% - 2rem); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@keyframes slideInLeft { |
||||||
|
from { |
||||||
|
left: -100% |
||||||
|
} |
||||||
|
to { |
||||||
|
left: 0; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@keyframes slideInRight { |
||||||
|
from { |
||||||
|
left: 100% |
||||||
|
} |
||||||
|
to { |
||||||
|
left: 0; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.temSlideOutLeft { |
||||||
|
animation: slideOutLeft ease-in-out 500ms forwards; |
||||||
|
} |
||||||
|
|
||||||
|
.temSlideOutRight { |
||||||
|
animation: slideOutRight ease-in-out 500ms forwards; |
||||||
|
} |
||||||
|
|
||||||
|
.temSlideInLeft { |
||||||
|
animation: slideInLeft ease-in-out 500ms forwards; |
||||||
|
} |
||||||
|
|
||||||
|
.temSlideInRight { |
||||||
|
animation: slideInRight ease-in-out 500ms forwards; |
||||||
|
} |
After Width: | Height: | Size: 573 B |
@ -0,0 +1,28 @@ |
|||||||
|
import {defineConfig} from 'vite' |
||||||
|
import react from '@vitejs/plugin-react' |
||||||
|
import {resolve} from "path"; |
||||||
|
|
||||||
|
// https://vitejs.dev/config/
|
||||||
|
export default defineConfig({ |
||||||
|
plugins: [react()], |
||||||
|
resolve: { |
||||||
|
alias: [ |
||||||
|
{ |
||||||
|
find: '@', |
||||||
|
replacement: resolve(__dirname, 'src') |
||||||
|
}, |
||||||
|
] |
||||||
|
}, |
||||||
|
server: { |
||||||
|
proxy: { |
||||||
|
'/api': { // 匹配请求路径,localhost:3000/snow
|
||||||
|
target: 'http://localhost:3000', // 代理的目标地址
|
||||||
|
changeOrigin: true, // 开发模式,默认的origin是真实的 origin:localhost:3000 代理服务会把origin修改为目标地址
|
||||||
|
// secure: true, // 是否https接口
|
||||||
|
// ws: true, // 是否代理websockets
|
||||||
|
// rewrite target目标地址 + '/abc',如果接口是这样的,那么不用重写
|
||||||
|
// rewrite: (path) => path.replace(/^\/snow/, '') // 路径重写,本项目不需要重写
|
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
}) |
Loading…
Reference in new issue