Merged PR 7: Add new application

This commit is contained in:
xue jiahao
2024-11-24 07:55:15 +00:00
committed by 小哲 馬
5 changed files with 103 additions and 33 deletions

View File

@@ -1,4 +1,4 @@
import datetime from datetime import datetime
from fastapi import HTTPException, status from fastapi import HTTPException, status
from sqlalchemy.orm import Session from sqlalchemy.orm import Session
from sqlalchemy import and_ from sqlalchemy import and_
@@ -246,14 +246,13 @@ def edit_flow(
#見つからない時新規作成 #見つからない時新規作成
return create_flow(db,domainurl,flow,userid) return create_flow(db,domainurl,flow,userid)
db_flow.appid =flow.appid, db_flow.appid =flow.appid
db_flow.eventid=flow.eventid, db_flow.eventid=flow.eventid
db_flow.domainurl=domainurl, db_flow.domainurl=domainurl
db_flow.name=flow.name, db_flow.name=flow.name
db_flow.content=flow.content, db_flow.content=flow.content
db_flow.updateuserid = userid, db_flow.updateuserid = userid
db_flow.update_time = datetime.now
db.add(db_flow) db.add(db_flow)
db.commit() db.commit()
db.refresh(db_flow) db.refresh(db_flow)

View File

@@ -17,28 +17,38 @@
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import { ref, onMounted, reactive, watchEffect } from 'vue' import { ref, onMounted, reactive, watchEffect, PropType } from 'vue'
import { api } from 'boot/axios'; import { api } from 'boot/axios';
interface IAppDisplay {
id: string;
name: string;
description: string;
createdate: string;
}
export default { export default {
name: 'AppSelectBox', name: 'AppSelectBox',
props: { props: {
name: String, name: String,
type: String, type: String,
filter: String, filter: String,
filterInitRowsFunc: {
type: Function as PropType<(app: IAppDisplay) => boolean>,
},
updateSelectApp: { updateSelectApp: {
type: Function type: Function
} }
}, },
setup(props) { setup(props) {
const columns = [ const columns = [
{ name: 'id', required: true, label: 'ID', align: 'left', field: 'id', sortable: true }, { name: 'id', required: true, label: 'ID', align: 'left', field: 'id', sortable: true, sort: (a: string, b: string) => parseInt(a, 10) - parseInt(b, 10) },
{ name: 'name', label: 'アプリ名', field: 'name', sortable: true, align: 'left' }, { name: 'name', label: 'アプリ名', field: 'name', sortable: true, align: 'left' },
{ name: 'description', label: '概要', field: 'description', align: 'left', sortable: false }, { name: 'description', label: '概要', field: 'description', align: 'left', sortable: false },
{ name: 'createdate', label: '作成日時', field: 'createdate', align: 'left' } { name: 'createdate', label: '作成日時', field: 'createdate', align: 'left' }
] ]
const isLoaded = ref(false); const isLoaded = ref(false);
const rows: any[] = reactive([]); const rows = reactive<IAppDisplay[]>([]);
const selected = ref([]) const selected = ref([])
watchEffect(()=>{ watchEffect(()=>{
@@ -49,12 +59,16 @@ export default {
onMounted(() => { onMounted(() => {
api.get('api/v1/allapps').then(res => { api.get('api/v1/allapps').then(res => {
res.data.apps.forEach((item: any) => { res.data.apps.forEach((item: any) => {
rows.push({ const row : IAppDisplay = {
id: item.appId, id: item.appId,
name: item.name, name: item.name,
description: item.description, description: item.description,
createdate: dateFormat(item.createdAt) createdate: dateFormat(item.createdAt)
}); }
if (props.filterInitRowsFunc && !props.filterInitRowsFunc(row)) {
return;
}
rows.push(row);
}); });
isLoaded.value = true; isLoaded.value = true;
}); });

View File

@@ -12,7 +12,7 @@
<slot></slot> <slot></slot>
</q-card-section> </q-card-section>
<q-card-actions v-if="!disableBtn" align="right" class="text-primary"> <q-card-actions v-if="!disableBtn" align="right" class="text-primary">
<q-btn flat label="確定" v-close-popup @click="CloseDialogue('OK')" /> <q-btn flat label="確定" :loading="okBtnLoading" :v-close-popup="okBtnAutoClose" @click="CloseDialogue('OK')" />
<q-btn flat label="キャンセル" v-close-popup @click="CloseDialogue('Cancel')" /> <q-btn flat label="キャンセル" v-close-popup @click="CloseDialogue('Cancel')" />
</q-card-actions> </q-card-actions>
</q-card> </q-card>
@@ -30,6 +30,11 @@ export default {
height:String, height:String,
minWidth:String, minWidth:String,
minHeight:String, minHeight:String,
okBtnLoading:Boolean,
okBtnAutoClose:{
type: Boolean,
default: true
},
disableBtn:{ disableBtn:{
type: Boolean, type: Boolean,
default: false default: false

View File

@@ -8,7 +8,7 @@
<q-table title="Treats" :rows="rows" :columns="columns" row-key="id" :filter="filter" :loading="loading" :pagination="pagination"> <q-table title="Treats" :rows="rows" :columns="columns" row-key="id" :filter="filter" :loading="loading" :pagination="pagination">
<template v-slot:top> <template v-slot:top>
<q-btn disabled color="primary" :disable="loading" label="新規" @click="addRow" /> <q-btn color="primary" :disable="loading" label="新規" @click="showAddAppDialog" />
<q-space /> <q-space />
<q-input borderless dense filled debounce="300" v-model="filter" placeholder="検索"> <q-input borderless dense filled debounce="300" v-model="filter" placeholder="検索">
<template v-slot:append> <template v-slot:append>
@@ -26,15 +26,24 @@
<template v-slot:body-cell-actions="p"> <template v-slot:body-cell-actions="p">
<q-td :props="p"> <q-td :props="p">
<q-btn-group flat> <q-btn-group flat>
<q-btn flat color="primary" padding="xs" size="1em" icon="edit_note" @click="editFlow(p.row)" /> <q-btn flat color="primary" padding="xs" size="1em" icon="edit_note" @click="toEditFlowPage(p.row)" />
<q-btn disabled flat color="primary" padding="xs" size="1em" icon="history" @click="showHistory(p.row)" /> <q-btn disabled flat color="primary" padding="xs" size="1em" icon="history" @click="showHistory(p.row)" />
<q-btn disabled flat color="negative" padding="xs" size="1em" icon="delete_outline" @click="removeRow(p.row)" /> <q-btn disabled flat color="negative" padding="xs" size="1em" icon="delete_outline" @click="removeRow(p.row)" />
</q-btn-group> </q-btn-group>
</q-td> </q-td>
</template> </template>
</q-table> </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="filter" placeholder="検索" clearable>
<template v-slot:before>
<q-icon name="search" />
</template>
</q-input>
</template>
<app-select-box ref="appDialog" name="アプリ" type="single" :filter="filter" :filterInitRowsFunc="filterInitRows" />
</show-dialog>
</div> </div>
</template> </template>
@@ -46,9 +55,12 @@ import { useFlowEditorStore } from 'stores/flowEditor';
import { router } from 'src/router'; import { router } from 'src/router';
import { date } from 'quasar' import { date } from 'quasar'
import { IManagedApp } from 'src/types/AppTypes'; import { IManagedApp } from 'src/types/AppTypes';
import ShowDialog from 'src/components/ShowDialog.vue';
import AppSelectBox from 'src/components/AppSelectBox.vue';
interface IAppDisplay{ interface IAppDisplay{
id:string; id:string;
sortId: number;
name:string; name:string;
url:string; url:string;
user:string; user:string;
@@ -65,7 +77,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', sortable: true}, { name: 'version', label: 'バージョン', field: 'version', align: 'left', sortable: true, sort: numberStringSorting },
{ name: 'actions', label: '操作', field: 'actions' } { name: 'actions', label: '操作', field: 'actions' }
]; ];
@@ -73,21 +85,21 @@ const pagination = ref({ sortBy: 'id', descending: true, rowsPerPage: 20 });
const loading = ref(false); const loading = ref(false);
const filter = ref(''); const filter = ref('');
const rows = ref<IAppDisplay[]>([]); const rows = ref<IAppDisplay[]>([]);
const rowIds = new Set<string>();
const store = useFlowEditorStore(); const store = useFlowEditorStore();
const appDialog = ref();
const showSelectApp=ref(false);
const isAdding = ref(false);
const getApps = async () => { const getApps = async () => {
loading.value = true; loading.value = true;
rowIds.clear();
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 { rowIds.add(item.appid);
id: item.appid, return appToAppDisplay(item)
name: item.appname, }).sort((a: IAppDisplay, b: IAppDisplay) => a.sortId - b.sortId); // set default order
url: `${item.domainurl}/k/${item.appid}`,
user: `${item.updateuser.first_name} ${item.updateuser.last_name}` ,
updatetime:date.formatDate(item.update_time, 'YYYY/MM/DD HH:mm'),
version: Number(item.version)
}
}).sort((a: IAppDisplay, b: IAppDisplay) => numberStringSorting(a.id, b.id)); // set default order
loading.value = false; loading.value = false;
} }
@@ -100,8 +112,22 @@ watch(() => authStore.currentDomain.id, async () => {
await getApps(); await getApps();
}); });
const addRow = () => { const filterInitRows = (row: {id: string}) => {
return return !rowIds.has(row.id);
}
const showAddAppDialog = () => {
showSelectApp.value = true;
}
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;
} }
const removeRow = (app:IAppDisplay) => { const removeRow = (app:IAppDisplay) => {
@@ -112,7 +138,19 @@ const showHistory = (app:IAppDisplay) => {
return return
} }
const editFlow = (app:IAppDisplay) => { const appToAppDisplay = (app: IManagedApp) => {
return {
id: app.appid,
sortId: parseInt(app.appid, 10),
name: app.appname,
url: `${app.domainurl}/k/${app.appid}`,
user: `${app.updateuser.first_name} ${app.updateuser.last_name}` ,
updatetime:date.formatDate(app.update_time, 'YYYY/MM/DD HH:mm'),
version: app.version
}
}
const toEditFlowPage = (app:IAppDisplay) => {
store.setApp({ store.setApp({
appId: app.id, appId: app.id,
name: app.name name: app.name

View File

@@ -328,8 +328,22 @@ const fetchData = async () => {
} }
const fetchAppById = async(id: string) => { const fetchAppById = async(id: string) => {
const result = await api.get('api/apps'); try {
return result.data.find((item: IManagedApp) => item.appid === id ) as IManagedApp; const result = await api.get('api/apps');
return result.data.find((item: IManagedApp) => item.appid === id ) as IManagedApp;
} catch (e) {
console.error(e);
const result = await api.get(`api/v1/app?app=${id}`);
const data = result?.data;
if (data?.message) {
$q.notify({
type: 'negative',
caption: "エラー",
message: data.message
});
}
return { appid: data.appId, appname: data.name };
}
} }
const onClearFilter=()=>{ const onClearFilter=()=>{