181 lines
5.6 KiB
Vue
181 lines
5.6 KiB
Vue
<template>
|
|
<q-dialog :auto-close="false" :model-value="visible" persistent bordered>
|
|
<q-card style="min-width: 40vw; max-width: 80vw; max-height: 95vh;" >
|
|
<q-toolbar class="bg-grey-4">
|
|
<q-toolbar-title>「{{domain.name}}」のドメインを共有する</q-toolbar-title>
|
|
<q-space></q-space>
|
|
<slot name="toolbar"></slot>
|
|
<q-btn flat round dense icon="close" @click="close" />
|
|
</q-toolbar>
|
|
<q-card-section>
|
|
<!-- <q-select
|
|
filled
|
|
v-model="filterInput"
|
|
use-input
|
|
use-chips
|
|
multiple
|
|
input-debounce="0"
|
|
:options="filterUsers"
|
|
@filter="filterFn"
|
|
/> -->
|
|
|
|
<q-table :rows="canSharedUsers" :filter="filterUnshared" :columns="columns" row-key="id" :loading="loading" :pagination="paginationUnshared">
|
|
<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="add" @click="shareTo(p.row)" />
|
|
</q-btn-group>
|
|
</q-td>
|
|
</template>
|
|
<template v-slot:top-right>
|
|
<q-input borderless dense filled debounce="300" v-model="filterUnshared" placeholder="検索">
|
|
<template v-slot:append>
|
|
<q-icon name="search" />
|
|
</template>
|
|
</q-input>
|
|
</template>
|
|
</q-table>
|
|
|
|
<!-- <q-btn flat label="共有する" @click="shareTo" /> -->
|
|
<q-table :rows="sharedUsers" :filter="filterShared" :columns="columns" row-key="id" :loading="loading" :pagination="paginationShared" >
|
|
<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="person_off" @click="removeShareTo(p.row)" />
|
|
</q-btn-group>
|
|
</q-td>
|
|
</template>
|
|
<template v-slot:top-right>
|
|
<q-input borderless dense filled debounce="300" v-model="filterShared" placeholder="検索">
|
|
<template v-slot:append>
|
|
<q-icon name="search" />
|
|
</template>
|
|
</q-input>
|
|
</template>
|
|
</q-table>
|
|
</q-card-section>
|
|
<q-card-actions align="right" class="text-primary">
|
|
<q-btn flat label="確定" @click="close" />
|
|
<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 { IDomainDisplay } from '../../types/DomainTypes';
|
|
import { IUser, IUserDisplay } from '../../types/UserTypes';
|
|
import { api } from 'boot/axios';
|
|
|
|
interface Props {
|
|
modelValue: boolean;
|
|
domain: IDomainDisplay;
|
|
}
|
|
|
|
const props = defineProps<Props>();
|
|
|
|
const emit = defineEmits<{
|
|
(e: 'update:modelValue', value: boolean): void;
|
|
(e: 'close'): void;
|
|
}>();
|
|
|
|
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 },
|
|
];
|
|
const paginationUnshared = ref({ sortBy: 'id', descending: true, rowsPerPage: 10 });
|
|
const filterUnshared = ref('');
|
|
const paginationShared = ref({ sortBy: 'id', descending: true, rowsPerPage: 10 });
|
|
const filterShared = ref('');
|
|
|
|
const loading = ref(true);
|
|
const visible = ref(props.modelValue);
|
|
|
|
const allUsers = ref<IUserDisplay[]>([]);
|
|
const sharedUsers = ref<IUserDisplay[]>([]);
|
|
const sharedUsersIdSet = new Set<number>();
|
|
const canSharedUsers = ref<IUserDisplay[]>([]);
|
|
|
|
watch(
|
|
() => props.modelValue,
|
|
async (newValue) => {
|
|
visible.value = newValue;
|
|
if (newValue) {
|
|
await loadShared();
|
|
}
|
|
}
|
|
);
|
|
|
|
watch(
|
|
() => visible.value,
|
|
(newValue) => {
|
|
emit('update:modelValue', newValue);
|
|
}
|
|
);
|
|
|
|
const close = () => {
|
|
emit('close');
|
|
};
|
|
|
|
const shareTo = async (user: IUserDisplay) => {
|
|
loading.value = true;
|
|
await api.post(`api/domain/${user.id}?domainid=${props.domain.id}`)
|
|
await loadShared();
|
|
loading.value = false;
|
|
}
|
|
|
|
const removeShareTo = async (user: IUserDisplay) => {
|
|
loading.value = true;
|
|
await api.delete(`api/domain/${props.domain.id}/${user.id}`)
|
|
await loadShared();
|
|
loading.value = false;
|
|
};
|
|
|
|
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));
|
|
|
|
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.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,
|
|
roles: item.roles,
|
|
isActive: item.is_active,
|
|
} as IUserDisplay
|
|
}
|
|
</script>
|
|
|
|
<style lang="scss"></style>
|