Add share manage dialog

This commit is contained in:
xue jiahao
2024-12-16 14:47:03 +08:00
parent 78e7f1c840
commit c0bda31353
7 changed files with 190 additions and 38 deletions

View File

@@ -0,0 +1,19 @@
<template>
<q-badge v-if="isOwner" color="purple">所有者</q-badge>
<q-badge v-else-if="isManager" color="primary">管理者</q-badge>
</template>
<script setup lang="ts">
import { computed } from 'vue';
import { IDomainOwnerDisplay } from '../../types/DomainTypes';
interface Props {
user: { id: number };
domain: IDomainOwnerDisplay;
}
const props = defineProps<Props>();
const isOwner = computed(() => props.user.id === props.domain.owner.id);
const isManager = computed(() => props.user.id === props.domain.owner.id); // TODO
</script>

View File

@@ -2,7 +2,7 @@
<q-dialog :auto-close="false" :model-value="visible" persistent bordered>
<q-card class="dialog-content" >
<q-toolbar class="bg-grey-4">
<q-toolbar-title>{{domain.name}}のドメイン利用権限設定</q-toolbar-title>
<q-toolbar-title>{{ dialogTitle }}</q-toolbar-title>
<q-btn flat round dense icon="close" @click="close" />
</q-toolbar>
@@ -23,7 +23,7 @@
<template v-slot:selected-item="scope">
<span v-if="canSharedUserFilter">
{{ canSharedUserFilter.fullName }} {{ canSharedUserFilter.email }}
<q-badge v-if="isOwner(scope.opt.id)" color="purple">所有者</q-badge>
<role-label :domain="domain" :user="scope.opt"></role-label>
</span>
</template>
@@ -38,18 +38,17 @@
<q-item-section>{{scope.opt.email}}</q-item-section>
<q-item-section side>
<div style="width: 4em;">
<q-badge v-if="isOwner(scope.opt.id)" color="purple">所有者</q-badge>
<role-label :domain="domain" :user="scope.opt"></role-label>
</div>
</q-item-section>
</q-item>
</template>
</q-select>
<sharing-user-list class="q-mt-md" style="height: 330px" :users="sharedUsers" :loading="loading" title="ドメイン利用権限を持つユーザー">
<sharing-user-list class="q-mt-md" style="height: 330px" :users="sharedUsers" :loading="loading" :title="userListTitle">
<template v-slot:body-cell-role="{ row }">
<q-td>
<q-badge v-if="row.role == 2" color="purple">所有者</q-badge>
<!-- <q-badge v-else-if="row.id === domain.owner.id" color="primary">管理者</q-badge> -->
<role-label :domain="domain" :user="row"></role-label>
</q-td>
</template>
@@ -74,16 +73,22 @@ import { IDomainOwnerDisplay } from '../../types/DomainTypes';
import { IUser, IUserDisplay } from '../../types/UserTypes';
import { api } from 'boot/axios';
import SharingUserList from 'components/ShareDomain/SharingUserList.vue';
import RoleLabel from 'components/ShareDomain/RoleLabel.vue';
import { Dialog } from 'quasar'
interface Props {
modelValue: boolean;
domain: IDomainOwnerDisplay;
dialogTitle: string;
userListTitle: string;
shareApi: (user: IUserDisplay, domain: IDomainOwnerDisplay) => Promise<any>;
removeSharedApi: (user: IUserDisplay, domain: IDomainOwnerDisplay) => Promise<any>;
getSharedApi: (domain: IDomainOwnerDisplay) => Promise<any>;
}
interface IUserDisplayWithShareRole extends IUserDisplay {
isRemoving: boolean;
role: number; // 2: 所有者1: 管理者, 0: 利用者
role: number;
}
const props = defineProps<Props>();
@@ -126,6 +131,9 @@ watch(
loading.value = false;
addLoading.value = false;
if (newValue) {
if (Object.keys(allUsers.value).length == 0) {
await getUsers();
}
await loadShared();
}
}
@@ -167,10 +175,7 @@ const close = () => {
const shareTo = async (user: IUserDisplayWithShareRole) => {
addLoading.value = true;
loading.value = true;
await api.post(`api/userdomain`, {
'userid': user.id,
'domainid': props.domain.id
})
await props.shareApi(user, props.domain);
await loadShared();
canSharedUserFilter.value = undefined;
loading.value = false;
@@ -180,7 +185,7 @@ const shareTo = async (user: IUserDisplayWithShareRole) => {
const removeShareTo = async (user: IUserDisplayWithShareRole) => {
loading.value = true;
user.isRemoving = true;
await api.delete(`api/domain/${props.domain.id}/${user.id}`)
await props.removeSharedApi(user, props.domain);
await loadShared();
loading.value = false;
};
@@ -189,10 +194,18 @@ const loadShared = async () => {
loading.value = true;
sharedUsersIdSet.clear();
const { data } = await api.get(`/api/domainshareduser/${props.domain.id}`);
const { data } = await props.getSharedApi(props.domain);
sharedUsers.value = data.data.map((item: IUser) => {
const val = itemToDisplay(item);
sharedUsersIdSet.add(val.id);
// for sort
if (isOwner(item.id)) {
val.role = 2;
} else if (isManager(item.id)) {
val.role = 1;
} else {
val.role = 0;
}
return val;
}).reverse().sort((a: IUserDisplayWithShareRole, b: IUserDisplayWithShareRole) => b.role - a.role);
@@ -202,24 +215,21 @@ const loadShared = async () => {
loading.value = false;
}
onMounted(async () => {
await getUsers();
})
function isOwner(userId: number) {
return userId === props.domain?.owner?.id
}
function isManager(userId: number) {
return false // TODO
}
const getUsers = async () => {
if (Object.keys(allUsers.value).length > 0) {
return;
}
loading.value = true;
const result = await api.get(`api/v1/users`);
allUsers.value = result.data.data.map(itemToDisplay);
loading.value = false;
}
function isOwner(userId: number) {
return userId === props.domain.owner.id
}
const itemToDisplay = (item: IUser) => {
return {
id: item.id,
@@ -230,9 +240,10 @@ const itemToDisplay = (item: IUser) => {
email: item.email,
isSuperuser: item.is_superuser,
isActive: item.is_active,
role: isOwner(item.id) ? 2 : 0, // TODO
role: 0,
} as IUserDisplayWithShareRole
}
</script>
<style lang="scss">

View File

@@ -0,0 +1,56 @@
<template>
<share-domain-dialog
:dialogTitle="`「${domain.name}」のドメイン管理権限設定`"
userListTitle="ドメイン管理権限を持つユーザー"
:domain="domain"
:share-api="shareApi"
:remove-shared-api="removeSharedApi"
:get-shared-api="getSharedApi"
:model-value="modelValue"
@update:modelValue="updateModelValue"
@close="close"
/>
</template>
<script setup lang="ts">
import { defineProps, defineEmits } from 'vue';
import ShareDomainDialog from 'components/ShareDomain/ShareDomainDialog.vue';
import { IUserDisplay } from '../../types/UserTypes';
import { IDomainOwnerDisplay } from '../../types/DomainTypes';
import { api } from 'boot/axios';
interface Props {
modelValue: boolean;
domain: IDomainOwnerDisplay;
}
const props = defineProps<Props>();
async function shareApi(user: IUserDisplay, domain: IDomainOwnerDisplay) {
return api.post(`api/managedomain`, {
userid: user.id,
domainid: domain.id,
});
}
async function removeSharedApi(user: IUserDisplay, domain: IDomainOwnerDisplay) {
return api.delete(`api/managedomain/${domain.id}/${user.id}`);
}
async function getSharedApi(domain: IDomainOwnerDisplay) {
return api.get(`/api/managedomainuser/${domain.id}`);
}
const emit = defineEmits<{
(e: 'update:modelValue', value: boolean): void;
(e: 'close'): void;
}>();
const updateModelValue = (value: boolean) => {
emit('update:modelValue', value);
};
const close = () => {
emit('close');
};
</script>

View File

@@ -0,0 +1,56 @@
<template>
<share-domain-dialog
:dialogTitle="`「${domain.name}」のドメイン利用権限設定`"
userListTitle="ドメイン利用権限を持つユーザー"
:domain="domain"
:share-api="shareApi"
:remove-shared-api="removeSharedApi"
:get-shared-api="getSharedApi"
:model-value="modelValue"
@update:modelValue="updateModelValue"
@close="close"
/>
</template>
<script setup lang="ts">
import { defineProps, defineEmits } from 'vue';
import ShareDomainDialog from 'components/ShareDomain/ShareDomainDialog.vue';
import { IUserDisplay } from '../../types/UserTypes';
import { IDomainOwnerDisplay } from '../../types/DomainTypes';
import { api } from 'boot/axios';
interface Props {
modelValue: boolean;
domain: IDomainOwnerDisplay;
}
const props = defineProps<Props>();
async function shareApi(user: IUserDisplay, domain: IDomainOwnerDisplay) {
return api.post(`api/userdomain`, {
userid: user.id,
domainid: domain.id,
});
}
async function removeSharedApi(user: IUserDisplay, domain: IDomainOwnerDisplay) {
return api.delete(`api/domain/${domain.id}/${user.id}`);
}
async function getSharedApi(domain: IDomainOwnerDisplay) {
return api.get(`/api/domainshareduser/${domain.id}`);
}
const emit = defineEmits<{
(e: 'update:modelValue', value: boolean): void;
(e: 'close'): void;
}>();
const updateModelValue = (value: boolean) => {
emit('update:modelValue', value);
};
const close = () => {
emit('close');
};
</script>

View File

@@ -44,7 +44,7 @@ const columns = [
{ name: 'id', label: 'ID', field: 'id', align: 'left', sortable: true },
{ name: 'fullName', label: '名前', field: 'fullName', align: 'left', sortable: true },
{ name: 'email', label: '電子メール', field: 'email', align: 'left', sortable: true },
{ name: 'role', label: '権限', field: 'role', align: 'left', sortable: true },
{ name: 'role', label: '', field: 'role', align: 'left', sortable: false },
{ name: 'actions', label: '', field: 'actions', sortable: false },
];

View File

@@ -115,7 +115,7 @@
<!-- -1 loading -->
<q-card-section v-if="deleteLoadingState == -1" class="row items-center">
<q-spinner color="primary" size="2em"/>
<span class="q-ml-sm">ドメイン利用権限を確認中</span>
<span class="q-ml-sm">ドメイン利用/管理権限を確認中</span>
</q-card-section>
<!-- > 0 can't delete -->
<q-card-section v-else-if="deleteLoadingState > 0" class="row items-center">
@@ -131,14 +131,15 @@
<q-card-actions align="right">
<q-btn flat label="キャンセル" color="primary" v-close-popup />
<!-- > 0 can't delete -->
<q-btn v-if="deleteLoadingState > 0" label="実行" color="primary" v-close-popup @click="openShareDg(editId)" />
<q-btn v-if="deleteLoadingState > 0" label="実行" color="primary" v-close-popup @click="openShareDg(SHARE_MANAGE, editId)" />
<!-- 0/-2 can delete -->
<q-btn flat v-else label="OK" :disabled="deleteLoadingState == -1" :loading="deleteLoadingState == -2" color="primary" @click="deleteDomain()" />
</q-card-actions>
</q-card>
</q-dialog>
<share-domain-dialog v-model="shareDg" :domain="shareDomain" @close="closeShareDg()" />
<share-usage-dialog v-model="shareDg" :domain="shareDomain" @close="shareDg = false" />
<share-manage-dialog v-model="shareManageDg" :domain="shareDomain" @close="shareManageDg = false" />
</div>
</template>
@@ -147,7 +148,8 @@
import { ref, onMounted, computed } from 'vue';
import { api } from 'boot/axios';
import { useAuthStore } from 'stores/useAuthStore';
import ShareDomainDialog from 'components/ShareDomain/ShareDomainDialog.vue';
import ShareUsageDialog from 'components/ShareDomain/ShareUsageDialog.vue';
import ShareManageDialog from 'components/ShareDomain/ShareManageDialog.vue';
import TableActionMenu from 'components/TableActionMenu.vue';
import { IDomain, IDomainDisplay, IDomainOwnerDisplay, IDomainSubmit } from '../types/DomainTypes';
@@ -196,6 +198,7 @@ const domainActive = ref(true);
const isCreate = ref(true);
let editId = ref(0);
const shareDg = ref(false);
const shareManageDg = ref(false);
const shareDomain = ref<IDomainOwnerDisplay>({} as IDomainOwnerDisplay);
const activeOptions = [
@@ -219,9 +222,13 @@ const activeFilterUpdate = (option: {value: number}) => {
}
}
const SHARE_USE = 'use';
const SHARE_MANAGE = 'manage';
const actionList = [
{ label: '編集', icon: 'edit_note', action: editRow },
{ label: '利用権限設定', icon: 'person_add_alt', action: openShareDg },
{ label: '利用権限設定', icon: 'person_add_alt', action: (row: IDomainOwnerDisplay) => {openShareDg(SHARE_USE, row)} },
{ label: '管理権限設定', icon: 'add_moderator', action: (row: IDomainOwnerDisplay) => {openShareDg(SHARE_MANAGE, row)} },
{ separator: true },
{ label: '削除', icon: 'delete_outline', class: 'text-red', action: removeRow },
];
@@ -340,18 +347,18 @@ const onSubmit = () => {
})
}
function openShareDg(row: IDomainOwnerDisplay|number) {
function openShareDg(type: typeof SHARE_MANAGE|typeof SHARE_USE, row: IDomainOwnerDisplay|number) {
if (typeof row === 'number') {
row = rows.value.find(item => item.id === row) as IDomainOwnerDisplay;
}
shareDomain.value = row ;
shareDg.value = true;
shareDomain.value = row;
if (type === SHARE_USE) {
shareDg.value = true;
} else if (type === SHARE_MANAGE) {
shareManageDg.value = true;
}
};
function closeShareDg() {
shareDg.value = false;
}
const onReset = () => {
name.value = '';
url.value = '';

View File

@@ -112,7 +112,10 @@ const addUserDomainFinished = async (val: string) => {
const selected = addDomainRef.value.selected;
if (val == 'OK' && selected.length > 0) {
addUserDomainLoading.value = true;
const { data } = await api.post(`api/domain/${authStore.userId}?domainid=${selected[0].id}`)
const { data } = await api.post(`api/userdomain`, {
userid: authStore.userId,
domainid: selected[0].id,
});
if (rows.value.length === 0 && data.data) {
const domain = data.data;
await authStore.setCurrentDomain({