update app home

master
veypi 1 year ago
parent 5ae9c6eb50
commit 36d55d1f1f

@ -2,6 +2,15 @@
name = "oab" name = "oab"
version = "0.1.0" version = "0.1.0"
edition = "2021" edition = "2021"
default-run = "web"
[[bin]]
name = "web"
path = "src/main.rs"
[[bin]]
name = "test"
path = "src/test.rs"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

@ -5,8 +5,8 @@
// Distributed under terms of the Apache license. // Distributed under terms of the Apache license.
// //
// //
use actix_web::{delete, get, post, web, Responder}; use actix_web::{delete, get, patch, post, put, web, Responder};
use proc::{access_create, access_read}; use proc::{access_create, access_delete, access_read, access_update};
use sea_orm::{ActiveModelTrait, EntityTrait, TransactionTrait}; use sea_orm::{ActiveModelTrait, EntityTrait, TransactionTrait};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use tracing::info; use tracing::info;
@ -54,12 +54,6 @@ pub struct App {
#[access_read("app")] #[access_read("app")]
pub async fn list(stat: web::Data<AppState>) -> Result<impl Responder> { pub async fn list(stat: web::Data<AppState>) -> Result<impl Responder> {
let res = app::Entity::find().all(stat.db()).await?; let res = app::Entity::find().all(stat.db()).await?;
// let result = sqlx::query_as::<_,app::Model>(
// "select app.*,app_userstatus as status from app left join app_user on app_user.user_id = ? && app_user.app_id = app.id",
// ).bind(_auth_token.id)
// .fetch_all(stat.sqlx())
// .await?;
Ok(web::Json(res)) Ok(web::Json(res))
} }
@ -101,12 +95,46 @@ pub async fn create(
level: sea_orm::ActiveValue::Set(AccessLevel::ALL as i32), level: sea_orm::ActiveValue::Set(AccessLevel::ALL as i32),
..Default::default() ..Default::default()
}; };
let ac: access::Model = ac.insert(&db).await?; ac.insert(&db).await?;
libs::user::connect_to_app(t.id.clone(), obj.id.clone(), &db, Some(obj.clone())).await?; libs::user::connect_to_app(t.id.clone(), obj.id.clone(), &db, Some(obj.clone())).await?;
db.commit().await?; db.commit().await?;
Ok(web::Json(obj)) Ok(web::Json(obj))
} }
#[derive(Debug, Deserialize, Serialize)]
pub struct UpdateOpt {
name: Option<String>,
icon: Option<String>,
enable_register: Option<String>,
des: Option<String>,
host: Option<String>,
redirect: Option<String>,
}
#[patch("/app/{id}")]
#[access_update("app")]
pub async fn update(
id: web::Path<String>,
stat: web::Data<AppState>,
data: web::Json<UpdateOpt>,
) -> Result<impl Responder> {
let data = data.into_inner();
let id = id.into_inner();
let obj = app::Entity::find_by_id(&id).one(stat.db()).await?;
let mut obj: app::ActiveModel = match obj {
Some(o) => o.into(),
None => return Err(Error::NotFound(id)),
};
if let Some(name) = data.name {
obj.name = sea_orm::Set(name)
};
let obj = obj.update(stat.db()).await?;
Ok(web::Json(obj))
}
#[delete("/app/{id}")] #[delete("/app/{id}")]
#[access_delete("app")]
pub async fn del(_id: web::Path<String>) -> Result<impl Responder> { pub async fn del(_id: web::Path<String>) -> Result<impl Responder> {
Ok("") Ok("")
} }

@ -5,11 +5,12 @@
// Distributed under terms of the MIT license. // Distributed under terms of the MIT license.
// //
use actix_web::{get, web, Responder}; use actix_web::{get, post, web, Responder};
use proc::access_read; use proc::access_read;
use sea_orm::{ColumnTrait, EntityTrait, QueryFilter}; use sea_orm::{ColumnTrait, EntityTrait, QueryFilter, TransactionTrait};
use crate::{ use crate::{
libs,
models::{app, app_user}, models::{app, app_user},
AppState, Error, Result, AppState, Error, Result,
}; };
@ -51,3 +52,16 @@ pub async fn get(
Ok(web::Json(res)) Ok(web::Json(res))
} }
} }
#[post("/app/{aid}/user/{uid}")]
#[access_read("app")]
pub async fn add(
params: web::Path<(String, String)>,
stat: web::Data<AppState>,
) -> Result<impl Responder> {
let (aid, uid) = params.into_inner();
let db = stat.db().begin().await?;
let res = libs::user::connect_to_app(uid, aid, &db, None).await?;
db.commit().await?;
Ok(web::Json(res))
}

@ -27,5 +27,5 @@ pub fn routes(cfg: &mut web::ServiceConfig) {
.service(app::create) .service(app::create)
.service(app::del); .service(app::del);
cfg.service(appuser::get); cfg.service(appuser::get).service(appuser::add);
} }

@ -0,0 +1,6 @@
//
// app.rs
// Copyright (C) 2023 veypi <i@veypi.com>
// 2023-10-06 19:39
// Distributed under terms of the MIT license.
//

@ -9,3 +9,4 @@ pub mod auth;
pub mod cors; pub mod cors;
pub mod fs; pub mod fs;
pub mod user; pub mod user;
pub mod app;

@ -9,7 +9,9 @@ use crate::{
models::{self, app, app_user, user_role}, models::{self, app, app_user, user_role},
Error, Result, Error, Result,
}; };
use sea_orm::{ActiveModelTrait, ConnectionTrait, DatabaseTransaction, EntityTrait}; use sea_orm::{
ActiveModelTrait, ColumnTrait, ConnectionTrait, DatabaseTransaction, EntityTrait, QueryFilter,
};
// 尝试绑定应用 // 尝试绑定应用
pub async fn connect_to_app( pub async fn connect_to_app(
@ -18,6 +20,15 @@ pub async fn connect_to_app(
db: &DatabaseTransaction, db: &DatabaseTransaction,
app_obj: Option<app::Model>, app_obj: Option<app::Model>,
) -> Result<app_user::Model> { ) -> Result<app_user::Model> {
match app_user::Entity::find()
.filter(app_user::Column::AppId.eq(&aid))
.filter(app_user::Column::UserId.eq(&uid))
.one(db)
.await?
{
Some(au) => return Ok(au),
None => {}
};
let app_obj = match app_obj { let app_obj = match app_obj {
Some(o) => o, Some(o) => o,
None => match app::Entity::find_by_id(&aid).one(db).await? { None => match app::Entity::find_by_id(&aid).one(db).await? {

@ -168,7 +168,6 @@ impl From<Box<dyn std::fmt::Display>> for Error {
} }
} }
impl actix_web::Responder for Error { impl actix_web::Responder for Error {
type Body = actix_web::body::BoxBody; type Body = actix_web::body::BoxBody;
fn respond_to(self, _req: &actix_web::HttpRequest) -> HttpResponse<Self::Body> { fn respond_to(self, _req: &actix_web::HttpRequest) -> HttpResponse<Self::Body> {
@ -182,7 +181,7 @@ impl error::ResponseError for Error {
HttpResponse::build(self.status_code()) HttpResponse::build(self.status_code())
.insert_header(ContentType::html()) .insert_header(ContentType::html())
.insert_header(("error", self.to_string())) .insert_header(("error", self.to_string()))
.body("".to_string()) .body(self.to_string())
} }
fn status_code(&self) -> StatusCode { fn status_code(&self) -> StatusCode {

@ -0,0 +1,8 @@
//
// test.rs
// Copyright (C) 2023 veypi <i@veypi.com>
// 2023-10-06 22:45
// Distributed under terms of the MIT license.
//
fn main() {}

@ -14,15 +14,16 @@
}, },
"dependencies": { "dependencies": {
"@quasar/extras": "^1.16.4", "@quasar/extras": "^1.16.4",
"@veypi/msg": "^0.1.0", "@veypi/msg": "^0.1.1",
"@veypi/one-icon": "2",
"@veypi/oaer": "^0.0.1", "@veypi/oaer": "^0.0.1",
"@veypi/one-icon": "2",
"animate.css": "^4.1.1", "animate.css": "^4.1.1",
"axios": "^1.2.1", "axios": "^1.2.1",
"js-base64": "^3.7.5", "js-base64": "^3.7.5",
"mitt": "^3.0.1", "mitt": "^3.0.1",
"pinia": "^2.0.11", "pinia": "^2.0.11",
"quasar": "^2.6.0", "quasar": "^2.6.0",
"vditor": "^3.9.6",
"vue": "^3.0.0", "vue": "^3.0.0",
"vue-i18n": "^9.2.2", "vue-i18n": "^9.2.2",
"vue-router": "^4.0.0", "vue-router": "^4.0.0",

@ -155,6 +155,7 @@ module.exports = configure(function(/* ctx */) {
plugins: [ plugins: [
'LoadingBar', 'LoadingBar',
'AppFullscreen', 'AppFullscreen',
'Dialog'
] ]
}, },

@ -37,7 +37,7 @@ export default {
list(id: string) { list(id: string) {
return ajax.get(this.local + id) return ajax.get(this.local + id)
}, },
add(uid: number) { add(uid: string) {
return ajax.post(this.local + uid) return ajax.post(this.local + uid)
}, },
update(uid: number, status: string) { update(uid: number, status: string) {

@ -9,11 +9,15 @@
import { boot } from 'quasar/wrappers' import { boot } from 'quasar/wrappers'
import '@veypi/msg/index.css' import '@veypi/msg/index.css'
import { conf } from '@veypi/msg'
import '../assets/icon.js' import '../assets/icon.js'
import '@veypi/oaer/dist/index.css' import '@veypi/oaer/dist/index.css'
import { Cfg } from '@veypi/oaer' import { Cfg } from '@veypi/oaer'
import 'vditor/dist/index.css';
conf.timeout = 5000
Cfg.host.value = 'http://' + window.location.host Cfg.host.value = 'http://' + window.location.host
Cfg.token.value = localStorage.getItem('auth_token') || '' Cfg.token.value = localStorage.getItem('auth_token') || ''
Cfg.uuid.value = 'FR9P5t8debxc11aFF' Cfg.uuid.value = 'FR9P5t8debxc11aFF'

@ -17,6 +17,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import msg from "@veypi/msg"; import msg from "@veypi/msg";
import { useQuasar } from "quasar";
import api from "src/boot/api"; import api from "src/boot/api";
import { AUStatus, modelsApp, modelsAppUser } from "src/models"; import { AUStatus, modelsApp, modelsAppUser } from "src/models";
import { useUserStore } from "src/stores/user"; import { useUserStore } from "src/stores/user";
@ -27,50 +28,46 @@ const router = useRouter()
let props = withDefaults(defineProps<{ let props = withDefaults(defineProps<{
core: modelsApp core: modelsApp,
is_part: boolean
}>(), }>(),
{} {}
) )
const $q = useQuasar()
const u = useUserStore()
function Go() { function Go() {
switch (props.core.au.status) { if (props.is_part) {
case AUStatus.OK: router.push({ name: "app.home", params: { id: props.core.id } });
router.push({ name: "app.home", params: { id: props.core.id } }); return
return;
case AUStatus.Applying:
msg.Info("请等待管理员审批进入");
return;
case AUStatus.Deny:
msg.Warn("进入申请未通过");
return;
case AUStatus.Disabled:
msg.Warn("已被禁止使用");
return;
} }
// api.app.user(props.core.id).add(useUserStore().id).then(e => { // $q.dialog({
// console.log(e) // title: '',
// }) // message: ' ' + props.core.name,
// api.app // cancel: true,
// .user(props.core.UUID) // }).onOk(() => {
// .add(store.state.user.id) api.app.user(props.core.id).add(u.id).then(e => {
// .Start( switch (e.status) {
// (e) => { case AUStatus.OK:
// bar.finish(); msg.Info('加入成功')
// if (e.Status === "ok") { router.push({ name: "app.home", params: { id: props.core.id } });
// router.push({ name: "app.main", params: { uuid: props.core.UUID } }); return;
// return; case AUStatus.Applying:
// } msg.Info("请等待管理员审批进入");
// props.core.UserStatus = e.Status; return;
// msg.info(""); case AUStatus.Deny:
// }, msg.Warn("进入申请未通过");
// (e) => { return;
// msg.warning(": " + e); case AUStatus.Disabled:
// bar.error(); msg.Warn("已被禁止使用");
// } return;
// ); }
// return;
}).catch(e => {
msg.Warn("加入失败" + e)
})
} }
</script> </script>
<style scoped> <style scoped>

@ -5,8 +5,13 @@
* Distributed under terms of the MIT license. * Distributed under terms of the MIT license.
--> -->
<template> <template>
<div> <div class="p-4">
<h1>{{ app.name }}</h1> <div class="flex items-center">
<q-avatar class="mx-2" round size="4rem">
<img :src="app.icon">
</q-avatar>
<h1 class="text-4xl">{{ app.name }}</h1>
</div>
<router-view :data="{ a: 1 }" /> <router-view :data="{ a: 1 }" />
</div> </div>
</template> </template>
@ -14,10 +19,11 @@
<script lang="ts" setup> <script lang="ts" setup>
import msg from '@veypi/msg'; import msg from '@veypi/msg';
import api from 'src/boot/api'; import api from 'src/boot/api';
import { modelsApp } from 'src/models'; import { MenuLink, modelsApp } from 'src/models';
import { useMenuStore } from 'src/stores/menu'; import { useMenuStore } from 'src/stores/menu';
import { computed, watch, ref, onMounted, provide, onBeforeUnmount } from 'vue'; import { computed, watch, ref, onMounted, provide, onBeforeUnmount } from 'vue';
import { useRoute } from 'vue-router'; import { useRoute } from 'vue-router';
import { RouteLocationNamedRaw } from 'vue-router';
let route = useRoute(); let route = useRoute();
let menu = useMenuStore() let menu = useMenuStore()
@ -29,19 +35,52 @@ provide('app', app)
const sync_app = () => { const sync_app = () => {
api.app.get(id.value as string).then((e: modelsApp) => { api.app.get(id.value as string).then((e: modelsApp) => {
app.value = e app.value = e
Links.value[1].title = e.name
for (let i in Links.value) {
let l: RouteLocationNamedRaw = Links.value[i].to as any
if (l.params) {
l.params.id = e.id
}
}
}).catch(e => { }).catch(e => {
msg.Warn('sync app data failed: ' + e) msg.Warn('sync app data failed: ' + e)
}) })
} }
watch(id, () => { const Links = ref([
sync_app() {
title: '应用中心',
caption: '',
icon: 'apps',
to: { name: 'home' }
},
{
title: '',
caption: '',
icon: 'home',
to: { name: 'app.home', params: { id: id.value } }
},
{
title: '用户管理',
caption: 'oa.veypi.com',
icon: 'people',
to: { name: 'app.user', params: { id: id.value } }
},
{
title: '应用设置',
caption: '',
icon: 'settings',
to: { name: 'app.settings', params: { id: id.value } }
},
] as MenuLink[])
watch(id, (e) => {
if (e) {
sync_app()
}
}) })
onMounted(() => { onMounted(() => {
sync_app() sync_app()
menu.set([ menu.set(Links.value)
])
}) })
onBeforeUnmount(() => { onBeforeUnmount(() => {
menu.load_default() menu.load_default()

@ -16,7 +16,7 @@
<q-icon class="mx-2" size="1.5rem" @click="$q.dark.toggle" <q-icon class="mx-2" size="1.5rem" @click="$q.dark.toggle"
:name="$q.dark.mode ? 'light_mode' : 'dark_mode'"></q-icon> :name="$q.dark.mode ? 'light_mode' : 'dark_mode'"></q-icon>
<OAer @logout="user.logout" :is-dark="$q.dark.mode as boolean"></OAer> <OAer v-if="user.ready" @logout="user.logout" :is-dark="$q.dark.mode as boolean"></OAer>
</q-toolbar> </q-toolbar>
<!-- <q-toolbar class=""> --> <!-- <q-toolbar class=""> -->
<!-- <q-icon @click="toggleLeftDrawer" class="cursor-pointer" name="menu" size="sm"></q-icon> --> <!-- <q-icon @click="toggleLeftDrawer" class="cursor-pointer" name="menu" size="sm"></q-icon> -->
@ -35,16 +35,20 @@
<q-page-container class="flex"> <q-page-container class="flex">
<q-page class="w-full"> <q-page class="w-full">
<router-view /> <router-view v-slot="{ Component }">
<transition mode="out-in" enter-active-class="animate__fadeInLeft" leave-active-class="animate__fadeOutRight">
<component class="animate__animated animate__400ms" :is="Component"></component>
</transition>
</router-view>
</q-page> </q-page>
</q-page-container> </q-page-container>
<q-footer bordered class="bg-grey-8 text-white flex justify-around"> <!-- <q-footer bordered class="bg-grey-8 text-white flex justify-around"> -->
<span class="hover:text-black cursor-pointer" @click="$router.push({ name: 'about' })">关于OA</span> <!-- <span class="hover:text-black cursor-pointer" @click="$router.push({ name: 'about' })">关于OA</span> -->
<span class="hover:text-black cursor-pointer">使用须知</span> <!-- <span class="hover:text-black cursor-pointer">使用须知</span> -->
<span class="hover:text-black cursor-pointer" @click="util.goto('https://veypi.com')"> <!-- <span class="hover:text-black cursor-pointer" @click="util.goto('https://veypi.com')"> -->
©2021 veypi <!-- ©2021 veypi -->
</span> <!-- </span> -->
</q-footer> <!-- </q-footer> -->
</q-layout> </q-layout>
</template> </template>
@ -74,3 +78,9 @@ function toggleLeftDrawer() {
leftDrawerOpen.value = !leftDrawerOpen.value leftDrawerOpen.value = !leftDrawerOpen.value
} }
</script> </script>
<style scoped>
.animate__400ms {
--animate-duration: 300ms;
}
</style>

@ -6,17 +6,57 @@
--> -->
<template> <template>
<div> <div>
{{ app }} <q-page-sticky position="top-right" :offset="[27, 27]">
<q-btn @click="sync_editor" :style="{
color: edit_mode ? 'red' :
''
}" round icon="save_as" class="" />
</q-page-sticky>
<div v-if="edit_mode" id="vditor"></div>
<div v-else>
{{ app }}
</div>
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { inject } from 'vue'; import { inject, onMounted, ref } from 'vue';
import { modelsApp } from 'src/models'; import { modelsApp } from 'src/models';
import Vditor from 'vditor';
import api from 'src/boot/api';
let edit_mode = ref(false)
const vditor = ref<Vditor | null>(null);
let app = inject('app') as modelsApp let app = inject('app') as modelsApp
const sync_editor = () => {
if (edit_mode.value) {
api.app.update(app.id, { des: "" }).then(e => {
edit_mode.value = false
console.log(e)
})
return
}
edit_mode.value = true
setTimeout(() => {
vditor.value = new Vditor('vditor', {
toolbarConfig: {
hide: true
},
after: () => {
// vditor.value is a instance of Vditor now and thus can be safely used here
vditor.value!.setValue('Vue Composition API + Vditor + TypeScript Minimal Example');
},
});
}, 0)
}
onMounted(() => {
})
</script> </script>
<style scoped></style> <style scoped></style>

@ -0,0 +1,17 @@
<!--
* AppUser.vue
* Copyright (C) 2023 veypi <i@veypi.com>
* 2023-10-06 20:44
* Distributed under terms of the MIT license.
-->
<template>
<div>
app.user
</div>
</template>
<script lang="ts" setup>
</script>
<style scoped></style>

@ -8,9 +8,9 @@
</q-btn> </q-btn>
</div> </div>
</div> </div>
<div class="grid gap-4 grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5 text-center"> <div class="grid gap-4 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5 text-center">
<div v-for="(item, k) in ofApps" class="flex items-center justify-center" :key="k"> <div v-for="(item, k) in ofApps" class="flex items-center justify-center" :key="k">
<AppCard :core="item"></AppCard> <AppCard :core="item" :is_part="true"></AppCard>
</div> </div>
</div> </div>
</div> </div>
@ -18,7 +18,7 @@
<h1 class="page-h1">应用中心</h1> <h1 class="page-h1">应用中心</h1>
<div class="grid gap-4 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5 text-center"> <div class="grid gap-4 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5 text-center">
<div v-for="(item, k) in apps" class="flex items-center justify-center" :key="k"> <div v-for="(item, k) in apps" class="flex items-center justify-center" :key="k">
<AppCard :core="item"></AppCard> <AppCard :core="item" :is_part="false"></AppCard>
</div> </div>
</div> </div>
</div> </div>
@ -74,11 +74,10 @@ function getApps() {
api.app.list().then( api.app.list().then(
(e: modelsApp[]) => { (e: modelsApp[]) => {
apps.value = e; apps.value = e;
api.app.user('-').list(user.id).then((aus: modelsAppUser[]) => { api.app.user('-').list(user.id).then((aus: modelsApp[]) => {
for (let i in aus) { for (let i in aus) {
let ai = apps.value.findIndex(a => a.id === aus[i].app_id) let ai = apps.value.findIndex(a => a.id === aus[i].id)
if (ai >= 0) { if (ai >= 0) {
apps.value[ai].au = aus[i]
if (aus[i].status === AUStatus.OK) { if (aus[i].status === AUStatus.OK) {
ofApps.value.push(apps.value[ai]) ofApps.value.push(apps.value[ai])
apps.value.splice(ai, 1) apps.value.splice(ai, 1)

@ -19,7 +19,7 @@ import routes from './routes';
* with the Router instance. * with the Router instance.
*/ */
export default route(function(/* { store, ssrContext } */) { function newRouter(/* { store, ssrContext } */) {
const createHistory = process.env.SERVER const createHistory = process.env.SERVER
? createMemoryHistory ? createMemoryHistory
: (process.env.VUE_ROUTER_MODE === 'history' ? createWebHistory : createWebHashHistory); : (process.env.VUE_ROUTER_MODE === 'history' ? createWebHistory : createWebHashHistory);
@ -33,7 +33,6 @@ export default route(function(/* { store, ssrContext } */) {
// quasar.conf.js -> build -> publicPath // quasar.conf.js -> build -> publicPath
history: createHistory(process.env.VUE_ROUTER_BASE), history: createHistory(process.env.VUE_ROUTER_BASE),
}); });
const u = useUserStore()
Router.beforeEach((to, from) => { Router.beforeEach((to, from) => {
if (to.meta.requiresAuth && !util.checkLogin()) { if (to.meta.requiresAuth && !util.checkLogin()) {
@ -46,6 +45,7 @@ export default route(function(/* { store, ssrContext } */) {
} }
} }
if (to.meta.checkAuth) { if (to.meta.checkAuth) {
const u = useUserStore()
if (!to.meta.checkAuth(u.auth, to)) { if (!to.meta.checkAuth(u.auth, to)) {
// if (window.$msg) { // if (window.$msg) {
@ -56,4 +56,6 @@ export default route(function(/* { store, ssrContext } */) {
} }
}) })
return Router; return Router;
}); };
export default newRouter();

@ -34,14 +34,16 @@ const routes: RouteRecordRaw[] = [
children: [ children: [
loadcomponents('home', 'home', 'IndexPage'), loadcomponents('home', 'home', 'IndexPage'),
loadcomponents('user', 'user', '404'), loadcomponents('user', 'user', '404'),
loadcomponents('file', 'file', '404'),
loadcomponents('settings', 'settings', '404'), loadcomponents('settings', 'settings', '404'),
{ {
path: 'app/:id?', path: 'app/:id?',
component: () => import("../layouts/AppLayout.vue"), component: () => import("../layouts/AppLayout.vue"),
redirect: { name: 'app.home' }, redirect: { name: 'app.home' },
children: [ children: [
loadcomponents('home', 'app.home', 'IndexPage'), loadcomponents('home', 'app.home', 'AppHome'),
loadcomponents('user', 'app.user', 'AppHome'), loadcomponents('user', 'app.user', 'AppUser'),
loadcomponents('settings', 'app.settings', 'IndexPage'),
] ]
} }
], ],

@ -17,7 +17,7 @@ const defaultLinks: MenuLink[] = [
to: { name: 'home' } to: { name: 'home' }
}, },
{ {
title: '用户管理', title: '账号设置',
caption: 'oa.veypi.com', caption: 'oa.veypi.com',
icon: 'person', icon: 'person',
to: { name: 'user' } to: { name: 'user' }

@ -8,8 +8,8 @@
import { defineStore } from 'pinia'; import { defineStore } from 'pinia';
import { Auths, modelsUser, NewAuths } from 'src/models'; import { Auths, modelsUser, NewAuths } from 'src/models';
import { useRouter } from 'vue-router';
import { Base64 } from 'js-base64' import { Base64 } from 'js-base64'
import router from 'src/router';
import api from 'src/boot/api'; import api from 'src/boot/api';
export const useUserStore = defineStore('user', { export const useUserStore = defineStore('user', {
@ -23,10 +23,9 @@ export const useUserStore = defineStore('user', {
}, },
actions: { actions: {
logout() { logout() {
// this.ready = false this.ready = false
// localStorage.removeItem('auth_token') localStorage.removeItem('auth_token')
// const r = useRouter() router.push({ name: 'login' })
// r.push({ name: 'login' })
}, },
fetchUserData() { fetchUserData() {
let token = localStorage.getItem('auth_token')?.split('.'); let token = localStorage.getItem('auth_token')?.split('.');

@ -465,6 +465,11 @@
resolved "https://registry.yarnpkg.com/@veypi/msg/-/msg-0.1.0.tgz#2ebe899527a11ed11f68c2c96f468cfcc66ad3d4" resolved "https://registry.yarnpkg.com/@veypi/msg/-/msg-0.1.0.tgz#2ebe899527a11ed11f68c2c96f468cfcc66ad3d4"
integrity sha512-58dj5nnpHsxaiK5sbPiDK5t8OF4uvN+kAmWhU0BRAgXHpkxkZNZ8rn7hXvSVybG1BbM8EuMNkq0lIxGYNKl8aw== integrity sha512-58dj5nnpHsxaiK5sbPiDK5t8OF4uvN+kAmWhU0BRAgXHpkxkZNZ8rn7hXvSVybG1BbM8EuMNkq0lIxGYNKl8aw==
"@veypi/msg@^0.1.1":
version "0.1.1"
resolved "https://registry.yarnpkg.com/@veypi/msg/-/msg-0.1.1.tgz#94864ae2c0a81991b8a30d87f12d2245fdebbead"
integrity sha512-UiAF/Y0EGT/37tGApptzHBNUpo78LbnrEkCqGAGMkJp86wrUyOgTAvuvQ197Ifqw9PIbjZM9dAgMv4DfMJQEYA==
"@veypi/oaer@^0.0.1": "@veypi/oaer@^0.0.1":
version "0.0.1" version "0.0.1"
resolved "https://registry.yarnpkg.com/@veypi/oaer/-/oaer-0.0.1.tgz#b22ebaf72a7bfd5abf62f099b72b533a8cf27abd" resolved "https://registry.yarnpkg.com/@veypi/oaer/-/oaer-0.0.1.tgz#b22ebaf72a7bfd5abf62f099b72b533a8cf27abd"
@ -1207,6 +1212,11 @@ didyoumean@^1.2.2:
resolved "https://registry.yarnpkg.com/didyoumean/-/didyoumean-1.2.2.tgz#989346ffe9e839b4555ecf5666edea0d3e8ad037" resolved "https://registry.yarnpkg.com/didyoumean/-/didyoumean-1.2.2.tgz#989346ffe9e839b4555ecf5666edea0d3e8ad037"
integrity sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw== integrity sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==
diff-match-patch@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/diff-match-patch/-/diff-match-patch-1.0.5.tgz#abb584d5f10cd1196dfc55aa03701592ae3f7b37"
integrity sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw==
dir-glob@^3.0.1: dir-glob@^3.0.1:
version "3.0.1" version "3.0.1"
resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f"
@ -3469,6 +3479,13 @@ vary@~1.1.2:
resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==
vditor@^3.9.6:
version "3.9.6"
resolved "https://registry.yarnpkg.com/vditor/-/vditor-3.9.6.tgz#c6a9e460984992d00b7d4b1f9f79bc75cbba4e34"
integrity sha512-97sPNHnBpfEFnk5WARCpmdKxgUiPtp0/fPLAUmzZ+axFFf7kExWHRNIUO7OTQzEUMJP/rcXESQTlYGhgKYrsOQ==
dependencies:
diff-match-patch "^1.0.5"
vite@^2.9.13: vite@^2.9.13:
version "2.9.16" version "2.9.16"
resolved "https://registry.yarnpkg.com/vite/-/vite-2.9.16.tgz#daf7ba50f5cc37a7bf51b118ba06bc36e97898e9" resolved "https://registry.yarnpkg.com/vite/-/vite-2.9.16.tgz#daf7ba50f5cc37a7bf51b118ba06bc36e97898e9"

Loading…
Cancel
Save