Merged PR 81: ユーザー/ドメインの登録、編集のUI
下記の管理機能を追加しました。 1.ユーザー登録、編集、削除 2.ドメインの登録、編集、削除 3.ユーザーを使用可能なドメインの適用設定
This commit is contained in:
@@ -1,9 +1,9 @@
|
|||||||
from fastapi import Request,Depends, APIRouter, UploadFile,HTTPException,File
|
from fastapi import Query, Request,Depends, APIRouter, UploadFile,HTTPException,File
|
||||||
from app.db import Base,engine
|
from app.db import Base,engine
|
||||||
from app.db.session import get_db
|
from app.db.session import get_db
|
||||||
from app.db.crud import *
|
from app.db.crud import *
|
||||||
from app.db.schemas import *
|
from app.db.schemas import *
|
||||||
from typing import List
|
from typing import List, Optional
|
||||||
from app.core.auth import get_current_active_user,get_current_user
|
from app.core.auth import get_current_active_user,get_current_user
|
||||||
from app.core.apiexception import APIException
|
from app.core.apiexception import APIException
|
||||||
|
|
||||||
@@ -233,16 +233,17 @@ async def domain_delete(
|
|||||||
|
|
||||||
@r.get(
|
@r.get(
|
||||||
"/domain",
|
"/domain",
|
||||||
response_model=List[Domain],
|
# response_model=List[Domain],
|
||||||
response_model_exclude_none=True,
|
response_model_exclude_none=True,
|
||||||
)
|
)
|
||||||
async def userdomain_details(
|
async def userdomain_details(
|
||||||
request: Request,
|
request: Request,
|
||||||
|
userId: Optional[int] = Query(None, alias="userId"),
|
||||||
user=Depends(get_current_user),
|
user=Depends(get_current_user),
|
||||||
db=Depends(get_db),
|
db=Depends(get_db),
|
||||||
):
|
):
|
||||||
try:
|
try:
|
||||||
domains = get_domain(db, user.id)
|
domains = get_domain(db, userId if userId is not None else user.id)
|
||||||
return domains
|
return domains
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise APIException('platform:domain',request.url._url,f"Error occurred while get user({user.id}) domain:",e)
|
raise APIException('platform:domain',request.url._url,f"Error occurred while get user({user.id}) domain:",e)
|
||||||
@@ -285,11 +286,14 @@ async def userdomain_delete(
|
|||||||
)
|
)
|
||||||
async def get_useractivedomain(
|
async def get_useractivedomain(
|
||||||
request: Request,
|
request: Request,
|
||||||
|
userId: Optional[int] = Query(None, alias="userId"),
|
||||||
user=Depends(get_current_user),
|
user=Depends(get_current_user),
|
||||||
db=Depends(get_db),
|
db=Depends(get_db),
|
||||||
):
|
):
|
||||||
try:
|
try:
|
||||||
domain = get_activedomain(db, user.id)
|
# domain = get_activedomain(db, user.id)
|
||||||
|
|
||||||
|
domain = get_activedomain(db, userId if userId is not None else user.id)
|
||||||
return domain
|
return domain
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise APIException('platform:activedomain',request.url._url,f"Error occurred while get user({user.id}) activedomain:",e)
|
raise APIException('platform:activedomain',request.url._url,f"Error occurred while get user({user.id}) activedomain:",e)
|
||||||
@@ -301,11 +305,12 @@ async def get_useractivedomain(
|
|||||||
async def update_activeuserdomain(
|
async def update_activeuserdomain(
|
||||||
request: Request,
|
request: Request,
|
||||||
domainid:int,
|
domainid:int,
|
||||||
|
userId: Optional[int] = Query(None, alias="userId"),
|
||||||
user=Depends(get_current_user),
|
user=Depends(get_current_user),
|
||||||
db=Depends(get_db),
|
db=Depends(get_db),
|
||||||
):
|
):
|
||||||
try:
|
try:
|
||||||
domain = active_userdomain(db, user.id,domainid)
|
domain = active_userdomain(db, userId if userId is not None else user.id,domainid)
|
||||||
return domain
|
return domain
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise APIException('platform:activedomain',request.url._url,f"Error occurred while update user({user.id}) activedomain:",e)
|
raise APIException('platform:activedomain',request.url._url,f"Error occurred while update user({user.id}) activedomain:",e)
|
||||||
|
|||||||
@@ -253,8 +253,8 @@ def active_userdomain(db: Session, userid: int,domainid: int):
|
|||||||
|
|
||||||
def get_activedomain(db: Session, userid: int):
|
def get_activedomain(db: Session, userid: int):
|
||||||
db_domain = db.query(models.Domain).join(models.UserDomain,models.UserDomain.domainid == models.Domain.id ).filter(and_(models.UserDomain.userid == userid,models.UserDomain.active == True)).first()
|
db_domain = db.query(models.Domain).join(models.UserDomain,models.UserDomain.domainid == models.Domain.id ).filter(and_(models.UserDomain.userid == userid,models.UserDomain.active == True)).first()
|
||||||
if not db_domain:
|
# if not db_domain:
|
||||||
raise HTTPException(status.HTTP_404_NOT_FOUND, detail="Domain not found")
|
# raise HTTPException(status.HTTP_404_NOT_FOUND, detail="Domain not found")
|
||||||
return db_domain
|
return db_domain
|
||||||
|
|
||||||
def get_domain(db: Session, userid: str):
|
def get_domain(db: Session, userid: str):
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
</q-item-section>
|
</q-item-section>
|
||||||
</q-item>
|
</q-item>
|
||||||
<q-separator
|
<q-separator
|
||||||
|
class="q-my-sm"
|
||||||
v-if="isSeparator"
|
v-if="isSeparator"
|
||||||
inset
|
inset
|
||||||
/>
|
/>
|
||||||
|
|||||||
36
frontend/src/components/UserList.vue
Normal file
36
frontend/src/components/UserList.vue
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
<template>
|
||||||
|
<q-table :rows="rows" :columns="columns" row-key="id" :filter="props.filter" :loading="loading"
|
||||||
|
:pagination="pagination" selection="single" v-model:selected="selected"></q-table>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, onMounted } from 'vue'
|
||||||
|
import { api } from 'boot/axios';
|
||||||
|
const props = defineProps<{filter:string}>()
|
||||||
|
const columns = [
|
||||||
|
{ name: 'id', label: 'ID', field: 'id', align: 'left', sortable: true },
|
||||||
|
{ name: 'firstName', label: '氏名', field: 'firstName', align: 'left', sortable: true },
|
||||||
|
{ name: 'lastName', label: '苗字', field: 'lastName', align: 'left', sortable: true },
|
||||||
|
{ name: 'email', label: '電子メール', field: 'email', align: 'left', sortable: true },
|
||||||
|
];
|
||||||
|
|
||||||
|
const pagination = ref({ sortBy: 'id', descending: true, rowsPerPage: 10 });
|
||||||
|
const rows = ref([]);
|
||||||
|
const loading = ref(false);
|
||||||
|
const selected = ref([]);
|
||||||
|
defineExpose({
|
||||||
|
selected
|
||||||
|
})
|
||||||
|
const getUsers = async (filter = () => true) => {
|
||||||
|
loading.value = true;
|
||||||
|
const result = await api.get(`api/v1/users`);
|
||||||
|
rows.value = result.data.map((item) => {
|
||||||
|
return { id: item.id, firstName: item.first_name, lastName: item.last_name, email: item.email, isSuperuser: item.is_superuser, isActive: item.is_active }
|
||||||
|
}).filter(filter);
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
await getUsers();
|
||||||
|
})
|
||||||
|
</script>
|
||||||
@@ -2,40 +2,26 @@
|
|||||||
<q-layout view="lHh Lpr lFf">
|
<q-layout view="lHh Lpr lFf">
|
||||||
<q-header elevated>
|
<q-header elevated>
|
||||||
<q-toolbar>
|
<q-toolbar>
|
||||||
<q-btn
|
<q-btn flat dense round icon="menu" aria-label="Menu" @click="toggleLeftDrawer" />
|
||||||
flat
|
|
||||||
dense
|
|
||||||
round
|
|
||||||
icon="menu"
|
|
||||||
aria-label="Menu"
|
|
||||||
@click="toggleLeftDrawer"
|
|
||||||
/>
|
|
||||||
<q-toolbar-title>
|
<q-toolbar-title>
|
||||||
{{ productName }}
|
{{ productName }}
|
||||||
<q-badge align="top" outline>V{{ version }}</q-badge>
|
<q-badge align="top" outline>V{{ version }}</q-badge>
|
||||||
</q-toolbar-title>
|
</q-toolbar-title>
|
||||||
<domain-selector></domain-selector>
|
<domain-selector></domain-selector>
|
||||||
<q-btn flat round dense icon="logout" @click="authStore.logout()"/>
|
<q-btn flat round dense icon="logout" @click="authStore.logout()" />
|
||||||
</q-toolbar>
|
</q-toolbar>
|
||||||
</q-header>
|
</q-header>
|
||||||
|
|
||||||
<q-drawer
|
<q-drawer :model-value="authStore.LeftDrawer" :show-if-above="false" bordered>
|
||||||
:model-value="authStore.LeftDrawer"
|
|
||||||
:show-if-above="false"
|
|
||||||
bordered
|
|
||||||
>
|
|
||||||
<q-list>
|
<q-list>
|
||||||
<q-item-label
|
<q-item-label header>
|
||||||
header
|
|
||||||
>
|
|
||||||
メニュー
|
メニュー
|
||||||
</q-item-label>
|
</q-item-label>
|
||||||
|
|
||||||
<EssentialLink
|
<EssentialLink v-for="link in essentialLinks" :key="link.title" v-bind="link" />
|
||||||
v-for="link in essentialLinks"
|
<div v-if="isAdmin()">
|
||||||
:key="link.title"
|
<EssentialLink v-for="link in adminLinks" :key="link.title" v-bind="link" />
|
||||||
v-bind="link"
|
</div>
|
||||||
/>
|
|
||||||
</q-list>
|
</q-list>
|
||||||
</q-drawer>
|
</q-drawer>
|
||||||
|
|
||||||
@@ -54,19 +40,19 @@ import { useAuthStore } from 'stores/useAuthStore';
|
|||||||
const authStore = useAuthStore();
|
const authStore = useAuthStore();
|
||||||
|
|
||||||
const essentialLinks: EssentialLinkProps[] = [
|
const essentialLinks: EssentialLinkProps[] = [
|
||||||
{
|
{
|
||||||
title: 'ホーム',
|
title: 'ホーム',
|
||||||
caption: '設計書から導入する',
|
caption: '設計書から導入する',
|
||||||
icon: 'home',
|
icon: 'home',
|
||||||
link: '/',
|
link: '/',
|
||||||
target:'_self'
|
target: '_self'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'フローエディター',
|
title: 'フローエディター',
|
||||||
caption: 'イベントを設定する',
|
caption: 'イベントを設定する',
|
||||||
icon: 'account_tree',
|
icon: 'account_tree',
|
||||||
link: '/#/FlowChart',
|
link: '/#/FlowChart',
|
||||||
target:'_self'
|
target: '_self'
|
||||||
},
|
},
|
||||||
// {
|
// {
|
||||||
// title: '条件エディター',
|
// title: '条件エディター',
|
||||||
@@ -76,8 +62,8 @@ const essentialLinks: EssentialLinkProps[] = [
|
|||||||
// target:'_self'
|
// target:'_self'
|
||||||
// },
|
// },
|
||||||
{
|
{
|
||||||
title:'',
|
title: '',
|
||||||
isSeparator:true
|
isSeparator: true
|
||||||
},
|
},
|
||||||
// {
|
// {
|
||||||
// title:'Kintone ポータル',
|
// title:'Kintone ポータル',
|
||||||
@@ -151,8 +137,33 @@ const essentialLinks: EssentialLinkProps[] = [
|
|||||||
// }
|
// }
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const adminLinks: EssentialLinkProps[] = [
|
||||||
|
{
|
||||||
|
title: 'ユーザー管理',
|
||||||
|
caption: 'ユーザーを管理する',
|
||||||
|
icon: 'manage_accounts',
|
||||||
|
link: '/#/user',
|
||||||
|
target: '_self'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'ドメイン管理',
|
||||||
|
caption: 'kintoneのドメイン設定',
|
||||||
|
icon: 'domain',
|
||||||
|
link: '/#/domain',
|
||||||
|
target: '_self'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'ドメイン適用',
|
||||||
|
caption: 'ユーザー使用可能なドメインの設定',
|
||||||
|
icon: 'assignment_ind',
|
||||||
|
link: '/#/userDomain',
|
||||||
|
target: '_self'
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
const version = process.env.version;
|
const version = process.env.version;
|
||||||
const productName = process.env.productName;
|
const productName = process.env.productName;
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
authStore.toggleLeftMenu();
|
authStore.toggleLeftMenu();
|
||||||
});
|
});
|
||||||
@@ -160,4 +171,8 @@ onMounted(() => {
|
|||||||
function toggleLeftDrawer() {
|
function toggleLeftDrawer() {
|
||||||
authStore.toggleLeftMenu();
|
authStore.toggleLeftMenu();
|
||||||
}
|
}
|
||||||
|
function isAdmin(){
|
||||||
|
const permission = authStore.permissions;
|
||||||
|
return permission === 'admin'
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -1,6 +1,11 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="q-pa-md">
|
<div class="q-pa-md">
|
||||||
<q-table title="Treats" :rows="rows" :columns="columns" row-key="id" :filter="filter" :loading="loading">
|
<div class="q-gutter-sm row items-start">
|
||||||
|
<q-breadcrumbs>
|
||||||
|
<q-breadcrumbs-el icon="domain" label="ドメイン管理" />
|
||||||
|
</q-breadcrumbs>
|
||||||
|
</div>
|
||||||
|
<q-table title="Treats" :rows="rows" :columns="columns" row-key="id" :filter="filter" :loading="loading" :pagination="pagination">
|
||||||
|
|
||||||
<template v-slot:top>
|
<template v-slot:top>
|
||||||
<q-btn color="primary" :disable="loading" label="新規" @click="addRow" />
|
<q-btn color="primary" :disable="loading" label="新規" @click="addRow" />
|
||||||
@@ -130,7 +135,7 @@ const columns = [
|
|||||||
{ name: 'actions', label: '操作', field: 'actions' }
|
{ name: 'actions', label: '操作', field: 'actions' }
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const pagination = ref({ sortBy: 'id', descending: true, rowsPerPage: 20 });
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
const filter = ref('');
|
const filter = ref('');
|
||||||
const rows = ref([]);
|
const rows = ref([]);
|
||||||
|
|||||||
@@ -1,17 +1,39 @@
|
|||||||
<template>
|
<template>
|
||||||
|
|
||||||
<div class="q-pa-lg">
|
<div class="q-pa-lg">
|
||||||
<q-table grid grid-header title="Domain" selection="single" :rows="rows" :columns="columns"
|
<div class="q-gutter-sm row items-start">
|
||||||
v-model:selected="selected" row-key="name" :filter="filter" hide-header>
|
<q-breadcrumbs>
|
||||||
|
<q-breadcrumbs-el icon="assignment_ind" label="ドメイン適用" />
|
||||||
|
</q-breadcrumbs>
|
||||||
|
</div>
|
||||||
|
<q-table grid grid-header title="Domain" selection="single" :rows="rows" :columns="columns" row-key="name"
|
||||||
|
:filter="userDomainTableFilter" virtual-scroll v-model:pagination="pagination">
|
||||||
<template v-slot:top>
|
<template v-slot:top>
|
||||||
<div class="q-gutter-sm">
|
|
||||||
<q-btn class="q-mx-none" color="primary" label="追加" @click="newDomain()" />
|
<q-btn class="q-mx-none" color="primary" label="追加" @click="clickAddDomain()" />
|
||||||
</div>
|
|
||||||
<q-space />
|
<q-space />
|
||||||
<q-input borderless dense filled debounce="300" v-model="filter" placeholder="Search">
|
<div class="row q-gutter-md">
|
||||||
<template v-slot:append>
|
<q-item v-if="authStore.permissions === 'admin'" tag="label" dense @click="clickSwitchUser()">
|
||||||
<q-icon name="search" />
|
<q-item-section>
|
||||||
</template>
|
<q-item-label>適用するユーザ : </q-item-label>
|
||||||
</q-input>
|
</q-item-section>
|
||||||
|
<q-item-section avatar>
|
||||||
|
{{ currentUserName }}
|
||||||
|
</q-item-section>
|
||||||
|
</q-item>
|
||||||
|
|
||||||
|
<q-input borderless dense filled debounce="300" v-model="userDomainTableFilter" placeholder="Search">
|
||||||
|
<template v-slot:append>
|
||||||
|
<q-icon name="search" />
|
||||||
|
</template>
|
||||||
|
</q-input>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template v-slot:header>
|
||||||
|
<div style="height: 1dvh">
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template v-slot:item="props">
|
<template v-slot:item="props">
|
||||||
@@ -36,12 +58,12 @@
|
|||||||
<div style="width: 98%;">
|
<div style="width: 98%;">
|
||||||
<div class="row items-center justify-between">
|
<div class="row items-center justify-between">
|
||||||
<div class="q-table__grid-item-value"
|
<div class="q-table__grid-item-value"
|
||||||
:class="isActive(props.row.id) === 'Active' ? 'text-positive' : 'text-negative'">{{
|
:class="isActive(props.row.id) ? 'text-positive' : 'text-negative'">{{
|
||||||
isActive(props.row.id) }}</div>
|
isActive(props.row.id)?'既定':'' }}</div>
|
||||||
<div class="col-auto">
|
<div class="col-auto">
|
||||||
<q-btn v-if="isActive(props.row.id) !== 'Active'" flat
|
<q-btn v-if="!isActive(props.row.id)" flat
|
||||||
@click="activeDomain(props.row.id)">有効</q-btn>
|
@click="activeDomain(props.row.id)">既定にする</q-btn>
|
||||||
<q-btn flat @click="deleteConfirm(props.row)">削除</q-btn>
|
<q-btn flat @click="clickDeleteConfirm(props.row)">削除</q-btn>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -51,11 +73,35 @@
|
|||||||
</template>
|
</template>
|
||||||
</q-table>
|
</q-table>
|
||||||
|
|
||||||
<show-dialog v-model:visible="show" name="ドメイン" @close="closeDg">
|
<show-dialog v-model:visible="showAddDomainDg" name="ドメイン" @close="addUserDomainFinished">
|
||||||
<domain-select ref="domainDg" name="ドメイン" type="multiple"></domain-select>
|
<domain-select ref="addDomainRef" name="ドメイン" type="multiple"></domain-select>
|
||||||
</show-dialog>
|
</show-dialog>
|
||||||
|
|
||||||
<q-dialog v-model="confirm" persistent>
|
<show-dialog v-model:visible="showSwitchUserDd" name="ドメイン" minWidth="35vw" @close="switchUserFinished">
|
||||||
|
<template v-slot:toolbar>
|
||||||
|
<q-input dense placeholder="検索" v-model="switchUserFilter">
|
||||||
|
<template v-slot:append>
|
||||||
|
<q-icon name="search" />
|
||||||
|
</template>
|
||||||
|
</q-input>
|
||||||
|
</template>
|
||||||
|
<div class="q-gutter-md">
|
||||||
|
<q-item tag="label" class="q-pl-sm q-pr-none q-py-xs">
|
||||||
|
<q-item-section>
|
||||||
|
<q-item-label>他のユーザーを選択する</q-item-label>
|
||||||
|
</q-item-section>
|
||||||
|
<q-item-section avatar>
|
||||||
|
<q-toggle v-model="useOtherUser" />
|
||||||
|
</q-item-section>
|
||||||
|
</q-item>
|
||||||
|
<div v-if="useOtherUser">
|
||||||
|
<user-list ref="switchUserRef" name="ドメイン" :filter="switchUserFilter" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</show-dialog>
|
||||||
|
|
||||||
|
<q-dialog v-model="showDeleteConfirm" persistent>
|
||||||
<q-card>
|
<q-card>
|
||||||
<q-card-section class="row items-center">
|
<q-card-section class="row items-center">
|
||||||
<div class="q-ma-sm q-mt-md">
|
<div class="q-ma-sm q-mt-md">
|
||||||
@@ -66,7 +112,7 @@
|
|||||||
|
|
||||||
<q-card-actions align="right">
|
<q-card-actions align="right">
|
||||||
<q-btn flat label="Cancel" color="primary" v-close-popup />
|
<q-btn flat label="Cancel" color="primary" v-close-popup />
|
||||||
<q-btn flat label="OK" color="primary" v-close-popup @click="deleteDomain()" />
|
<q-btn flat label="OK" color="primary" v-close-popup @click="deleteDomainFinished()" />
|
||||||
</q-card-actions>
|
</q-card-actions>
|
||||||
</q-card>
|
</q-card>
|
||||||
</q-dialog>
|
</q-dialog>
|
||||||
@@ -74,22 +120,17 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, onMounted } from 'vue'
|
import { ref, onMounted, computed } from 'vue'
|
||||||
import ShowDialog from 'components/ShowDialog.vue';
|
import { api } from 'boot/axios';
|
||||||
import DomainSelect from 'components/DomainSelect.vue';
|
|
||||||
import { useAuthStore } from 'stores/useAuthStore';
|
import { useAuthStore } from 'stores/useAuthStore';
|
||||||
|
|
||||||
|
import ShowDialog from 'components/ShowDialog.vue';
|
||||||
|
import DomainSelect from 'components/DomainSelect.vue';
|
||||||
|
import UserList from 'components/UserList.vue';
|
||||||
|
|
||||||
const authStore = useAuthStore();
|
const authStore = useAuthStore();
|
||||||
import { api } from 'boot/axios';
|
const pagination = ref({ sortBy: 'id', rowsPerPage: 0 });
|
||||||
const domainDg = ref();
|
const rows = ref([] as any[]);
|
||||||
const selected = ref([])
|
|
||||||
|
|
||||||
const show = ref(false);
|
|
||||||
const confirm = ref(false)
|
|
||||||
const filter = ref()
|
|
||||||
|
|
||||||
let editId = ref(0);
|
|
||||||
let activedomainid = ref(0);
|
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
{ name: 'id' },
|
{ name: 'id' },
|
||||||
@@ -99,63 +140,96 @@ const columns = [
|
|||||||
{ name: 'kintonepwd' },
|
{ name: 'kintonepwd' },
|
||||||
{ name: 'active', field: 'active' }
|
{ name: 'active', field: 'active' }
|
||||||
]
|
]
|
||||||
|
const userDomainTableFilter = ref()
|
||||||
|
|
||||||
const rows = ref([] as any[]);
|
const currentUserName = ref('')
|
||||||
|
const useOtherUser = ref(false);
|
||||||
|
const otherUserId = ref('')
|
||||||
|
|
||||||
const isActive = (id: number) => {
|
let editId = ref(0);
|
||||||
if (id == activedomainid.value)
|
|
||||||
return "Active";
|
|
||||||
else
|
|
||||||
return "Inactive";
|
|
||||||
}
|
|
||||||
|
|
||||||
const newDomain = () => {
|
const showAddDomainDg = ref(false);
|
||||||
|
const addDomainRef = ref();
|
||||||
|
|
||||||
|
const clickAddDomain = () => {
|
||||||
editId.value = 0;
|
editId.value = 0;
|
||||||
show.value = true;
|
showAddDomainDg.value = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const addUserDomainFinished = (val: string) => {
|
||||||
const activeDomain = (id: number) => {
|
|
||||||
api.put(`api/activedomain/` + id).then(() => {
|
|
||||||
getDomain();
|
|
||||||
})
|
|
||||||
};
|
|
||||||
|
|
||||||
const deleteConfirm = (row: object) => {
|
|
||||||
confirm.value = true;
|
|
||||||
editId.value = row.id;
|
|
||||||
};
|
|
||||||
|
|
||||||
const deleteDomain = () => {
|
|
||||||
console.log(authStore.getCurrentDomain);
|
|
||||||
|
|
||||||
api.delete(`api/domain/${editId.value}/${authStore.userId}`).then(() => {
|
|
||||||
getDomain();
|
|
||||||
})
|
|
||||||
editId.value = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
const closeDg = (val: string) => {
|
|
||||||
if (val == 'OK') {
|
if (val == 'OK') {
|
||||||
let dodmainids = [];
|
let dodmainids = [];
|
||||||
let domains = JSON.parse(JSON.stringify(domainDg.value.selected));
|
let domains = JSON.parse(JSON.stringify(addDomainRef.value.selected));
|
||||||
for (var key in domains) {
|
for (var key in domains) {
|
||||||
dodmainids.push(domains[key].id);
|
dodmainids.push(domains[key].id);
|
||||||
}
|
}
|
||||||
api.post(`api/domain/${authStore.userId}`, dodmainids).then(() => { getDomain(); });
|
api.post(`api/domain/${useOtherUser.value ? otherUserId.value : authStore.userId}`, dodmainids)
|
||||||
|
.then(() => { getDomain(useOtherUser.value ? otherUserId.value : undefined); });
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
const getDomain = async () => {
|
|
||||||
const resp = await api.get(`api/activedomain`);
|
const showDeleteConfirm = ref(false)
|
||||||
activedomainid.value = resp.data.id;
|
|
||||||
const domainResult = await api.get(`api/domain`);
|
const clickDeleteConfirm = (row: any) => {
|
||||||
|
showDeleteConfirm.value = true;
|
||||||
|
editId.value = row.id;
|
||||||
|
};
|
||||||
|
|
||||||
|
const deleteDomainFinished = () => {
|
||||||
|
api.delete(`api/domain/${editId.value}/${useOtherUser.value ? otherUserId.value : authStore.userId}`).then(() => {
|
||||||
|
getDomain(useOtherUser.value ? otherUserId.value : undefined);
|
||||||
|
})
|
||||||
|
editId.value = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
const activeDomain = (id: number) => {
|
||||||
|
api.put(`api/activedomain/${id}${useOtherUser.value ? `?userId=${otherUserId.value}` : ''}`)
|
||||||
|
.then(() => { getDomain(useOtherUser.value ? otherUserId.value : undefined); })
|
||||||
|
};
|
||||||
|
|
||||||
|
let activeDomainId = ref(0);
|
||||||
|
|
||||||
|
const isActive = computed(() => (id: number) => {
|
||||||
|
return id == activeDomainId.value;
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
const showSwitchUserDd = ref(false);
|
||||||
|
const switchUserRef = ref();
|
||||||
|
const switchUserFilter = ref('')
|
||||||
|
|
||||||
|
const clickSwitchUser = () => {
|
||||||
|
showSwitchUserDd.value = true;
|
||||||
|
useOtherUser.value = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
const switchUserFinished = async (val: string) => {
|
||||||
|
if (val == 'OK') {
|
||||||
|
if (useOtherUser.value) {
|
||||||
|
const user = switchUserRef.value.selected[0]
|
||||||
|
currentUserName.value = user.email;
|
||||||
|
otherUserId.value = user.id
|
||||||
|
await getDomain(user.id)
|
||||||
|
} else {
|
||||||
|
currentUserName.value = authStore.userInfo.email
|
||||||
|
await getDomain();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getDomain = async (userId? : string) => {
|
||||||
|
const resp = await api.get(`api/activedomain${useOtherUser.value ? `?userId=${otherUserId.value}` : ''}`);
|
||||||
|
activeDomainId.value = resp?.data?.id;
|
||||||
|
const domainResult = userId ? await api.get(`api/domain?userId=${userId}`) : await api.get(`api/domain`);
|
||||||
const domains = domainResult.data as any[];
|
const domains = domainResult.data as any[];
|
||||||
rows.value = domains.map((item) => {
|
rows.value = domains.map((item) => {
|
||||||
return { id: item.id, name: item.name, url: item.url, kintoneuser: item.kintoneuser, kintonepwd: item.kintonepwd }
|
return { id: item.id, name: item.name, url: item.url, kintoneuser: item.kintoneuser, kintonepwd: item.kintonepwd }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
|
currentUserName.value = authStore.userInfo.email
|
||||||
await getDomain();
|
await getDomain();
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
307
frontend/src/pages/UserManagement.vue
Normal file
307
frontend/src/pages/UserManagement.vue
Normal file
@@ -0,0 +1,307 @@
|
|||||||
|
<template>
|
||||||
|
<div class="q-pa-md">
|
||||||
|
<div class="q-gutter-sm row items-start">
|
||||||
|
<q-breadcrumbs>
|
||||||
|
<q-breadcrumbs-el icon="manage_accounts" label="ユーザー管理" />
|
||||||
|
</q-breadcrumbs>
|
||||||
|
</div>
|
||||||
|
<q-table title="ユーザーリスト" :rows="rows" :columns="columns" row-key="id" :filter="filter" :loading="loading"
|
||||||
|
:pagination="pagination" >
|
||||||
|
|
||||||
|
<template v-slot:top>
|
||||||
|
<q-btn color="primary" :disable="loading" label="新規" @click="addRow" />
|
||||||
|
<q-space />
|
||||||
|
<q-input borderless dense filled debounce="300" v-model="filter" placeholder="検索">
|
||||||
|
<template v-slot:append>
|
||||||
|
<q-icon name="search" />
|
||||||
|
</template>
|
||||||
|
</q-input>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template v-slot:body-cell-status="props">
|
||||||
|
<q-td :props="props">
|
||||||
|
<div class="row">
|
||||||
|
<div v-if="props.row.isActive">
|
||||||
|
<q-chip square color="positive" text-color="white" icon="done" label="使用可能" size="sm" />
|
||||||
|
</div>
|
||||||
|
<div v-else>
|
||||||
|
<q-chip square color="negative" text-color="white" icon="block" label="使用不可" size="sm" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<q-chip v-if="props.row.isSuperuser" square color="accent" text-color="white" icon="admin_panel_settings"
|
||||||
|
label="システム管理者" size="sm" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</q-td>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template v-slot:header-cell-status="p">
|
||||||
|
<q-th :props="p">
|
||||||
|
<div class="row items-center">
|
||||||
|
<label class="q-mr-md">{{ p.col.label }}</label>
|
||||||
|
<q-select v-model="statusFilter" :options="options" @update:model-value="updateStatusFilter" borderless
|
||||||
|
dense options-dense style="font-size: 12px; padding-top: 1px;" />
|
||||||
|
</div>
|
||||||
|
</q-th>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template v-slot:body-cell-actions="p">
|
||||||
|
<q-td :props="p">
|
||||||
|
<q-btn-group flat>
|
||||||
|
<q-btn flat color="primary" padding="xs" size="1em" icon="edit_note" @click="editRow(p.row)" />
|
||||||
|
<q-btn flat color="negative" padding="xs" size="1em" icon="delete_outline" @click="removeRow(p.row)" />
|
||||||
|
</q-btn-group>
|
||||||
|
</q-td>
|
||||||
|
</template>
|
||||||
|
</q-table>
|
||||||
|
|
||||||
|
<q-dialog :model-value="show" persistent>
|
||||||
|
<q-card style="min-width: 36em">
|
||||||
|
<q-form class="q-gutter-md" @submit="onSubmit" autocomplete="off">
|
||||||
|
<q-card-section>
|
||||||
|
<div class="text-h6 q-ma-sm">K-True Account</div>
|
||||||
|
</q-card-section>
|
||||||
|
|
||||||
|
<q-card-section class="q-pt-none q-mt-none">
|
||||||
|
<div class="q-gutter-lg">
|
||||||
|
|
||||||
|
<q-input filled v-model="firstName" label="氏名 *" hint="ユーザーの氏名を入力してください" lazy-rules
|
||||||
|
:rules="[val => val && val.length > 0 || 'ユーザーの氏名を入力してください。']" />
|
||||||
|
|
||||||
|
<q-input filled v-model="lastName" label="苗字 *" hint="ユーザーの苗字を入力してください" lazy-rules
|
||||||
|
:rules="[val => val && val.length > 0 || 'ユーザーの苗字を入力してください']" />
|
||||||
|
|
||||||
|
<q-input filled type="email" v-model="email" label="電子メール *" hint="電子メール、ログインとしても使用" lazy-rules
|
||||||
|
:rules="[val => val && val.length > 0 || '電子メールを入力してください']" autocomplete="new-password" />
|
||||||
|
|
||||||
|
<q-input v-if="isCreate" v-model="pwd" filled :type="isPwd ? 'password' : 'text'" hint="パスワード"
|
||||||
|
label="パスワード" :disable="!isCreate" lazy-rules
|
||||||
|
:rules="[val => val && val.length > 0 || 'Please type something']" autocomplete="new-password">
|
||||||
|
<template v-slot:append>
|
||||||
|
<q-icon :name="isPwd ? 'visibility_off' : 'visibility'" class="cursor-pointer"
|
||||||
|
@click="isPwd = !isPwd" />
|
||||||
|
</template>
|
||||||
|
</q-input>
|
||||||
|
|
||||||
|
<q-item tag="label" class="q-pl-sm q-pr-none q-py-xs">
|
||||||
|
<q-item-section>
|
||||||
|
<q-item-label>システム管理者</q-item-label>
|
||||||
|
</q-item-section>
|
||||||
|
<q-item-section avatar>
|
||||||
|
<q-toggle v-model="isSuperuser" />
|
||||||
|
</q-item-section>
|
||||||
|
</q-item>
|
||||||
|
|
||||||
|
<q-item tag="label" class="q-pl-sm q-pr-none q-py-xs">
|
||||||
|
<q-item-section>
|
||||||
|
<q-item-label>使用可能</q-item-label>
|
||||||
|
</q-item-section>
|
||||||
|
<q-item-section avatar>
|
||||||
|
<q-toggle v-model="isActive" />
|
||||||
|
</q-item-section>
|
||||||
|
</q-item>
|
||||||
|
|
||||||
|
<div class="q-gutter-y-md" v-if="!isCreate">
|
||||||
|
<q-separator />
|
||||||
|
|
||||||
|
<q-item tag="label" class="q-pl-sm q-pr-none q-py-xs">
|
||||||
|
<q-item-section>
|
||||||
|
<q-item-label>パスワードリセット</q-item-label>
|
||||||
|
</q-item-section>
|
||||||
|
<q-item-section avatar>
|
||||||
|
<q-toggle v-model="resetPsw" />
|
||||||
|
</q-item-section>
|
||||||
|
</q-item>
|
||||||
|
|
||||||
|
<q-input v-model="pwd" filled :type="isPwd ? 'password' : 'text'" hint="パスワードを入力してください" label="パスワード"
|
||||||
|
:disable="!resetPsw" lazy-rules :rules="[val => val && val.length > 0 || 'Please type something']"
|
||||||
|
autocomplete="new-password">
|
||||||
|
<template v-slot:append>
|
||||||
|
<q-icon :name="isPwd ? 'visibility_off' : 'visibility'" class="cursor-pointer"
|
||||||
|
@click="isPwd = !isPwd" />
|
||||||
|
</template>
|
||||||
|
</q-input>
|
||||||
|
<!-- <q-btn label="asdf"/> -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</q-card-section>
|
||||||
|
<q-card-actions align="right" class="text-primary q-mb-md q-mx-sm">
|
||||||
|
<q-btn label="保存" type="submit" color="primary" />
|
||||||
|
<q-btn label="キャンセル" type="cancel" color="primary" flat class="q-ml-sm" @click="closeDg()" />
|
||||||
|
</q-card-actions>
|
||||||
|
</q-form>
|
||||||
|
</q-card>
|
||||||
|
|
||||||
|
</q-dialog>
|
||||||
|
|
||||||
|
<q-dialog v-model="confirm" persistent>
|
||||||
|
<q-card>
|
||||||
|
<q-card-section class="row items-center">
|
||||||
|
<q-icon name="warning" color="warning" size="2em" />
|
||||||
|
<span class="q-ml-sm">削除してもよろしいですか?</span>
|
||||||
|
</q-card-section>
|
||||||
|
|
||||||
|
<q-card-actions align="right">
|
||||||
|
<q-btn flat label="Cancel" color="primary" v-close-popup />
|
||||||
|
<q-btn flat label="OK" color="primary" v-close-popup @click="deleteUser()" />
|
||||||
|
</q-card-actions>
|
||||||
|
</q-card>
|
||||||
|
</q-dialog>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, onMounted } from 'vue';
|
||||||
|
import { api } from 'boot/axios';
|
||||||
|
|
||||||
|
const columns = [
|
||||||
|
{ name: 'id', label: 'ID', field: 'id', align: 'left', sortable: true },
|
||||||
|
{ name: 'firstName', label: '氏名', field: 'firstName', align: 'left', sortable: true },
|
||||||
|
{ name: 'lastName', label: '苗字', field: 'lastName', align: 'left', sortable: true },
|
||||||
|
{ name: 'email', label: '電子メール', field: 'email', align: 'left', sortable: true },
|
||||||
|
{ name: 'status', label: '状況', field: 'status', align: 'left' },
|
||||||
|
{ name: 'actions', label: '操作', field: 'actions' }
|
||||||
|
];
|
||||||
|
|
||||||
|
const pagination = ref({ sortBy: 'id', descending: true, rowsPerPage: 20 });
|
||||||
|
|
||||||
|
const loading = ref(false);
|
||||||
|
const filter = ref('');
|
||||||
|
const statusFilter = ref('全データ');
|
||||||
|
const rows = ref([]);
|
||||||
|
const show = ref(false);
|
||||||
|
const confirm = ref(false);
|
||||||
|
const resetPsw = ref(false);
|
||||||
|
|
||||||
|
const firstName = ref('');
|
||||||
|
const lastName = ref('');
|
||||||
|
const email = ref('');
|
||||||
|
const isSuperuser = ref(false);
|
||||||
|
const isActive = ref(true);
|
||||||
|
|
||||||
|
const isPwd = ref(true);
|
||||||
|
const pwd = ref('');
|
||||||
|
const isCreate = ref(true);
|
||||||
|
let editId = ref(0);
|
||||||
|
|
||||||
|
const getUsers = async (filter = () => true) => {
|
||||||
|
loading.value = true;
|
||||||
|
const result = await api.get(`api/v1/users`);
|
||||||
|
rows.value = result.data.map((item) => {
|
||||||
|
return { id: item.id, firstName: item.first_name, lastName: item.last_name, email: item.email, isSuperuser: item.is_superuser, isActive: item.is_active }
|
||||||
|
}).filter(filter);
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const updateStatusFilter = (status) => {
|
||||||
|
switch (status) {
|
||||||
|
case 'システム管理者のみ':
|
||||||
|
getUsers((row) => row.isSuperuser)
|
||||||
|
break;
|
||||||
|
case '使用可能':
|
||||||
|
getUsers((row) => row.isActive)
|
||||||
|
break;
|
||||||
|
case '使用不可':
|
||||||
|
getUsers((row) => !row.isActive)
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
getUsers()
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
await getUsers();
|
||||||
|
})
|
||||||
|
|
||||||
|
const options = ['全データ', 'システム管理者のみ', '使用可能', '使用不可']
|
||||||
|
|
||||||
|
// emulate fetching data from server
|
||||||
|
const addRow = () => {
|
||||||
|
// editId.value
|
||||||
|
onReset();
|
||||||
|
show.value = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const removeRow = (row) => {
|
||||||
|
confirm.value = true;
|
||||||
|
editId.value = row.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
const deleteUser = () => {
|
||||||
|
api.delete(`api/v1/users/${editId.value}`).then(() => {
|
||||||
|
getUsers();
|
||||||
|
})
|
||||||
|
editId.value = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
const editRow = (row) => {
|
||||||
|
isCreate.value = false
|
||||||
|
editId.value = row.id;
|
||||||
|
|
||||||
|
firstName.value = row.firstName;
|
||||||
|
lastName.value = row.lastName;
|
||||||
|
email.value = row.email;
|
||||||
|
pwd.value = row.password;
|
||||||
|
|
||||||
|
isSuperuser.value = row.isSuperuser;
|
||||||
|
isActive.value = row.isActive;
|
||||||
|
|
||||||
|
isPwd.value = true;
|
||||||
|
show.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
const closeDg = () => {
|
||||||
|
show.value = false;
|
||||||
|
onReset();
|
||||||
|
}
|
||||||
|
|
||||||
|
const onSubmit = () => {
|
||||||
|
if (editId.value !== 0) {
|
||||||
|
api.put(`api/v1/users/${editId.value}`, {
|
||||||
|
'first_name': firstName.value,
|
||||||
|
'last_name': lastName.value,
|
||||||
|
'is_superuser': isSuperuser.value,
|
||||||
|
'is_active': isActive.value,
|
||||||
|
'email': email.value,
|
||||||
|
...(isCreate.value || resetPsw.value ? { password: pwd.value } : {})
|
||||||
|
}).then(() => {
|
||||||
|
getUsers();
|
||||||
|
closeDg();
|
||||||
|
onReset();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
api.post(`api/v1/users`, {
|
||||||
|
'id': 0,
|
||||||
|
'first_name': firstName.value,
|
||||||
|
'last_name': lastName.value,
|
||||||
|
'is_superuser': isSuperuser.value,
|
||||||
|
'is_active': isActive.value,
|
||||||
|
'email': email.value,
|
||||||
|
'password': pwd.value
|
||||||
|
}).then(() => {
|
||||||
|
getUsers();
|
||||||
|
closeDg();
|
||||||
|
onReset();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const onReset = () => {
|
||||||
|
firstName.value = '';
|
||||||
|
lastName.value = '';
|
||||||
|
email.value = '';
|
||||||
|
pwd.value = '';
|
||||||
|
isActive.value = true;
|
||||||
|
isSuperuser.value = false;
|
||||||
|
isPwd.value = true;
|
||||||
|
editId.value = 0;
|
||||||
|
isCreate.value = true;
|
||||||
|
resetPsw.value = false
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -26,6 +26,7 @@ const routes: RouteRecordRaw[] = [
|
|||||||
{ path: 'right', component: () => import('pages/testRight.vue') },
|
{ path: 'right', component: () => import('pages/testRight.vue') },
|
||||||
{ path: 'domain', component: () => import('pages/TenantDomain.vue') },
|
{ path: 'domain', component: () => import('pages/TenantDomain.vue') },
|
||||||
{ path: 'userdomain', component: () => import('pages/UserDomain.vue')},
|
{ path: 'userdomain', component: () => import('pages/UserDomain.vue')},
|
||||||
|
{ path: 'user', component: () => import('pages/UserManagement.vue')},
|
||||||
{ path: 'condition', component: () => import('pages/conditionPage.vue') }
|
{ path: 'condition', component: () => import('pages/conditionPage.vue') }
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -3,12 +3,20 @@ import { api } from 'boot/axios';
|
|||||||
import { router } from 'src/router';
|
import { router } from 'src/router';
|
||||||
import { IDomainInfo } from '../types/ActionTypes';
|
import { IDomainInfo } from '../types/ActionTypes';
|
||||||
import { jwtDecode } from 'jwt-decode';
|
import { jwtDecode } from 'jwt-decode';
|
||||||
|
interface UserInfo {
|
||||||
|
firstName: string;
|
||||||
|
lastName: string;
|
||||||
|
email: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface IUserState {
|
export interface IUserState {
|
||||||
token?: string;
|
token?: string;
|
||||||
returnUrl: string;
|
returnUrl: string;
|
||||||
currentDomain: IDomainInfo;
|
currentDomain: IDomainInfo;
|
||||||
LeftDrawer: boolean;
|
LeftDrawer: boolean;
|
||||||
userId?: string;
|
userId?: string;
|
||||||
|
userInfo: UserInfo;
|
||||||
|
permissions: 'admin' | 'user';
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useAuthStore = defineStore('auth', {
|
export const useAuthStore = defineStore('auth', {
|
||||||
@@ -18,6 +26,8 @@ export const useAuthStore = defineStore('auth', {
|
|||||||
LeftDrawer: false,
|
LeftDrawer: false,
|
||||||
currentDomain: {} as IDomainInfo,
|
currentDomain: {} as IDomainInfo,
|
||||||
userId: '',
|
userId: '',
|
||||||
|
userInfo: {} as UserInfo,
|
||||||
|
permissions: 'user',
|
||||||
}),
|
}),
|
||||||
getters: {
|
getters: {
|
||||||
toggleLeftDrawer(): boolean {
|
toggleLeftDrawer(): boolean {
|
||||||
@@ -36,9 +46,12 @@ export const useAuthStore = defineStore('auth', {
|
|||||||
const result = await api.post(`api/token`, params);
|
const result = await api.post(`api/token`, params);
|
||||||
console.info(result);
|
console.info(result);
|
||||||
this.token = result.data.access_token;
|
this.token = result.data.access_token;
|
||||||
this.userId = jwtDecode(result.data.access_token).sub;
|
const tokenJson = jwtDecode(result.data.access_token);
|
||||||
|
this.userId = tokenJson.sub;
|
||||||
|
this.permissions = (tokenJson as any).permissions ?? 'user';
|
||||||
api.defaults.headers['Authorization'] = 'Bearer ' + this.token;
|
api.defaults.headers['Authorization'] = 'Bearer ' + this.token;
|
||||||
this.currentDomain = await this.getCurrentDomain();
|
this.currentDomain = await this.getCurrentDomain();
|
||||||
|
this.userInfo = await this.getUserInfo();
|
||||||
router.push(this.returnUrl || '/');
|
router.push(this.returnUrl || '/');
|
||||||
return true;
|
return true;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -63,6 +76,14 @@ export const useAuthStore = defineStore('auth', {
|
|||||||
kintoneUrl: data.url,
|
kintoneUrl: data.url,
|
||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
|
async getUserInfo():Promise<UserInfo>{
|
||||||
|
const resp = (await api.get(`api/v1/users/me`)).data;
|
||||||
|
return {
|
||||||
|
firstName: resp.first_name,
|
||||||
|
lastName: resp.last_name,
|
||||||
|
email: resp.email,
|
||||||
|
}
|
||||||
|
},
|
||||||
logout() {
|
logout() {
|
||||||
this.token = '';
|
this.token = '';
|
||||||
this.currentDomain = {} as IDomainInfo; // 清空当前域
|
this.currentDomain = {} as IDomainInfo; // 清空当前域
|
||||||
|
|||||||
Reference in New Issue
Block a user