add owner column

This commit is contained in:
xue jiahao
2024-12-03 12:23:20 +08:00
parent dcfe0d44fd
commit 2a76f5a4c7
8 changed files with 49 additions and 206 deletions

View File

@@ -1,180 +0,0 @@
<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>

View File

@@ -33,10 +33,10 @@ export default {
const columns = [
{ name: 'id', label: 'ID', field: 'id', align: 'left', sortable: true, classes: inactiveRowClass },
{ name: 'tenantid', required: true,label: 'テナント',align: 'left',field: 'tenantid',sortable: true, classes: inactiveRowClass},
{ name: 'name', align: 'center', label: 'ドメイン', field: 'name', sortable: true, classes: inactiveRowClass },
{ name: 'url', label: 'URL', field: 'url', sortable: true, classes: inactiveRowClass },
{ name: 'user', label: 'アカウント', field: 'user', classes: inactiveRowClass }
{ name: 'name', align: 'left', label: 'ドメイン', field: 'name', sortable: true, classes: inactiveRowClass },
{ name: 'url', label: 'URL', field: 'url',align: 'left', sortable: true, classes: inactiveRowClass },
{ name: 'user', label: 'アカウント', field: 'user',align: 'left', classes: inactiveRowClass },
{ name: 'owner', label: '所有者', field: row => row.owner.fullName, align: 'left', classes: inactiveRowClass },
]
const rows = reactive([]);
@@ -51,6 +51,16 @@ export default {
name: data.name,
url: data.url,
user: data.kintoneuser,
owner: {
id: data.owner.id,
firstName: data.owner.first_name,
lastName: data.owner.last_name,
fullNameSearch: (data.owner.last_name + data.owner.first_name).toLowerCase(),
fullName: data.owner.last_name + ' ' + data.owner.first_name,
email: data.owner.email,
isActive: data.owner.is_active,
isSuperuser: data.owner.is_superuser,
}
}
if (props.filterInitRowsFunc && !props.filterInitRowsFunc(item)) {
return;

View File

@@ -50,14 +50,14 @@
<script setup lang="ts">
import { ref, watch, onMounted } from 'vue';
import { IDomainDisplay } from '../../types/DomainTypes';
import { IDomainOwnerDisplay } from '../../types/DomainTypes';
import { IUser, IUserDisplay } from '../../types/UserTypes';
import { api } from 'boot/axios';
import SharingUserList from 'components/ShareDomain/SharingUserList.vue';
interface Props {
modelValue: boolean;
domain: IDomainDisplay;
domain: IDomainOwnerDisplay;
}
const props = defineProps<Props>();
@@ -174,7 +174,6 @@ const itemToDisplay = (item: IUser) => {
fullName: item.last_name + ' ' + item.first_name,
email: item.email,
isSuperuser: item.is_superuser,
roles: item.roles,
isActive: item.is_active,
} as IUserDisplay
}

View File

@@ -9,8 +9,8 @@ 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: 'lastName', label: '氏名', field: 'lastName', align: 'left', sortable: true },
{ name: 'firstName', label: '苗字', field: 'firstName', align: 'left', sortable: true },
{ name: 'email', label: '電子メール', field: 'email', align: 'left', sortable: true },
];

View File

@@ -54,7 +54,7 @@
:rules="[val => val && val.length > 0 || 'kintoneの環境名を入力してください。']" />
<q-input filled type="url" v-model.trim="url" label="Kintone url" hint="KintoneのURLを入力してください" lazy-rules
:rules="[val => val && val.length > 0, isDomain || 'KintoneのURLを入力してください']" />
:rules="[val => val && val.length > 0 || 'KintoneのURLを入力してください']" />
<q-input filled v-model="kintoneuser" label="ログイン名 *" hint="Kintoneのログイン名を入力してください" lazy-rules
:rules="[val => val && val.length > 0 || 'Kintoneのログイン名を入力してください']" autocomplete="new-password" />
@@ -145,11 +145,11 @@ import { api } from 'boot/axios';
import { useAuthStore } from 'stores/useAuthStore';
import { useDomainStore } from 'stores/useDomainStore';
import ShareDomainDialog from 'components/ShareDomain/ShareDomainDialog.vue';
import { IDomain, IDomainDisplay, IDomainSubmit } from '../types/DomainTypes';
import { IDomain, IDomainOwnerDisplay, IDomainSubmit } from '../types/DomainTypes';
const authStore = useAuthStore();
const domainStore = useDomainStore();
const inactiveRowClass = (row: IDomainDisplay) => row.domainActive ? '' : 'inactive-row';
const inactiveRowClass = (row: IDomainOwnerDisplay) => row.domainActive ? '' : 'inactive-row';
const columns = [
{ name: 'id', label: 'ID', field: 'id', align: 'left', sortable: true, classes: inactiveRowClass },
@@ -164,8 +164,8 @@ const columns = [
// },
{ name: 'name', label: '環境名', field: 'name', align: 'left', sortable: true, classes: inactiveRowClass },
{ name: 'url', label: 'URL', field: 'url', align: 'left', sortable: true, classes: inactiveRowClass },
// { name: 'owner', label: '所有者', field: 'owner', align: 'left', classes: inactiveRowClass },
{ name: 'user', label: 'ログイン名', field: 'user', align: 'left', classes: inactiveRowClass },
{ name: 'owner', label: '所有者', field: row => row.owner.fullName, align: 'left', classes: inactiveRowClass },
{ name: 'actions', label: '操作', field: 'actions', classes: inactiveRowClass }
];
@@ -175,7 +175,7 @@ const addEditLoading = ref(false);
const deleteLoadingState = ref<number>(-1); // -1: loading, 0: allow, > 0: user count
const filter = ref('');
const rows = ref<IDomainDisplay[]>([]);
const rows = ref<IDomainOwnerDisplay[]>([]);
const show = ref(false);
const confirm = ref(false);
const resetPsw = ref(false);
@@ -191,9 +191,8 @@ const kintonepwdBK = ref('');
const domainActive = ref(true);
const isCreate = ref(true);
let editId = ref(0);
let ownerid = ref('');
const shareDg = ref(false);
const shareDomain = ref<IDomainDisplay|object>({});
const shareDomain = ref<IDomainOwnerDisplay>();
const getDomain = async () => {
loading.value = true;
@@ -207,6 +206,16 @@ const getDomain = async () => {
url: item.url,
user: item.kintoneuser,
password: item.kintonepwd,
owner: {
id: item.owner.id,
firstName: item.owner.first_name,
lastName: item.owner.last_name,
fullNameSearch: (item.owner.last_name + item.owner.first_name).toLowerCase(),
fullName: item.owner.last_name + ' ' + item.owner.first_name,
email: item.owner.email,
isActive: item.owner.is_active,
isSuperuser: item.owner.is_superuser,
}
}
});
loading.value = false;
@@ -223,7 +232,7 @@ const addRow = () => {
show.value = true;
}
const removeRow = async (row: IDomainDisplay) => {
const removeRow = async (row: IDomainOwnerDisplay) => {
confirm.value = true;
deleteLoadingState.value = -1;
editId.value = row.id;
@@ -294,9 +303,9 @@ const onSubmit = () => {
})
}
const openShareDg = (row: IDomainDisplay|number) => {
const openShareDg = (row: IDomainOwnerDisplay|number) => {
if (typeof row === 'number') {
row = rows.value.find(item => item.id === row) as IDomainDisplay;
row = rows.value.find(item => item.id === row) as IDomainOwnerDisplay;
}
shareDomain.value = row ;
shareDg.value = true;
@@ -313,7 +322,6 @@ const onReset = () => {
kintonepwd.value = '';
isPwd.value = true;
editId.value = 0;
ownerid.value = '';
isCreate.value = true;
domainActive.value = true;
resetPsw.value = false

View File

@@ -65,10 +65,10 @@
<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
<q-input filled v-model="lastName" label="氏名 *" hint="ユーザーの氏名を入力してください" lazy-rules
:rules="[val => val && val.length > 0 || 'ユーザーの氏名を入力してください。']" />
<q-input filled v-model="lastName" label="苗字 *" hint="ユーザーの苗字を入力してください" lazy-rules
<q-input filled v-model="firstName" label="苗字 *" hint="ユーザーの苗字を入力してください" lazy-rules
:rules="[val => val && val.length > 0 || 'ユーザーの苗字を入力してください']" />
<q-input filled type="email" v-model="email" label="電子メール *" hint="電子メール、ログインとしても使用" lazy-rules
@@ -158,8 +158,8 @@ 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: 'lastName', label: '氏名', field: 'lastName', align: 'left', sortable: true },
{ name: 'firstName', label: '苗字', field: 'firstName', 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' }

View File

@@ -1,5 +1,4 @@
import { IDomain } from './ActionTypes';
import { IUser } from './UserTypes';
import { IUser, IUserDisplay } from './UserTypes';
export interface IDomainInfo {
id: number;
@@ -32,4 +31,8 @@ export interface IDomainDisplay {
user: string;
password?: string;
domainActive: boolean;
}
export interface IDomainOwnerDisplay extends IDomainDisplay {
owner: IUserDisplay
}

View File

@@ -17,5 +17,8 @@ export interface IUserDisplay {
email: string;
isActive: boolean,
isSuperuser: boolean,
}
export interface IUserRolesDisplay extends IUserDisplay {
roles: object[]
}