[Update] 拆分GenricCreateUpdateForm

This commit is contained in:
ibuler
2020-05-06 15:22:47 +08:00
parent af0398d9d5
commit 99328722e9
10 changed files with 348 additions and 181 deletions

View File

@@ -1,20 +1,20 @@
<template> <template>
<el-card class="box-card"> <IBox :title="title" fa="fa-info-circle">
<div slot="header" class="clearfix">
<span>{{ title }}</span>
</div>
<div class="content"> <div class="content">
<el-row v-for="item in items" :key="'card-' + item.key" class="item" :gutter="10"> <el-row v-for="item in items" :key="'card-' + item.key" class="item" :gutter="10">
<el-col :span="6"><div class="item-label" :style="{ 'text-align': align}"><label>{{ item.key }}: </label></div></el-col> <el-col :span="6"><div class="item-label" :style="{ 'text-align': align}"><label>{{ item.key }}: </label></div></el-col>
<el-col :span="18"><div class="item-text">{{ item.value }}</div></el-col> <el-col :span="18"><div class="item-text">{{ item.value }}</div></el-col>
</el-row> </el-row>
</div> </div>
</el-card> </IBox>
</template> </template>
<script> <script>
import IBox from '../IBox'
export default { export default {
name: 'DetailCard', name: 'DetailCard',
components: { IBox },
props: { props: {
title: { title: {
type: String, type: String,

View File

@@ -1,7 +1,7 @@
<template> <template>
<el-card :class="'ibox ' + type" shadow="never" v-bind="$attrs"> <el-card :class="'ibox ' + type" shadow="never" v-bind="$attrs">
<div v-if="title" slot="header" class="clearfix ibox-title"> <div v-if="title" slot="header" class="clearfix ibox-title">
<h5><i v-if="fa" :class="'fa ' + fa" /> {{ title }}</h5> <i v-if="fa" :class="'fa ' + fa" /> {{ title }}
</div> </div>
<slot /> <slot />
</el-card> </el-card>
@@ -21,7 +21,7 @@ export default {
}, },
type: { type: {
type: String, type: String,
default: 'primary' default: 'default'
} }
}, },
computed: { computed: {
@@ -44,14 +44,16 @@ export default {
border-color: #e7eaec; border-color: #e7eaec;
border-image: none; border-image: none;
margin-bottom: 0; margin-bottom: 0;
padding: 14px 15px 7px; padding: 10px 15px;
min-height: 48px; min-height: 30px;
line-height: 1.32;
font-weight: normal;
} }
.ibox-title h5 { .ibox-title h5 {
display: inline-block; display: inline-block;
font-size: 14px; font-size: 14px;
margin: 0 0 7px; margin: 0;
padding: 0; padding: 0;
text-overflow: ellipsis; text-overflow: ellipsis;
float: left; float: left;

View File

@@ -1,5 +1,9 @@
<template> <template>
<IBox fa="fa-edit" :title="title" v-bind="$attrs" /> <IBox fa="fa-edit" :title="title" v-bind="$attrs">
<div class="quick-actions">
<slot />
</div>
</IBox>
</template> </template>
<script> <script>
@@ -22,5 +26,22 @@ export default {
</script> </script>
<style scoped> <style scoped>
.quick-actions >>> table {
width: 100%;
}
.quick-actions >>> tr > td {
line-height: 1.43;
padding: 8px;
vertical-align: top;
font-size: 13px;
width: 50%;
}
.quick-actions >>> tr > td > span:last-child {
float: right;
}
.quick-actions >>> button {
padding: 1px 13px;
}
</style> </style>

View File

@@ -1,5 +1,5 @@
<template> <template>
<IBox :fa="icon" :title="title" v-bind="$attrs"> <IBox :fa="icon" :type="type" :title="title" v-bind="$attrs">
<table style="width: 100%"> <table style="width: 100%">
<tr> <tr>
<td colspan="2"> <td colspan="2">
@@ -8,7 +8,7 @@
</tr> </tr>
<tr> <tr>
<td colspan="2"> <td colspan="2">
<el-button type="primary" size="small" :loading="submitLoading" @click="addObjects">{{ $tc('Add') }}</el-button> <el-button :type="type" size="small" :loading="submitLoading" @click="addObjects">{{ $tc('Add') }}</el-button>
</td> </td>
</tr> </tr>
<tr v-for="obj of iHasObjects" :key="obj.value" style="width: 100%" class="item"> <tr v-for="obj of iHasObjects" :key="obj.value" style="width: 100%" class="item">
@@ -21,7 +21,7 @@
</tr> </tr>
<tr v-if="params.hasMore" class="item"> <tr v-if="params.hasMore" class="item">
<td colspan="2"> <td colspan="2">
<el-button type="primary" size="small" style="width: 100%" @click="loadMore"> <el-button :type="type" size="small" style="width: 100%" @click="loadMore">
<i class="fa fa-arrow-down" /> <i class="fa fa-arrow-down" />
{{ $tc('More') }} {{ $tc('More') }}
</el-button> </el-button>
@@ -51,6 +51,10 @@ export default {
type: String, type: String,
default: '' default: ''
}, },
type: {
type: String,
default: 'primary'
},
// 地址发送给select2的查询所有的objects, 和select2 ajax一样 // 地址发送给select2的查询所有的objects, 和select2 ajax一样
objectsAjax: { objectsAjax: {
type: Object, type: Object,

View File

@@ -0,0 +1,57 @@
<template>
<el-switch
v-model="iValue"
:active-color="activeColor"
inactive-color="#dcdfe6"
v-bind="$attrs"
/>
</template>
<script>
export default {
name: 'Switcher',
props: {
type: {
type: String,
default: 'primary'
},
value: {
type: Boolean,
default: true
}
},
data() {
return {
}
},
computed: {
activeColor() {
// $--color-primary: #1ab394;
// $--color-success: #1c84c6;
// $--color-info: #23c6c8;
// $--color-warning: #f8ac59;
// $--color-danger: #ed5565;
switch (this.type) {
case 'primary':
return '#1ab394'
case 'danger':
return '#ed5565'
default:
return '#1ab394'
}
},
iValue: {
set: function(newValue) {
this.$emit('input', newValue)
},
get: function() {
return this.value
}
}
}
}
</script>
<style scoped>
</style>

View File

@@ -19,3 +19,4 @@ export { default as SvgIcon } from './SvgIcon'
export { default as TreeTable } from './TreeTable' export { default as TreeTable } from './TreeTable'
export { default as IBox } from './IBox' export { default as IBox } from './IBox'
export { default as QuickActions } from './QuickActions' export { default as QuickActions } from './QuickActions'
export { default as Switcher } from './Swicher'

View File

@@ -84,7 +84,8 @@ const cn = {
'Username': '用户名', 'Username': '用户名',
'Email': '邮件', 'Email': '邮件',
'Role': '角色', 'Role': '角色',
'Date expired': '失效日期' 'Date expired': '失效日期',
'Quick update': '快速更新'
}, },
route: { route: {
'dashboard': '仪表盘', 'dashboard': '仪表盘',

View File

@@ -0,0 +1,174 @@
<template>
<AutoDataForm
ref="form"
:method="method"
:form="form"
:fields="fields"
:url="totalUrl"
v-bind="$attrs"
v-on="$listeners"
@submit="handleSubmit"
/>
</template>
<script>
import AutoDataForm from '@/components/AutoDataForm'
export default {
name: 'GenericCreateUpdateForm',
components: {
AutoDataForm
},
props: {
url: {
type: String,
default: ''
},
fields: {
type: Array,
default: () => {
return []
}
},
object: {
type: Object,
default: null
},
initial: {
type: Object,
default: () => ({})
},
cleanFormValue: {
type: Function,
default: (value) => value
},
onSubmit: {
type: Function,
default: null
},
performSubmit: {
type: Function,
default: null
},
createSuccessMsg: {
type: String,
default: function() {
return this.$tc('Create success')
}
},
updateSuccessMsg: {
type: String,
default: function() {
return this.$tc('Update success')
}
},
createSuccessNextRoute: {
type: Object,
default: function() {
const routeName = this.$route.name.replace('Create', 'List')
return { name: routeName }
}
},
updateSuccessNextRoute: {
type: Object,
default: function() {
const routeName = this.$route.name.replace('Update', 'List')
return { name: routeName }
}
},
getMethod: {
type: Function,
default: function() {
const params = this.$route.params
if (params.id) {
return 'put'
} else {
return 'post'
}
}
},
getUrl: {
type: Function,
default: function() {
const params = this.$route.params
let url = this.url
if (params.id) {
url = `${url}/${params.id}/`
}
return url
}
}
},
data() {
return {
form: {},
loading: true
}
},
computed: {
method() {
return this.getMethod(this)
},
totalUrl() {
return this.getUrl()
}
},
async mounted() {
this.loading = true
try {
this.form = await this.getFormValue()
} finally {
this.loading = false
}
},
methods: {
handleSubmit(values) {
let handler = this.onSubmit || this.defaultOnSubmit
handler = handler.bind(this)
values = this.cleanFormValue(values)
return handler(values)
},
defaultPerformSubmit(validValues) {
return this.$axios[this.method](this.totalUrl, validValues)
},
defaultOnSubmit(validValues) {
const performSubmit = this.performSubmit || this.defaultPerformSubmit
const msg = this.method === 'post' ? this.createSuccessMsg : this.updateSuccessMsg
const route = this.method === 'post' ? this.createSuccessNextRoute : this.updateSuccessNextRoute
performSubmit(validValues).then(() => {
this.$message.success(msg)
this.$router.push(route)
}).catch(error => {
const response = error.response
const data = response.data
if (response.status === 400) {
for (const key of Object.keys(data)) {
let value = data[key]
if (value instanceof Array) {
value = value.join(';')
}
this.$refs.form.setFieldError(key, value)
}
}
})
},
async getFormValue() {
if (this.method !== 'put') {
return Object.assign(this.form, this.initial)
}
if (this.object === null) {
this.object = await this.getObjectDetail()
}
return this.object
},
async getObjectDetail() {
return this.$axios.get(this.totalUrl)
}
}
}
</script>
<style scoped>
.ibox >>> .el-card__body {
padding-top: 30px;
}
</style>

View File

@@ -1,173 +1,18 @@
<template> <template>
<Page v-loading="loading"> <Page>
<IBox v-if="!loading"> <IBox>
<AutoDataForm <GenericCreateUpdateForm v-bind="$attrs" v-on="$listeners" />
ref="form"
:method="method"
:form="form"
:fields="fields"
:url="totalUrl"
v-bind="$attrs"
v-on="$listeners"
@submit="handleSubmit"
/>
</IBox> </IBox>
</Page> </Page>
</template> </template>
<script> <script>
import { IBox } from '@/components' import { IBox } from '@/components'
import { Page } from '@/layout/components' import { Page } from '@/layout/components'
import AutoDataForm from '@/components/AutoDataForm' import GenericCreateUpdateForm from '../GenericCreateUpdateForm'
export default { export default {
name: 'GenericCreateUpdatePage', name: 'GenericCreateUpdatePage',
components: { components: {
Page, IBox, AutoDataForm Page, IBox, GenericCreateUpdateForm
},
props: {
url: {
type: String,
required: true
},
fields: {
type: Array,
default: () => {
return []
}
},
object: {
type: Object,
default: null
},
initial: {
type: Object,
default: () => ({})
},
cleanFormValue: {
type: Function,
default: (value) => value
},
onSubmit: {
type: Function,
default: null
},
performSubmit: {
type: Function,
default: null
},
createSuccessMsg: {
type: String,
default: function() {
return this.$tc('Create success')
}
},
updateSuccessMsg: {
type: String,
default: function() {
return this.$tc('Update success')
}
},
createSuccessNextRoute: {
type: Object,
default: function() {
const routeName = this.$route.name.replace('Create', 'List')
return { name: routeName }
}
},
updateSuccessNextRoute: {
type: Object,
default: function() {
const routeName = this.$route.name.replace('Update', 'List')
return { name: routeName }
}
},
getMethod: {
type: Function,
default: function() {
const params = this.$route.params
if (params.id) {
return 'put'
} else {
return 'post'
}
}
},
getUrl: {
type: Function,
default: function() {
const params = this.$route.params
let url = this.url
if (params.id) {
url = `${url}/${params.id}/`
}
return url
}
}
},
data() {
return {
form: {},
loading: true
}
},
computed: {
method() {
return this.getMethod(this)
},
totalUrl() {
return this.getUrl()
}
},
async mounted() {
this.loading = true
try {
this.form = await this.getFormValue()
} finally {
this.loading = false
}
},
methods: {
handleSubmit(values) {
let handler = this.onSubmit || this.defaultOnSubmit
handler = handler.bind(this)
values = this.cleanFormValue(values)
return handler(values)
},
defaultPerformSubmit(validValues) {
return this.$axios[this.method](this.totalUrl, validValues)
},
defaultOnSubmit(validValues) {
const performSubmit = this.performSubmit || this.defaultPerformSubmit
const msg = this.method === 'post' ? this.createSuccessMsg : this.updateSuccessMsg
const route = this.method === 'post' ? this.createSuccessNextRoute : this.updateSuccessNextRoute
performSubmit(validValues).then(() => {
this.$message.success(msg)
this.$router.push(route)
}).catch(error => {
const response = error.response
const data = response.data
if (response.status === 400) {
for (const key of Object.keys(data)) {
let value = data[key]
if (value instanceof Array) {
value = value.join(';')
}
this.$refs.form.setFieldError(key, value)
}
}
})
},
async getFormValue() {
if (this.method !== 'put') {
return Object.assign(this.form, this.initial)
}
if (this.object === null) {
this.object = await this.getObjectDetail()
}
return this.object
},
async getObjectDetail() {
return this.$axios.get(this.totalUrl)
}
} }
} }
</script> </script>

View File

@@ -4,21 +4,82 @@
<DetailCard :title="cardTitle" :items="detailItems" /> <DetailCard :title="cardTitle" :items="detailItems" />
</el-col> </el-col>
<el-col :md="10" :sm="24"> <el-col :md="10" :sm="24">
<QuickActions :type="'success'" /> <QuickActions type="primary">
<RelationCard v-bind="relationConfig" /> <table>
<tr>
<td>激活中:</td>
<td>
<span>
<Switcher v-model="value" />
</span>
</td>
</tr>
<tr>
<td>多因子认证:</td>
<td>
<span>
<el-slider
v-model="value2"
:min="0"
:max="2"
:step="1"
format-tooltip=""
show-stops
style="width: 50px"
/>
</span>
</td>
</tr>
<tr>
<td>重置多因子认证:</td>
<td>
<span>
<el-button type="primary" size="mini">重置</el-button>
</span>
</td>
</tr>
<tr>
<td>发送重置密码邮件:</td>
<td>
<span>
<el-button type="primary" size="mini">发送</el-button>
</span>
</td>
</tr>
<tr>
<td>发送重置密钥邮件:</td>
<td>
<span>
<el-button type="primary" size="mini">发送</el-button>
</span>
</td>
</tr>
<tr style="display:none">
<td>解除登录限制</td>
<td>
<span>
<el-button type="primary" size="mini">解除</el-button>
</span>
</td>
</tr>
</table>
</QuickActions>
<RelationCard type="info" style="margin-top: 15px" v-bind="relationConfig" />
</el-col> </el-col>
</el-row> </el-row>
</template> </template>
<script> <script>
import { DetailCard, RelationCard, QuickActions } from '@/components' import { DetailCard, RelationCard, QuickActions, Switcher } from '@/components'
export default { export default {
name: 'UserInfo', name: 'UserInfo',
components: { components: {
DetailCard, DetailCard,
RelationCard, RelationCard,
QuickActions QuickActions,
Switcher
}, },
props: { props: {
object: { object: {
@@ -28,6 +89,8 @@ export default {
}, },
data() { data() {
return { return {
value: false,
value2: 0,
relationConfig: { relationConfig: {
icon: 'fa-user', icon: 'fa-user',
title: this.$t('users.User groups'), title: this.$t('users.User groups'),
@@ -116,8 +179,7 @@ export default {
this.relationConfig.hasObjectsId = iNew.users this.relationConfig.hasObjectsId = iNew.users
} }
}, },
methods: { methods: {}
}
} }
</script> </script>