移植后的第一次Commit

master
expressgy 2 years ago
commit a43f7c8f5d
  1. 25
      .gitignore
  2. BIN
      README.md
  3. 0
      baseSys/baseSys.dirname
  4. 3
      baseSys/userSys/README.md
  5. 1629
      baseSys/userSys/design/database/sys22_user.ndm2
  6. 66
      baseSys/userSys/design/database/sys22_user.sql
  7. 0
      baseSys/userSys/design/design.dirname
  8. BIN
      baseSys/userSys/design/接口概览.xmind
  9. BIN
      baseSys/userSys/design/模块设计.xmind
  10. BIN
      baseSys/userSys/design/用户系统表.xmind
  11. 12
      baseSys/userSys/design/需求分析.md
  12. 7
      baseSys/userSys/realization/READE.md
  13. 118
      baseSys/userSys/realization/app.js
  14. 86
      baseSys/userSys/realization/bin/www.js
  15. 66
      baseSys/userSys/realization/config/database/sys22_user.sql
  16. 52
      baseSys/userSys/realization/config/default.config.js
  17. 34
      baseSys/userSys/realization/package.json
  18. 1113
      baseSys/userSys/realization/pnpm-lock.yaml
  19. 0
      baseSys/userSys/realization/reallization.dirname
  20. 1210
      baseSys/userSys/realization/src/API/index.js
  21. 73
      baseSys/userSys/realization/src/Database/initDatabase.js
  22. 135
      baseSys/userSys/realization/src/Database/userBase.js
  23. 41
      baseSys/userSys/realization/src/Routes/index.js
  24. 18
      baseSys/userSys/realization/src/Routes/test/index.js
  25. 27
      baseSys/userSys/realization/src/Routes/user/authority.js
  26. 20
      baseSys/userSys/realization/src/Routes/user/index.js
  27. 25
      baseSys/userSys/realization/src/Routes/user/role.js
  28. 21
      baseSys/userSys/realization/src/Routes/user/signed.js
  29. 20
      baseSys/userSys/realization/src/Routes/user/will.js
  30. 31
      baseSys/userSys/realization/test/redisjson.js
  31. 22
      baseSys/userSys/realization/test/testDelToken.js
  32. 35
      baseSys/userSys/realization/test/testRedis.js
  33. 13
      baseSys/userSys/realization/test/testTime.js
  34. 11
      baseSys/userSys/realization/test/testToken.js
  35. 3
      baseSys/userSys/realization/test/trimr.js
  36. 21
      baseSys/userSys/realization/test/连表查询.js
  37. 10
      baseSys/userSys/realization/tools/RandomString.js
  38. 70
      baseSys/userSys/realization/tools/console/index.js
  39. 65
      baseSys/userSys/realization/tools/database/createConnection.js
  40. 14
      baseSys/userSys/realization/tools/database/formatSQL.js
  41. 17
      baseSys/userSys/realization/tools/getEnv.js
  42. 75
      baseSys/userSys/realization/tools/mail.js
  43. 308
      baseSys/userSys/realization/tools/redisJSON.js
  44. 136
      baseSys/userSys/realization/tools/user/encryptionString.js
  45. 3
      baseSys/userSys/realization/tools/user/sendEmail.js
  46. 34
      baseSys/userSys/realization/tools/user/token.js
  47. 11
      baseSys/userSys/realization/tools/uuid.js
  48. 0
      baseSys/userSys/userSys.dirname
  49. 24
      baseSys/userSys/vision/.gitignore
  50. 14
      baseSys/userSys/vision/index.html
  51. 25
      baseSys/userSys/vision/package.json
  52. 1039
      baseSys/userSys/vision/pnpm-lock.yaml
  53. 1
      baseSys/userSys/vision/public/vite.svg
  54. 14
      baseSys/userSys/vision/src/App.jsx
  55. 87
      baseSys/userSys/vision/src/api/index.js
  56. 111
      baseSys/userSys/vision/src/assets/index.css
  57. 1
      baseSys/userSys/vision/src/assets/react.svg
  58. 53
      baseSys/userSys/vision/src/components/Button/index.jsx
  59. 162
      baseSys/userSys/vision/src/components/Button/index.module.scss
  60. 1
      baseSys/userSys/vision/src/components/Modal/close.svg
  61. 68
      baseSys/userSys/vision/src/components/Modal/index.jsx
  62. 64
      baseSys/userSys/vision/src/components/Modal/index.module.scss
  63. 15
      baseSys/userSys/vision/src/components/RouterAuth/index.jsx
  64. 5
      baseSys/userSys/vision/src/config/sys22.js
  65. 38
      baseSys/userSys/vision/src/main.jsx
  66. 31
      baseSys/userSys/vision/src/router/index.jsx
  67. 5
      baseSys/userSys/vision/src/store/index.js
  68. 92
      baseSys/userSys/vision/src/store/netStore.js
  69. 63
      baseSys/userSys/vision/src/store/userStore.js
  70. 9
      baseSys/userSys/vision/src/view/Home/index.jsx
  71. BIN
      baseSys/userSys/vision/src/view/Index/background.jpg
  72. 23
      baseSys/userSys/vision/src/view/Index/index.jsx
  73. 28
      baseSys/userSys/vision/src/view/Index/index.module.scss
  74. 236
      baseSys/userSys/vision/src/view/Login/index.jsx
  75. 433
      baseSys/userSys/vision/src/view/Login/index.module.scss
  76. 1
      baseSys/userSys/vision/src/view/Login/next.svg
  77. 28
      baseSys/userSys/vision/vite.config.js
  78. 8
      list.md

25
.gitignore vendored

@ -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?

Binary file not shown.

@ -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`)
);

@ -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,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

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>

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; }

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="35.93" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 228"><path fill="#00D8FF" d="M210.483 73.824a171.49 171.49 0 0 0-8.24-2.597c.465-1.9.893-3.777 1.273-5.621c6.238-30.281 2.16-54.676-11.769-62.708c-13.355-7.7-35.196.329-57.254 19.526a171.23 171.23 0 0 0-6.375 5.848a155.866 155.866 0 0 0-4.241-3.917C100.759 3.829 77.587-4.822 63.673 3.233C50.33 10.957 46.379 33.89 51.995 62.588a170.974 170.974 0 0 0 1.892 8.48c-3.28.932-6.445 1.924-9.474 2.98C17.309 83.498 0 98.307 0 113.668c0 15.865 18.582 31.778 46.812 41.427a145.52 145.52 0 0 0 6.921 2.165a167.467 167.467 0 0 0-2.01 9.138c-5.354 28.2-1.173 50.591 12.134 58.266c13.744 7.926 36.812-.22 59.273-19.855a145.567 145.567 0 0 0 5.342-4.923a168.064 168.064 0 0 0 6.92 6.314c21.758 18.722 43.246 26.282 56.54 18.586c13.731-7.949 18.194-32.003 12.4-61.268a145.016 145.016 0 0 0-1.535-6.842c1.62-.48 3.21-.974 4.76-1.488c29.348-9.723 48.443-25.443 48.443-41.52c0-15.417-17.868-30.326-45.517-39.844Zm-6.365 70.984c-1.4.463-2.836.91-4.3 1.345c-3.24-10.257-7.612-21.163-12.963-32.432c5.106-11 9.31-21.767 12.459-31.957c2.619.758 5.16 1.557 7.61 2.4c23.69 8.156 38.14 20.213 38.14 29.504c0 9.896-15.606 22.743-40.946 31.14Zm-10.514 20.834c2.562 12.94 2.927 24.64 1.23 33.787c-1.524 8.219-4.59 13.698-8.382 15.893c-8.067 4.67-25.32-1.4-43.927-17.412a156.726 156.726 0 0 1-6.437-5.87c7.214-7.889 14.423-17.06 21.459-27.246c12.376-1.098 24.068-2.894 34.671-5.345a134.17 134.17 0 0 1 1.386 6.193ZM87.276 214.515c-7.882 2.783-14.16 2.863-17.955.675c-8.075-4.657-11.432-22.636-6.853-46.752a156.923 156.923 0 0 1 1.869-8.499c10.486 2.32 22.093 3.988 34.498 4.994c7.084 9.967 14.501 19.128 21.976 27.15a134.668 134.668 0 0 1-4.877 4.492c-9.933 8.682-19.886 14.842-28.658 17.94ZM50.35 144.747c-12.483-4.267-22.792-9.812-29.858-15.863c-6.35-5.437-9.555-10.836-9.555-15.216c0-9.322 13.897-21.212 37.076-29.293c2.813-.98 5.757-1.905 8.812-2.773c3.204 10.42 7.406 21.315 12.477 32.332c-5.137 11.18-9.399 22.249-12.634 32.792a134.718 134.718 0 0 1-6.318-1.979Zm12.378-84.26c-4.811-24.587-1.616-43.134 6.425-47.789c8.564-4.958 27.502 2.111 47.463 19.835a144.318 144.318 0 0 1 3.841 3.545c-7.438 7.987-14.787 17.08-21.808 26.988c-12.04 1.116-23.565 2.908-34.161 5.309a160.342 160.342 0 0 1-1.76-7.887Zm110.427 27.268a347.8 347.8 0 0 0-7.785-12.803c8.168 1.033 15.994 2.404 23.343 4.08c-2.206 7.072-4.956 14.465-8.193 22.045a381.151 381.151 0 0 0-7.365-13.322Zm-45.032-43.861c5.044 5.465 10.096 11.566 15.065 18.186a322.04 322.04 0 0 0-30.257-.006c4.974-6.559 10.069-12.652 15.192-18.18ZM82.802 87.83a323.167 323.167 0 0 0-7.227 13.238c-3.184-7.553-5.909-14.98-8.134-22.152c7.304-1.634 15.093-2.97 23.209-3.984a321.524 321.524 0 0 0-7.848 12.897Zm8.081 65.352c-8.385-.936-16.291-2.203-23.593-3.793c2.26-7.3 5.045-14.885 8.298-22.6a321.187 321.187 0 0 0 7.257 13.246c2.594 4.48 5.28 8.868 8.038 13.147Zm37.542 31.03c-5.184-5.592-10.354-11.779-15.403-18.433c4.902.192 9.899.29 14.978.29c5.218 0 10.376-.117 15.453-.343c-4.985 6.774-10.018 12.97-15.028 18.486Zm52.198-57.817c3.422 7.8 6.306 15.345 8.596 22.52c-7.422 1.694-15.436 3.058-23.88 4.071a382.417 382.417 0 0 0 7.859-13.026a347.403 347.403 0 0 0 7.425-13.565Zm-16.898 8.101a358.557 358.557 0 0 1-12.281 19.815a329.4 329.4 0 0 1-23.444.823c-7.967 0-15.716-.248-23.178-.732a310.202 310.202 0 0 1-12.513-19.846h.001a307.41 307.41 0 0 1-10.923-20.627a310.278 310.278 0 0 1 10.89-20.637l-.001.001a307.318 307.318 0 0 1 12.413-19.761c7.613-.576 15.42-.876 23.31-.876H128c7.926 0 15.743.303 23.354.883a329.357 329.357 0 0 1 12.335 19.695a358.489 358.489 0 0 1 11.036 20.54a329.472 329.472 0 0 1-11 20.722Zm22.56-122.124c8.572 4.944 11.906 24.881 6.52 51.026c-.344 1.668-.73 3.367-1.15 5.09c-10.622-2.452-22.155-4.275-34.23-5.408c-7.034-10.017-14.323-19.124-21.64-27.008a160.789 160.789 0 0 1 5.888-5.4c18.9-16.447 36.564-22.941 44.612-18.3ZM128 90.808c12.625 0 22.86 10.235 22.86 22.86s-10.235 22.86-22.86 22.86s-22.86-10.235-22.86-22.86s10.235-22.86 22.86-22.86Z"></path></svg>

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;
}
}

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1666169304891" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3611" xmlns:xlink="http://www.w3.org/1999/xlink" width="2000" height="2000"><path d="M1024 512c0 282.7776-229.2224 512-512 512S0 794.7776 0 512 229.2224 0 512 0s512 229.2224 512 512z m-372.736-194.9184L512 456.3456l-139.264-139.264A39.424 39.424 0 0 0 317.0816 372.736L456.3456 512l-139.264 139.264a39.424 39.424 0 1 0 55.6544 55.6544l139.264-139.264 139.264 139.264a39.424 39.424 0 1 0 55.6544-55.6544L567.6544 512l139.264-139.264a39.424 39.424 0 0 0-55.6544-55.6544z" p-id="3612" data-spm-anchor-id="a313x.7781069.0.i4" class="selected" fill="#E84545"></path></svg>

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>
)
}

Binary file not shown.

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;
}

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1667652583766" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2521" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M729.6 448H128v85.333333h601.6L597.333333 665.6l59.733334 59.733333 234.666666-234.666666L661.333333 256l-59.733333 59.733333 128 132.266667z" fill="#fefefe" p-id="2522" data-spm-anchor-id="a313x.7781069.0.i0" class="selected"></path></svg>

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/, '') // 路径重写,本项目不需要重写
}
}
},
})

@ -0,0 +1,8 @@
# 文档结构说明
```bash
|------baseSys # 基础系统
|------.gitignore # git排除文件
|------list.md # 根目录结构说明
|------README.md # 系统说明
```
Loading…
Cancel
Save