240 lines
7.9 KiB
Vue
240 lines
7.9 KiB
Vue
<template>
|
||
<div class="q-pa-md">
|
||
<div class="q-gutter-sm row items-start">
|
||
<q-breadcrumbs>
|
||
<q-breadcrumbs-el icon="widgets" label="アプリ管理" />
|
||
</q-breadcrumbs>
|
||
</div>
|
||
<q-table title="Treats" :rows="rows" :columns="columns" row-key="id" :filter="filter" :loading="loading" :pagination="pagination">
|
||
|
||
<template v-slot:top>
|
||
<q-btn color="primary" :disable="loading" label="新規" @click="showAddAppDialog" />
|
||
<q-space />
|
||
<q-input borderless dense filled debounce="300" v-model="filter" placeholder="検索">
|
||
<template v-slot:append>
|
||
<q-icon name="search" />
|
||
</template>
|
||
</q-input>
|
||
</template>
|
||
<template v-slot:body-cell-name="prop">
|
||
<q-td :props="prop">
|
||
<q-btn flat dense :label="prop.row.name" @click="toEditFlowPage(prop.row)" ></q-btn>
|
||
</q-td>
|
||
</template>
|
||
<template v-slot:body-cell-url="prop">
|
||
<q-td :props="prop">
|
||
<a :href="prop.row.url" target="_blank" :title="prop.row.name" >
|
||
{{ prop.row.url }}
|
||
</a>
|
||
</q-td>
|
||
</template>
|
||
<template v-slot:body-cell-actions="p">
|
||
<q-td :props="p">
|
||
<table-action-menu :row="p.row" :actions="actionList" />
|
||
</q-td>
|
||
</template>
|
||
</q-table>
|
||
|
||
<show-dialog v-model:visible="showSelectApp" name="アプリ選択" @close="closeSelectAppDialog" min-width="50vw" min-height="50vh" :ok-btn-auto-close="false" :ok-btn-loading="isAdding">
|
||
<template v-slot:toolbar>
|
||
<q-input dense debounce="300" v-model="dgFilter" placeholder="検索" clearable>
|
||
<template v-slot:before>
|
||
<q-icon name="search" />
|
||
</template>
|
||
</q-input>
|
||
</template>
|
||
<app-select-box ref="appDialog" name="アプリ" type="single" :filter="dgFilter" :filterInitRowsFunc="filterInitRows" />
|
||
</show-dialog>
|
||
|
||
|
||
<show-dialog v-model:visible="showVersionHistory" :name="targetRow?.name + 'のバージョン履歴'" @close="closeHistoryDg" min-width="30vw" :ok-btn-auto-close="false" :ok-btn-loading="isAdding"
|
||
ok-btn-label="選択">
|
||
<version-history ref="versionDialog" :app="targetRow" />
|
||
</show-dialog>
|
||
|
||
<q-dialog v-model="deleteDialog" persistent>
|
||
<q-card>
|
||
<q-card-section class="row items-center">
|
||
<q-icon name="warning" color="warning" 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" :loading="deleteUserLoading" @click="deleteApp" />
|
||
</q-card-actions>
|
||
</q-card>
|
||
</q-dialog>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { ref, onMounted, watch, reactive } from 'vue';
|
||
import { useQuasar } from 'quasar'
|
||
import { api } from 'boot/axios';
|
||
import { useAuthStore } from 'stores/useAuthStore';
|
||
import { useFlowEditorStore } from 'stores/flowEditor';
|
||
import { router } from 'src/router';
|
||
import { date } from 'quasar'
|
||
import { IManagedApp, IAppDisplay, IAppVersion } from 'src/types/AppTypes';
|
||
import ShowDialog from 'src/components/ShowDialog.vue';
|
||
import AppSelectBox from 'src/components/AppSelectBox.vue';
|
||
import TableActionMenu from 'components/TableActionMenu.vue';
|
||
import VersionHistory from 'components/dialog/VersionHistory.vue';
|
||
|
||
const authStore = useAuthStore();
|
||
const numberStringSorting = (a: string, b: string) => parseInt(a, 10) - parseInt(b, 10);
|
||
|
||
const columns = [
|
||
{ name: 'id', label: 'アプリID', field: 'id', align: 'left', sortable: true, sort: numberStringSorting },
|
||
{ name: 'name', label: 'アプリ名', field: 'name', align: 'left', sortable: true },
|
||
{ name: 'url', label: 'URL', field: 'url', align: 'left', sortable: true },
|
||
{ name: 'updateUser', label: '最後更新者', field: (row: IAppDisplay) => row.updateUser.fullName, align: 'left', sortable: true},
|
||
{ name: 'updateTime', label: '最後更新日', field: 'updateTime', align: 'left', sortable: true},
|
||
{ name: 'version', label: 'バージョン', field: 'version', align: 'left', sortable: true, sort: numberStringSorting },
|
||
{ name: 'actions', label: '', field: 'actions' }
|
||
];
|
||
|
||
const pagination = ref({ sortBy: 'id', descending: true, rowsPerPage: 20 });
|
||
const loading = ref(false);
|
||
const filter = ref('');
|
||
const dgFilter = ref('');
|
||
const rows = ref<IAppDisplay[]>([]);
|
||
const targetRow = ref<IAppDisplay>();
|
||
const rowIds = new Set<string>();
|
||
|
||
const $q = useQuasar()
|
||
const store = useFlowEditorStore();
|
||
const appDialog = ref();
|
||
const versionDialog = ref();
|
||
const showSelectApp=ref(false);
|
||
const showVersionHistory=ref(false);
|
||
const isAdding = ref(false);
|
||
const deleteDialog = ref(false);
|
||
const deleteUserLoading = ref(false);
|
||
|
||
const actionList = [
|
||
{ label: '設定', icon: 'account_tree', action: toEditFlowPage },
|
||
{ label: '履歴', icon: 'history', action: showHistory },
|
||
{ separator: true },
|
||
{ label: '削除', icon: 'delete_outline', class: 'text-red', action: removeRow },
|
||
];
|
||
|
||
const getApps = async () => {
|
||
loading.value = true;
|
||
rowIds.clear();
|
||
try {
|
||
const { data } = await api.get('api/apps');
|
||
rows.value = data.data.map((item: IManagedApp) => {
|
||
rowIds.add(item.appid);
|
||
return appToAppDisplay(item)
|
||
}).sort((a: IAppDisplay, b: IAppDisplay) => a.sortId - b.sortId); // set default order
|
||
} catch (error) {
|
||
$q.notify({
|
||
icon: 'error',
|
||
color: 'negative',
|
||
message: 'アプリ一覧の読み込みに失敗しました'
|
||
});
|
||
} finally {
|
||
loading.value = false;
|
||
}
|
||
}
|
||
|
||
onMounted(async () => {
|
||
await getApps();
|
||
});
|
||
|
||
watch(() => authStore.currentDomain.id, async () => {
|
||
await getApps();
|
||
});
|
||
|
||
const filterInitRows = (row: {id: string}) => {
|
||
return !rowIds.has(row.id);
|
||
}
|
||
|
||
const showAddAppDialog = () => {
|
||
showSelectApp.value = true;
|
||
dgFilter.value = ''
|
||
}
|
||
|
||
const closeSelectAppDialog = async (val: 'OK'|'Cancel') => {
|
||
showSelectApp.value = true;
|
||
if (val == 'OK' && appDialog.value.selected[0]) {
|
||
isAdding.value = true;
|
||
toEditFlowPage(appDialog.value.selected[0]);
|
||
}
|
||
showSelectApp.value = false;
|
||
isAdding.value = false;
|
||
}
|
||
|
||
function removeRow(app:IAppDisplay) {
|
||
targetRow.value = app;
|
||
deleteDialog.value = true;
|
||
}
|
||
|
||
const deleteApp = async () => {
|
||
deleteUserLoading.value = true;
|
||
try {
|
||
await api.delete(`api/apps/${targetRow.value?.id}`);
|
||
await getApps();
|
||
} catch (error) {
|
||
$q.notify({
|
||
icon: 'error',
|
||
color: 'negative',
|
||
message: 'アプリの削除に失敗しました'
|
||
});
|
||
} finally {
|
||
deleteUserLoading.value = false;
|
||
deleteDialog.value = false;
|
||
}
|
||
}
|
||
|
||
function showHistory(app:IAppDisplay) {
|
||
targetRow.value = app;
|
||
showVersionHistory.value = true;
|
||
dgFilter.value = ''
|
||
}
|
||
|
||
const closeHistoryDg = async (val: 'OK'|'Cancel') => {
|
||
showVersionHistory.value = true;
|
||
if (val == 'OK' && versionDialog.value.selected[0]) {
|
||
isAdding.value = true;
|
||
await api.put(`api/appversions/${targetRow.value?.id}/${versionDialog.value.selected[0].id}`)
|
||
await getApps();
|
||
}
|
||
showVersionHistory.value = false;
|
||
isAdding.value = false;
|
||
}
|
||
|
||
const appToAppDisplay = (app: IManagedApp) => {
|
||
const user = app.updateuser;
|
||
return {
|
||
id: app.appid,
|
||
sortId: parseInt(app.appid, 10),
|
||
name: app.appname,
|
||
url: `${app.domainurl}/k/${app.appid}`,
|
||
version: app.version,
|
||
updateTime:date.formatDate(app.update_time, 'YYYY/MM/DD HH:mm'),
|
||
updateUser: {
|
||
id: user.id,
|
||
firstName: user.first_name,
|
||
lastName: user.last_name,
|
||
fullNameSearch: (user.last_name + user.first_name).toLowerCase(),
|
||
fullName: user.last_name + ' ' + user.first_name,
|
||
email: user.email,
|
||
isSuperuser: user.is_superuser,
|
||
isActive: user.is_active,
|
||
}
|
||
} as IAppDisplay
|
||
}
|
||
|
||
async function toEditFlowPage(app:IAppDisplay) {
|
||
store.setApp({
|
||
appId: app.id,
|
||
name: app.name
|
||
});
|
||
store.selectFlow(undefined);
|
||
await router.push('/FlowChart/' + app.id);
|
||
};
|
||
</script>
|