source merge

This commit is contained in:
xiaozhe.ma
2024-12-06 11:00:23 +09:00
33 changed files with 1467 additions and 522 deletions

View File

@@ -17,9 +17,15 @@
</q-input>
</template>
<template v-slot:body-cell-name="p">
<q-td class="flex justify-between items-center" :props="p">
{{ p.row.name }}
<template v-slot:header-cell-active="p">
<q-th auto-width :props="p">
<q-select class="filter-header" v-model="activeFilter" :options="activeOptions" @update:model-value="activeFilterUpdate" borderless
dense options-dense hide-bottom-space/>
</q-th>
</template>
<template v-slot:body-cell-active="p">
<q-td auto-width :props="p">
<q-badge v-if="!p.row.domainActive" color="grey">未使用</q-badge>
<q-badge v-if="p.row.id == currentDomainId" color="primary">既定</q-badge>
</q-td>
@@ -27,10 +33,31 @@
<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-btn flat padding="xs" round size="1em" icon="more_vert">
<q-menu >
<q-list dense style="min-width: 100px">
<q-item clickable v-close-popup @click="editRow(p.row)">
<q-item-section>
<q-icon size="1.2em" name="edit_note" />
</q-item-section>
<q-item-section>編集</q-item-section>
</q-item>
<q-item clickable v-close-popup @click="openShareDg(p.row)">
<q-item-section>
<q-icon size="1.2em" name="person_add_alt" />
</q-item-section>
<q-item-section>共有</q-item-section>
</q-item>
<q-separator />
<q-item class="text-red" clickable v-close-popup @click="removeRow(p.row)">
<q-item-section>
<q-icon size="1.2em" name="delete_outline" />
</q-item-section>
<q-item-section>削除</q-item-section>
</q-item>
</q-list>
</q-menu>
</q-btn>
</q-td>
</template>
@@ -46,15 +73,11 @@
<q-card-section class="q-pt-none q-mt-none">
<div class="q-gutter-lg">
<q-input filled v-model="tenantid" label="テナントID" hint="テナントIDを入力してください。" lazy-rules
:rules="[val => val && val.length > 0 || 'テナントIDを入力してください。']" />
<q-input filled v-model="name" label="環境名 *" hint="kintoneの環境名を入力してください" lazy-rules
: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" />
@@ -103,7 +126,7 @@
</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 :loading="addEditLoading" label="保存" type="submit" color="primary" />
<q-btn label="キャンセル" type="cancel" color="primary" flat class="q-ml-sm" @click="closeDg()" />
</q-card-actions>
</q-form>
@@ -113,18 +136,29 @@
<q-dialog v-model="confirm" persistent>
<q-card>
<q-card-section class="row items-center">
<q-card-section v-if="deleteLoadingState == -1" class="row items-center">
<q-spinner color="primary" size="2em"/>
<span class="q-ml-sm">共有ユーザーのチェック</span>
</q-card-section>
<q-card-section v-else-if="deleteLoadingState == 0" class="row items-center">
<q-icon name="warning" color="warning" size="2em" />
<span class="q-ml-sm">削除してもよろしいですか</span>
</q-card-section>
<q-card-section v-else class="row items-center">
<q-icon name="error" color="negative" 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="deleteDomain()" />
<q-btn v-if="deleteLoadingState > 0" label="処理に行く" color="primary" v-close-popup @click="openShareDg(editId)" />
<q-btn flat v-else label="OK" :disabled="deleteLoadingState" color="primary" v-close-popup @click="deleteDomain()" />
</q-card-actions>
</q-card>
</q-dialog>
<share-domain-dialog v-model="shareDg" :domain="shareDomain" @close="closeShareDg()" />
</div>
</template>
@@ -133,39 +167,49 @@ import { ref, onMounted, computed } from 'vue';
import { api } from 'boot/axios';
import { useAuthStore } from 'stores/useAuthStore';
import { useDomainStore } from 'stores/useDomainStore';
import { IDomain, IDomainDisplay, IDomainSubmit } from '../types/DomainTypes';
import ShareDomainDialog from 'components/ShareDomain/ShareDomainDialog.vue';
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 },
{
name: 'tenantid',
required: true,
label: 'テナントID',
field: 'tenantid',
align: 'left',
sortable: true,
classes: inactiveRowClass
},
// {
// name: 'tenantid',
// required: true,
// label: 'テナントID',
// field: 'tenantid',
// align: 'left',
// sortable: true,
// classes: inactiveRowClass
// },
{ name: 'name', label: '環境名', field: 'name', align: 'left', sortable: true, classes: inactiveRowClass },
{ name: 'active', label: 'x', align: 'left', field: 'domainActive', classes: inactiveRowClass },
{ name: 'url', label: 'URL', field: 'url', align: 'left', sortable: true, classes: inactiveRowClass },
{ name: 'user', label: 'ログイン名', field: 'user', align: 'left', classes: inactiveRowClass },
{ name: 'actions', label: '操作', field: 'actions' }
{ name: 'owner', label: '所有者', field: row => row.owner.fullName, align: 'left', classes: inactiveRowClass },
{ name: 'actions', label: '', field: 'actions', classes: inactiveRowClass }
];
const pagination = ref({ sortBy: 'id', descending: true, rowsPerPage: 20 });
const loading = ref(false);
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);
const activeOptions = ['全データ', '启用', '未启用']
const activeFilter = ref('全データ');
const currentDomainId = computed(() => authStore.currentDomain.id);
const tenantid = ref(authStore.currentDomain.id);
// const tenantid = ref(authStore.currentDomain.id);
const name = ref('');
const url = ref('');
const isPwd = ref(true);
@@ -175,9 +219,24 @@ 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<IDomainOwnerDisplay>();
const getDomain = async () => {
const activeFilterUpdate = (selected) => {
switch (selected) {
case '启用':
getDomain((row) => row.domainActive)
break;
case '未启用':
getDomain((row) => !row.domainActive)
break;
default:
getDomain()
break;
}
}
const getDomain = async (filter = () => true) => {
loading.value = true;
const { data } = await api.get<{data:IDomain[]}>(`api/domains`);
rows.value = data.data.map((item) => {
@@ -189,8 +248,18 @@ 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,
}
}
});
}).filter(filter);
loading.value = false;
}
@@ -205,23 +274,31 @@ const addRow = () => {
show.value = true;
}
const removeRow = (row: IDomainDisplay) => {
const removeRow = async (row: IDomainOwnerDisplay) => {
confirm.value = true;
deleteLoadingState.value = -1;
editId.value = row.id;
const { data } = await api.get(`/api/domainshareduser/${row.id}`);
deleteLoadingState.value = data.data.length;
}
const deleteDomain = () => {
api.delete(`api/domain/${editId.value}`).then(() => {
api.delete(`api/domain/${editId.value}`).then(({ data }) => {
if (!data.data) {
// TODO dialog
}
getDomain();
// authStore.setCurrentDomain();
})
editId.value = 0; // set in removeRow()
deleteLoadingState.value = -1;
};
const editRow = (row) => {
isCreate.value = false
editId.value = row.id;
tenantid.value = row.tenantid;
// tenantid.value = row.tenantid;
name.value = row.name;
url.value = row.url;
kintoneuser.value = row.user;
@@ -246,10 +323,11 @@ const closeDg = () => {
}
const onSubmit = () => {
addEditLoading.value = true;
const method = editId.value !== 0 ? 'put' : 'post';
const param: IDomainSubmit = {
'id': editId.value,
'tenantid': tenantid.value,
'tenantid': '1', // TODO: テナントIDを取得する
'name': name.value,
'url': url.value,
'kintoneuser': kintoneuser.value,
@@ -258,14 +336,31 @@ const onSubmit = () => {
'ownerid': authStore.userId || ''
}
// for search: api.put(`api/domain`)、api.post(`api/domain`)
api[method].apply(api, [`api/domain`, param]).then(() => {
api[method].apply(api, [`api/domain`, param]).then(async (resp: any) => {
const res = resp.data;
if (res.data.id === currentDomainId.value && !res.data.is_active) {
await authStore.setCurrentDomain();
}
getDomain();
domainStore.loadUserDomains();
closeDg();
onReset();
addEditLoading.value = false;
})
}
const openShareDg = (row: IDomainOwnerDisplay|number) => {
if (typeof row === 'number') {
row = rows.value.find(item => item.id === row) as IDomainOwnerDisplay;
}
shareDomain.value = row ;
shareDg.value = true;
};
const closeShareDg = () => {
shareDg.value = false;
}
const onReset = () => {
name.value = '';
url.value = '';
@@ -273,14 +368,25 @@ const onReset = () => {
kintonepwd.value = '';
isPwd.value = true;
editId.value = 0;
ownerid.value = '';
isCreate.value = true;
domainActive.value = true;
resetPsw.value = false
addEditLoading.value = false;
}
</script>
<style lang="scss">
.filter-header .q-field__native {
font-size: 12px;
font-weight: 500;
}
.filter-header .q-icon {
width: 12px;
}
.q-table td.inactive-row {
color: #aaa;
background-color: #fafafa;
}
.q-table tr > td.inactive-row:last-child {
color: inherit;
}
</style>