Merged PR 5: some fix for apps management page
1. 修改了 /apps 下的时间列格式 2. 修复了 /apps 下切换 domain 时更新 table 3. 修复了 /apps 下的 id 排序(使用数值,而非字符串字典序) 4. /flowChart 添加 id,从而在页面上支持刷新 5. /flowChart 添加了返回按钮 --- # 更新: 1. /flowChart 更新了面包屑导航 2. /flowChart 下禁止切换 domain  Related work items: #63, #64
This commit is contained in:
@@ -1,12 +1,15 @@
|
|||||||
<template>
|
<template>
|
||||||
<q-btn-dropdown
|
<q-btn-dropdown
|
||||||
color="primay"
|
class="customized-disabled-btn"
|
||||||
push
|
push
|
||||||
flat
|
flat
|
||||||
no-caps
|
no-caps
|
||||||
icon="share"
|
icon="share"
|
||||||
size="md"
|
size="md"
|
||||||
:label="userStore.currentDomain.domainName"
|
:label="userStore.currentDomain.domainName"
|
||||||
|
:disable-dropdown="isUnclickable"
|
||||||
|
:dropdown-icon="isUnclickable ? 'none' : ''"
|
||||||
|
:disable="isUnclickable"
|
||||||
>
|
>
|
||||||
<q-list>
|
<q-list>
|
||||||
<q-item v-for="domain in domains" :key="domain.domainName"
|
<q-item v-for="domain in domains" :key="domain.domainName"
|
||||||
@@ -26,18 +29,32 @@
|
|||||||
<script setup lang="ts" >
|
<script setup lang="ts" >
|
||||||
import { IDomainInfo } from 'src/types/ActionTypes';
|
import { IDomainInfo } from 'src/types/ActionTypes';
|
||||||
import { useAuthStore,IUserState } from 'stores/useAuthStore';
|
import { useAuthStore,IUserState } from 'stores/useAuthStore';
|
||||||
import { ref } from 'vue';
|
import { ref, computed } from 'vue';
|
||||||
|
import { useRoute } from 'vue-router';
|
||||||
const userStore = useAuthStore();
|
const userStore = useAuthStore();
|
||||||
|
const route = useRoute()
|
||||||
const domains = ref<IDomainInfo[]>([]);
|
const domains = ref<IDomainInfo[]>([]);
|
||||||
(async ()=>{
|
(async ()=>{
|
||||||
domains.value = await userStore.getUserDomains();
|
domains.value = await userStore.getUserDomains();
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
const isUnclickable = computed(()=>{
|
||||||
|
return route.path.startsWith('/FlowChart/') || domains.value === undefined || domains.value.length === 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
const onItemClick=(domain:IDomainInfo)=>{
|
const onItemClick=(domain:IDomainInfo)=>{
|
||||||
console.log(domain);
|
console.log(domain);
|
||||||
userStore.setCurrentDomain(domain);
|
userStore.setCurrentDomain(domain);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
|
.q-btn.disabled.customized-disabled-btn {
|
||||||
|
opacity: 1 !important;
|
||||||
|
cursor: default !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.q-btn.disabled.customized-disabled-btn * {
|
||||||
|
cursor: default !important;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -39,26 +39,13 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, onMounted, reactive } from 'vue';
|
import { ref, onMounted, watch, reactive } from 'vue';
|
||||||
import { api } from 'boot/axios';
|
import { api } from 'boot/axios';
|
||||||
import { useAuthStore } from 'stores/useAuthStore';
|
import { useAuthStore } from 'stores/useAuthStore';
|
||||||
import { useFlowEditorStore } from 'stores/flowEditor';
|
import { useFlowEditorStore } from 'stores/flowEditor';
|
||||||
import { router } from 'src/router';
|
import { router } from 'src/router';
|
||||||
|
import { date } from 'quasar'
|
||||||
interface IUser{
|
import { IManagedApp } from 'src/types/AppTypes';
|
||||||
first_name:string;
|
|
||||||
last_name:string;
|
|
||||||
email:string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface IManagedApp{
|
|
||||||
appid:string;
|
|
||||||
appname:string;
|
|
||||||
domainurl:string;
|
|
||||||
version:string;
|
|
||||||
user:IUser;
|
|
||||||
update_time:string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface IAppDisplay{
|
interface IAppDisplay{
|
||||||
id:string;
|
id:string;
|
||||||
@@ -69,7 +56,6 @@ interface IAppDisplay{
|
|||||||
updatetime:string;
|
updatetime:string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const authStore = useAuthStore();
|
const authStore = useAuthStore();
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
@@ -78,7 +64,7 @@ const columns = [
|
|||||||
{ name: 'url', label: 'URL', field: 'url', align: 'left', sortable: true },
|
{ name: 'url', label: 'URL', field: 'url', align: 'left', sortable: true },
|
||||||
{ name: 'user', label: '最後更新者', field: 'user', align: 'left', sortable: true},
|
{ name: 'user', label: '最後更新者', field: 'user', align: 'left', sortable: true},
|
||||||
{ name: 'updatetime', label: '最後更新日', field: 'updatetime', align: 'left', sortable: true},
|
{ name: 'updatetime', label: '最後更新日', field: 'updatetime', align: 'left', sortable: true},
|
||||||
{ name: 'version', label: 'バージョン', field: 'version', align: 'left'},
|
{ name: 'version', label: 'バージョン', field: 'version', align: 'left', sortable: true},
|
||||||
{ name: 'actions', label: '操作', field: 'actions' }
|
{ name: 'actions', label: '操作', field: 'actions' }
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -88,20 +74,19 @@ const filter = ref('');
|
|||||||
const rows = ref<IAppDisplay[]>([]);
|
const rows = ref<IAppDisplay[]>([]);
|
||||||
const store = useFlowEditorStore();
|
const store = useFlowEditorStore();
|
||||||
|
|
||||||
const tenantid = ref(authStore.currentDomain.id);
|
|
||||||
|
|
||||||
const getApps = async () => {
|
const getApps = async () => {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
const result = await api.get('api/apps');
|
const result = await api.get('api/apps');
|
||||||
rows.value = result.data.map((item:IManagedApp) => {
|
rows.value = result.data.map((item:IManagedApp) => {
|
||||||
return {
|
return {
|
||||||
id: item.appid,
|
id: Number(item.appid),
|
||||||
name: item.appname,
|
name: item.appname,
|
||||||
url: `${item.domainurl}/k/${item.appid}`,
|
url: `${item.domainurl}/k/${item.appid}`,
|
||||||
user: `${item.user.first_name} ${item.user.last_name}` ,
|
user: `${item.user.first_name} ${item.user.last_name}` ,
|
||||||
updatetime:item.update_time,
|
updatetime:date.formatDate(item.update_time, 'YYYY/MM/DD HH:mm'),
|
||||||
version: item.version }
|
version: Number(item.version)
|
||||||
});
|
}
|
||||||
|
}).sort((a, b) => a.id - b.id); // set default order
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,6 +95,10 @@ onMounted(async () => {
|
|||||||
await getApps();
|
await getApps();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
watch(() => authStore.currentDomain.id, async () => {
|
||||||
|
await getApps();
|
||||||
|
});
|
||||||
|
|
||||||
const addRow = () => {
|
const addRow = () => {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -127,6 +116,7 @@ const editFlow = (app:IAppDisplay) => {
|
|||||||
appId: app.id,
|
appId: app.id,
|
||||||
name: app.name
|
name: app.name
|
||||||
});
|
});
|
||||||
router.push('/FlowChart');
|
store.selectFlow(undefined);
|
||||||
|
router.push('/FlowChart/' + app.id);
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -3,11 +3,7 @@
|
|||||||
<q-layout container class="absolute-full shadow-2 rounded-borders">
|
<q-layout container class="absolute-full shadow-2 rounded-borders">
|
||||||
<div class="q-pa-sm q-gutter-sm ">
|
<div class="q-pa-sm q-gutter-sm ">
|
||||||
<q-drawer side="left" :overlay="true" bordered v-model="drawerLeft" :show-if-above="false" elevated>
|
<q-drawer side="left" :overlay="true" bordered v-model="drawerLeft" :show-if-above="false" elevated>
|
||||||
<div class="flex-center fixed-top app-selector">
|
<div class="flex-center absolute-full" style="padding:15px">
|
||||||
<AppSelector />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex-center absolute-full" style="padding-top:65px;padding-left:15px;padding-right:15px;">
|
|
||||||
<q-scroll-area class="fit" :horizontal-thumb-style="{ opacity: '0' }">
|
<q-scroll-area class="fit" :horizontal-thumb-style="{ opacity: '0' }">
|
||||||
<EventTree />
|
<EventTree />
|
||||||
</q-scroll-area>
|
</q-scroll-area>
|
||||||
@@ -42,8 +38,24 @@
|
|||||||
</div>
|
</div>
|
||||||
<q-btn flat dense round
|
<q-btn flat dense round
|
||||||
:icon="drawerLeft?'keyboard_double_arrow_left':'keyboard_double_arrow_right'"
|
:icon="drawerLeft?'keyboard_double_arrow_left':'keyboard_double_arrow_right'"
|
||||||
:style="[drawerLeft?{'left':'300px'}:{'left':'0px'}]"
|
:style="{'left': fixedLeftPosition}"
|
||||||
@click="drawerLeft=!drawerLeft" class="expand" />
|
@click="drawerLeft=!drawerLeft" class="expand" />
|
||||||
|
<q-breadcrumbs v-if="store.appInfo" class="fixed q-pl-md"
|
||||||
|
:style="{'left': fixedLeftPosition}">
|
||||||
|
<q-breadcrumbs-el icon="widgets" label="アプリ管理" to="/app" />
|
||||||
|
<q-breadcrumbs-el>
|
||||||
|
<template v-slot>
|
||||||
|
<a class="full-width" :href="!store.appInfo?'':`${authStore.currentDomain.kintoneUrl}/k/${store.appInfo?.appId}`" target="_blank" title="Kiontoneへ">
|
||||||
|
{{ store.appInfo?.name }}
|
||||||
|
<q-icon
|
||||||
|
class="q-ma-xs"
|
||||||
|
name="open_in_new"
|
||||||
|
color="grey-9"
|
||||||
|
/>
|
||||||
|
</a>
|
||||||
|
</template>
|
||||||
|
</q-breadcrumbs-el>
|
||||||
|
</q-breadcrumbs>
|
||||||
<div class="q-pa-md q-gutter-sm" :style="{minWidth: minPanelWidth}">
|
<div class="q-pa-md q-gutter-sm" :style="{minWidth: minPanelWidth}">
|
||||||
<div class="flowchart" v-if="store.currentFlow" :style="[drawerLeft?{paddingLeft:'300px'}:{}]">
|
<div class="flowchart" v-if="store.currentFlow" :style="[drawerLeft?{paddingLeft:'300px'}:{}]">
|
||||||
<node-item v-if="rootNode!==undefined" :key="rootNode.id" :isSelected="rootNode === store.activeNode"
|
<node-item v-if="rootNode!==undefined" :key="rootNode.id" :isSelected="rootNode === store.activeNode"
|
||||||
@@ -63,31 +75,40 @@
|
|||||||
</template>
|
</template>
|
||||||
<action-select ref="appDg" name="model" :filter="filter" type="single" @clearFilter="onClearFilter" ></action-select>
|
<action-select ref="appDg" name="model" :filter="filter" type="single" @clearFilter="onClearFilter" ></action-select>
|
||||||
</ShowDialog>
|
</ShowDialog>
|
||||||
|
<q-inner-loading
|
||||||
|
:showing="initLoading"
|
||||||
|
color="primary"
|
||||||
|
label="読み込み中..."
|
||||||
|
/>
|
||||||
</q-page>
|
</q-page>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, reactive, computed, onMounted } from 'vue';
|
import { ref, reactive, computed, onMounted } from 'vue';
|
||||||
|
import { useRoute } from 'vue-router';
|
||||||
import { IActionNode, ActionNode, IActionFlow, ActionFlow, RootAction, IActionProperty } from 'src/types/ActionTypes';
|
import { IActionNode, ActionNode, IActionFlow, ActionFlow, RootAction, IActionProperty } from 'src/types/ActionTypes';
|
||||||
|
import { IManagedApp } from 'src/types/AppTypes';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import { useFlowEditorStore } from 'stores/flowEditor';
|
import { useFlowEditorStore } from 'stores/flowEditor';
|
||||||
import { useAuthStore } from 'stores/useAuthStore';
|
import { useAuthStore } from 'stores/useAuthStore';
|
||||||
|
import { api } from 'boot/axios';
|
||||||
|
|
||||||
import NodeItem from 'src/components/main/NodeItem.vue';
|
import NodeItem from 'src/components/main/NodeItem.vue';
|
||||||
import ShowDialog from 'components/ShowDialog.vue';
|
import ShowDialog from 'components/ShowDialog.vue';
|
||||||
import ActionSelect from 'components/ActionSelect.vue';
|
import ActionSelect from 'components/ActionSelect.vue';
|
||||||
import PropertyPanel from 'components/right/PropertyPanel.vue';
|
import PropertyPanel from 'components/right/PropertyPanel.vue';
|
||||||
import AppSelector from 'components/left/AppSelector.vue';
|
|
||||||
import EventTree from 'components/left/EventTree.vue';
|
import EventTree from 'components/left/EventTree.vue';
|
||||||
import { FlowCtrl } from '../control/flowctrl';
|
import { FlowCtrl } from '../control/flowctrl';
|
||||||
import { useQuasar } from 'quasar';
|
import { useQuasar } from 'quasar';
|
||||||
|
|
||||||
const deployLoading = ref(false);
|
const deployLoading = ref(false);
|
||||||
const saveLoading = ref(false);
|
const saveLoading = ref(false);
|
||||||
|
const initLoading = ref(true);
|
||||||
const drawerLeft = ref(false);
|
const drawerLeft = ref(false);
|
||||||
const $q = useQuasar();
|
const $q = useQuasar();
|
||||||
const store = useFlowEditorStore();
|
const store = useFlowEditorStore();
|
||||||
const authStore = useAuthStore();
|
const authStore = useAuthStore();
|
||||||
|
const route = useRoute()
|
||||||
|
|
||||||
const appDg = ref();
|
const appDg = ref();
|
||||||
const prevNodeIfo = ref({
|
const prevNodeIfo = ref({
|
||||||
@@ -111,6 +132,9 @@ const minPanelWidth=computed(()=>{
|
|||||||
return "300px";
|
return "300px";
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
const fixedLeftPosition = computed(()=>{
|
||||||
|
return drawerLeft.value?"300px":"0px";
|
||||||
|
});
|
||||||
|
|
||||||
const addNode = (node: IActionNode, inputPoint: string) => {
|
const addNode = (node: IActionNode, inputPoint: string) => {
|
||||||
if (drawerRight.value) {
|
if (drawerRight.value) {
|
||||||
@@ -290,10 +314,24 @@ const onSaveAllFlow= async ()=>{
|
|||||||
}
|
}
|
||||||
|
|
||||||
const fetchData = async () => {
|
const fetchData = async () => {
|
||||||
|
initLoading.value = true;
|
||||||
|
if (store.appInfo === undefined && route?.params?.id !== undefined) {
|
||||||
|
const { appid, appname } = await fetchAppById(route.params.id as string);
|
||||||
|
store.setApp({
|
||||||
|
appId: appid,
|
||||||
|
name: appname
|
||||||
|
});
|
||||||
|
};
|
||||||
await store.loadFlow();
|
await store.loadFlow();
|
||||||
|
initLoading.value = false
|
||||||
drawerLeft.value = true;
|
drawerLeft.value = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const fetchAppById = async(id: string) => {
|
||||||
|
const result = await api.get('api/apps');
|
||||||
|
return result.data.find((item: IManagedApp) => item.appid === id ) as IManagedApp;
|
||||||
|
}
|
||||||
|
|
||||||
const onClearFilter=()=>{
|
const onClearFilter=()=>{
|
||||||
filter.value='';
|
filter.value='';
|
||||||
}
|
}
|
||||||
@@ -305,11 +343,6 @@ onMounted(() => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.app-selector {
|
|
||||||
padding: 15px;
|
|
||||||
z-index: 999;
|
|
||||||
}
|
|
||||||
|
|
||||||
.flowchart {
|
.flowchart {
|
||||||
padding-top: 10px;
|
padding-top: 10px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ const routes: RouteRecordRaw[] = [
|
|||||||
component: () => import('pages/LoginPage.vue')
|
component: () => import('pages/LoginPage.vue')
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path:'/FlowChart',
|
path:'/FlowChart/:id',
|
||||||
component:()=>import('layouts/MainLayout.vue'),
|
component:()=>import('layouts/MainLayout.vue'),
|
||||||
children:[
|
children:[
|
||||||
{path:'',component:()=>import('pages/FlowChart.vue')}
|
{path:'',component:()=>import('pages/FlowChart.vue')}
|
||||||
|
|||||||
14
frontend/src/types/AppTypes.ts
Normal file
14
frontend/src/types/AppTypes.ts
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
interface IUser {
|
||||||
|
first_name: string;
|
||||||
|
last_name: string;
|
||||||
|
email: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IManagedApp {
|
||||||
|
appid: string;
|
||||||
|
appname: string;
|
||||||
|
domainurl: string;
|
||||||
|
version: string;
|
||||||
|
user: IUser;
|
||||||
|
update_time: string;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user