crud macro / login token redirect

master
veypi 1 year ago
parent 5f752ba9ac
commit 521aee9683

@ -5,9 +5,9 @@
// Distributed under terms of the MIT license. // Distributed under terms of the MIT license.
// //
use proc_macro2::{Ident, Span}; use proc_macro2::Span;
use quote::{format_ident, quote, ToTokens}; use quote::{format_ident, quote, ToTokens};
use syn::{AttributeArgs, ItemFn, NestedMeta, ReturnType, Token}; use syn::{AttributeArgs, ItemFn, NestedMeta, ReturnType};
pub struct CrudWrap { pub struct CrudWrap {
func: ItemFn, func: ItemFn,
@ -17,14 +17,11 @@ pub struct CrudWrap {
impl CrudWrap { impl CrudWrap {
pub fn new(args: AttributeArgs, func: ItemFn, method: i32) -> syn::Result<Self> { pub fn new(args: AttributeArgs, func: ItemFn, method: i32) -> syn::Result<Self> {
let args = Crud::new(args)?; let args = Crud::new(args, method)?;
Ok(Self { func, args, method }) Ok(Self { func, args, method })
} }
} fn update(&self, tokens: &mut proc_macro2::TokenStream) {
impl ToTokens for CrudWrap {
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
let func_vis = &self.func.vis; let func_vis = &self.func.vis;
let func_block = &self.func.block; let func_block = &self.func.block;
@ -42,7 +39,7 @@ impl ToTokens for CrudWrap {
}; };
let model_name = &self.args.model; let model_name = &self.args.model;
let builder_fields = self.args.attrs.iter().map(|field| { let builder_fields = self.args.props.iter().map(|field| {
quote! { quote! {
if let Some(#field) = _data.#field { if let Some(#field) = _data.#field {
obj.#field = sea_orm::Set(#field.into()) obj.#field = sea_orm::Set(#field.into())
@ -51,12 +48,10 @@ impl ToTokens for CrudWrap {
}); });
let (args_fields, filter_fields) = match self.args.filters.len() { let (args_fields, filter_fields) = match self.args.filters.len() {
1 => { 1 => {
let pair = &self.args.filters[0]; let k = &self.args.filters[0];
let k = &pair[0]; let _k = format_ident!("_{}", k);
let _k = format_ident!("_{}", &pair[0]);
let v = &pair[1];
( (
vec![quote! {let #_k = #v; }], vec![quote! {let #_k = _id; }],
vec![quote! { vec![quote! {
filter(crate::models::#model_name::Column::#k.eq(#_k)) filter(crate::models::#model_name::Column::#k.eq(#_k))
}], }],
@ -67,17 +62,17 @@ impl ToTokens for CrudWrap {
.filters .filters
.iter() .iter()
.enumerate() .enumerate()
.map(|(idx, [k, v])| { .map(|(idx, k)| {
let _k = format_ident!("_{}", k); let _k = format_ident!("_{}", k);
quote! { quote! {
let #_k = #v.#idx; let #_k = &_id[#idx];
} }
}) })
.collect(), .collect(),
self.args self.args
.filters .filters
.iter() .iter()
.map(|[k, _]| { .map(|k| {
let _k = format_ident!("_{}", k); let _k = format_ident!("_{}", k);
quote! { quote! {
filter(crate::models::#model_name::Column::#k.eq(#_k)) filter(crate::models::#model_name::Column::#k.eq(#_k))
@ -115,19 +110,43 @@ impl ToTokens for CrudWrap {
let _stream = tokens.extend(stream); let _stream = tokens.extend(stream);
} }
fn copy(&self, _: &mut proc_macro2::TokenStream) {
let _ = self.args.attrs.len();
}
}
impl ToTokens for CrudWrap {
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
match self.method {
3 => self.update(tokens),
// 3 => self.update(tokens),
_ => self.copy(tokens),
}
}
} }
struct Crud { struct Crud {
model: syn::Ident, model: syn::Ident,
attrs: Vec<syn::Ident>, attrs: Vec<syn::Ident>,
filters: Vec<[syn::Ident; 2]>, filters: Vec<syn::Ident>,
props: Vec<syn::Ident>,
} }
impl Crud { impl Crud {
fn new(args: AttributeArgs) -> syn::Result<Self> { fn new(args: AttributeArgs, method: i32) -> syn::Result<Self> {
let mut model: Option<syn::Ident> = None; let mut model: Option<syn::Ident> = None;
let mut attrs: Vec<syn::Ident> = Vec::new(); let mut attrs: Vec<syn::Ident> = Vec::new();
let mut filters: Vec<[syn::Ident; 2]> = Vec::new(); let mut filters: Vec<syn::Ident> = Vec::new();
let mut props: Vec<syn::Ident> = Vec::new();
if method == 0 {
return Ok(Self {
model: format_ident!("a"),
attrs,
filters,
props,
});
}
for arg in args { for arg in args {
match arg { match arg {
// NestedMeta::Lit(syn::Lit::Str(lit)) => { // NestedMeta::Lit(syn::Lit::Str(lit)) => {
@ -147,17 +166,32 @@ impl Crud {
lit: syn::Lit::Str(lit_str), lit: syn::Lit::Str(lit_str),
.. ..
})) => { })) => {
match path.get_ident() { if path.is_ident("filter") {
Some(expr) => { filters = lit_str
filters.push([expr.to_owned(), format_ident!("{}", lit_str.value())]) .value()
} .replace(" ", "")
None => { .split(",")
return Err(syn::Error::new_spanned( .into_iter()
path, .map(|l| {
"Unknown identifier. Available: 'aid='AppId'", return format_ident!("{}", l);
)); })
} .collect();
}; } else if path.is_ident("props") {
props = lit_str
.value()
.replace(" ", "")
.split(",")
.into_iter()
.map(|l| {
return format_ident!("{}", l);
})
.collect();
} else {
return Err(syn::Error::new_spanned(
path,
"Unknown identifier. Available: filter, props ",
));
}
} }
_ => { _ => {
@ -165,12 +199,12 @@ impl Crud {
} }
} }
} }
println!("|||||||||||____________________");
match model { match model {
Some(model) => Ok(Self { Some(model) => Ok(Self {
model, model,
attrs, attrs,
filters, filters,
props,
}), }),
None => Err(syn::Error::new( None => Err(syn::Error::new(
Span::call_site(), Span::call_site(),

@ -53,6 +53,11 @@ pub fn crud_update(args: TokenStream, input: TokenStream) -> TokenStream {
derive_crud(3, args, input) derive_crud(3, args, input)
} }
#[proc_macro_attribute]
pub fn crud_test(args: TokenStream, input: TokenStream) -> TokenStream {
derive_crud(0, args, input)
}
fn derive_crud(method: i32, args: TokenStream, input: TokenStream) -> TokenStream { fn derive_crud(method: i32, args: TokenStream, input: TokenStream) -> TokenStream {
let args = parse_macro_input!(args as AttributeArgs); let args = parse_macro_input!(args as AttributeArgs);
let func = parse_macro_input!(input as ItemFn); let func = parse_macro_input!(input as ItemFn);

@ -87,9 +87,9 @@ pub struct UpdateOpt {
#[patch("/app/{aid}/access/{id}")] #[patch("/app/{aid}/access/{id}")]
#[access_delete("app")] #[access_delete("app")]
#[crud_update(access, AppId = "_id", Id = "_id", level, rid)] #[crud_update(access, filter = "AppId, Id", props = "level, rid")]
pub async fn update( pub async fn update(
id: web::Path<(String, String)>, id: web::Path<[String; 2]>,
data: web::Json<UpdateOpt>, data: web::Json<UpdateOpt>,
stat: web::Data<AppState>, stat: web::Data<AppState>,
) -> Result<impl Responder> { ) -> Result<impl Responder> {
@ -111,3 +111,34 @@ pub async fn delete(
info!("{:#?}", res); info!("{:#?}", res);
Ok("ok") Ok("ok")
} }
// mod test {
// use crate::{
// models::{self},
// AppState, Error, Result,
// };
// use actix_web::{delete, get, patch, post, web, Responder};
// use proc::crud_test;
// use proc::{access_create, access_delete, access_read, crud_update};
// use sea_orm::{ActiveModelTrait, ColumnTrait, EntityTrait, QueryFilter};
// use serde::{Deserialize, Serialize};
// use tracing::info;
// #[derive(Debug, Clone, Deserialize, Serialize)]
// pub struct UpdateOpt {
// pub level: Option<i32>,
// pub rid: Option<String>,
// }
// #[derive(Debug, Clone, Deserialize, Serialize)]
// pub struct IDOpt {
// pub app_id: Option<String>,
// pub id: Option<String>,
// }
// #[crud_test(access, filter = "AppId, Id", props = "level, rid")]
// pub async fn update(
// id: web::Path<[String; 2]>,
// data: web::Json<UpdateOpt>,
// stat: web::Data<AppState>,
// ) -> Result<impl Responder> {
// Ok("")
// }
// }

@ -96,15 +96,8 @@ pub struct UpdateOpt {
#[access_update("app")] #[access_update("app")]
#[crud_update( #[crud_update(
app, app,
Id = "_id", filter = "Id",
name, props = "name,icon,des,join_method,role_id,redirect,host,status"
icon,
des,
join_method,
role_id,
redirect,
host,
status
)] )]
pub async fn update( pub async fn update(
id: web::Path<String>, id: web::Path<String>,

@ -102,9 +102,9 @@ pub struct UpdateOpt {
#[patch("/app/{aid}/user/{uid}")] #[patch("/app/{aid}/user/{uid}")]
#[access_delete("app")] #[access_delete("app")]
#[crud_update(app_user, AppId = "_id", UserId = "_id", status)] #[crud_update(app_user, filter = "AppId, UserId", props = "status")]
pub async fn update( pub async fn update(
id: web::Path<(String, String)>, id: web::Path<[String; 2]>,
data: web::Json<UpdateOpt>, data: web::Json<UpdateOpt>,
stat: web::Data<AppState>, stat: web::Data<AppState>,
) -> Result<impl Responder> { ) -> Result<impl Responder> {

@ -11,6 +11,7 @@ mod app;
mod appuser; mod appuser;
mod resource; mod resource;
mod role; mod role;
mod token;
mod upload; mod upload;
mod user; mod user;
use actix_web::web; use actix_web::web;
@ -29,6 +30,7 @@ pub fn routes(cfg: &mut web::ServiceConfig) {
.service(app::update) .service(app::update)
.service(app::del); .service(app::del);
// cfg.route("/acc", web::get().to(access::UpdateOpt::update)); // cfg.route("/acc", web::get().to(access::UpdateOpt::update));
cfg.service(token::get);
cfg.service(appuser::get) cfg.service(appuser::get)
.service(appuser::add) .service(appuser::add)

@ -6,9 +6,7 @@
// //
use actix_web::{delete, get, patch, post, web, Responder}; use actix_web::{delete, get, patch, post, web, Responder};
use proc::{access_create, access_delete, access_read, crud_update}; use proc::{access_create, access_delete, access_read, crud_update};
use sea_orm::{ use sea_orm::{ActiveModelTrait, ColumnTrait, EntityTrait, QueryFilter};
ActiveModelTrait, ColumnTrait, EntityTrait, LoaderTrait, QueryFilter, TransactionTrait,
};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use tracing::info; use tracing::info;
@ -78,9 +76,9 @@ pub struct UpdateOpt {
#[patch("/app/{aid}/resource/{rid}")] #[patch("/app/{aid}/resource/{rid}")]
#[access_delete("app")] #[access_delete("app")]
#[crud_update(resource, AppId = "_id", Name = "_id", des)] #[crud_update(resource, filter = "AppId, Name", des)]
pub async fn update( pub async fn update(
id: web::Path<(String, String)>, id: web::Path<[String; 2]>,
data: web::Json<UpdateOpt>, data: web::Json<UpdateOpt>,
stat: web::Data<AppState>, stat: web::Data<AppState>,
) -> Result<impl Responder> { ) -> Result<impl Responder> {

@ -7,15 +7,11 @@
// //
use actix_web::{delete, get, patch, post, web, Responder}; use actix_web::{delete, get, patch, post, web, Responder};
use proc::{access_create, access_delete, access_read, access_update, crud_update}; use proc::{access_create, access_delete, access_read, access_update, crud_update};
use sea_orm::{ use sea_orm::{ActiveModelTrait, ColumnTrait, ConnectionTrait, EntityTrait, QueryFilter};
ActiveModelTrait, ColumnTrait, ConnectionTrait, EntityTrait, LoaderTrait, QueryFilter,
TransactionTrait,
};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use tracing::info; use tracing::info;
use crate::{ use crate::{
libs,
models::{self}, models::{self},
AppState, Error, Result, AppState, Error, Result,
}; };
@ -82,10 +78,10 @@ pub struct UpdateOpt {
} }
#[patch("/app/{aid}/role/{rid}")] #[patch("/app/{aid}/role/{rid}")]
#[access_update("app", id = "&id.clone().0")] #[access_update("app", id = "&id.clone()[0]")]
#[crud_update(role, AppId = "_id", Id = "_id", des)] #[crud_update(role, filter = "AppId, Id", props = "des")]
pub async fn update( pub async fn update(
id: web::Path<(String, String)>, id: web::Path<[String; 2]>,
data: web::Json<UpdateOpt>, data: web::Json<UpdateOpt>,
stat: web::Data<AppState>, stat: web::Data<AppState>,
) -> Result<impl Responder> { ) -> Result<impl Responder> {

@ -0,0 +1,68 @@
//
// token.rs
// Copyright (C) 2023 veypi <i@veypi.com>
// 2023-10-13 02:29
// Distributed under terms of the MIT license.
//
use actix_web::{get, web, Responder};
use proc::access_read;
use sea_orm::{ColumnTrait, EntityTrait, QueryFilter};
use std::time::{Duration, Instant};
use tokio::{self};
use crate::{
models::{self, AUStatus, Token, UserPlugin},
AppState, Error, Result,
};
#[get("/app/{aid}/token/")]
#[access_read("app")]
pub async fn get(
aid: web::Path<String>,
stat: web::Data<AppState>,
t: web::ReqData<Token>,
) -> Result<impl Responder> {
let n = aid.into_inner();
if !n.is_empty() {
let s = models::app_user::Entity::find()
.filter(models::app_user::Column::AppId.eq(&n))
.filter(models::app_user::Column::UserId.eq(&t.id))
.one(stat.db())
.await?;
if s.is_none() {
return Err(Error::NotAuthed);
};
let s = s.unwrap();
if s.status == AUStatus::OK as i32 {
let result = sqlx::query_as::<_, models::AccessCore>(
"select access.name, access.rid, access.level from access, user_role, role WHERE user_role.user_id = ? && access.role_id=user_role.role_id && role.id=user_role.role_id && role.app_id = ?",
)
.bind(&t.id)
.bind(n)
.fetch_all(stat.sqlx())
.await?;
let u = models::user::Entity::find_by_id(&t.id)
.one(stat.db())
.await?
.unwrap();
let str = u.token(result).to_string()?;
// tokio::spawn(async move {
// let mut interval = tokio::time::interval(Duration::from_secs(5));
// interval.tick().await;
// let start = Instant::now();
// println!("time:{:?}", start);
// loop {
// interval.tick().await;
// println!("time:{:?}", start.elapsed());
// }
// });
Ok(str)
} else {
Err(Error::NotAuthed)
}
} else {
Err(Error::Missing("id".to_string()))
}
}

@ -66,47 +66,3 @@ async fn save_files(
Ok(web::Json(res)) Ok(web::Json(res))
} }
// #[actix_web::main]
// async fn main() -> std::io::Result<()> {
// HttpServer::new(|| {
// App::new()
// .wrap(middleware::Logger::default())
// .app_data(TempFileConfig::default().directory("./tmp"))
// .service(
// web::resource("/")
// .route(web::get().to(index))
// .route(web::post().to(save_files)),
// )
// })
// .bind(("127.0.0.1", 8080))?
// .workers(2)
// .run()
// .await
// }
// /// Example of the old manual way of processing multipart forms.
// #[allow(unused)]
// async fn save_file_manual(mut payload: Multipart) -> Result<HttpResponse, Error> {
// // iterate over multipart stream
// while let Some(mut field) = payload.try_next().await? {
// // A multipart/form-data stream has to contain `content_disposition`
// let content_disposition = field.content_disposition();
// let filename = content_disposition
// .get_filename()
// .map_or_else(|| Uuid::new_v4().to_string(), sanitize_filename::sanitize);
// let filepath = format!("./tmp/{filename}");
// // File::create is blocking operation, use threadpool
// let mut f = web::block(|| std::fs::File::create(filepath)).await??;
// // Field in turn is stream of *Bytes* object
// while let Some(chunk) = field.try_next().await? {
// // filesystem operations are blocking, we have to use threadpool
// f = web::block(move || f.write_all(&chunk).map(|_| f)).await??;
// }
// }
// Ok(HttpResponse::Ok().into())
// }

@ -14,7 +14,7 @@ use crate::{
}; };
use actix_web::{delete, get, head, http, patch, post, web, HttpResponse, Responder}; use actix_web::{delete, get, head, http, patch, post, web, HttpResponse, Responder};
use base64; use base64;
use chrono::{DateTime, Local, NaiveDateTime}; use chrono::Local;
use proc::{access_read, access_update, crud_update}; use proc::{access_read, access_update, crud_update};
use rand::Rng; use rand::Rng;
use sea_orm::{ActiveModelTrait, ColumnTrait, EntityTrait, QueryFilter, TransactionTrait}; use sea_orm::{ActiveModelTrait, ColumnTrait, EntityTrait, QueryFilter, TransactionTrait};
@ -222,7 +222,7 @@ pub struct UpdateOpt {
#[patch("/user/{id}")] #[patch("/user/{id}")]
#[access_update("user")] #[access_update("user")]
#[crud_update(user, Id = "_id", username, icon, nickname, email, phone)] #[crud_update(user, filter = "Id", props = "username, icon, nickname, email, phone")]
pub async fn update( pub async fn update(
id: web::Path<String>, id: web::Path<String>,
stat: web::Data<AppState>, stat: web::Data<AppState>,

@ -9,8 +9,8 @@ mod app_plugin;
pub mod entity; pub mod entity;
mod user_plugin; mod user_plugin;
use chrono::DateTime;
use sea_orm::EntityTrait;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use tracing::info; use tracing::info;

@ -61,7 +61,7 @@ impl UserPlugin for super::entity::user::Model {
fn token(&self, ac: Vec<AccessCore>) -> Token { fn token(&self, ac: Vec<AccessCore>) -> Token {
let default_ico = "/media/".to_string(); let default_ico = "/media/".to_string();
let t = Token { let t = Token {
iss: "onedt".to_string(), iss: "oa".to_string(),
aud: "".to_string(), aud: "".to_string(),
exp: (Utc::now() + Duration::days(4)).timestamp(), exp: (Utc::now() + Duration::days(4)).timestamp(),
iat: Utc::now().timestamp(), iat: Utc::now().timestamp(),

@ -7,7 +7,7 @@
</q-avatar> </q-avatar>
</div> </div>
<div class="col-span-3 grid grid-cols-1 items-center text-left"> <div class="col-span-3 grid grid-cols-1 items-center text-left">
<div class="h-10 flex items-center text-2xl italic font-bold"> <div class="truncate h-10 flex items-center text-xl italic font-bold">
{{ core.name }} {{ core.name }}
</div> </div>
<span class="truncate">{{ }}</span> <span class="truncate">{{ }}</span>

@ -35,6 +35,8 @@
item[k.name] }} item[k.name] }}
</span> </span>
</template> </template>
<slot :name="`k_${k.name}_append`" :row="item" :value="item[k.name]" :set="setv(item, k.name)">
</slot>
</slot> </slot>
</div> </div>
</template> </template>

@ -5,7 +5,7 @@
* Distributed under terms of the MIT license. * Distributed under terms of the MIT license.
--> -->
<template> <template>
<div class="w-full h-full relative"> <div class="w-full h-full">
<!-- <div class="absolute bg-red-400 left-0 top-0 w-full h-full"></div> --> <!-- <div class="absolute bg-red-400 left-0 top-0 w-full h-full"></div> -->
<div class="w-full h-full" :id="eid"></div> <div class="w-full h-full" :id="eid"></div>
</div> </div>
@ -85,6 +85,7 @@ const init = () => {
let config = { let config = {
value: props.content, value: props.content,
id: props.eid, id: props.eid,
// isPreviewOnly: true,
callback: { callback: {
}, },
fileUpload: fileUpload, fileUpload: fileUpload,
@ -112,6 +113,7 @@ iframe.cherry-dialog-iframe {
.cherry { .cherry {
background: none; background: none;
box-shadow: none; box-shadow: none;
height: 100%;
} }
.cherry-previewer { .cherry-previewer {

@ -14,7 +14,8 @@
</div> </div>
<router-view v-slot="{ Component }"> <router-view v-slot="{ Component }">
<transition mode="out-in" enter-active-class="animate__fadeIn" leave-active-class="animate__fadeOut"> <transition mode="out-in" enter-active-class="animate__fadeIn" leave-active-class="animate__fadeOut">
<component class="animate__animated animate__400ms" :is="Component"></component> <component class="animate__animated animate__400ms p-10" style="min-height:calc(100% - 96px)" :is="Component">
</component>
</transition> </transition>
</router-view> </router-view>
</div> </div>

@ -5,7 +5,7 @@
* Distributed under terms of the MIT license. * Distributed under terms of the MIT license.
--> -->
<template> <template>
<div class="px-10"> <div class="">
<div class="flex justify-between"> <div class="flex justify-between">
<div class="text-3xl">角色管理</div> <div class="text-3xl">角色管理</div>
<q-btn @click="created(0)"></q-btn> <q-btn @click="created(0)"></q-btn>

@ -23,6 +23,9 @@
<q-btn color='primary'>获取秘钥</q-btn> <q-btn color='primary'>获取秘钥</q-btn>
</div> </div>
</template> </template>
<template #k_redirect_append>
<q-btn class="mx-8" @click="$router.push('/login?uuid=' + app.id)">Go</q-btn>
</template>
</CRUD> </CRUD>
</div> </div>
<div v-if="newApp" class="flex justify-center gap-8 mt-6"> <div v-if="newApp" class="flex justify-center gap-8 mt-6">

@ -5,11 +5,11 @@
* Distributed under terms of the MIT license. * Distributed under terms of the MIT license.
--> -->
<template> <template>
<div> <div class="-mt-16">
<q-page-sticky position="top-right" style="z-index: 20" :offset="[27, 27]"> <q-page-sticky position="top-right" style="z-index: 20" :offset="[27, 27]">
<q-btn v-if="preview_mode" @click="preview_mode = false" round icon="save_as" class="" /> <q-btn v-if="preview_mode" @click="preview_mode = false" round icon="save_as" class="" />
</q-page-sticky> </q-page-sticky>
<Editor v-if="app.id" :eid="app.id + '.des'" v-model="preview_mode" :content="content" @save="save"></Editor> <Editor style="" v-if="app.id" :eid="app.id + '.des'" v-model="preview_mode" :content="content" @save="save"></Editor>
</div> </div>
</template> </template>

@ -5,7 +5,7 @@
* Distributed under terms of the MIT license. * Distributed under terms of the MIT license.
--> -->
<template> <template>
<div class="px-10"> <div class="">
<q-table title="用户管理" :rows="rows" :columns="columns" row-key="name"> <q-table title="用户管理" :rows="rows" :columns="columns" row-key="name">
<template #body-cell-created="props"> <template #body-cell-created="props">
<q-td :props="props"> <q-td :props="props">

@ -29,6 +29,7 @@ import util from 'src/libs/util'
import { useUserStore } from 'src/stores/user' import { useUserStore } from 'src/stores/user'
import { useAppStore } from 'src/stores/app' import { useAppStore } from 'src/stores/app'
import { AUStatus, modelsApp } from 'src/models' import { AUStatus, modelsApp } from 'src/models'
import { Base64 } from 'js-base64'
const app = useAppStore() const app = useAppStore()
@ -88,24 +89,25 @@ function redirect(url: string) {
api.app.get(uuid.value as string).then((app: modelsApp) => { api.app.get(uuid.value as string).then((app: modelsApp) => {
api.token(uuid.value as string).get().then(e => { api.token(uuid.value as string).get().then(e => {
url = url || app.redirect url = url || app.redirect
// let data = JSON.parse(Base64.decode(e.split('.')[1]))
// console.log(data)
e = encodeURIComponent(e)
console.log(e) console.log(e)
// e = encodeURIComponent(e) url = url.replaceAll('$token', e)
// url = url.replaceAll('$token', e) console.log(url)
window.location.href = url window.location.href = url
}) })
}) })
} else if (util.checkLogin()) { } else if (url) {
if (url) { router.push(url)
router.push(url) } else {
} else { router.push({ name: 'home' })
router.push({ name: 'home' })
}
} }
} }
onMounted(() => { onMounted(() => {
if (!ifLogOut.value) { if (!ifLogOut.value && util.checkLogin()) {
redirect('') redirect('')
} }
}) })

Loading…
Cancel
Save