mirror of
https://github.com/jumpserver/lina.git
synced 2025-09-28 15:55:24 +00:00
Merge branch 'master' into jym_dev
This commit is contained in:
@@ -22,6 +22,7 @@
|
|||||||
"js-cookie": "2.2.0",
|
"js-cookie": "2.2.0",
|
||||||
"less": "^3.10.3",
|
"less": "^3.10.3",
|
||||||
"less-loader": "^5.0.0",
|
"less-loader": "^5.0.0",
|
||||||
|
"lodash": "^4.17.15",
|
||||||
"lodash.clonedeep": "^4.5.0",
|
"lodash.clonedeep": "^4.5.0",
|
||||||
"lodash.frompairs": "^4.0.1",
|
"lodash.frompairs": "^4.0.1",
|
||||||
"lodash.get": "^4.4.2",
|
"lodash.get": "^4.4.2",
|
||||||
|
9
src/api/common.js
Normal file
9
src/api/common.js
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
export function createSourceIdCache(ids) {
|
||||||
|
return request({
|
||||||
|
url: '/api/v1/common/resources/cache/',
|
||||||
|
method: 'post',
|
||||||
|
data: {resources: ids}
|
||||||
|
})
|
||||||
|
}
|
@@ -1,62 +1,91 @@
|
|||||||
<template>
|
<template>
|
||||||
<elFormRender ref="dataForm" :content="content" v-bind="$attrs" v-on="$listeners">
|
<ElFormRender
|
||||||
|
ref="dataForm"
|
||||||
|
:content="fields"
|
||||||
|
v-bind="$attrs"
|
||||||
|
:form="basicForm"
|
||||||
|
label-position="right"
|
||||||
|
label-width="17%"
|
||||||
|
v-on="$listeners"
|
||||||
|
>
|
||||||
<!-- slot 透传 -->
|
<!-- slot 透传 -->
|
||||||
<slot v-for="item in content" :slot="`id:${item.id}`" :name="`id:${item.id}`" />
|
<slot v-for="item in fields" :slot="`id:${item.id}`" :name="`id:${item.id}`" />
|
||||||
<slot v-for="item in content" :slot="`$id:${item.id}`" :name="`$id:${item.id}`" />
|
<slot v-for="item in fields" :slot="`$id:${item.id}`" :name="`$id:${item.id}`" />
|
||||||
|
|
||||||
<el-form-item v-if="defaultButton">
|
<el-form-item v-if="defaultButton">
|
||||||
<el-button size="small" type="primary" @click="submitForm('dataForm')">submit</el-button>
|
<el-button size="small" @click="resetForm('dataForm')">{{ $tc('Reset') }}</el-button>
|
||||||
<el-button size="small" @click="resetForm('dataForm')">reset</el-button>
|
<el-button size="small" type="primary" @click="submitForm('dataForm')">{{ $tc('Submit') }}</el-button>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<slot name="Actions" />
|
<slot name="Actions" />
|
||||||
</elFormRender>
|
</ElFormRender>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import elFormRender from './components/el-form-renderer'
|
import ElFormRender from './components/el-form-renderer'
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
elFormRender
|
ElFormRender
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
defaultButton: {
|
defaultButton: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true
|
default: true
|
||||||
},
|
},
|
||||||
content: {
|
fields: {
|
||||||
type: Array,
|
type: Array,
|
||||||
default: () => []
|
default: () => []
|
||||||
|
},
|
||||||
|
// 初始值
|
||||||
|
form: {
|
||||||
|
type: Object,
|
||||||
|
default: () => { return {} }
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
basicForm: {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.basicForm = this.form
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
// 获取表单数据
|
||||||
submitForm(formName) {
|
submitForm(formName) {
|
||||||
this.$refs[formName].validate((valid) => {
|
this.$refs[formName].validate((valid) => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
this.$emit('submit')
|
this.$emit('submit', this.$refs[formName].getFormValue())
|
||||||
} else {
|
} else {
|
||||||
console.log('error submit!!')
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
// 重置表单
|
||||||
resetForm(formName) {
|
resetForm(formName) {
|
||||||
this.$refs[formName].resetFields()
|
this.$refs[formName].resetFields()
|
||||||
},
|
|
||||||
getBasic() {
|
|
||||||
if (this.url) {
|
|
||||||
console.log('has Url')
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
.el-form /deep/ .el-form-item {
|
.el-form /deep/ .el-form-item {
|
||||||
margin-bottom: 12px;
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
margin-left:12%;
|
.el-form /deep/ .el-form-item__content {
|
||||||
width:73%;
|
width: 75%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.el-form /deep/ .el-form-item__label {
|
||||||
|
padding: 0 30px 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-form /deep/ .el-form-item__error {
|
||||||
|
position: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-form /deep/ .form-group-header {
|
||||||
|
margin-left: 50px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
14
src/components/DataForm/rules/index.js
Normal file
14
src/components/DataForm/rules/index.js
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import i18n from '@/i18n/i18n'
|
||||||
|
|
||||||
|
export const Required = {
|
||||||
|
required: true, message: i18n.t('common.' + 'This field is required'), trigger: 'blur'
|
||||||
|
}
|
||||||
|
|
||||||
|
export const RequiredChange = {
|
||||||
|
required: true, message: i18n.t('common.' + 'This field is required'), trigger: 'change'
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
Required,
|
||||||
|
RequiredChange
|
||||||
|
}
|
@@ -102,8 +102,9 @@
|
|||||||
<div
|
<div
|
||||||
:is="col.formatter"
|
:is="col.formatter"
|
||||||
:key="row.id"
|
:key="row.id"
|
||||||
:setting="data"
|
:table-data="data"
|
||||||
:row="row"
|
:row="row"
|
||||||
|
:reload="getList"
|
||||||
:col="col"
|
:col="col"
|
||||||
:cell-value="row[col.prop]"
|
:cell-value="row[col.prop]"
|
||||||
>
|
>
|
||||||
@@ -730,7 +731,8 @@ export default {
|
|||||||
// JSON.stringify是为了后面深拷贝作准备
|
// JSON.stringify是为了后面深拷贝作准备
|
||||||
initExtraQuery: JSON.stringify(this.extraQuery || this.customQuery || {}),
|
initExtraQuery: JSON.stringify(this.extraQuery || this.customQuery || {}),
|
||||||
isSearchCollapse: false,
|
isSearchCollapse: false,
|
||||||
showNoData: false
|
showNoData: false,
|
||||||
|
innerQuery: {}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@@ -852,6 +854,7 @@ export default {
|
|||||||
formValue = this.$refs.searchForm.getFormValue()
|
formValue = this.$refs.searchForm.getFormValue()
|
||||||
Object.assign(query, formValue)
|
Object.assign(query, formValue)
|
||||||
}
|
}
|
||||||
|
Object.assign(query, this.innerQuery)
|
||||||
Object.assign(query, this._extraQuery)
|
Object.assign(query, this._extraQuery)
|
||||||
|
|
||||||
query[this.pageSizeKey] = this.hasPagination
|
query[this.pageSizeKey] = this.hasPagination
|
||||||
@@ -942,18 +945,9 @@ export default {
|
|||||||
this.loading = false
|
this.loading = false
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
async search() {
|
search(attrs) {
|
||||||
const form = this.$refs.searchForm
|
this.innerQuery = Object.assign(this.innerQuery, attrs)
|
||||||
const valid = await new Promise(r => form.validate(r))
|
return this.getList()
|
||||||
if (!valid) return
|
|
||||||
|
|
||||||
try {
|
|
||||||
await this.beforeSearch(form.getFormValue())
|
|
||||||
this.page = defaultFirstPage
|
|
||||||
this.getList()
|
|
||||||
} catch (err) {
|
|
||||||
this.$emit('error', err)
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* 重置查询,相当于点击「重置」按钮
|
* 重置查询,相当于点击「重置」按钮
|
||||||
@@ -1168,15 +1162,12 @@ export default {
|
|||||||
return record[this.treeChildKey] && record[this.treeChildKey].length > 0
|
return record[this.treeChildKey] && record[this.treeChildKey].length > 0
|
||||||
},
|
},
|
||||||
onSortChange({ column, prop, order }) {
|
onSortChange({ column, prop, order }) {
|
||||||
if (!this.extraQuery) {
|
|
||||||
this.extraQuery = {}
|
|
||||||
}
|
|
||||||
if (!order) {
|
if (!order) {
|
||||||
delete this.extraQuery['sort']
|
delete this.innerQuery['sort']
|
||||||
delete this.extraQuery['direction']
|
delete this.innerQuery['direction']
|
||||||
} else {
|
} else {
|
||||||
this.extraQuery['sort'] = prop
|
this.innerQuery['sort'] = prop
|
||||||
this.extraQuery['direction'] = order
|
this.innerQuery['direction'] = order
|
||||||
}
|
}
|
||||||
this.getList()
|
this.getList()
|
||||||
}
|
}
|
||||||
|
@@ -1,92 +0,0 @@
|
|||||||
<template>
|
|
||||||
<ActionsGroup :size="'mini'" :actions="actions" :more-actions="moreActions" @actionClick="handleActionClick"></ActionsGroup>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import ActionsGroup from '@/components/ActionsGroup'
|
|
||||||
import BaseFormatter from './base'
|
|
||||||
export default {
|
|
||||||
name: 'ActionsFormatter',
|
|
||||||
components: { ActionsGroup },
|
|
||||||
extends: BaseFormatter,
|
|
||||||
data() {
|
|
||||||
const defaultActions = [
|
|
||||||
{
|
|
||||||
name: 'update',
|
|
||||||
title: this.$tc('Update'),
|
|
||||||
type: 'primary',
|
|
||||||
has: this.col.actions.hasUpdate || true,
|
|
||||||
can: this.col.actions.canUpdate || true,
|
|
||||||
callback: this.col.actions.onUpdate
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'delete',
|
|
||||||
title: this.$tc('Delete'),
|
|
||||||
type: 'danger',
|
|
||||||
has: this.col.actions.hasDelete || true,
|
|
||||||
can: this.col.actions.canDelete || true,
|
|
||||||
callback: this.col.actions.onDelete
|
|
||||||
}
|
|
||||||
]
|
|
||||||
const extraActions = this.col.actions.extraActions || []
|
|
||||||
return {
|
|
||||||
defaultActions: defaultActions,
|
|
||||||
extraActions: extraActions
|
|
||||||
}
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
validActions() {
|
|
||||||
const actions = [...this.defaultActions, ...this.extraActions]
|
|
||||||
const validActions = []
|
|
||||||
for (const v of actions) {
|
|
||||||
const has = this.checkItem(v, 'has')
|
|
||||||
if (!has) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
const can = this.checkItem(v, 'can')
|
|
||||||
v.disabled = !can
|
|
||||||
validActions.push(v)
|
|
||||||
}
|
|
||||||
return validActions
|
|
||||||
},
|
|
||||||
actions() {
|
|
||||||
return this.validActions.slice(0, 2)
|
|
||||||
},
|
|
||||||
moreActions() {
|
|
||||||
return this.validActions.slice(2, this.validActions.length)
|
|
||||||
},
|
|
||||||
namedValidActions() {
|
|
||||||
const actions = {}
|
|
||||||
for (const action of this.validActions) {
|
|
||||||
if (!action || !action.hasOwnProperty('name')) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
actions[action.name] = action
|
|
||||||
}
|
|
||||||
return actions
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
handleActionClick(item) {
|
|
||||||
const action = this.namedValidActions[item]
|
|
||||||
if (action && action.callback) {
|
|
||||||
console.log(this.setting)
|
|
||||||
action.callback(this.row, this.col, this.cellValue)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
checkItem(item, attr) {
|
|
||||||
let ok = item[attr]
|
|
||||||
if (typeof ok === 'function') {
|
|
||||||
ok = ok(this.row, this.cellValue)
|
|
||||||
} else if (ok == null) {
|
|
||||||
ok = true
|
|
||||||
}
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
|
|
||||||
</style>
|
|
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<ElDatableTable class="el-table" v-bind="tableConfig" v-on="$listeners"></ElDatableTable>
|
<ElDatableTable ref="table" class="el-table" v-bind="tableConfig" v-on="$listeners"></ElDatableTable>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@@ -36,16 +36,12 @@ export default {
|
|||||||
hasDelete: userTableActions.hasDelete !== false,
|
hasDelete: userTableActions.hasDelete !== false,
|
||||||
hasNew: false,
|
hasNew: false,
|
||||||
// editText: this.$t('action.update'), // 编辑按钮文案
|
// editText: this.$t('action.update'), // 编辑按钮文案
|
||||||
operationAttrs: {
|
|
||||||
align: 'center',
|
|
||||||
width: '150px'
|
|
||||||
},
|
|
||||||
operationButtonType: 'button',
|
|
||||||
buttonSize: 'mini',
|
buttonSize: 'mini',
|
||||||
tableAttrs: {
|
tableAttrs: {
|
||||||
stripe: true, // 斑马纹表格
|
stripe: true, // 斑马纹表格
|
||||||
border: true, // 表格边框
|
border: true, // 表格边框
|
||||||
fit: true // 宽度自适应
|
fit: true, // 宽度自适应,
|
||||||
|
tooltipEffect: 'dark'
|
||||||
},
|
},
|
||||||
extraButtons: userTableActions.extraButtons,
|
extraButtons: userTableActions.extraButtons,
|
||||||
onEdit: (row) => {
|
onEdit: (row) => {
|
||||||
@@ -90,6 +86,15 @@ export default {
|
|||||||
const config = Object.assign(this.defaultConfig, this.config)
|
const config = Object.assign(this.defaultConfig, this.config)
|
||||||
return config
|
return config
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getList() {
|
||||||
|
this.$refs.table.clearSelection()
|
||||||
|
return this.$refs.table.getList()
|
||||||
|
},
|
||||||
|
search(attrs) {
|
||||||
|
return this.$refs.table.search(attrs)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
@@ -102,7 +107,6 @@ export default {
|
|||||||
}
|
}
|
||||||
.el-table /deep/ .el-table__row > td> div > span {
|
.el-table /deep/ .el-table__row > td> div > span {
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
-moz-text-overflow: ellipsis;
|
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
40
src/components/Dialog/index.vue
Normal file
40
src/components/Dialog/index.vue
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
<template>
|
||||||
|
<el-dialog :title="title" v-bind="$attrs" v-on="$listeners">
|
||||||
|
<slot></slot>
|
||||||
|
<div slot="footer" class="dialog-footer">
|
||||||
|
<slog name="footer">
|
||||||
|
<el-button size="small" @click="onCancel">{{ $t('Cancel') }}</el-button>
|
||||||
|
<el-button type="primary" size="small" @click="onConfirm">{{ $tc('Ok') }}</el-button>
|
||||||
|
</slog>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'Dialog',
|
||||||
|
props: {
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
visible: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onCancel() {
|
||||||
|
|
||||||
|
},
|
||||||
|
onConfirm() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
@@ -1,96 +1,237 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="table-header">
|
<div class="table-header">
|
||||||
<slot name="header">
|
<slot name="header">
|
||||||
<!--TODO: 事件交互 -->
|
|
||||||
<div class="table-header-left-side">
|
<div class="table-header-left-side">
|
||||||
<ActionsGroup :actions="actions" :more-actions="moreActions" class="header-action" @actionClick="handleActionClick"></ActionsGroup>
|
<ActionsGroup :actions="actions" :more-actions="moreActions" class="header-action" @actionClick="handleActionClick"></ActionsGroup>
|
||||||
</div>
|
</div>
|
||||||
<!-- TODO: 事件交互 -->
|
|
||||||
<div class="table-action-right-side">
|
<div class="table-action-right-side">
|
||||||
<el-input v-model="keyword" suffix-icon="el-icon-search" :placeholder="$tc('Search')" class="right-side-item action-search" size="small" clearable @change="handleSearch" @input="handleSearch"></el-input>
|
<el-input v-model="keyword" suffix-icon="el-icon-search" :placeholder="$tc('Search')" class="right-side-item action-search" size="small" clearable @change="handleSearch" @input="handleSearch"></el-input>
|
||||||
<ActionsGroup :is-fa="true" :actions="rightSideActions" class="right-side-actions right-side-item" @actionClick="handleActionClick"></ActionsGroup>
|
<ActionsGroup :is-fa="true" :actions="defaultRightSideActions" class="right-side-actions right-side-item" @actionClick="handleActionClick"></ActionsGroup>
|
||||||
</div>
|
</div>
|
||||||
|
<Dialog :title="$t('Export')">
|
||||||
|
<el-form>
|
||||||
|
<el-form-item label="导出范围" :label-width="'100px'">
|
||||||
|
<el-radio v-model="exportValue" class="export-item" label="1">导出全部</el-radio>
|
||||||
|
<el-radio v-model="exportValue" class="export-item" label="2">仅导出选中项</el-radio>
|
||||||
|
<el-radio v-model="exportValue" class="export-item" label="3">仅导出搜索项</el-radio>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</Dialog>
|
||||||
</slot>
|
</slot>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import ActionsGroup from '@/components/ActionsGroup'
|
import ActionsGroup from '@/components/ActionsGroup'
|
||||||
|
import { Dialog } from '../Dialog'
|
||||||
|
import _ from 'lodash'
|
||||||
|
import { createSourceIdCache } from '@/api/common'
|
||||||
|
|
||||||
const defaultTrue = { type: Boolean, default: true }
|
const defaultTrue = { type: Boolean, default: true }
|
||||||
|
const defaultFalse = { type: Boolean, default: false }
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'TableAction',
|
name: 'TableAction',
|
||||||
components: {
|
components: {
|
||||||
ActionsGroup
|
ActionsGroup,
|
||||||
|
Dialog
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
hasExport: defaultTrue,
|
hasExport: defaultTrue,
|
||||||
hasImport: defaultTrue,
|
hasImport: defaultTrue,
|
||||||
hasRefresh: defaultTrue,
|
hasRefresh: defaultTrue,
|
||||||
hasCreate: defaultTrue,
|
hasCreate: defaultTrue,
|
||||||
hasDelete: defaultTrue,
|
hasBulkDelete: defaultTrue,
|
||||||
hasUpdate: defaultTrue,
|
hasBulkUpdate: defaultFalse,
|
||||||
hasLeftActions: defaultTrue,
|
hasLeftActions: defaultTrue,
|
||||||
hasSearch: defaultTrue,
|
hasSearch: defaultTrue,
|
||||||
hasRightActions: defaultTrue
|
hasRightActions: defaultTrue,
|
||||||
|
tableUrl: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
createRoute: {
|
||||||
|
type: String,
|
||||||
|
default: '404'
|
||||||
|
},
|
||||||
|
reloadTable: {
|
||||||
|
type: Function,
|
||||||
|
default: () => {}
|
||||||
|
},
|
||||||
|
performBulkDelete: {
|
||||||
|
type: Function,
|
||||||
|
default: () => {}
|
||||||
|
},
|
||||||
|
searchTable: {
|
||||||
|
type: Function,
|
||||||
|
default: () => {}
|
||||||
|
},
|
||||||
|
selectedRows: {
|
||||||
|
type: Array,
|
||||||
|
default: () => ([])
|
||||||
|
},
|
||||||
|
extraActions: {
|
||||||
|
type: Array,
|
||||||
|
default: () => ([])
|
||||||
|
},
|
||||||
|
extraMoreActions: {
|
||||||
|
type: Array,
|
||||||
|
default: () => ([])
|
||||||
|
},
|
||||||
|
extraRightSideActions: {
|
||||||
|
type: Array,
|
||||||
|
default: () => ([])
|
||||||
|
}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
defaultRightSideActions: {
|
|
||||||
Export: { name: 'actionExport', fa: 'fa-download' },
|
|
||||||
Import: { name: 'actionImport', fa: 'fa-upload' },
|
|
||||||
Refresh: { name: 'actionRefresh', fa: 'fa-refresh' }
|
|
||||||
},
|
|
||||||
defaultCreateAction: {
|
|
||||||
name: 'actionCreate',
|
|
||||||
title: this.$tc('Create'),
|
|
||||||
type: 'primary'
|
|
||||||
},
|
|
||||||
keyword: '',
|
keyword: '',
|
||||||
defaultMoreActions: {
|
defaultRightSideActions: [
|
||||||
Delete: {
|
{ name: 'actionExport', fa: 'fa-download', has: this.hasExport, callback: this.handleExport },
|
||||||
title: this.$tc('Delete selected'),
|
{ name: 'actionImport', fa: 'fa-upload', has: this.hasImport, callback: this.handleImport },
|
||||||
name: 'actionDeleteSelected'
|
{ name: 'actionRefresh', fa: 'fa-refresh', has: this.hasRefresh, callback: this.handleRefresh }
|
||||||
},
|
],
|
||||||
Update: {
|
defaultActions: [
|
||||||
title: this.$tc('Update selected'),
|
{
|
||||||
name: 'actionUpdateSelected'
|
name: 'actionCreate',
|
||||||
|
title: this.$tc('Create'),
|
||||||
|
type: 'primary',
|
||||||
|
has: this.hasCreate,
|
||||||
|
can: true,
|
||||||
|
callback: this.handleCreate
|
||||||
}
|
}
|
||||||
}
|
],
|
||||||
|
defaultMoreActions: [
|
||||||
|
{
|
||||||
|
title: this.$tc('Delete selected'),
|
||||||
|
name: 'actionDeleteSelected',
|
||||||
|
can: (rows) => rows.length > 0,
|
||||||
|
has: this.hasBulkDelete,
|
||||||
|
callback: this.defaultBulkDeleteCallback
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: this.$tc('Update selected'),
|
||||||
|
name: 'actionUpdateSelected',
|
||||||
|
can: (rows) => rows.length > 0,
|
||||||
|
has: this.hasBulkUpdate,
|
||||||
|
callback: this.handleBulkUpdate
|
||||||
|
}
|
||||||
|
],
|
||||||
|
dialogExportVisible: false,
|
||||||
|
exportValue: 2
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
rightSideActions() {
|
rightSideActions() {
|
||||||
const actions = []
|
const actions = [...this.defaultRightSideActions, ...this.extraRightSideActions]
|
||||||
for (const k in this.defaultRightSideActions) {
|
return this.cleanActions(actions)
|
||||||
if (this['has' + k]) {
|
|
||||||
actions.push(this.defaultRightSideActions[k])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return actions
|
|
||||||
},
|
},
|
||||||
actions() {
|
actions() {
|
||||||
const actions = []
|
const actions = [...this.defaultActions, ...this.extraActions]
|
||||||
if (this.hasCreate) {
|
return this.cleanActions(actions)
|
||||||
actions.push(this.defaultCreateAction)
|
|
||||||
}
|
|
||||||
return actions
|
|
||||||
},
|
},
|
||||||
moreActions() {
|
moreActions() {
|
||||||
const actions = []
|
const actions = [...this.defaultMoreActions, ...this.extraMoreActions]
|
||||||
for (const k in this.defaultMoreActions) {
|
return this.cleanActions(actions)
|
||||||
if (this['has' + k]) {
|
},
|
||||||
actions.push(this.defaultMoreActions[k])
|
|
||||||
|
namedActions() {
|
||||||
|
const totalActions = [...this.actions, ...this.moreActions, ...this.rightSideActions]
|
||||||
|
const actions = {}
|
||||||
|
for (const action of totalActions) {
|
||||||
|
if (!action || !action.hasOwnProperty('name')) {
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
actions[action.name] = action
|
||||||
}
|
}
|
||||||
return actions
|
return actions
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
handleSearch(keyword) {
|
handleSearch: _.debounce(function() {
|
||||||
console.log('Search: ', keyword)
|
this.searchTable({search: this.keyword})
|
||||||
},
|
}, 500),
|
||||||
handleActionClick(item) {
|
handleActionClick(item) {
|
||||||
this.$emit('clickAction', item)
|
console.log('name cations', this.namedActions)
|
||||||
|
let handler = this.namedActions[item] ? this.namedActions[item].callback : null
|
||||||
|
if (!handler) {
|
||||||
|
handler = () => {
|
||||||
|
console.log('No handler found for ', item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
handler(this.selectedRows)
|
||||||
|
},
|
||||||
|
handleCreate() {
|
||||||
|
const routeName = this.createRoute
|
||||||
|
this.$router.push({ name: routeName })
|
||||||
|
console.log('handle create')
|
||||||
|
},
|
||||||
|
defaultBulkDeleteCallback(rows) {
|
||||||
|
const msg = this.$tc('Are you sure to delete') + ' ' + rows.length + ' ' + this.$tc('rows')
|
||||||
|
const title = this.$tc('Info')
|
||||||
|
const performDelete = this.performBulkDelete || this.defaultPerformBulkDelete
|
||||||
|
this.$alert(msg, title, {
|
||||||
|
type: 'warning',
|
||||||
|
confirmButtonClass: 'el-button--danger',
|
||||||
|
showCancelButton: true,
|
||||||
|
beforeClose: async(action, instance, done) => {
|
||||||
|
if (action !== 'confirm') return done()
|
||||||
|
instance.confirmButtonLoading = true
|
||||||
|
try {
|
||||||
|
await performDelete(rows)
|
||||||
|
done()
|
||||||
|
this.reloadTable()
|
||||||
|
this.$message.success(this.$tc('Delete success'))
|
||||||
|
} catch (error) {
|
||||||
|
this.$message.error(this.$tc('Delete failed'))
|
||||||
|
console.warn(error)
|
||||||
|
} finally {
|
||||||
|
instance.confirmButtonLoading = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).catch(() => {
|
||||||
|
/* 取消*/
|
||||||
|
})
|
||||||
|
},
|
||||||
|
async defaultPerformBulkDelete(rows) {
|
||||||
|
const ids = rows.map((v) => {
|
||||||
|
return v.id
|
||||||
|
})
|
||||||
|
const data = await createSourceIdCache(ids)
|
||||||
|
const url = `${this.tableUrl}?spm=` + data.spm
|
||||||
|
return this.$axios.delete(url)
|
||||||
|
},
|
||||||
|
handleBulkUpdate(rows) {
|
||||||
|
},
|
||||||
|
handleExport() {
|
||||||
|
this.dialogExportVisible = true
|
||||||
|
},
|
||||||
|
handleImport() {
|
||||||
|
},
|
||||||
|
handleRefresh() {
|
||||||
|
this.reloadTable()
|
||||||
|
},
|
||||||
|
cleanActions(actions) {
|
||||||
|
const validActions = []
|
||||||
|
for (const action of actions) {
|
||||||
|
let ok = this.checkItem(action, 'has')
|
||||||
|
if (!ok) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
ok = this.checkItem(action, 'can')
|
||||||
|
action.disabled = !ok
|
||||||
|
validActions.push(action)
|
||||||
|
}
|
||||||
|
return validActions
|
||||||
|
},
|
||||||
|
checkItem(item, attr) {
|
||||||
|
let ok = item[attr]
|
||||||
|
if (typeof ok === 'function') {
|
||||||
|
ok = ok(this.selectedRows)
|
||||||
|
} else if (ok == null) {
|
||||||
|
ok = true
|
||||||
|
}
|
||||||
|
return ok
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -141,4 +282,9 @@ export default {
|
|||||||
justify-content:center;
|
justify-content:center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.export-item {
|
||||||
|
display: block;
|
||||||
|
padding: 5px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
139
src/components/ListTable/formatters/ActionsFormatter.vue
Normal file
139
src/components/ListTable/formatters/ActionsFormatter.vue
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
<template>
|
||||||
|
<ActionsGroup :size="'mini'" :actions="actions" :more-actions="moreActions" @actionClick="handleActionClick"></ActionsGroup>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import ActionsGroup from '@/components/ActionsGroup/index'
|
||||||
|
import BaseFormatter from './base'
|
||||||
|
|
||||||
|
const defaultPerformDelete = function({row, col}) {
|
||||||
|
const id = row.id
|
||||||
|
const url = `/api/v1/users/groups/${id}/`
|
||||||
|
return this.$axios.delete(url)
|
||||||
|
}
|
||||||
|
const defaultUpdateCallback = function({row, col}) {
|
||||||
|
const id = row.id
|
||||||
|
const routeName = col.actions.updateRoute || '404'
|
||||||
|
this.$router.push({name: routeName, params: {id: id}})
|
||||||
|
}
|
||||||
|
|
||||||
|
const defaultDeleteCallback = function({row, col, cellValue, reload}) {
|
||||||
|
const msg = this.$tc('Are you sure to delete') + ' "' + row.name + '"'
|
||||||
|
const title = this.$tc('Info')
|
||||||
|
const performDelete = col.actions.performDelete || defaultPerformDelete.bind(this)
|
||||||
|
this.$alert(msg, title, {
|
||||||
|
type: 'warning',
|
||||||
|
confirmButtonClass: 'el-button--danger',
|
||||||
|
showCancelButton: true,
|
||||||
|
beforeClose: async(action, instance, done) => {
|
||||||
|
if (action !== 'confirm') return done()
|
||||||
|
instance.confirmButtonLoading = true
|
||||||
|
try {
|
||||||
|
await performDelete({row: row, col: col})
|
||||||
|
done()
|
||||||
|
reload()
|
||||||
|
this.$message.success(this.$tc('Delete success'))
|
||||||
|
} catch (error) {
|
||||||
|
this.$message.error(this.$tc('Delete failed'))
|
||||||
|
console.warn(error)
|
||||||
|
} finally {
|
||||||
|
instance.confirmButtonLoading = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).catch(() => {
|
||||||
|
/* 取消*/
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'ActionsFormatter',
|
||||||
|
components: { ActionsGroup },
|
||||||
|
extends: BaseFormatter,
|
||||||
|
data() {
|
||||||
|
const colActions = this.col.actions || {}
|
||||||
|
const defaultActions = [
|
||||||
|
{
|
||||||
|
name: 'update',
|
||||||
|
title: this.$tc('Update'),
|
||||||
|
type: 'primary',
|
||||||
|
has: colActions.hasUpdate || true,
|
||||||
|
can: colActions.canUpdate || true,
|
||||||
|
callback: colActions.onUpdate || defaultUpdateCallback.bind(this)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'delete',
|
||||||
|
title: this.$tc('Delete'),
|
||||||
|
type: 'danger',
|
||||||
|
has: colActions.hasDelete || true,
|
||||||
|
can: colActions.canDelete || true,
|
||||||
|
callback: colActions.onDelete || defaultDeleteCallback.bind(this)
|
||||||
|
}
|
||||||
|
]
|
||||||
|
const extraActions = colActions.extraActions || []
|
||||||
|
return {
|
||||||
|
defaultActions: defaultActions,
|
||||||
|
extraActions: extraActions
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
validActions() {
|
||||||
|
const actions = [...this.defaultActions, ...this.extraActions]
|
||||||
|
const validActions = []
|
||||||
|
for (const v of actions) {
|
||||||
|
const has = this.checkItem(v, 'has')
|
||||||
|
if (!has) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
const can = this.checkItem(v, 'can')
|
||||||
|
v.disabled = !can
|
||||||
|
validActions.push(v)
|
||||||
|
}
|
||||||
|
return validActions
|
||||||
|
},
|
||||||
|
actions() {
|
||||||
|
return this.validActions.slice(0, 2)
|
||||||
|
},
|
||||||
|
moreActions() {
|
||||||
|
return this.validActions.slice(2, this.validActions.length)
|
||||||
|
},
|
||||||
|
namedValidActions() {
|
||||||
|
const actions = {}
|
||||||
|
for (const action of this.validActions) {
|
||||||
|
if (!action || !action.hasOwnProperty('name')) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
actions[action.name] = action
|
||||||
|
}
|
||||||
|
return actions
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleActionClick(item) {
|
||||||
|
const action = this.namedValidActions[item]
|
||||||
|
if (action && action.callback) {
|
||||||
|
const attrs = {
|
||||||
|
reload: this.reload,
|
||||||
|
row: this.row,
|
||||||
|
col: this.col,
|
||||||
|
cellValue: this.cellValue,
|
||||||
|
tableData: this.tableData
|
||||||
|
}
|
||||||
|
action.callback(attrs)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
checkItem(item, attr) {
|
||||||
|
let ok = item[attr]
|
||||||
|
if (typeof ok === 'function') {
|
||||||
|
ok = ok(this.row, this.cellValue)
|
||||||
|
} else if (ok == null) {
|
||||||
|
ok = true
|
||||||
|
}
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
@@ -5,6 +5,10 @@
|
|||||||
export default {
|
export default {
|
||||||
name: 'BaseFormatter',
|
name: 'BaseFormatter',
|
||||||
props: {
|
props: {
|
||||||
|
reload: {
|
||||||
|
type: Function,
|
||||||
|
default: ({reloading}) => ({})
|
||||||
|
},
|
||||||
row: {
|
row: {
|
||||||
type: Object,
|
type: Object,
|
||||||
default: () => ({})
|
default: () => ({})
|
||||||
@@ -17,7 +21,7 @@ export default {
|
|||||||
type: [String, Boolean, Number, Object],
|
type: [String, Boolean, Number, Object],
|
||||||
default: null
|
default: null
|
||||||
},
|
},
|
||||||
setting: {
|
tableData: {
|
||||||
type: Array,
|
type: Array,
|
||||||
default: () => ({})
|
default: () => ({})
|
||||||
}
|
}
|
@@ -1,11 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<TableAction v-bind="headerActions" @clickAction="handleActionClick"></TableAction>
|
<TableAction :table-url="tableConfig.url" :search-table="search" v-bind="headerActions" :selected-rows="selectedRows" :reload-table="reloadTable"></TableAction>
|
||||||
<el-card class="table-content" shadow="never">
|
<el-card class="table-content" shadow="never">
|
||||||
<DataTable :config="tableConfig" @selection-change="handleSelectionChange">
|
<DataTable ref="dataTable" :config="tableConfig" @selection-change="handleSelectionChange">
|
||||||
<template v-slot:actions="row">
|
|
||||||
{{ row.id }}
|
|
||||||
</template>
|
|
||||||
</DataTable>
|
</DataTable>
|
||||||
</el-card>
|
</el-card>
|
||||||
</div>
|
</div>
|
||||||
@@ -15,6 +12,7 @@
|
|||||||
/* eslint-disable no-unused-vars */
|
/* eslint-disable no-unused-vars */
|
||||||
import DataTable from '../DataTable'
|
import DataTable from '../DataTable'
|
||||||
import TableAction from './TableAction'
|
import TableAction from './TableAction'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'ListTable',
|
name: 'ListTable',
|
||||||
components: {
|
components: {
|
||||||
@@ -35,56 +33,24 @@ export default {
|
|||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
selectRows: [],
|
selectedRows: []
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
actionColumn() {
|
hasSelected() {
|
||||||
const actions = []
|
return this.selectedRows.length > 0
|
||||||
let tc = this.tableConfig
|
|
||||||
if (tc.hasEdit !== false) {
|
|
||||||
actions.push({
|
|
||||||
name: 'update',
|
|
||||||
title: this.$tc('Update')
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tc.hasDelete !== false) {
|
|
||||||
actions.push({
|
|
||||||
name: 'delete',
|
|
||||||
title: this.$tc('Delete')
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
handleSelectionChange(val) {
|
handleSelectionChange(val) {
|
||||||
this.selectRows = val
|
this.selectedRows = val
|
||||||
this.multipleSelection = val;
|
console.log(this.selectedRows)
|
||||||
(val.length > 0) ? (this.selectDisable = false) : (this.selectDisable = true)
|
|
||||||
},
|
},
|
||||||
handleActionClick(item) {
|
reloadTable() {
|
||||||
const handler = this.getActionHandler(item)
|
this.$refs.dataTable.getList()
|
||||||
handler(this.selectRows)
|
|
||||||
},
|
},
|
||||||
handleActionCreate() {
|
search(attrs) {
|
||||||
const routeName = this.headerActions.createRoute || ''
|
return this.$refs.dataTable.search(attrs)
|
||||||
this.$router.push({ name: routeName })
|
|
||||||
console.log('handle create')
|
|
||||||
},
|
|
||||||
getActionHandler(item) {
|
|
||||||
let handler = this.headerActions.item
|
|
||||||
const defaultHandlerName = 'handle' + item[0].toUpperCase() + item.slice(1, item.length)
|
|
||||||
if (!handler) {
|
|
||||||
handler = this[defaultHandlerName]
|
|
||||||
}
|
|
||||||
if (!handler) {
|
|
||||||
handler = () => {
|
|
||||||
console.log('No handler found for ', item)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
console.log(handler)
|
|
||||||
return handler
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -144,7 +144,6 @@ export default {
|
|||||||
}
|
}
|
||||||
data.results.forEach((v) => {
|
data.results.forEach((v) => {
|
||||||
this.options.push(v)
|
this.options.push(v)
|
||||||
console.log(v)
|
|
||||||
})
|
})
|
||||||
}).catch(err => {
|
}).catch(err => {
|
||||||
console.log(err)
|
console.log(err)
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div class="form-group-header">
|
||||||
<div v-if="line" class="hr-line-dashed" />
|
<div v-if="line" class="hr-line-dashed" />
|
||||||
<h3>{{ title }}</h3>
|
<h3>{{ title }}</h3>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -38,9 +38,19 @@ const cn = {
|
|||||||
'More actions': '更多操作',
|
'More actions': '更多操作',
|
||||||
'Delete selected': '删除所选',
|
'Delete selected': '删除所选',
|
||||||
'Update selected': '更新所选',
|
'Update selected': '更新所选',
|
||||||
|
'Delete success': '删除成功',
|
||||||
'Search': '搜索',
|
'Search': '搜索',
|
||||||
'Source': '来源',
|
'Source': '来源',
|
||||||
'Status': '状态'
|
'Status': '状态',
|
||||||
|
'Actions': '动作',
|
||||||
|
'Monitor': '监控',
|
||||||
|
'Run': '执行',
|
||||||
|
'Are you sure to delete': '你确定要删除',
|
||||||
|
'Info': '提示',
|
||||||
|
'More': '更多',
|
||||||
|
'Submit': '提交',
|
||||||
|
'Reset': '重置',
|
||||||
|
'This field is required': '这个字段是必填项'
|
||||||
},
|
},
|
||||||
route: {
|
route: {
|
||||||
'dashboard': '仪表盘',
|
'dashboard': '仪表盘',
|
||||||
@@ -81,6 +91,7 @@ const cn = {
|
|||||||
'OperateLog': '操作日志',
|
'OperateLog': '操作日志',
|
||||||
'PasswordChangeLog': '改密日志',
|
'PasswordChangeLog': '改密日志',
|
||||||
'Settings': '系统设置',
|
'Settings': '系统设置',
|
||||||
|
'UserCreate': '创建用户'
|
||||||
},
|
},
|
||||||
// 用户模块翻译
|
// 用户模块翻译
|
||||||
users: {
|
users: {
|
||||||
|
@@ -67,13 +67,20 @@ export const constantRoutes = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'users/create',
|
path: 'users/create',
|
||||||
component: () => import('@/views/users/UserEdit.vue'), // Parent router-view
|
component: () => import('@/views/users/UserCreateUpdate.vue'), // Parent router-view
|
||||||
name: 'UserCreate',
|
name: 'UserCreate',
|
||||||
hidden: true,
|
hidden: true,
|
||||||
meta: { title: 'UserCreate' }
|
meta: { title: 'UserCreate', activeMenu: '/users/users'}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'users/:id',
|
path: 'users/update/:id',
|
||||||
|
component: () => import('@/views/users/UserCreateUpdate.vue'), // Parent router-view
|
||||||
|
name: 'UserEdit',
|
||||||
|
hidden: true,
|
||||||
|
meta: { title: 'UserEdit' }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'users/detail/:id',
|
||||||
component: () => import('@/views/users/UserDetail.vue'), // Parent router-view
|
component: () => import('@/views/users/UserDetail.vue'), // Parent router-view
|
||||||
name: 'UserDetail',
|
name: 'UserDetail',
|
||||||
hidden: true,
|
hidden: true,
|
||||||
@@ -87,10 +94,10 @@ export const constantRoutes = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'groups/:id/update',
|
path: 'groups/:id/update',
|
||||||
component: () => import('@/views/users/UserGroupEdit.vue'), // Parent router-view
|
component: () => import('@/views/users/UserGroupUpdate.vue'), // Parent router-view
|
||||||
name: 'UserGroupEdit',
|
name: 'UserGroupUpdate',
|
||||||
hidden: true,
|
hidden: true,
|
||||||
meta: { title: 'UserGroupEdit' }
|
meta: { title: 'UserGroupUpdate' }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'groups/:id',
|
path: 'groups/:id',
|
||||||
@@ -101,7 +108,7 @@ export const constantRoutes = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'groups/create',
|
path: 'groups/create',
|
||||||
component: () => import('@/views/users/UserEdit.vue'), // Parent router-view
|
component: () => import('@/views/users/UserCreateUpdate.vue'), // Parent router-view
|
||||||
name: 'UserGroupCreate',
|
name: 'UserGroupCreate',
|
||||||
hidden: true,
|
hidden: true,
|
||||||
meta: { title: 'UserGroupCreate' }
|
meta: { title: 'UserGroupCreate' }
|
||||||
|
@@ -162,7 +162,15 @@ td .el-button.el-button--mini {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
height: 35px;
|
height: 34px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-input--small .el-input__inner {
|
||||||
|
height: 34px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-input--small .el-input__icon {
|
||||||
|
line-height: 34px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-select-dropdown.is-multiple .el-select-dropdown__item.selected {
|
.el-select-dropdown.is-multiple .el-select-dropdown__item.selected {
|
||||||
@@ -223,3 +231,7 @@ td .el-button.el-button--mini {
|
|||||||
.text-success {
|
.text-success {
|
||||||
color: $--color-success;
|
color: $--color-success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.el-radio__input.is-checked+.el-radio__label {
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
254
src/views/users/UserCreateUpdate.vue
Normal file
254
src/views/users/UserCreateUpdate.vue
Normal file
@@ -0,0 +1,254 @@
|
|||||||
|
<template>
|
||||||
|
<Page>
|
||||||
|
<IBox>
|
||||||
|
<DataForm :form="form" :fields="fields">
|
||||||
|
<FormGroupHeader slot="id:name" title="账户" :line="false" />
|
||||||
|
<FormGroupHeader slot="id:passwordrule" title="认证" :line="true" />
|
||||||
|
<FormGroupHeader slot="id:role" title="角色安全" :line="true" />
|
||||||
|
<FormGroupHeader slot="id:phone" title="认证" :line="true" />
|
||||||
|
</DataForm>
|
||||||
|
</IBox>
|
||||||
|
</page>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
/* eslint-disable vue/no-unused-components */
|
||||||
|
import FormGroupHeader from '@/components/formGroupHeader'
|
||||||
|
import { Page, IBox } from '@/layout/components'
|
||||||
|
import DataForm from '@/components/DataForm'
|
||||||
|
import rules from '@/components/DataForm/rules'
|
||||||
|
import select2 from '@/components/Select2'
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
Page,
|
||||||
|
IBox,
|
||||||
|
DataForm,
|
||||||
|
select2,
|
||||||
|
FormGroupHeader
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
form: {
|
||||||
|
passwordrule: '1',
|
||||||
|
mfa_level: 0,
|
||||||
|
source: 'local',
|
||||||
|
role: 'Admin',
|
||||||
|
date_expired: '2099-12-31 00:00:00 +0800'
|
||||||
|
},
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
type: 'input',
|
||||||
|
id: 'name',
|
||||||
|
label: this.$t('users.name'),
|
||||||
|
el: {
|
||||||
|
},
|
||||||
|
rules: [
|
||||||
|
rules.Required
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'input',
|
||||||
|
id: 'username',
|
||||||
|
label: this.$t('users.username'),
|
||||||
|
el: {
|
||||||
|
},
|
||||||
|
rules: [
|
||||||
|
rules.Required
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'input',
|
||||||
|
id: 'email',
|
||||||
|
label: this.$t('users.email'),
|
||||||
|
el: {
|
||||||
|
},
|
||||||
|
rules: [
|
||||||
|
rules.Required
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'users',
|
||||||
|
label: '用户组',
|
||||||
|
el: {
|
||||||
|
placeholder: '添加到用户组',
|
||||||
|
value: [
|
||||||
|
{
|
||||||
|
label: 'hello',
|
||||||
|
value: '1a775bbf-6861-4acb-8ae4-2f684794c8cc'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'test',
|
||||||
|
value: '4dccdf84-7728-4de0-a507-67c905b3091b'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'whold',
|
||||||
|
value: 'c5ec4b91-1fb2-478e-89bc-5a4abc0f9c6c'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
url: '/api/v1/users/users/'
|
||||||
|
},
|
||||||
|
// 自定义组件
|
||||||
|
// 可以取到自定义组件的值
|
||||||
|
// https://femessage.github.io/el-form-renderer/#/Guide?id=guide-custom-component
|
||||||
|
|
||||||
|
component: select2
|
||||||
|
}, {
|
||||||
|
type: 'radio-group',
|
||||||
|
id: 'passwordrule',
|
||||||
|
label: '密码策略',
|
||||||
|
el: {
|
||||||
|
},
|
||||||
|
hidden: (formValue, item) => {
|
||||||
|
return this.$route.params.id
|
||||||
|
},
|
||||||
|
options: [{
|
||||||
|
label: '生成重置密码链接,通过邮件发送给用户',
|
||||||
|
value: '1'
|
||||||
|
}, {
|
||||||
|
label: '设置密码',
|
||||||
|
value: '2'
|
||||||
|
}],
|
||||||
|
rules: [
|
||||||
|
{ required: true, message: 'miss resource', trigger: 'change' }
|
||||||
|
]
|
||||||
|
}, {
|
||||||
|
type: 'input',
|
||||||
|
id: 'password',
|
||||||
|
label: '密码',
|
||||||
|
hidden: (formValue, item) => {
|
||||||
|
if (this.$route.params.id === undefined) {
|
||||||
|
return (formValue.passwordrule !== '2')
|
||||||
|
} else {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
el: {
|
||||||
|
type: 'password'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'input',
|
||||||
|
id: 'sshkey',
|
||||||
|
label: 'ssh公钥',
|
||||||
|
hidden: (formValue, item) => {
|
||||||
|
return !this.$route.params.id
|
||||||
|
},
|
||||||
|
el: {
|
||||||
|
placeholder: 'ssh-rsa AAAA...',
|
||||||
|
type: 'textarea',
|
||||||
|
rows: 3
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'radio-group',
|
||||||
|
id: 'mfa_level',
|
||||||
|
label: '多因子认证',
|
||||||
|
el: {
|
||||||
|
},
|
||||||
|
size: 0,
|
||||||
|
options: [{
|
||||||
|
label: '禁用',
|
||||||
|
value: 0
|
||||||
|
}, {
|
||||||
|
label: '启用',
|
||||||
|
value: 1
|
||||||
|
}, {
|
||||||
|
label: '强制启用',
|
||||||
|
value: 2
|
||||||
|
}],
|
||||||
|
rules: [
|
||||||
|
rules.Required
|
||||||
|
]
|
||||||
|
}, {
|
||||||
|
type: 'select',
|
||||||
|
id: 'source',
|
||||||
|
label: '来源',
|
||||||
|
el: {
|
||||||
|
},
|
||||||
|
default: '数据库',
|
||||||
|
options: [{
|
||||||
|
label: '数据库',
|
||||||
|
value: 'local'
|
||||||
|
}],
|
||||||
|
rules: [
|
||||||
|
rules.Required
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'select',
|
||||||
|
id: 'role',
|
||||||
|
label: '角色',
|
||||||
|
el: {
|
||||||
|
},
|
||||||
|
default: 'User',
|
||||||
|
options: [{
|
||||||
|
label: '管理员',
|
||||||
|
value: 'Admin'
|
||||||
|
}, {
|
||||||
|
label: '用户',
|
||||||
|
value: 'User'
|
||||||
|
}, {
|
||||||
|
label: '审计员',
|
||||||
|
value: 'Auditor'
|
||||||
|
}],
|
||||||
|
rules: [
|
||||||
|
rules.Required
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'date-picker',
|
||||||
|
id: 'date_expired',
|
||||||
|
label: '过期时间',
|
||||||
|
el: {
|
||||||
|
type: 'datetime',
|
||||||
|
placeholder: 'select date'
|
||||||
|
},
|
||||||
|
rules: [
|
||||||
|
rules.Required
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'input',
|
||||||
|
id: 'phone',
|
||||||
|
label: '手机',
|
||||||
|
el: {
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
type: 'input',
|
||||||
|
id: 'wechat',
|
||||||
|
label: '微信',
|
||||||
|
el: {
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
type: 'input',
|
||||||
|
id: 'comment',
|
||||||
|
label: '备注',
|
||||||
|
el: {
|
||||||
|
type: 'textarea',
|
||||||
|
row: '4'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
debug() {
|
||||||
|
console.log(this)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
console.log('>>>>>>>>>>')
|
||||||
|
console.log(rules)
|
||||||
|
console.log(rules.Required)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.el-form /deep/ .el-select{
|
||||||
|
width:100%;
|
||||||
|
}
|
||||||
|
.el-form /deep/ .el-form-item__content > .el-date-editor{
|
||||||
|
width:100%;
|
||||||
|
}
|
||||||
|
</style>
|
@@ -1,162 +0,0 @@
|
|||||||
<template>
|
|
||||||
<Page>
|
|
||||||
<template>
|
|
||||||
<el-card>
|
|
||||||
<dataform :content="content" label-position="left" label-width="140px" :form="form">
|
|
||||||
<formgroupheader slot="id:name" title="账户" :line="false" style="margin:0 50px;" />
|
|
||||||
<formgroupheader slot="id:passwordrule" title="认证" :line="true" style="margin:0 50px;" />
|
|
||||||
</dataform>
|
|
||||||
</el-card>
|
|
||||||
</template>
|
|
||||||
</page>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
/* eslint-disable vue/no-unused-components */
|
|
||||||
import formgroupheader from '@/components/formGroupHeader'
|
|
||||||
import { Page } from '@/layout/components'
|
|
||||||
import dataform from '@/components/DataForm'
|
|
||||||
import select2 from '@/components/Select2'
|
|
||||||
export default {
|
|
||||||
components: {
|
|
||||||
Page,
|
|
||||||
dataform,
|
|
||||||
select2,
|
|
||||||
formgroupheader
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
content: [
|
|
||||||
{
|
|
||||||
type: 'input',
|
|
||||||
id: 'name',
|
|
||||||
label: this.$t('users.name'),
|
|
||||||
el: {
|
|
||||||
size: 'mini'
|
|
||||||
},
|
|
||||||
rules: [
|
|
||||||
{ required: true, message: 'miss name', trigger: 'blur' }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'input',
|
|
||||||
id: 'username',
|
|
||||||
label: this.$t('users.username'),
|
|
||||||
el: {
|
|
||||||
size: 'mini'
|
|
||||||
},
|
|
||||||
rules: [
|
|
||||||
{ required: true, message: 'miss name', trigger: 'blur' }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'input',
|
|
||||||
id: 'email',
|
|
||||||
label: this.$t('users.email'),
|
|
||||||
el: {
|
|
||||||
size: 'mini'
|
|
||||||
},
|
|
||||||
rules: [
|
|
||||||
{ required: true, message: 'miss name', trigger: 'blur' }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'users',
|
|
||||||
label: '用户组',
|
|
||||||
el: {
|
|
||||||
size: 'mini',
|
|
||||||
placeholder: '添加到用户组',
|
|
||||||
value: [
|
|
||||||
{
|
|
||||||
label: 'hello',
|
|
||||||
value: '1a775bbf-6861-4acb-8ae4-2f684794c8cc'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'test',
|
|
||||||
value: '4dccdf84-7728-4de0-a507-67c905b3091b'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'whold',
|
|
||||||
value: 'c5ec4b91-1fb2-478e-89bc-5a4abc0f9c6c'
|
|
||||||
}
|
|
||||||
],
|
|
||||||
url: '/api/v1/users/users/'
|
|
||||||
},
|
|
||||||
// 自定义组件
|
|
||||||
// 可以取到自定义组件的值
|
|
||||||
// https://femessage.github.io/el-form-renderer/#/Guide?id=guide-custom-component
|
|
||||||
|
|
||||||
component: select2
|
|
||||||
}, {
|
|
||||||
type: 'radio-group',
|
|
||||||
id: 'passwordrule',
|
|
||||||
label: '密码策略',
|
|
||||||
el: {
|
|
||||||
size: 'small'
|
|
||||||
},
|
|
||||||
options: [{
|
|
||||||
label: '生成重置密码链接,通过邮件发送给用户',
|
|
||||||
value: '1'
|
|
||||||
}, {
|
|
||||||
label: '设置密码',
|
|
||||||
value: '2'
|
|
||||||
}],
|
|
||||||
rules: [
|
|
||||||
{ required: true, message: 'miss resource', trigger: 'change' }
|
|
||||||
]
|
|
||||||
}, {
|
|
||||||
type: 'input',
|
|
||||||
id: 'password',
|
|
||||||
label: '密码',
|
|
||||||
hidden: (formValue, item) => {
|
|
||||||
console.log(formValue, item)
|
|
||||||
formValue.passwordrule !== '2'
|
|
||||||
},
|
|
||||||
el: {
|
|
||||||
size: 'mini',
|
|
||||||
type: 'password'
|
|
||||||
},
|
|
||||||
rules: [
|
|
||||||
{ required: true, message: 'miss name', trigger: 'blur' }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'radio-group',
|
|
||||||
id: 'mfa',
|
|
||||||
label: '密码策略',
|
|
||||||
el: {
|
|
||||||
size: 'small'
|
|
||||||
},
|
|
||||||
options: [{
|
|
||||||
label: '禁用'
|
|
||||||
}, {
|
|
||||||
label: '启用'
|
|
||||||
}, {
|
|
||||||
label: '强制启用'
|
|
||||||
}],
|
|
||||||
rules: [
|
|
||||||
{ required: true, message: 'miss resource', trigger: 'change' }
|
|
||||||
]
|
|
||||||
}, {
|
|
||||||
type: 'select',
|
|
||||||
id: 'source',
|
|
||||||
label: '来源',
|
|
||||||
el: {
|
|
||||||
size: 'small'
|
|
||||||
},
|
|
||||||
options: [{
|
|
||||||
label: 'area1',
|
|
||||||
value: 'shanghai'
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="less" scoped>
|
|
||||||
.el-form /deep/ .el-select{
|
|
||||||
width:100%;
|
|
||||||
}
|
|
||||||
</style>
|
|
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { GenericListPage } from '@/layout/components'
|
import { GenericListPage } from '@/layout/components'
|
||||||
import { DetailFormatter, ActionsFormatter } from '@/components/DataTable/formatters/index'
|
import { DetailFormatter, ActionsFormatter } from '@/components/ListTable/formatters/index'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
@@ -15,21 +15,17 @@ export default {
|
|||||||
tableConfig: {
|
tableConfig: {
|
||||||
url: '/api/v1/users/groups/',
|
url: '/api/v1/users/groups/',
|
||||||
columns: [
|
columns: [
|
||||||
{
|
|
||||||
label: 'ID',
|
|
||||||
type: 'index'
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
prop: 'name',
|
prop: 'name',
|
||||||
label: this.$tc('Name'),
|
label: this.$tc('Name'),
|
||||||
formatter: DetailFormatter,
|
formatter: DetailFormatter,
|
||||||
sortable: true,
|
sortable: true,
|
||||||
route: 'UserDetail'
|
route: 'UserGroupDetail'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
prop: 'users_amount',
|
prop: 'users_amount',
|
||||||
label: this.$t('users.User'),
|
label: this.$t('users.User'),
|
||||||
key: 'users_amount',
|
key: 'users_amount'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
prop: 'comment',
|
prop: 'comment',
|
||||||
@@ -38,55 +34,27 @@ export default {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
prop: 'id',
|
prop: 'id',
|
||||||
label: this.$tc('Action'),
|
label: this.$tc('Actions'),
|
||||||
align: 'center',
|
align: 'center',
|
||||||
formatter: ActionsFormatter,
|
formatter: ActionsFormatter,
|
||||||
|
width: '200px',
|
||||||
actions: {
|
actions: {
|
||||||
hasUpdate: (row, cellValue) => {
|
updateRoute: 'UserGroupUpdate',
|
||||||
return true
|
|
||||||
},
|
|
||||||
canUpdate: (row, cellValue) => {
|
|
||||||
console.log('On table update')
|
|
||||||
return true
|
|
||||||
},
|
|
||||||
hasDelete: true,
|
|
||||||
canDelete: (row, cellValue) => {
|
|
||||||
return true
|
|
||||||
},
|
|
||||||
onDelete: (row, cellValue) => {
|
|
||||||
this.$confirm('你好啊', '提示', {
|
|
||||||
type: 'warning',
|
|
||||||
confirmButtonClass: 'el-button--danger',
|
|
||||||
beforeClose: async(action, instance, done) => {
|
|
||||||
}
|
|
||||||
}).catch(() => {
|
|
||||||
/* 取消*/
|
|
||||||
})
|
|
||||||
},
|
|
||||||
extraActions: [
|
extraActions: [
|
||||||
{
|
{
|
||||||
name: 'run',
|
name: 'run',
|
||||||
title: this.$tc('Run'),
|
title: this.$tc('Run')
|
||||||
callback: (row, cellValue) => {
|
|
||||||
console.log('On run')
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'monitor',
|
|
||||||
title: this.$tc('Monitor')
|
|
||||||
}
|
}
|
||||||
],
|
]
|
||||||
order: []
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
]
|
||||||
// 写路由名字,table组件会自动传作为参数
|
|
||||||
tableActions: {
|
|
||||||
editRoute: '404'
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
headerActions: {
|
headerActions: {
|
||||||
createRoute: 'UserGroupCreate'
|
createRoute: 'UserGroupCreate',
|
||||||
|
performBulkDelete: function(rows) {
|
||||||
|
console.log('hello')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
<Page>
|
<Page>
|
||||||
<template>
|
<template>
|
||||||
<el-card>
|
<el-card>
|
||||||
<dataform :content="content" label-position="right" label-width="100px" :form="form" />
|
<dataform fields="content" label-position="right" label-width="100px" :form="form" />
|
||||||
</el-card>
|
</el-card>
|
||||||
</template>
|
</template>
|
||||||
</page>
|
</page>
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
<script>
|
<script>
|
||||||
/* eslint-disable vue/no-unused-components */
|
/* eslint-disable vue/no-unused-components */
|
||||||
import { Page } from '@/layout/components'
|
import { Page } from '@/layout/components'
|
||||||
import dataform from '@/components/DataForm'
|
import DataForm from '@/components/DataForm'
|
||||||
import select2 from '@/components/Select2'
|
import select2 from '@/components/Select2'
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { GenericListPage } from '@/layout/components'
|
import { GenericListPage } from '@/layout/components'
|
||||||
import { DetailFormatter, DisplayFormatter, ChoicesFormatter } from '@/components/DataTable/formatters/index'
|
import { DetailFormatter, DisplayFormatter, ChoicesFormatter, ActionsFormatter } from '@/components/ListTable/formatters/index'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
@@ -49,6 +49,22 @@ export default {
|
|||||||
formatter: ChoicesFormatter,
|
formatter: ChoicesFormatter,
|
||||||
align: 'center',
|
align: 'center',
|
||||||
width: '80px'
|
width: '80px'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'id',
|
||||||
|
label: this.$tc('Actions'),
|
||||||
|
align: 'center',
|
||||||
|
formatter: ActionsFormatter,
|
||||||
|
width: '200px',
|
||||||
|
actions: {
|
||||||
|
updateRoute: 'UserUpdate',
|
||||||
|
extraActions: [
|
||||||
|
{
|
||||||
|
name: 'run',
|
||||||
|
title: this.$tc('Run')
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
// 写路由名字,table组件会自动传作为参数
|
// 写路由名字,table组件会自动传作为参数
|
||||||
@@ -57,7 +73,17 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
headerActions: {
|
headerActions: {
|
||||||
createRoute: 'UserGroupCreate'
|
createRoute: 'UserCreate',
|
||||||
|
extraMoreActions: [
|
||||||
|
{
|
||||||
|
name: 'deactiveSelected',
|
||||||
|
title: this.$tc('Deactive selected')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'activeSelected',
|
||||||
|
title: this.$tc('Active selected')
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user