Commit 5b1aef24 by Moxun Committed by elunez

1. 简化CRUD,少量代码即可实现单表维护,只需提供基本的CRUD方法、默认表单数据、和自定义的查询 (#57)

2. 增加搜索条件重置、操作栏(新增、修改、删除、导出、控制搜索栏可见性、刷新、过滤表格列显示)
3. 表单和头部(搜索栏)组件从主页面分类出来,方便代码组织维护
parent 54f04c82
<template>
<div class="crud-opts">
<span class="crud-opts-left">
<el-button
v-permission="permission.add"
class="filter-item"
size="mini"
type="primary"
icon="el-icon-plus"
@click="crud.toAdd"
>
新增
</el-button>
<el-button
v-permission="permission.edit"
class="filter-item"
size="mini"
type="success"
icon="el-icon-edit"
:disabled="crud.selections.length !== 1"
@click="crud.toEdit(crud.selections[0])"
>
修改
</el-button>
<el-button
slot="reference"
v-permission="permission.delete"
class="filter-item"
type="danger"
icon="el-icon-delete"
size="mini"
:disabled="crud.selections.length === 0"
@click="toDelete(crud.selections)"
>
删除
</el-button>
<el-button
:loading="crud.downloadLoading"
class="filter-item"
size="mini"
type="warning"
icon="el-icon-download"
@click="crud.doExport"
>导出</el-button>
</span>
<el-button-group class="crud-opts-right">
<el-button
size="mini"
plain
type="info"
icon="el-icon-search"
@click="toggleSearch()"
/>
<el-button
size="mini"
icon="el-icon-refresh"
@click="crud.refresh()"
/>
<el-popover
placement="bottom-end"
width="150"
trigger="click"
>
<el-button
slot="reference"
size="mini"
icon="el-icon-s-grid"
>
<i
class="fa fa-caret-down"
aria-hidden="true"
/>
</el-button>
<el-checkbox
v-for="item in crud.props.tableColumns"
:key="item.label"
v-model="item.visible"
>
{{ item.label }}
</el-checkbox>
</el-popover>
</el-button-group>
</div>
</template>
<script>
import { crud } from '@crud/crud'
export default {
mixins: [crud()],
props: {
permission: {
type: Object,
required: true
}
},
data() {
return {
}
},
created() {
this.crud.updateProp('searchToggle', true)
},
methods: {
toDelete(datas) {
this.$confirm(`确认删除选中的${datas.length}条数据?`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
if (datas.length === 1) {
this.crud.doDelete(datas[0])
} else {
this.crud.doDeletes(datas)
}
}).catch(() => {
})
},
toggleSearch() {
this.crud.props.searchToggle = !this.crud.props.searchToggle
}
}
}
</script>
<style>
.crud-opts {
padding: 6px 0;
display: -webkit-flex;
display: flex;
align-items: center;
}
.crud-opts .crud-opts-right {
margin-left: auto;
}
</style>
<template>
<el-pagination
:page-size.sync="page.size"
:total="page.total"
:current-page.sync="page.page"
style="margin-top: 8px;"
layout="total, prev, pager, next, sizes"
@size-change="crud.sizeChangeHandler($event)"
@current-change="crud.pageChangeHandler"
/>
</template>
<script>
import { pagination } from '@crud/crud'
export default {
mixins: [pagination()]
}
</script>
<template>
<span>
<el-button
class="filter-item"
size="mini"
type="success"
icon="el-icon-search"
@click="crud.toQuery"
>
搜索
</el-button>
<el-button
class="filter-item"
size="mini"
type="warning"
icon="el-icon-refresh-left"
@click="crud.resetQuery()"
>
重置
</el-button>
</span>
</template>
<script>
export default {
props: {
crud: {
type: Object,
required: true
},
itemClass: {
type: String,
required: false,
default: ''
}
}
}
</script>
<template>
<div>
<el-button
v-permission="permission.edit"
size="mini"
type="primary"
icon="el-icon-edit"
@click="crud.toEdit(data)"
/>
<el-popover
v-model="pop"
v-permission="permission.delete"
placement="top"
width="180"
trigger="manual"
>
<p>确定删除本条数据吗?</p>
<div
v-loading="crud.dataStatus[data.id].delete === 2"
style="text-align: right; margin: 0"
>
<el-button
size="mini"
type="text"
@click="doCancel"
>
取消
</el-button>
<el-button
type="primary"
size="mini"
@click="crud.doDelete(data)"
>
确定
</el-button>
</div>
<el-button
slot="reference"
type="danger"
icon="el-icon-delete"
size="mini"
@click="toDelete"
/>
</el-popover>
</div>
</template>
<script>
import CRUD, { crud } from '@crud/crud'
export default {
mixins: [crud()],
props: {
data: {
type: Object,
required: true
},
permission: {
type: Object,
required: true
}
},
data() {
return {
pop: false
}
},
methods: {
doCancel() {
this.pop = false
this.crud.cancelDelete(this.data)
},
toDelete() {
this.pop = true
},
[CRUD.HOOK.afterDelete](crud, data) {
if (data === this.data) {
this.pop = false
}
}
}
}
</script>
...@@ -2,186 +2,94 @@ ...@@ -2,186 +2,94 @@
<div class="app-container"> <div class="app-container">
<!--工具栏--> <!--工具栏-->
<div class="head-container"> <div class="head-container">
<!-- 搜索 --> <eHeader :dict="dict" :permission="permission" />
<el-input v-model="query.name" clearable size="small" placeholder="输入岗位名称搜索" style="width: 200px;" class="filter-item" @keyup.enter.native="toQuery" /> <crudOperation :permission="permission" />
<el-date-picker
v-model="query.createTime"
:default-time="['00:00:00','23:59:59']"
type="daterange"
range-separator=":"
size="small"
class="date-item"
value-format="yyyy-MM-dd HH:mm:ss"
start-placeholder="开始日期"
end-placeholder="结束日期"
/>
<el-select v-model="query.enabled" clearable size="small" placeholder="状态" class="filter-item" style="width: 90px" @change="toQuery">
<el-option v-for="item in enabledTypeOptions" :key="item.key" :label="item.display_name" :value="item.key" />
</el-select>
<el-button class="filter-item" size="mini" type="success" icon="el-icon-search" @click="toQuery">搜索</el-button>
<!-- 新增按钮 -->
<el-button
v-permission="['admin','job:add']"
class="filter-item"
size="mini"
type="primary"
icon="el-icon-plus"
@click="showAddFormDialog"
>新增</el-button>
<!-- 导出按钮 -->
<el-button
:loading="downloadLoading"
size="mini"
class="filter-item"
type="warning"
icon="el-icon-download"
@click="downloadMethod"
>导出</el-button>
</div> </div>
<!--表单渲染-->
<el-dialog :append-to-body="true" :close-on-click-modal="false" :before-close="cancel" :visible.sync="dialog" :title="getFormTitle()" width="500px">
<el-form ref="form" :model="form" :rules="rules" size="small" label-width="80px">
<el-form-item label="名称" prop="name">
<el-input v-model="form.name" style="width: 370px;" />
</el-form-item>
<el-form-item label="排序" prop="sort">
<el-input-number v-model.number="form.sort" :min="0" :max="999" controls-position="right" style="width: 370px;" />
</el-form-item>
<el-form-item v-if="form.pid !== 0" label="状态" prop="enabled">
<el-radio v-for="item in dict.job_status" :key="item.id" v-model="form.enabled" :label="item.value">{{ item.label }}</el-radio>
</el-form-item>
<el-form-item label="部门" prop="dept.id">
<treeselect v-model="form.dept.id" :options="depts" style="width: 370px" placeholder="选择部门" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="text" @click="cancel">取消</el-button>
<el-button :loading="loading" type="primary" @click="submitMethod">确认</el-button>
</div>
</el-dialog>
<!--表格渲染--> <!--表格渲染-->
<el-table v-loading="loading" :data="data" style="width: 100%;"> <el-table ref="table" v-loading="crud.loading" :data="crud.data" size="small" style="width: 100%;" @selection-change="crud.selectionChangeHandler">
<el-table-column prop="name" label="名称" /> <el-table-column type="selection" width="55" />
<el-table-column label="所属部门"> <el-table-column v-if="columns.visible('name')" prop="name" label="名称" />
<el-table-column v-if="columns.visible('dept')" prop="dept" label="所属部门">
<template slot-scope="scope"> <template slot-scope="scope">
<div>{{ scope.row.deptSuperiorName ? scope.row.deptSuperiorName + ' / ' : '' }}{{ scope.row.dept.name }}</div> <div>{{ scope.row.deptSuperiorName ? scope.row.deptSuperiorName + ' / ' : '' }}{{ scope.row.dept.name }}</div>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="sort" label="排序"> <el-table-column v-if="columns.visible('sort')" prop="sort" label="排序">
<template slot-scope="scope"> <template slot-scope="scope">
{{ scope.row.sort }} {{ scope.row.sort }}
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="状态" align="center"> <el-table-column v-if="columns.visible('status')" prop="status" label="状态" align="center">
<template slot-scope="scope"> <template slot-scope="scope">
<el-switch <el-switch
v-model="scope.row.enabled" v-model="scope.row.enabled"
active-color="#409EFF" active-color="#409EFF"
inactive-color="#F56C6C" inactive-color="#F56C6C"
@change="changeEnabled(scope.row, scope.row.enabled,)" @change="changeEnabled(scope.row, scope.row.enabled)"
/> />
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="createTime" label="创建日期"> <el-table-column v-if="columns.visible('createTime')" prop="createTime" label="创建日期">
<template slot-scope="scope"> <template slot-scope="scope">
<span>{{ parseTime(scope.row.createTime) }}</span> <span>{{ parseTime(scope.row.createTime) }}</span>
</template> </template>
</el-table-column> </el-table-column>
<!-- 编辑与删除 --> <!-- 编辑与删除 -->
<el-table-column v-if="checkPermission(['admin','job:edit','job:del'])" label="操作" width="130px" align="center" fixed="right"> <el-table-column
v-permission="['ADMIN','USERJOB_ALL','USERJOB_EDIT','USERJOB_DELETE']"
label="操作"
width="130px"
align="center"
fixed="right"
>
<template slot-scope="scope"> <template slot-scope="scope">
<el-button v-permission="['admin','job:edit']" size="mini" type="primary" icon="el-icon-edit" @click="showEditFormDialog(scope.row)" /> <udOperation
<el-popover :data="scope.row"
:ref="scope.row.id" :permission="permission"
v-permission="['admin','job:del']" />
placement="top"
width="180"
>
<p>确定删除本条数据吗?</p>
<div style="text-align: right; margin: 0">
<el-button size="mini" type="text" @click="$refs[scope.row.id].doClose()">取消</el-button>
<el-button :loading="delLoading" type="primary" size="mini" @click="delMethod(scope.row.id)">确定</el-button>
</div>
<el-button slot="reference" type="danger" icon="el-icon-delete" size="mini" />
</el-popover>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
<!--分页组件--> <!--分页组件-->
<el-pagination <pagination />
:total="total" <!--表单渲染-->
:current-page="page + 1" <eForm :job-status="dict.job_status" />
style="margin-top: 8px;"
layout="total, prev, pager, next, sizes"
@size-change="sizeChange"
@current-change="pageChange"
/>
</div> </div>
</template> </template>
<script> <script>
import crud from '@/mixins/crud'
import crudJob from '@/api/system/job' import crudJob from '@/api/system/job'
import { getDepts } from '@/api/system/dept' import eHeader from './module/header'
import Treeselect from '@riophae/vue-treeselect' import eForm from './module/form'
import '@riophae/vue-treeselect/dist/vue-treeselect.css' import CRUD, { presenter } from '@crud/crud'
import crudOperation from '@crud/CRUD.operation'
import pagination from '@crud/Pagination'
import udOperation from '@crud/UD.operation'
// crud交由presenter持有
const crud = CRUD({
title: '岗位',
url: 'api/job',
sort: ['sort,asc', 'id,desc'],
crudMethod: { ...crudJob }
})
export default { export default {
name: 'Job', name: 'Job',
components: { Treeselect }, components: { eHeader, eForm, crudOperation, pagination, udOperation },
mixins: [crud], mixins: [presenter(crud)],
// 数据字典 // 数据字典
dicts: ['job_status'], dicts: ['job_status'],
data() { data() {
return { return {
crudMethod: { permission: {
...crudJob add: ['admin', 'job:add'],
}, edit: ['admin', 'job:edit'],
sort: ['sort,asc', 'id,desc'], delete: ['admin', 'job:delete']
title: '岗位',
enabledTypeOptions: [
{ key: 'true', display_name: '正常' },
{ key: 'false', display_name: '禁用' }
],
form: { id: null, name: null, sort: 999, enabled: 'true', dept: { id: null }},
depts: [],
rules: {
name: [
{ required: true, message: '请输入名称', trigger: 'blur' }
],
sort: [
{ required: true, message: '请输入序号', trigger: 'blur', type: 'number' }
]
} }
} }
}, },
created() {
this.$nextTick(() => {
this.init()
})
},
methods: { methods: {
// 获取数据前设置好接口地址
beforeInit() {
this.url = 'api/job'
return true
},
// 打开新增弹窗前做的操作
beforeShowAddForm() {
this.getDepts()
},
// 打开编辑弹窗前做的操作
beforeShowEditForm(data) {
this.getDepts()
this.form.enabled = data.enabled.toString()
},
// 提交前的验证
beforeSubmitMethod() {
if (!this.form.dept.id) {
this.notify('所属部门不能为空', 'warning')
return false
}
return true
},
// 改变状态 // 改变状态
changeEnabled(data, val) { changeEnabled(data, val) {
this.$confirm('此操作将 "' + this.dict.label.job_status[val] + '" ' + data.name + '岗位, 是否继续?', '提示', { this.$confirm('此操作将 "' + this.dict.label.job_status[val] + '" ' + data.name + '岗位, 是否继续?', '提示', {
...@@ -189,21 +97,15 @@ export default { ...@@ -189,21 +97,15 @@ export default {
cancelButtonText: '取消', cancelButtonText: '取消',
type: 'warning' type: 'warning'
}).then(() => { }).then(() => {
this.crudMethod.edit(data).then(() => { crud.crudMethod.edit(data).then(() => {
this.notify(this.dict.label.job_status[val] + '成功', 'success') crud.notify(this.dict.label.job_status[val] + '成功', 'success')
}).catch(err => { }).catch(err => {
data.enabled = !data.enabled data.enabled = !data.enabled
console.log(err.response.data.message) console.log(err.data.message)
}) })
}).catch(() => { }).catch(() => {
data.enabled = !data.enabled data.enabled = !data.enabled
}) })
},
// 获取部门数据
getDepts() {
getDepts({ enabled: true }).then(res => {
this.depts = res.content
})
} }
} }
} }
......
<template>
<el-dialog
:append-to-body="true"
:close-on-click-modal="false"
:before-close="crud.cancelCU"
:visible="crud.status.cu > 0"
:title="crud.status.title"
width="500px"
>
<el-form
ref="form"
:model="form"
:rules="rules"
size="small"
label-width="80px"
>
<el-form-item
label="名称"
prop="name"
>
<el-input
v-model="form.name"
style="width: 370px;"
/>
</el-form-item>
<el-form-item
label="排序"
prop="sort"
>
<el-input-number
v-model.number="form.sort"
:min="0"
:max="999"
controls-position="right"
style="width: 370px;"
/>
</el-form-item>
<el-form-item
v-if="form.pid !== 0"
label="状态"
prop="enabled"
>
<el-radio
v-for="item in jobStatus"
:key="item.id"
v-model="form.enabled"
:label="item.value === 'true'"
>
{{ item.label }}
</el-radio>
</el-form-item>
<el-form-item
label="所属部门"
prop="dept.id"
:rules="rules.dept"
>
<treeselect
v-model="form.dept.id"
:options="depts"
style="width: 370px"
placeholder="选择部门"
/>
</el-form-item>
</el-form>
<div
slot="footer"
class="dialog-footer"
>
<el-button
type="text"
@click="crud.cancelCU"
>
取消
</el-button>
<el-button
:loading="crud.cu === 2"
type="primary"
@click="crud.submitCU"
>
确认
</el-button>
</div>
</el-dialog>
</template>
<script>
import CRUD, { form } from '@crud/crud'
import { getDepts } from '@/api/system/dept'
import Treeselect from '@riophae/vue-treeselect'
import '@riophae/vue-treeselect/dist/vue-treeselect.css'
const defaultForm = {
id: null,
name: '',
sort: 999,
enabled: true,
dept: {
id: null
}
}
export default {
components: { Treeselect },
mixins: [form(defaultForm)],
props: {
jobStatus: {
type: Array,
required: true
}
},
data() {
return {
depts: [],
rules: {
name: [
{ required: true, message: '请输入名称', trigger: 'blur' }
],
sort: [
{ required: true, message: '请输入序号', trigger: 'blur', type: 'number' }
],
dept: { required: true, message: '所属部门不能为空', trigger: 'select' }
}
}
},
methods: {
[CRUD.HOOK.beforeToCU]() {
getDepts({ enabled: true }).then(res => {
this.depts = res.content
})
},
// 提交前的验证
[CRUD.HOOK.afterValidateCU]() {
if (!this.form.dept.id) {
this.$notify({
title: '所属部门不能为空',
type: 'warning'
})
return false
}
return true
}
}
}
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
/deep/ .el-input-number .el-input__inner {
text-align: left;
}
</style>
<template>
<div
v-if="crud.props.searchToggle"
>
<el-input v-model="query.name" clearable size="small" placeholder="输入岗位名称搜索" style="width: 200px;" class="filter-item" @keyup.enter.native="crud.toQuery" />
<el-date-picker
v-model="query.createTime"
:default-time="['00:00:00','23:59:59']"
type="daterange"
range-separator=":"
size="small"
class="date-item"
value-format="yyyy-MM-dd HH:mm:ss"
start-placeholder="开始日期"
end-placeholder="结束日期"
/>
<el-select v-model="query.enabled" clearable size="small" placeholder="状态" class="filter-item" style="width: 90px" @change="crud.toQuery">
<el-option v-for="item in dict.dict.job_status" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
<rrOperation
:crud="crud"
/>
</div>
</template>
<script>
import { header } from '@crud/crud'
import rrOperation from '@crud/RR.operation'
export default {
components: { rrOperation },
mixins: [header()],
props: {
dict: {
type: Object,
required: true
},
permission: {
type: Object,
required: true
}
}
}
</script>
...@@ -46,7 +46,8 @@ module.exports = { ...@@ -46,7 +46,8 @@ module.exports = {
name: name, name: name,
resolve: { resolve: {
alias: { alias: {
'@': resolve('src') '@': resolve('src'),
'@crud': resolve('src/components/crud')
} }
} }
}, },
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment