226 lines
6.8 KiB
Vue
226 lines
6.8 KiB
Vue
<template>
|
||
<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-btn flat round dense icon="close" @click="close" />
|
||
</q-toolbar>
|
||
|
||
<q-card-section class="q-mx-md " >
|
||
<q-select
|
||
class="q-mt-md"
|
||
:disable="loading||!domain.domainActive"
|
||
filled
|
||
dense
|
||
v-model="canSharedUserFilter"
|
||
use-input
|
||
input-debounce="0"
|
||
:options="canSharedUserFilteredOptions"
|
||
clearable
|
||
:placeholder="canSharedUserFilter ? '' : domain.domainActive ? '権限を付与するユーザーを選択' : 'ドメインが無効なため、権限を付与できません'"
|
||
@filter="filterFn"
|
||
:display-value="canSharedUserFilter?`${canSharedUserFilter.fullName} (${canSharedUserFilter.email})`:''">
|
||
|
||
<template v-slot:after>
|
||
<q-btn :disable="!canSharedUserFilter" :loading="addLoading" label="付与" color="primary" @click="shareTo(canSharedUserFilter as IUserDisplay)" />
|
||
</template>
|
||
|
||
<template v-slot:option="scope">
|
||
<q-item v-bind="scope.itemProps">
|
||
<q-item-section avatar>{{scope.opt.id}}</q-item-section>
|
||
<q-item-section>{{scope.opt.fullName}}</q-item-section>
|
||
<q-item-section>{{scope.opt.email}}</q-item-section>
|
||
</q-item>
|
||
</template>
|
||
</q-select>
|
||
<sharing-user-list class="q-mt-md" style="height: 330px" :users="sharedUsers" :loading="loading" title="ドメイン利用権限を持つユーザー">
|
||
<template v-slot:actions="{ row }">
|
||
<q-btn title="解除" flat color="primary" padding="xs" size="1em" :loading="row.id == removingUser?.id" icon="person_off" @click="removeShareTo(row)" />
|
||
</template>
|
||
</sharing-user-list>
|
||
</q-card-section>
|
||
|
||
<q-card-actions align="right" class="text-primary">
|
||
<q-btn flat label="確定" @click="checkClose" />
|
||
<q-btn flat label="キャンセル" @click="close" />
|
||
</q-card-actions>
|
||
</q-card>
|
||
</q-dialog>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { ref, watch, onMounted } from 'vue';
|
||
import { IDomainOwnerDisplay } from '../../types/DomainTypes';
|
||
import { IUser, IUserDisplay } from '../../types/UserTypes';
|
||
import { api } from 'boot/axios';
|
||
import SharingUserList from 'components/ShareDomain/SharingUserList.vue';
|
||
import { Dialog } from 'quasar'
|
||
|
||
interface Props {
|
||
modelValue: boolean;
|
||
domain: IDomainOwnerDisplay;
|
||
}
|
||
|
||
interface IUserDisplayWithShareRole extends IUserDisplay {
|
||
role: number;
|
||
}
|
||
|
||
const props = defineProps<Props>();
|
||
|
||
const emit = defineEmits<{
|
||
(e: 'update:modelValue', value: boolean): void;
|
||
(e: 'close'): void;
|
||
}>();
|
||
|
||
const addLoading = ref(false);
|
||
const removingUser = ref<IUserDisplayWithShareRole>();
|
||
const loading = ref(true);
|
||
const visible = ref(props.modelValue);
|
||
|
||
const allUsers = ref<IUserDisplayWithShareRole[]>([]);
|
||
const sharedUsers = ref<IUserDisplayWithShareRole[]>([]);
|
||
const sharedUsersIdSet = new Set<number>();
|
||
|
||
const canSharedUsers = ref<IUserDisplayWithShareRole[]>([]);
|
||
const canSharedUserFilter = ref<IUserDisplayWithShareRole>();
|
||
const canSharedUserFilteredOptions = ref<IUserDisplayWithShareRole[]>([]);
|
||
|
||
const filterFn = (val:string, update: (cb: () => void) => void) => {
|
||
update(() => {
|
||
if (val === '') {
|
||
canSharedUserFilteredOptions.value = canSharedUsers.value;
|
||
return;
|
||
}
|
||
const needle = val.toLowerCase();
|
||
canSharedUserFilteredOptions.value = canSharedUsers.value.filter(v =>
|
||
v.email.toLowerCase().indexOf(needle) > -1 || v.fullNameSearch.toLowerCase().indexOf(needle) > -1);
|
||
})
|
||
}
|
||
|
||
watch(
|
||
() => props.modelValue,
|
||
async (newValue) => {
|
||
visible.value = newValue;
|
||
sharedUsers.value = [];
|
||
canSharedUserFilter.value = undefined
|
||
loading.value = false;
|
||
addLoading.value = false;
|
||
if (newValue) {
|
||
await loadShared();
|
||
}
|
||
}
|
||
);
|
||
|
||
watch(
|
||
() => visible.value,
|
||
(newValue) => {
|
||
emit('update:modelValue', newValue);
|
||
}
|
||
);
|
||
|
||
const checkClose = () => {
|
||
if (!canSharedUserFilter.value) {
|
||
close();
|
||
return;
|
||
}
|
||
Dialog.create({
|
||
title: '注意',
|
||
message: '選択済だがまだ付与未完了のユーザーがあります。<br>必要な操作を選んでください。',
|
||
html: true,
|
||
persistent: true,
|
||
ok: {
|
||
color: 'primary',
|
||
label: '付与'
|
||
},
|
||
cancel: '直接閉じる',
|
||
}).onCancel(() => {
|
||
close();
|
||
}).onOk(() => {
|
||
shareTo(canSharedUserFilter.value as IUserDisplayWithShareRole);
|
||
});
|
||
};
|
||
|
||
const close = () => {
|
||
emit('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 loadShared();
|
||
canSharedUserFilter.value = undefined;
|
||
loading.value = false;
|
||
addLoading.value = false;
|
||
}
|
||
|
||
const removeShareTo = async (user: IUserDisplayWithShareRole) => {
|
||
removingUser.value = user;
|
||
loading.value = true;
|
||
await api.delete(`api/domain/${props.domain.id}/${user.id}`)
|
||
await loadShared();
|
||
loading.value = false;
|
||
removingUser.value = undefined;
|
||
};
|
||
|
||
const loadShared = async () => {
|
||
loading.value = true;
|
||
sharedUsersIdSet.clear();
|
||
|
||
const { data } = await api.get(`/api/domainshareduser/${props.domain.id}`);
|
||
sharedUsers.value = data.data.map((item: IUser) => {
|
||
const val = itemToDisplay(item);
|
||
sharedUsersIdSet.add(val.id);
|
||
return val;
|
||
});
|
||
|
||
canSharedUsers.value = allUsers.value.filter((item) => !sharedUsersIdSet.has(item.id));
|
||
canSharedUserFilteredOptions.value = canSharedUsers.value;
|
||
|
||
loading.value = false;
|
||
}
|
||
|
||
onMounted(async () => {
|
||
await getUsers();
|
||
})
|
||
|
||
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;
|
||
}
|
||
|
||
const itemToDisplay = (item: IUser) => {
|
||
return {
|
||
id: item.id,
|
||
firstName: item.first_name,
|
||
lastName: item.last_name,
|
||
fullNameSearch: (item.last_name + item.first_name).toLowerCase(),
|
||
fullName: item.last_name + ' ' + item.first_name,
|
||
email: item.email,
|
||
isSuperuser: item.is_superuser,
|
||
isActive: item.is_active,
|
||
role: 0, // TODO
|
||
} as IUserDisplayWithShareRole
|
||
}
|
||
</script>
|
||
|
||
<style lang="scss">
|
||
.dialog-content {
|
||
width: 700px !important;
|
||
max-width: 80vw !important;
|
||
max-height: 80vh;
|
||
.q-select {
|
||
min-width: 0 !important;
|
||
}
|
||
}
|
||
|
||
</style>
|