master
git 2 years ago
parent ec228c63e3
commit 21701e405e

630
oab/Cargo.lock generated

File diff suppressed because it is too large Load Diff

@ -12,15 +12,15 @@ serde = { version = "1", features = ["derive"] }
serde_json = "*"
serde_yaml = "*"
clap = { version = "3", features = ["derive"] }
chrono = "0.4"
chrono = { version = "0.4", features = ["serde"] }
tokio = { version = "1", features = ["full"] }
futures-util = "*"
tracing = "*"
tracing-subscriber = "*"
thiserror = "1.0"
rbson = "2"
rbatis = { version = "*", default-features = false, features = ["runtime-tokio-rustls","mysql","debug_mode"] }
sqlx = { version = "0.5", features = [ "runtime-tokio-rustls", "mysql", "macros", "migrate", "chrono"] }
actix-web = "4"
jsonwebtoken = "8"
@ -30,3 +30,5 @@ block-padding = "0.3.2"
generic-array = "0.14.5"
serde-big-array = "0.4.1"
base64 = "0.13.0"
uuid = { version = "1.1", features = ["v3","v4", "fast-rng", "macro-diagnostics"]}

@ -40,7 +40,7 @@ CREATE TABLE IF NOT EXISTS `app`
`des` varchar(255),
`user_count` int NOT NULL DEFAULT 0,
`hide` tinyint(1) NOT NULL DEFAULT 0,
`join_method` enum('auto','disabled','applying') NOT NULL DEFAULT 'auto',
`join_method` int NOT NULL DEFAULT 0,
`role_id` varchar(32),
`redirect` varchar(255),
@ -56,7 +56,7 @@ CREATE TABLE IF NOT EXISTS `app_user`
`app_id` varchar(32) NOT NULL,
`user_id` varchar(32) NOT NULL,
`status` enum('ok', 'disabled', 'applying', 'deny') NOT NULL,
`status` int NOT NULL DEFAULT 0,
PRIMARY KEY (`user_id`,`app_id`) USING BTREE,
FOREIGN KEY (`app_id`) REFERENCES `app`(`id`),

@ -5,34 +5,36 @@
// Distributed under terms of the Apache license.
//
use crate::{dbtx, models, Error, Result, CONFIG, DB};
use actix_web::{delete, get, head, post, web, Responder};
use std::fmt::{format, Debug};
use crate::{models, Error, Result, CONFIG};
use actix_web::{delete, get, head, http, post, web, HttpResponse, Responder};
use base64;
use rbatis::crud::CRUD;
use serde::{Deserialize, Serialize};
use tracing::info;
use uuid::uuid;
#[get("/user/{id}")]
pub async fn get(id: web::Path<String>) -> Result<models::User> {
let n = id.into_inner();
if !n.is_empty() {
let u: Option<models::User> = DB.fetch_by_column("id", &n).await?;
match u {
Some(u) => {
info!("{:#?}", u.token());
return Ok(u);
}
None => Err(Error::NotFound(format!("user {}", n))),
}
let s = sqlx::query_as::<_, models::User>("select *& from user where id = ?")
.bind(n)
.fetch_one(CONFIG.db())
.await?;
info!("{:#?}", s);
Ok(s)
} else {
Err(Error::Missing("id".to_string()))
}
}
#[get("/user/")]
pub async fn list() -> impl Responder {
let result: Vec<models::User> = DB.fetch_list().await.unwrap();
web::Json(result)
pub async fn list() -> Result<impl Responder> {
let result = sqlx::query_as::<_, models::User>("select * from user")
.fetch_all(CONFIG.db())
.await?;
Ok(web::Json(result))
}
#[derive(Debug, Deserialize, Serialize)]
@ -42,18 +44,97 @@ pub struct LoginOpt {
}
#[head("/user/{id}")]
pub async fn login(q: web::Query<LoginOpt>, id: web::Path<String>) -> impl Responder {
pub async fn login(q: web::Query<LoginOpt>, id: web::Path<String>) -> Result<HttpResponse> {
let id = id.into_inner();
let q = q.into_inner();
info!("{} try to login{:#?}", id, q);
let mut w = DB.new_wrapper();
match q.typ {
_ => w = w.eq("username", id),
}
let u: Option<models::User> = DB.fetch_by_wrapper(w).await.unwrap();
info!("{:#?}", u);
let typ = match q.typ {
Some(t) => match t.as_str() {
"phone" => "phone",
"email" => "email",
_ => "username",
},
_ => "username",
};
let p = match base64::decode(q.password.as_bytes()) {
Err(_) => return Err(Error::ArgInvalid("password".to_string())),
Ok(p) => p,
};
let p = match std::str::from_utf8(&p) {
Ok(p) => p,
Err(_) => return Err(Error::ArgInvalid("password".to_string())),
};
let sql = format!("select * from user where {} = ?", typ);
let u = sqlx::query_as::<_, models::User>(&sql)
.bind(id)
.fetch_optional(CONFIG.db())
.await?;
let u = match u {
Some(u) => u,
None => return Err(Error::NotFound("user".to_string())),
};
""
u.check_pass(p)?;
let au = sqlx::query_as::<_, models::AppUser>(
"select * from app_user where app_id = ? and user_id = ?",
)
.bind(&CONFIG.uuid)
.bind(&u.id)
.fetch_optional(CONFIG.db())
.await?;
let i: i64 = match au {
Some(au) => match au.status {
models::AUStatus::OK => 0,
models::AUStatus::Deny => {
return Err(Error::BusinessException("apply denied".to_string()))
}
models::AUStatus::Disabled => {
return Err(Error::BusinessException("login disabled".to_string()))
}
models::AUStatus::Applying => {
return Err(Error::BusinessException("applying".to_string()))
}
},
None => {
let app = sqlx::query_as::<_, models::App>("select * from app where id = ?")
.bind(CONFIG.uuid.clone())
.fetch_one(CONFIG.db())
.await?;
info!("{:#?}", u);
let s = match app.join_method {
models::app::AppJoin::Disabled => {
return Err(Error::BusinessException(
"this app diabled login".to_string(),
))
}
models::app::AppJoin::Auto => models::AUStatus::OK,
models::app::AppJoin::Applying => models::AUStatus::Applying,
};
sqlx::query(
r#"
insert into app_user (app_id,user_id,status)
values ( ?, ?, ? )
"#,
)
.bind(&app.id)
.bind(&u.id)
.bind(&s)
.execute(CONFIG.db())
.await?;
match s {
models::AUStatus::OK => 0,
_ => 1,
}
}
};
if i == 0 {
Ok(HttpResponse::build(http::StatusCode::OK)
.insert_header(("auth_token", u.token().to_string()?))
.body("".to_string()))
} else {
Ok(HttpResponse::build(http::StatusCode::OK)
.insert_header(("data", "applying"))
.body("".to_string()))
}
}
#[derive(Debug, Deserialize, Serialize)]
@ -67,7 +148,11 @@ pub async fn register(q: web::Json<RegisterOpt>) -> Result<String> {
let q = q.into_inner();
// let mut tx = dbtx().await;
println!("{:#?}", q);
let u: Option<models::User> = DB.fetch_by_column("username", &q.username).await.unwrap();
let u: Option<models::User> =
sqlx::query_as::<_, models::User>("select * from user where username = ?")
.bind(q.username.clone())
.fetch_optional(CONFIG.db())
.await?;
let u: models::User = match u {
Some(_) => return Err(Error::ArgDuplicated(format!("username: {}", q.username))),
None => {
@ -86,8 +171,11 @@ pub async fn register(q: web::Json<RegisterOpt>) -> Result<String> {
u
}
};
let oa: Option<models::App> = DB.fetch_by_column("id", CONFIG.uuid.clone()).await?;
let oa = oa.unwrap();
let oa: models::App = sqlx::query_as::<_, models::App>("select * from app where id = ?")
.bind(CONFIG.uuid.clone())
.fetch_one(CONFIG.db())
.await?;
let mut au = models::AppUser::new();
au.app_id = oa.id;
au.user_id = u.id.clone();
@ -96,8 +184,31 @@ pub async fn register(q: web::Json<RegisterOpt>) -> Result<String> {
models::app::AppJoin::Auto => au.status = models::app::AUStatus::OK,
models::app::AppJoin::Applying => au.status = models::app::AUStatus::Applying,
}
DB.save(&u, &[]).await?;
DB.save(&au, &[]).await?;
let mut c = CONFIG.db().begin().await?;
sqlx::query!(
r#"
insert into user (id,username,real_code,check_code)
values ( ?, ?, ?, ?)
"#,
u.id,
u.username,
u.real_code,
u.check_code,
)
.execute(&mut c)
.await?;
sqlx::query!(
r#"
insert into app_user ( app_id, user_id, status)
values (?, ?, ? )
"#,
au.app_id,
au.user_id,
au.status,
)
.execute(&mut c)
.await?;
c.commit().await?;
Ok("ok".to_string())
}

@ -16,12 +16,8 @@ use std::{
use clap::{Args, Parser, Subcommand};
use lazy_static::lazy_static;
use rbatis::{logic_delete::RbatisLogicDeletePlugin, rbatis::Rbatis};
use sqlx::{mysql::MySqlPoolOptions, Pool};
use tracing::log::warn;
lazy_static! {
// Rbatis是线程、协程安全的运行时的方法是Send+Sync无需担心线程竞争
pub static ref DB:Rbatis= new_db();
}
lazy_static! {
pub static ref CLI: AppCli = AppCli::new();
@ -60,7 +56,7 @@ impl AppCli {
}
}
#[derive(Debug, PartialEq, serde::Serialize, serde::Deserialize)]
#[derive(Debug, serde::Serialize, serde::Deserialize)]
pub struct ApplicationConfig {
pub uuid: String,
pub key: String,
@ -76,28 +72,35 @@ pub struct ApplicationConfig {
pub log_pack_compress: Option<String>,
pub log_level: Option<String>,
pub jwt_secret: Option<String>,
#[serde(skip)]
pub _pool: Option<Pool<sqlx::MySql>>,
}
impl ApplicationConfig {
pub fn new() -> Self {
let mut res = Self::defaut();
let mut f = match File::open(CLI.cfg.clone()) {
Ok(f) => f,
Err(ref e) if e.kind() == io::ErrorKind::NotFound => return Self::defaut(),
Err(ref e) if e.kind() == io::ErrorKind::NotFound => {
res._pool = Some(res.connect());
return res;
}
Err(e) => panic!("{}", e),
};
File::open(CLI.cfg.clone()).unwrap();
let mut yml_data = String::new();
f.read_to_string(&mut yml_data).unwrap();
//读取配置
let result: ApplicationConfig =
serde_yaml::from_str(&yml_data).expect("load config file fail");
if result.debug {
println!("load config:{:?}", result);
res = serde_yaml::from_str(&yml_data).expect("load config file fail");
if res.debug {
println!("load config:{:?}", res);
println!("///////////////////// Start On Debug Mode ////////////////////////////");
} else {
println!("release_mode is enable!")
}
result
res._pool = Some(res.connect());
res
}
pub fn defaut() -> Self {
Self {
@ -114,39 +117,29 @@ impl ApplicationConfig {
log_pack_compress: None,
log_level: None,
jwt_secret: None,
_pool: None,
}
}
pub fn save(&self) {}
pub fn db(&self) -> &DB {
DB.borrow()
pub fn db(&self) -> &sqlx::MySqlPool {
match &self._pool {
Some(d) => d,
None => panic!("failed"),
}
}
pub async fn connect(&self) {
fn connect(&self) -> Pool<sqlx::MySql> {
let url = format!(
"mysql://{}:{}@{}/{}",
self.db_user, self.db_pass, self.db_url, self.db_name
);
DB.link(&url).await.unwrap();
let p = MySqlPoolOptions::new()
.max_connections(5)
.connect_lazy(&url)
.unwrap();
p
}
}
fn new_db() -> rbatis::rbatis::Rbatis {
let mut rb = rbatis::rbatis::Rbatis::new();
rb.logic_plugin = Some(Box::new(RbatisLogicDeletePlugin::new("delete_flag")));
rb
}
pub async fn dbtx() -> rbatis::executor::RBatisTxExecutorGuard<'static> {
DB.acquire_begin()
.await
.unwrap()
.defer_async(|mut tx1| async move {
if !tx1.is_done() {
_ = tx1.rollback().await;
warn!("db rollback!")
}
})
}
struct FormatTime;
impl tracing_subscriber::fmt::time::FormatTime for FormatTime {
fn format_time(&self, w: &mut tracing_subscriber::fmt::format::Writer<'_>) -> std::fmt::Result {

@ -10,5 +10,5 @@ mod cfg;
pub mod libs;
pub mod models;
mod result;
pub use cfg::{dbtx, init_log, ApplicationConfig, Clis, CLI, CONFIG, DB};
pub use cfg::{init_log, ApplicationConfig, Clis, CLI, CONFIG};
pub use result::{Error, Result};

@ -4,7 +4,11 @@
// 2022-07-07 23:51
// Distributed under terms of the Apache license.
//
use actix_web::{middleware, web, App, HttpServer};
use actix_web::{
middleware,
web::{self, Data},
App, HttpServer,
};
use oab::{api, init_log, models, Clis, Result, CLI, CONFIG};
use tracing::{info, warn};
@ -15,14 +19,12 @@ async fn main() -> Result<()> {
if let Some(c) = &CLI.command {
match c {
Clis::Init => {
CONFIG.connect().await;
models::init().await;
return Ok(());
}
_ => {}
};
};
CONFIG.connect().await;
web().await?;
Ok(())
}
@ -33,7 +35,7 @@ async fn web() -> Result<()> {
let logger = middleware::Logger::default();
let json_config = web::JsonConfig::default()
.limit(4096)
.error_handler(|err, _req|{
.error_handler(|err, _req| {
// create custom error response
// oab::Error::InternalServerError
warn!("{:#?}", err);
@ -49,6 +51,7 @@ async fn web() -> Result<()> {
.service(
web::scope("api")
.app_data(json_config)
.app_data(Data::new(CONFIG.db()))
.configure(api::routes),
)
});

@ -5,29 +5,28 @@
// Distributed under terms of the Apache license.
//
use rbatis::{crud_table, DateTimeNative};
use chrono::NaiveDateTime;
use serde::{Deserialize, Serialize};
#[derive(Debug, serde::Serialize, serde::Deserialize, Clone)]
#[serde(rename_all = "lowercase")]
#[derive(Debug, Serialize, Deserialize, Clone, sqlx::Type)]
#[repr(i64)]
pub enum AppJoin {
Auto,
Disabled,
Applying,
Auto = 0,
Disabled = 1,
Applying = 2,
}
#[crud_table]
#[derive(Debug, Clone)]
#[derive(Debug, Serialize, Deserialize, sqlx::FromRow)]
pub struct App {
pub id: String,
pub created: Option<DateTimeNative>,
pub updated: Option<DateTimeNative>,
pub created: Option<NaiveDateTime>,
pub updated: Option<NaiveDateTime>,
pub delete_flag: bool,
pub name: Option<String>,
pub des: Option<String>,
pub icon: Option<String>,
pub user_count: usize,
pub user_count: i64,
pub hide: bool,
pub join_method: AppJoin,
@ -40,7 +39,7 @@ pub struct App {
impl App {
pub fn new() -> Self {
Self {
id: rbatis::plugin::object_id::ObjectId::new().to_string(),
id: "".to_string(),
created: None,
updated: None,
delete_flag: false,
@ -58,20 +57,19 @@ impl App {
}
}
#[derive(Debug, Deserialize, Serialize, Clone)]
#[serde(rename_all = "lowercase")]
#[derive(Debug, Deserialize, Serialize, Clone, sqlx::Type)]
#[repr(i64)]
pub enum AUStatus {
OK,
Disabled,
Applying,
Deny,
OK = 0,
Disabled = 1,
Applying = 2,
Deny = 3,
}
#[crud_table]
#[derive(Debug, Serialize, Deserialize, Clone)]
#[derive(Debug, Serialize, Deserialize, sqlx::FromRow)]
pub struct AppUser {
pub created: Option<DateTimeNative>,
pub updated: Option<DateTimeNative>,
pub created: Option<NaiveDateTime>,
pub updated: Option<NaiveDateTime>,
pub app_id: String,
pub user_id: String,
pub status: AUStatus,

@ -8,23 +8,16 @@
pub mod app;
mod role;
mod user;
use std::{fs::File, io::Read};
use tracing::info;
use crate::DB;
pub use app::{AUStatus, App, AppUser};
pub use role::{Access, Resource, Role};
pub use user::User;
use crate::CONFIG;
pub async fn init() {
info!("init database");
let mut f = File::open("./sql/table.sql").unwrap();
let mut sql = String::new();
f.read_to_string(&mut sql).unwrap();
DB.exec(&sql, vec![]).await.unwrap();
}
pub fn new_id() -> rbatis::object_id::ObjectId {
rbatis::plugin::object_id::ObjectId::new()
sqlx::migrate!().run(CONFIG.db()).await.unwrap();
}

@ -4,14 +4,15 @@
// 2022-07-09 02:42
// Distributed under terms of the Apache license.
//
use rbatis::{crud_table, DateTimeNative};
#[crud_table]
#[derive(Debug, Clone, Default)]
use chrono::NaiveDateTime;
use serde::{Deserialize, Serialize};
#[derive(Debug, Default, Serialize, Deserialize)]
pub struct Role {
pub id: String,
pub created: Option<DateTimeNative>,
pub updated: Option<DateTimeNative>,
pub created: Option<NaiveDateTime>,
pub updated: Option<NaiveDateTime>,
pub delete_flag: bool,
pub app_id: String,
@ -20,11 +21,10 @@ pub struct Role {
pub user_count: usize,
}
#[crud_table]
#[derive(Debug, Clone, Default)]
#[derive(Debug, Default, Serialize, Deserialize)]
pub struct Resource {
pub created: Option<DateTimeNative>,
pub updated: Option<DateTimeNative>,
pub created: Option<NaiveDateTime>,
pub updated: Option<NaiveDateTime>,
pub delete_flag: bool,
pub app_id: String,
@ -32,11 +32,10 @@ pub struct Resource {
pub des: Option<String>,
}
#[crud_table]
#[derive(Debug, Clone, Default)]
#[derive(Debug, Default, Serialize, Deserialize)]
pub struct Access {
pub created: Option<DateTimeNative>,
pub updated: Option<DateTimeNative>,
pub created: Option<NaiveDateTime>,
pub updated: Option<NaiveDateTime>,
pub delete_flag: bool,
pub app_id: String,

@ -7,11 +7,9 @@
//
use actix_web::ResponseError;
use chrono::{prelude::*, Duration};
use generic_array::typenum::U32;
use chrono::{prelude::*, Duration};
use jsonwebtoken::{decode, encode, DecodingKey, EncodingKey, Header, Validation};
use rbatis::{crud_table, DateTimeNative};
use serde::{Deserialize, Serialize};
use tracing::info;
@ -20,7 +18,8 @@ use aes_gcm::aead::{Aead, NewAead};
use aes_gcm::{Aes256Gcm, Key, Nonce};
use block_padding::{Padding, Pkcs7};
use generic_array::{ArrayLength, GenericArray};
use generic_array::typenum::U32;
use generic_array::GenericArray;
use rand::distributions::Alphanumeric;
use rand::{thread_rng, Rng};
@ -44,12 +43,11 @@ fn rand_str(l: usize) -> String {
// block
// }
#[crud_table]
#[derive(Debug, Clone)]
#[derive(Debug, Serialize, Deserialize, sqlx::FromRow)]
pub struct User {
pub id: String,
pub created: Option<DateTimeNative>,
pub updated: Option<DateTimeNative>,
pub created: Option<NaiveDateTime>,
pub updated: Option<NaiveDateTime>,
pub delete_flag: bool,
pub username: String,
@ -58,10 +56,10 @@ pub struct User {
pub phone: Option<String>,
pub icon: Option<String>,
pub real_code: Option<String>,
pub check_code: Option<rbatis::Bytes>,
pub status: usize,
pub used: usize,
pub space: usize,
pub check_code: Option<Vec<u8>>,
pub status: i32,
pub used: i32,
pub space: i32,
}
impl User {
@ -75,6 +73,30 @@ impl User {
};
t
}
pub fn check_pass(&self, p: &str) -> Result<()> {
let p = p.as_bytes();
let mut key_block: GenericArray<u8, U32> = [0xff; 32].into();
key_block[..p.len()].copy_from_slice(p);
Pkcs7::pad(&mut key_block, p.len());
// key 32 Byte
let key = Key::from_slice(&key_block);
let cipher = Aes256Gcm::new(&key);
// 12 Byte
// 96-bits; unique per message
let nonce = Nonce::from_slice(&self.id.as_bytes()[..12]);
let plaintext = match cipher.decrypt(nonce, self.check_code.as_ref().unwrap().as_slice()) {
Ok(p) => p,
Err(_) => return Err(Error::ArgInvalid("password".to_string())),
};
let plaintext = std::str::from_utf8(&plaintext).unwrap();
if plaintext.eq(self.real_code.as_ref().unwrap()) {
Ok(())
} else {
Err(Error::ArgInvalid("password".to_string()))
}
}
pub fn update_pass(&mut self, p: &str) -> Result<()> {
if p.len() < 6 || p.len() > 32 {
return Err(Error::ArgInvalid("password".to_string()));
@ -107,8 +129,8 @@ impl User {
impl Default for User {
fn default() -> Self {
Self {
id: rbatis::plugin::object_id::ObjectId::new().to_string(),
created: Some(DateTimeNative::now()),
id: uuid::Uuid::new_v4().to_string().replace("-", ""),
created: None,
updated: None,
delete_flag: false,

@ -16,6 +16,7 @@ use actix_web::{
use serde::{Deserialize, Serialize};
use thiserror::Error as ThisError;
use tracing::info;
pub type Result<T> = std::result::Result<T, Error>;
@ -114,13 +115,13 @@ impl From<actix_web::Error> for Error {
Error::BusinessException(format!("{:?}", e))
}
}
impl From<jsonwebtoken::errors::Error> for Error {
fn from(e: jsonwebtoken::errors::Error) -> Self {
impl From<sqlx::Error> for Error {
fn from(e: sqlx::Error) -> Self {
Error::BusinessException(format!("{:?}", e))
}
}
impl From<rbatis::error::Error> for Error {
fn from(e: rbatis::error::Error) -> Self {
impl From<jsonwebtoken::errors::Error> for Error {
fn from(e: jsonwebtoken::errors::Error) -> Self {
Error::BusinessException(format!("{:?}", e))
}
}
@ -145,9 +146,11 @@ impl actix_web::Responder for Error {
impl error::ResponseError for Error {
fn error_response(&self) -> HttpResponse {
info!("{}", self.to_string());
HttpResponse::build(self.status_code())
.insert_header(ContentType::html())
.body(self.to_string())
.insert_header(("error", self.to_string()))
.body("".to_string())
}
fn status_code(&self) -> StatusCode {

@ -29,19 +29,14 @@ function baseRequests(url: string, method: any = 'GET', query: any, data: any, s
method: method,
headers: headers,
}).then((res: any) => {
if ('auth_token' in res.headers) {
localStorage.auth_token = res.headers.auth_token
store.commit('user/refreshToken', localStorage.auth_token)
}
if ('redirect_url' in res.headers) {
window.location.href = res.headers.redirect_url
return
}
console.log(res)
if (method === 'HEAD') {
success(res.headers)
} else {
success(res)
success(res.data)
}
})
.catch((e: any) => {
@ -51,7 +46,7 @@ function baseRequests(url: string, method: any = 'GET', query: any, data: any, s
}
let code = e.response.status
if (code === 400) {
msg.Warn(e.response.data)
msg.Warn(e.response.headers.error)
return
} else if (code === 401) {
console.log(e)

@ -1,116 +1,122 @@
<template>
<div class="flex items-center justify-center">
<div
:style="{background:Theme.me.lightBox, 'box-shadow': Theme.me.lightBoxShadow}"
class="px-10 pb-9 pt-28 rounded-xl w-96">
<n-form label-width="70px" label-align="left" :model="data" ref="form_ref" label-placement="left" :rules="rules">
<n-form-item required label="用户名" path="username">
<n-input @keydown.enter="divs[1].focus()" :ref="el => {if (el)divs[0]=el}"
v-model:value="data.username"></n-input>
</n-form-item>
<n-form-item required label="密码" path="password">
<n-input @keydown.enter="login" :ref="el => {if (el) divs[1]=el}" v-model:value="data.password"
type="password"></n-input>
</n-form-item>
<div class="flex justify-around mt-4">
<n-button @click="login"></n-button>
<n-button @click="router.push({name:'register'})"></n-button>
<div class="flex items-center justify-center">
<div :style="{ background: Theme.me.lightBox, 'box-shadow': Theme.me.lightBoxShadow }"
class="px-10 pb-9 pt-28 rounded-xl w-96">
<n-form label-width="70px" label-align="left" :model="data" ref="form_ref" label-placement="left"
:rules="rules">
<n-form-item required label="用户名" path="username">
<n-input @keydown.enter="divs[1].focus()" :ref="el => { if (el) divs[0] = el }"
v-model:value="data.username"></n-input>
</n-form-item>
<n-form-item required label="密码" path="password">
<n-input @keydown.enter="login" :ref="el => { if (el) divs[1] = el }" v-model:value="data.password"
type="password"></n-input>
</n-form-item>
<div class="flex justify-around mt-4">
<n-button @click="login"></n-button>
<n-button @click="router.push({ name: 'register' })">注册</n-button>
</div>
</n-form>
</div>
</n-form>
</div>
</div>
</template>
<script lang="ts" setup>
import {computed, onMounted, ref, watch} from 'vue'
import {Theme} from '@/theme'
import {useMessage} from 'naive-ui'
import { computed, onMounted, ref, watch } from 'vue'
import { Theme } from '@/theme'
import api from '@/api'
import {useRoute, useRouter} from 'vue-router'
import {store} from '@/store'
import {modelsApp} from '@/models'
import { useRoute, useRouter } from 'vue-router'
import { store } from '@/store'
import { modelsApp } from '@/models'
import util from '@/libs/util'
import msg from '@veypi/msg'
let msg = useMessage()
const route = useRoute()
const router = useRouter()
const divs = ref([])
let form_ref = ref(null)
let data = ref({
username: '',
password: '',
username: '',
password: '',
})
let rules = {
username: [
{
required: true,
validator(r: any, v: any) {
return (v && v.length >= 3 && v.length <= 16) || new Error('长度要求3~16')
},
trigger: ['input', 'blur'],
},
],
password: [{
required: true,
validator(r: any, v: any) {
return (v && v.length >= 6 && v.length <= 16) || new Error('长度要求6~16')
},
}],
username: [
{
required: true,
validator(r: any, v: any) {
return (v && v.length >= 3 && v.length <= 16) || new Error('长度要求3~16')
},
trigger: ['input', 'blur'],
},
],
password: [{
required: true,
validator(r: any, v: any) {
return (v && v.length >= 6 && v.length <= 16) || new Error('长度要求6~16')
},
}],
}
let uuid = computed(() => {
return route.query.uuid
return route.query.uuid
})
let ifLogOut = computed(() => {
return route.query.logout === '1'
return route.query.logout === '1'
})
function login() {
// @ts-ignore
form_ref.value.validate((e: any) => {
if (!e) {
api.user.login(data.value.username, data.value.password).Start((url: string) => {
msg.success('登录成功')
store.dispatch('user/fetchUserData')
redirect(route.query.redirect as string)
}, e => {
console.log(e)
msg.warning('登录失败:' + e)
})
}
})
// @ts-ignore
form_ref.value.validate((e: any) => {
if (!e) {
api.user.login(data.value.username, data.value.password).Start((headers: any) => {
if ('auth_token' in headers) {
localStorage.auth_token = headers.auth_token
store.commit('user/refreshToken', localStorage.auth_token)
msg.Info('登录成功')
store.dispatch('user/fetchUserData')
redirect(route.query.redirect as string)
} else {
msg.Info('正在申请加入,请等待管理员审批')
}
console.log(headers)
}, e => {
console.log(e)
msg.Warn('登录失败:' + e.headers.error)
})
}
})
}
function redirect(url?: string) {
if (uuid.value && uuid.value !== store.state.oauuid) {
api.app.get(uuid.value as string).Start((app: modelsApp) => {
api.token(uuid.value as string).get().Start(e => {
if (!url) {
url = app.UserRefreshUrl
if (uuid.value && uuid.value !== store.state.oauuid) {
api.app.get(uuid.value as string).Start((app: modelsApp) => {
api.token(uuid.value as string).get().Start(e => {
if (!url) {
url = app.UserRefreshUrl
}
e = encodeURIComponent(e)
url = url.replaceAll('$token', e)
window.location.href = url
})
}, e => {
})
} else if (util.checkLogin()) {
if (url) {
router.push(url)
} else {
router.push({ name: 'home' })
}
e = encodeURIComponent(e)
url = url.replaceAll('$token', e)
window.location.href = url
})
}, e => {
})
} else if (util.checkLogin()) {
if (url) {
router.push(url)
} else {
router.push({name: 'home'})
}
}
}
onMounted(() => {
if (!ifLogOut.value) {
redirect()
}
if (divs.value[0]) {
// @ts-ignore
divs.value[0].focus()
}
if (!ifLogOut.value) {
redirect()
}
if (divs.value[0]) {
// @ts-ignore
divs.value[0].focus()
}
})
</script>

Loading…
Cancel
Save