perf: update draw

This commit is contained in:
ibuler
2024-12-12 19:03:03 +08:00
parent d62c87b858
commit b4abcd4c90
10 changed files with 374 additions and 59 deletions

View File

@@ -6,35 +6,20 @@
:disabled="disabled"
:type="col.type || 'info'"
class="detail"
@click="goDetail"
@click="handleClick"
>
<slot>
{{ iTitle }}
</slot>
</el-link>
<Drawer v-if="showTableDetailDrawer" :title="drawerTitle" @close-drawer="showTableDetailDrawer = !showTableDetailDrawer">
<component :is="currentTemplate" />
</Drawer>
</div>
</template>
<script>
import BaseFormatter from './base.vue'
import Drawer from '@/components/Drawer/index.vue'
export default {
name: 'DetailFormatter',
components: {
Drawer,
AssetDetail: () => import('@/views/assets/Asset/AssetDetail'),
AssetAccountList: () => import('@/views/accounts/Account/AccountDetail/index.vue'),
AccountPushDetail: () => import('@/views/accounts/AccountPush/AccountPushDetail/index.vue'),
AccountDiscoverTaskDetail: () => import('@/views/accounts/AccountDiscover/TaskDetail/index'),
AccountBackupDetail: () => import('@/views/accounts/AccountBackup/AccountBackupDetail/index.vue'),
IntegrationApplicationDetail: () => import('@/views/pam/Integration/ApplicationDetail/index.vue'),
AccountTemplateDetail: () => import('@/views/accounts/AccountTemplate/AccountTemplateDetail/index.vue')
},
extends: BaseFormatter,
props: {
formatterArgsDefault: {
@@ -45,6 +30,7 @@ export default {
getRoute: null,
routeQuery: null,
can: true,
onClick: null,
openInNewPage: false,
removeColorOnClick: false,
getTitle({ col, row, cellValue }) {
@@ -91,6 +77,17 @@ export default {
}
},
methods: {
handleClick() {
if (this.formatterArgs.onClick) {
this.formatterArgs.onClick({
col: this.col,
row: this.row,
cellValue: this.cellValue
})
} else {
this.goDetail()
}
},
getDetailRoute() {
// const defaultRoute = this.$route.name.replace('List', 'Detail')
let route = this.formatterArgs.route

View File

@@ -13,6 +13,7 @@ import { toSentenceCase } from '@/utils/common'
router.beforeEach(async(to, from, next) => {
// start progress bar
// NProgress.start()
await store.dispatch('common/setDrawerActionMeta', {})
try {
await startup({ to, from, next })
next()

View File

@@ -133,8 +133,13 @@ export default {
submitMethod: {
type: [Function, String],
default: function() {
const params = this.$route.params
if (params.id) {
const cloneFrom = this.getCloneId()
console.log('Clone from: ', cloneFrom)
if (cloneFrom) {
return 'post'
}
const objectId = this.getUpdateId()
if (objectId) {
return 'put'
} else {
return 'post'
@@ -145,13 +150,13 @@ export default {
getUrl: {
type: Function,
default: function() {
const params = this.$route.params
const objectId = this.getUpdateId()
let url = this.url
if (params.id) {
url = getUpdateObjURL(url, params.id)
if (objectId) {
url = getUpdateObjURL(url, objectId)
}
const clone_from = this.$route.query['clone_from']
const clone_from = this.getCloneId()
const query = clone_from ? `clone_from=${clone_from}` : ''
if (query) {
if (url.indexOf('?') === -1) {
@@ -268,7 +273,11 @@ export default {
form: {},
loading: true,
isSubmitting: false,
clone: false
clone: false,
drawer: false,
action: '',
actionId: '',
row: {}
}
},
computed: {
@@ -297,19 +306,47 @@ export default {
}
},
async created() {
this.$log.debug('Object init is: ', this.object)
const drawActionMeta = await this.$store.dispatch('common/getDrawerActionMeta')
if (drawActionMeta) {
this.drawer = true
this.action = drawActionMeta.action
this.row = drawActionMeta.row
this.actionId = this.row?.id
}
this.$log.debug('Object init is: ', this.object, this.method)
console.log('Action: ', this.action, this.actionId)
this.loading = true
try {
const values = await this.getFormValue()
this.$log.debug('Final object is: ', values)
const formValue = Object.assign(this.form, values)
this.form = this.afterGetFormValue(formValue)
console.log('Form: ', this.form)
} finally {
this.loading = false
}
},
methods: {
getUpdateId() {
if (this.actionId && this.action === 'update') {
return this.actionId
} else {
return this.$route.params.id
}
},
getAction() {
return this.action
},
getCloneId() {
if (this.actionId && this.action === 'clone') {
return this.actionId
} else {
return this.$route.query['clone_from']
}
},
isUpdateMethod() {
console.log('This method: ', this.method)
return ['put', 'patch'].indexOf(this.method.toLowerCase()) > -1
},
encryptFields(values) {
@@ -352,27 +389,35 @@ export default {
}, 200)
})
},
async getUpdateForm() {
},
async getCloneForm(cloneFrom) {
const [curUrl, query] = this.url.split('?')
const url = `${curUrl}${cloneFrom}/${query ? ('?' + query) : ''}`
const object = await this.getObjectDetail(url)
let name = ''
let attr = ''
if (object['name']) {
name = object['name']
attr = 'name'
} else if (object['hostname']) {
name = object['hostname']
attr = 'hostname'
}
object[attr] = name + '-' + this.cloneNameSuffix.toString()
return object
},
async getFormValue() {
const cloneFrom = this.$route.query['clone_from']
if ((!this.isUpdateMethod() && !cloneFrom) || !this.needGetObjectDetail) {
const cloneFrom = this.getCloneId()
const objectId = this.getUpdateId()
if ((!objectId && !cloneFrom) || !this.needGetObjectDetail) {
return Object.assign(this.form, this.initial)
}
let object = this.object
if (!object || Object.keys(object).length === 0) {
if (cloneFrom) {
const [curUrl, query] = this.url.split('?')
const url = `${curUrl}${cloneFrom}/${query ? ('?' + query) : ''}`
object = await this.getObjectDetail(url)
let name = ''
let attr = ''
if (object['name']) {
name = object['name']
attr = 'name'
} else if (object['hostname']) {
name = object['hostname']
attr = 'hostname'
}
object[attr] = name + '-' + this.cloneNameSuffix.toString()
object = await this.getCloneForm(cloneFrom)
} else {
object = await this.getObjectDetail(this.iUrl)
}

View File

@@ -1,5 +1,5 @@
<template>
<Page v-bind="$attrs">
<Page :class="{drawer: drawer}" v-bind="$attrs">
<IBox>
<GenericCreateUpdateForm ref="createUpdateForm" v-bind="$attrs" v-on="$listeners" />
</IBox>
@@ -14,6 +14,19 @@ export default {
name: 'GenericCreateUpdatePage',
components: {
Page, IBox, GenericCreateUpdateForm
},
data() {
return {
drawer: false
}
},
mounted() {
this.$store.dispatch('common/getDrawerActionMeta').then((res) => {
console.log('res: ', res)
if (res.action) {
this.drawer = true
}
})
}
}
</script>
@@ -27,4 +40,8 @@ export default {
padding-bottom: 60px;
}
}
.drawer ::v-deep .page-heading {
display: none;
}
</style>

View File

@@ -98,13 +98,7 @@ export default {
},
data() {
const vm = this
const detailApiUrl = (function() {
if (vm.url) {
return `${vm.url}/${vm.$route.params.id}/`
} else {
return getApiPath(vm)
}
}())
const detailApiUrl = this.getDetailUrl()
const defaultActions = {
// Delete button
canDelete: vm.$hasCurrentResAction('delete'),
@@ -187,6 +181,14 @@ export default {
}
},
methods: {
getDetailUrl() {
const vm = this
if (vm.url) {
return `${vm.url}/${vm.$route.params.id}/`
} else {
return getApiPath(vm)
}
},
defaultDelete() {
const msg = this.$t('DeleteWarningMsg') + ' ' + this.iTitle + ' ?'
const title = this.$t('Info')

View File

@@ -0,0 +1,67 @@
<template>
<el-drawer
:title="title"
:visible.sync="iVisible"
class="form-drawer"
size="800px"
>
<component :is="component" v-bind="props" @close="closeDrawer" />
</el-drawer>
</template>
<script>
export default {
props: {
visible: {
type: Boolean,
required: true
},
title: {
type: String,
default: ''
},
component: {
type: [String, Function],
required: true
},
props: {
type: Object,
default: () => ({})
}
},
computed: {
iVisible: {
get() {
return this.visible
},
set(val) {
this.$emit('update:visible', val)
}
}
},
mounted() {
console.log('Mounted: ',)
},
methods: {
closeDrawer() {
this.iVisible = false
}
}
}
</script>
<style lang="scss" scoped>
.form-drawer {
/* 可自定义样式 */
::v-deep {
.el-drawer__header {
margin-bottom: 10px;
padding-top: 10px;
font-size: 16px;
font-weight: 500;
color: var(--color-text-primary);
}
}
}
</style>

View File

@@ -0,0 +1,181 @@
<template>
<div>
<Page v-bind="$attrs">
<GenericListTable
ref="ListTable"
:header-actions="iHeaderActions"
:table-config="iTableConfig"
v-bind="$attrs"
/>
</Page>
<Drawer
v-if="drawerVisible"
:component="drawerComponent"
:props="drawerProps"
:title="drawerTitle"
:visible.sync="drawerVisible"
/>
</div>
</template>
<script>
import Page from '@/layout/components/Page'
import GenericListTable from '@/layout/components/GenericListTable'
import Drawer from './Drawer'
import { toSentenceCase } from '@/utils/common'
const drawerType = [String, Function]
export default {
name: 'GenericListPage',
components: {
Page, GenericListTable, Drawer
},
props: {
detailDrawer: {
type: drawerType,
default: ''
},
createDrawer: {
type: drawerType,
default: ''
},
updateDrawer: {
type: drawerType,
default: ''
},
tableConfig: {
type: Object,
required: true
},
headerActions: {
type: Object,
required: true
}
},
data() {
return {
visible: false,
drawerVisible: false,
drawerComponent: '',
drawerProps: {},
iHeaderActions: {},
iTableConfig: {},
action: '',
iCreateDrawer: this.createDrawer,
iUpdateDrawer: this.updateDrawer,
iDetailDrawer: this.detailDrawer
}
},
computed: {
drawerTitle() {
let title = this.title || this.$route.meta.title
if (!title) {
title = this.$t('NoTitle')
}
title = toSentenceCase(this.action) + ' ' + title.toLowerCase()
return title
}
},
watch: {
visible(val) {
if (!val) {
this.$store.dispatch('common/cleanDrawerActionMeta')
}
}
},
mounted() {
if (!this.createDrawer) {
this.iCreateDrawer = this.getDefaultDrawer('create')
}
if (!this.updateDrawer) {
this.iUpdateDrawer = this.getDefaultDrawer('update')
}
if (!this.detailDrawer) {
this.iDetailDrawer = this.getDefaultDrawer('detail')
}
},
created() {
this.iHeaderActions = {
...this.headerActions,
onCreate: this.onCreate
}
this.iTableConfig = {
...this.tableConfig
}
_.set(this.iTableConfig, 'columnsMeta.actions.formatterArgs.onUpdate', this.onUpdate)
_.set(this.iTableConfig, 'columnsMeta.actions.formatterArgs.onClone', this.onClone)
_.set(this.iTableConfig, 'columnsMeta.name.formatterArgs.onClick', this.onDetail)
},
methods: {
getDefaultDrawer(action) {
const route = this.$route.name
const actionRouteName = route.replace('List', toSentenceCase(action))
return this.getRouteNameComponent(actionRouteName)
},
getRouteNameComponent(name) {
const routes = this.$router.resolve({ name: name })
if (!routes) {
return
}
const matched = routes.resolved.matched.filter(item => item.name === name && item.components)
if (matched.length === 0) {
return
}
if (matched[0] && matched[0].components?.default) {
return matched[0].components.default
}
},
onCreate() {
this.action = 'create'
this.drawerComponent = this.iCreateDrawer
this.$store.dispatch('common/setDrawerActionMeta', {
action: 'create'
}).then(() => {
this.drawerVisible = true
})
},
reloadTable() {
this.$refs.ListTable.reloadTable()
},
onClone({ row, col }) {
this.drawerComponent = this.iCreateDrawer
this.action = 'clone'
this.$store.dispatch('common/setDrawerActionMeta', {
action: 'clone',
row: row,
col: col
}).then(() => {
this.drawerVisible = true
})
},
onUpdate({ row, col }) {
this.action = 'update'
let updateDrawer = this.iUpdateDrawer
if (!updateDrawer) {
updateDrawer = this.iCreateDrawer
}
this.drawerComponent = updateDrawer
this.$store.dispatch('common/setDrawerActionMeta', {
action: 'update',
row: row,
col: col
}).then(() => {
this.drawerVisible = true
})
},
onDetail({ row, cellValue }) {
this.action = 'detail'
this.drawerComponent = this.iDetailDrawer
this.$store.dispatch('common/setDrawerActionMeta', {
action: 'detail',
row: row,
cellValue: cellValue
}).then(() => {
this.drawerVisible = true
})
}
}
}
</script>

View File

@@ -7,7 +7,8 @@ const getDefaultState = () => {
isRouterAlive: true,
sqlQueryCounter: [],
showSqlQueryCounter: true,
confirmDialogVisible: false
confirmDialogVisible: false,
drawerActionMeta: {}
}
}
@@ -85,6 +86,15 @@ const actions = {
},
showSqlQueryCounter({ commit, state }, show) {
state.showSqlQueryCounter = show
},
setDrawerActionMeta({ commit, state }, meta) {
state.drawerActionMeta = meta
},
getDrawerActionMeta({ commit, state }) {
return state.drawerActionMeta
},
cleanDrawerActionMeta({ commit, state }) {
state.drawerActionMeta = {}
}
}

View File

@@ -164,14 +164,6 @@ export default {
el: {}
}
},
submitMethod() {
const params = this.$route.params
if (params.id) {
return 'put'
} else {
return 'post'
}
},
afterGetFormValue(obj) {
if (obj?.id) {
obj.org_roles = obj.org_roles?.map(({ id }) => id)

View File

@@ -1,6 +1,6 @@
<template>
<div>
<GenericListPage
<GenericListDrawerPage
ref="GenericListPage"
:header-actions="headerActions"
:quick-filters="quickFilters"
@@ -19,7 +19,8 @@
<script>
import { mapGetters } from 'vuex'
import { GenericListPage, GenericUpdateFormDialog } from '@/layout/components'
import { GenericUpdateFormDialog } from '@/layout/components'
import GenericListDrawerPage from '@/layout/components/GenericListDrawerPage/index.vue'
import { createSourceIdCache } from '@/api/common'
import { getDayFuture } from '@/utils/time'
import InviteUsersDialog from './components/InviteUsersDialog'
@@ -28,7 +29,7 @@ import AmountFormatter from '@/components/Table/TableFormatters/AmountFormatter.
export default {
components: {
InviteUsersDialog,
GenericListPage,
GenericListDrawerPage,
GenericUpdateFormDialog
},
data() {
@@ -43,6 +44,8 @@ export default {
return !vm.currentOrgIsRoot
}
return {
createDrawer: () => import('@/views/users/User/UserCreateUpdate.vue'),
detailDrawer: () => import('@/views/users/User/UserDetail/index.vue'),
quickFilters: [
{
label: '快速筛选',