mirror of
https://github.com/jumpserver/lina.git
synced 2026-01-29 21:28:52 +00:00
Merge branch 'master' of https://github.com/jumpserver/lina
This commit is contained in:
@@ -39,6 +39,7 @@
|
||||
"vue": "2.6.10",
|
||||
"vue-i18n": "^8.15.5",
|
||||
"vue-router": "3.0.6",
|
||||
"vue-select": "^3.9.5",
|
||||
"vuex": "3.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
<template>
|
||||
<div :class="grouped ? 'el-button-group' : ''">
|
||||
<el-button v-for="item in actions" :key="item.name" :type="item.type" :size="size" :disabled="item.disabled" :icon="item.icon" @click="handleClick(item.name)">{{ item.title }}</el-button>
|
||||
<el-dropdown v-if="moreActions.length > 0" trigger="click">
|
||||
<el-button v-for="item in actions" :key="item.name" :size="size" v-bind="item" @click="handleClick(item.name)">
|
||||
<i v-if="item.fa" :class="'fa ' + item.fa"></i>
|
||||
{{ item.title }}
|
||||
</el-button>
|
||||
<el-dropdown v-if="moreActions.length > 0" trigger="click" @command="handleClick">
|
||||
<el-button :size="size" class="btn-more-actions">
|
||||
{{ this.$tc('More actions') }}<i class="el-icon-arrow-down el-icon--right" />
|
||||
{{ this.$tc('More actions') }}<i class="el-icon-arrow-down el-icon--right"></i>
|
||||
</el-button>
|
||||
<el-dropdown-menu slot="dropdown">
|
||||
<el-dropdown-item v-for="item in moreActions" :key="item.name" :icon="item.icon" @click="handleClick(item.name)">{{ item.title }} </el-dropdown-item>
|
||||
<el-dropdown-item v-for="item in moreActions" :key="item.name" :command="item.name" v-bind="item" @click="handleClick(item.name)">{{ item.title }} </el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
|
||||
@@ -74,9 +74,7 @@
|
||||
class="tree-ctrl"
|
||||
@click="toggleExpanded(scope.$index)"
|
||||
>
|
||||
<i
|
||||
:class="`el-icon-${scope.row._expanded ? 'minus' : 'plus'}`"
|
||||
/>
|
||||
<i :class="`el-icon-${scope.row._expanded ? 'minus' : 'plus'}`"/>
|
||||
</span>
|
||||
{{ scope.row[columns[0].prop] }}
|
||||
</template>
|
||||
@@ -92,11 +90,25 @@
|
||||
|
||||
<!--非树-->
|
||||
<template v-else>
|
||||
<el-data-table-column v-if="hasSelection" type="selection" :align="columnsAlign"></el-data-table-column>
|
||||
<el-data-table-column
|
||||
v-for="col in columns"
|
||||
:key="col.prop"
|
||||
:formatter="typeof col.formatter === 'function' ? col.formatter : null"
|
||||
v-bind="{align: columnsAlign, ...col}"
|
||||
>
|
||||
<template slot-scope="{row}">
|
||||
<div
|
||||
v-if="col.formatter && typeof col.formatter !== 'function'"
|
||||
:is="col.formatter"
|
||||
:row="row"
|
||||
:col="col"
|
||||
>
|
||||
</div>
|
||||
<template v-else>
|
||||
{{ row[col.prop] }}
|
||||
</template>
|
||||
</template>
|
||||
</el-data-table-column>
|
||||
</template>
|
||||
|
||||
@@ -119,6 +131,7 @@
|
||||
<self-loading-button
|
||||
v-if="hasEdit"
|
||||
type="primary"
|
||||
:disable="!canEdit(scope.row)"
|
||||
:size="operationButtonType === 'text' ? '' : buttonSize"
|
||||
:is-text="operationButtonType === 'text'"
|
||||
@click="onDefaultEdit(scope.row)"
|
||||
@@ -153,8 +166,9 @@
|
||||
</self-loading-button>
|
||||
</template>
|
||||
<self-loading-button
|
||||
v-if="!hasSelect && hasDelete && canDelete(scope.row)"
|
||||
v-if="hasDelete"
|
||||
type="danger"
|
||||
:disable="!canDelete(scope.row)"
|
||||
:size="operationButtonType === 'text' ? '' : buttonSize"
|
||||
:is-text="operationButtonType === 'text'"
|
||||
@click="onDefaultDelete(scope.row)"
|
||||
@@ -450,6 +464,12 @@ export default {
|
||||
return true
|
||||
}
|
||||
},
|
||||
canEdit: {
|
||||
type: Function,
|
||||
default() {
|
||||
return true
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 点击新增按钮时的方法, 当默认新增方法不满足需求时使用, 需要返回promise
|
||||
* 参数(data, row) data 是form表单的数据, row 是当前行的数据, 只有isTree为true时, 点击操作列的新增按钮才会有值
|
||||
@@ -466,12 +486,8 @@ export default {
|
||||
*/
|
||||
onEdit: {
|
||||
type: Function,
|
||||
default(data) {
|
||||
return this.$axios.put(
|
||||
`${this.url}/${this.row[this.id]}`,
|
||||
data,
|
||||
this.axiosConfig
|
||||
)
|
||||
default(row) {
|
||||
console.log('On delete row')
|
||||
}
|
||||
},
|
||||
/**
|
||||
@@ -484,7 +500,7 @@ export default {
|
||||
const ids = Array.isArray(data)
|
||||
? data.map(v => v[this.id]).join(',')
|
||||
: data[this.id]
|
||||
return this.$axios.delete(this.url + '/' + ids, this.axiosConfig)
|
||||
return this.$axios.delete(this.url + '/' + ids + '/', this.axiosConfig)
|
||||
}
|
||||
},
|
||||
/**
|
||||
@@ -750,6 +766,14 @@ export default {
|
||||
extraPaginationAttrs: {
|
||||
type: Object,
|
||||
default: () => {}
|
||||
},
|
||||
hasSelection: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
hasDetail: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
@@ -775,6 +799,7 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
hasSelect() {
|
||||
console.log(this.columns.length && this.columns[0].type === 'selection')
|
||||
return this.columns.length && this.columns[0].type === 'selection'
|
||||
},
|
||||
selectable() {
|
||||
@@ -854,8 +879,6 @@ export default {
|
||||
* @property {array} rows - 已选中的行数据的数组
|
||||
*/
|
||||
this.$emit('selection-change', val)
|
||||
console.log('Selected', this.selected)
|
||||
console.log('Val', val)
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
@@ -1067,7 +1090,7 @@ export default {
|
||||
},
|
||||
onDefaultEdit(row) {
|
||||
this.row = row
|
||||
this.$refs.dialog.show(dialogModes.edit, row)
|
||||
this.onEdit(row)
|
||||
},
|
||||
async onConfirm(isNew, formValue, done) {
|
||||
const data = {
|
||||
|
||||
34
src/components/DataTable/formatters/DetailFormatter.vue
Normal file
34
src/components/DataTable/formatters/DetailFormatter.vue
Normal file
@@ -0,0 +1,34 @@
|
||||
<template>
|
||||
<el-link :type="col.type || 'success'" @click="goDetail">{{ cellValue }}</el-link>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'DetailFormatter',
|
||||
props: {
|
||||
row: {
|
||||
type: Object,
|
||||
default: null
|
||||
},
|
||||
col: {
|
||||
type: Object,
|
||||
default: null
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
cellValue() {
|
||||
return this.row[this.col.prop]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
goDetail() {
|
||||
const routeName = this.col.route || ''
|
||||
this.$router.push({ name: routeName, params: { id: this.row.id }})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<ElDatableTable class="el-table" v-bind="tableConfig" />
|
||||
<ElDatableTable class="el-table" v-bind="tableConfig" v-on="$listeners"></ElDatableTable>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
@@ -17,6 +17,7 @@ export default {
|
||||
}
|
||||
},
|
||||
data() {
|
||||
const userTableActions = this.config.tableActions || {}
|
||||
return {
|
||||
defaultConfig: {
|
||||
axiosConfig: {
|
||||
@@ -25,21 +26,36 @@ export default {
|
||||
display: 1
|
||||
}
|
||||
},
|
||||
defaultAlign: 'left',
|
||||
dataPath: 'results',
|
||||
totalPath: 'count',
|
||||
saveQuery: false, // 关闭路径保存查询参数
|
||||
persistSelection: true, // 切换页面 已勾选项不会丢失
|
||||
hasEdit: false, // 有编辑按钮
|
||||
hasDelete: false,
|
||||
hasAction: false, // 是否有更多操作
|
||||
hasUpload: false,
|
||||
hasEdit: userTableActions.hasEdit !== false, // 有编辑按钮
|
||||
hasDelete: userTableActions.hasDelete !== false,
|
||||
hasNew: false,
|
||||
// editText: this.$t('action.update'), // 编辑按钮文案
|
||||
operationAttrs: {
|
||||
align: 'center',
|
||||
width: '150px'
|
||||
},
|
||||
tableAttrs: {
|
||||
stripe: true, // 斑马纹表格
|
||||
border: true, // 表格边框
|
||||
fit: true // 宽度自适应
|
||||
},
|
||||
extraButtons: userTableActions.extraButtons,
|
||||
onEdit: (row) => {
|
||||
const defaultOnEdit = (row) => {
|
||||
const routeName = userTableActions.editRoute
|
||||
this.$router.push({ name: routeName, params: { id: row.id }})
|
||||
}
|
||||
let onEdit = userTableActions.onEdit
|
||||
if (!onEdit) {
|
||||
onEdit = defaultOnEdit
|
||||
}
|
||||
return onEdit(row)
|
||||
},
|
||||
pageCount: 5,
|
||||
paginationLayout: 'total, sizes, prev, pager, next',
|
||||
transformQuery: query => {
|
||||
@@ -70,7 +86,7 @@ export default {
|
||||
|
||||
.el-table /deep/ .el-table__row > td {
|
||||
line-height: 1.5;
|
||||
padding: 8px;
|
||||
padding: 8px 0;
|
||||
}
|
||||
.el-table /deep/ .el-table__row > td> div > span {
|
||||
text-overflow: ellipsis;
|
||||
@@ -79,7 +95,7 @@ export default {
|
||||
white-space: nowrap;
|
||||
}
|
||||
.el-table /deep/ .el-table__header > thead > tr >th {
|
||||
padding: 8px;
|
||||
padding: 8px 0;
|
||||
background-color: #F5F5F6;
|
||||
font-size: 13px;
|
||||
line-height: 1.5;
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
<template>
|
||||
<ActionsGroup :actions="tActions" :more-actions="tMoreActions" @clickAction="handleClickAction" class="header-action"></ActionsGroup>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ActionsGroup from '../ActionsGroup'
|
||||
export default {
|
||||
name: 'HeaderActions',
|
||||
components: {
|
||||
ActionsGroup
|
||||
},
|
||||
props: {
|
||||
actions: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
moreActions: {
|
||||
type: Array,
|
||||
default: () => ([])
|
||||
},
|
||||
hasSelection: {
|
||||
type: Boolean,
|
||||
default: () => true
|
||||
},
|
||||
selectDisable: {
|
||||
type: Boolean,
|
||||
default: () => true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
value: ''
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
tActions() {
|
||||
console.log('actions', this.actions)
|
||||
return this.actions
|
||||
},
|
||||
tMoreActions() {
|
||||
console.log(this.moreActions)
|
||||
return this.moreActions
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleClickAction(item) {
|
||||
console.log(this)
|
||||
this.$emit('clickAction', item)
|
||||
},
|
||||
handleAction() {
|
||||
this.$emit('actionClick', this.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
|
||||
</style>
|
||||
|
||||
144
src/components/ListTable/TableAction.vue
Normal file
144
src/components/ListTable/TableAction.vue
Normal file
@@ -0,0 +1,144 @@
|
||||
<template>
|
||||
<div class="table-header">
|
||||
<slot name="header">
|
||||
<!--TODO: 事件交互 -->
|
||||
<div class="table-header-left-side">
|
||||
<ActionsGroup :actions="actions" :more-actions="moreActions" class="header-action" @actionClick="handleActionClick"></ActionsGroup>
|
||||
</div>
|
||||
<!-- TODO: 事件交互 -->
|
||||
<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>
|
||||
<ActionsGroup :is-fa="true" :actions="rightSideActions" class="right-side-actions right-side-item" @actionClick="handleActionClick"></ActionsGroup>
|
||||
</div>
|
||||
</slot>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ActionsGroup from '@/components/ActionsGroup'
|
||||
const defaultTrue = { type: Boolean, default: true }
|
||||
export default {
|
||||
name: 'TableAction',
|
||||
components: {
|
||||
ActionsGroup
|
||||
},
|
||||
props: {
|
||||
hasExport: defaultTrue,
|
||||
hasImport: defaultTrue,
|
||||
hasRefresh: defaultTrue,
|
||||
hasCreate: defaultTrue,
|
||||
hasDelete: defaultTrue,
|
||||
hasUpdate: defaultTrue,
|
||||
hasLeftActions: defaultTrue,
|
||||
hasSearch: defaultTrue,
|
||||
hasRightActions: defaultTrue
|
||||
},
|
||||
data() {
|
||||
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: '',
|
||||
defaultMoreActions: {
|
||||
Delete: {
|
||||
title: this.$tc('Delete selected'),
|
||||
name: 'actionDeleteSelected'
|
||||
},
|
||||
Update: {
|
||||
title: this.$tc('Update selected'),
|
||||
name: 'actionUpdateSelected'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
rightSideActions() {
|
||||
const actions = []
|
||||
for (const k in this.defaultRightSideActions) {
|
||||
if (this['has' + k]) {
|
||||
actions.push(this.defaultRightSideActions[k])
|
||||
}
|
||||
}
|
||||
return actions
|
||||
},
|
||||
actions() {
|
||||
const actions = []
|
||||
if (this.hasCreate) {
|
||||
actions.push(this.defaultCreateAction)
|
||||
}
|
||||
return actions
|
||||
},
|
||||
moreActions() {
|
||||
const actions = []
|
||||
for (const k in this.defaultMoreActions) {
|
||||
if (this['has' + k]) {
|
||||
actions.push(this.defaultMoreActions[k])
|
||||
}
|
||||
}
|
||||
return actions
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleSearch(keyword) {
|
||||
console.log('Search: ', keyword)
|
||||
},
|
||||
handleActionClick(item) {
|
||||
this.$emit('clickAction', item)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.table-header {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.right-side-item {
|
||||
}
|
||||
|
||||
.right-side-actions >>> .el-button {
|
||||
border: none;
|
||||
padding: 5px;
|
||||
font-size: 14px;
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
color: #888;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.right-side-actions >>> .fa {
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
}
|
||||
|
||||
.right-side-actions >>> .el-button:hover {
|
||||
background-color: rgb(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.action-search >>> .el-input__suffix i {
|
||||
font-weight: 500;
|
||||
color: #888;
|
||||
}
|
||||
|
||||
.right-side-actions {
|
||||
display: flex;
|
||||
padding-left: 10px;
|
||||
justify-content:center;
|
||||
}
|
||||
|
||||
.table-action-right-side {
|
||||
display: flex;
|
||||
justify-content:center;
|
||||
}
|
||||
|
||||
</style>
|
||||
@@ -1,28 +1,21 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="table-header">
|
||||
<slot name="header">
|
||||
<!--TODO: 事件交互 -->
|
||||
<HeaderActions :actions="totalActions" :more-actions="moreActions" />
|
||||
<!-- TODO: 事件交互 -->
|
||||
<search v-if="hasSearch" class="search" @serachAction="handleSearch" />
|
||||
</slot>
|
||||
</div>
|
||||
<DataTable :config="tableConfig" class="table-content" />
|
||||
<TableAction v-bind="headerActions" @clickAction="handleActionClick"></TableAction>
|
||||
<el-card class="table-content">
|
||||
<DataTable :config="tableConfig" @selection-change="handleSelectionChange"></DataTable>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/* eslint-disable no-unused-vars */
|
||||
import search from './search'
|
||||
import DataTable from '../DataTable'
|
||||
import HeaderActions from './HeaderActions'
|
||||
import TableAction from './TableAction'
|
||||
export default {
|
||||
name: 'ListTable',
|
||||
components: {
|
||||
HeaderActions,
|
||||
DataTable,
|
||||
search
|
||||
TableAction
|
||||
},
|
||||
props: {
|
||||
// 定义 table 的配置
|
||||
@@ -31,107 +24,55 @@ export default {
|
||||
default: () => {}
|
||||
},
|
||||
// 是否显示table左侧的action
|
||||
hasAction: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
hasSearch: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
hasCreate: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
createTitle: {
|
||||
type: String,
|
||||
default() {
|
||||
return this.$tc('Create')
|
||||
}
|
||||
},
|
||||
createAction: {
|
||||
headerActions: {
|
||||
type: Object,
|
||||
default() {
|
||||
return {
|
||||
type: 'primary',
|
||||
name: 'create',
|
||||
title: this.createTitle
|
||||
}
|
||||
}
|
||||
},
|
||||
moreActions: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
actions: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
default: () => ({ })
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
selectRows: [],
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
totalActions() {
|
||||
let actions = this.actions
|
||||
if (this.hasCreate) {
|
||||
actions = [
|
||||
this.createAction,
|
||||
... actions
|
||||
]
|
||||
}
|
||||
return actions
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleSearch(val) {
|
||||
this.loading = true
|
||||
// this.getData({ search: val, draw: this.current_page, limit: this.page_size, offset: this.offset }, { row: 1 }).then(response => {
|
||||
// console.log(response)
|
||||
// this.tabledata = response.results
|
||||
// this.total = response.count
|
||||
// this.loading = false
|
||||
// })
|
||||
},
|
||||
handleSelectionChange(val) {
|
||||
this.selectRows = val
|
||||
this.multipleSelection = val;
|
||||
(val.length > 0) ? (this.selectDisable = false) : (this.selectDisable = true)
|
||||
},
|
||||
handleEdit: function(index, row) {
|
||||
try {
|
||||
this.$router.push({ name: this.action.hasEdit, params: { id: row.id }})
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
handleActionClick(item) {
|
||||
const handler = this.getActionHandler(item)
|
||||
handler(this.selectRows)
|
||||
},
|
||||
handleActionCreate() {
|
||||
const routeName = this.headerActions.createRoute || ''
|
||||
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]
|
||||
}
|
||||
},
|
||||
handleHeaderActionClick(item) {
|
||||
this.$emit('headerActionClick', item)
|
||||
},
|
||||
handleDelete: (index, row) => {
|
||||
},
|
||||
get(draw, limit, offset) {
|
||||
this.loading = true
|
||||
// this.getData({ draw, limit, offset }, { row: 1 }).then(response => {
|
||||
// console.log(response)
|
||||
// this.tabledata = response.results
|
||||
// this.total = response.count
|
||||
// this.loading = false
|
||||
// })
|
||||
if (!handler) {
|
||||
handler = () => {
|
||||
console.log('No handler found for ', item)
|
||||
}
|
||||
}
|
||||
console.log(handler)
|
||||
return handler
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.table-header {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.table-content {
|
||||
margin-top: 15px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
//修改颜色
|
||||
// .el-button--text{
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-input v-model="input" placeholder="搜索..." class="input-with-select" size="small" clearable @input="serachAction">
|
||||
<el-button slot="append" icon="el-icon-search" />
|
||||
</el-input>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
input: ''
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
serachAction(val) {
|
||||
this.$emit('serachAction', val)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
|
||||
</style>
|
||||
|
||||
@@ -36,7 +36,8 @@ const cn = {
|
||||
'Create': '创建',
|
||||
'More actions': '更多操作',
|
||||
'Delete selected': '删除所选',
|
||||
'Update selected': '更新所选'
|
||||
'Update selected': '更新所选',
|
||||
'Search': '搜索'
|
||||
},
|
||||
route: {
|
||||
'dashboard': '仪表盘',
|
||||
|
||||
29
src/layout/components/GenericListPage/index.vue
Normal file
29
src/layout/components/GenericListPage/index.vue
Normal file
@@ -0,0 +1,29 @@
|
||||
<template>
|
||||
<Page>
|
||||
<el-alert v-if="helpMessage" type="success"> {{ helpMessage }} </el-alert>
|
||||
<ListTable :table-config="tableConfig" :header-actions="headerActions" />
|
||||
</Page>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Page } from '@/layout/components'
|
||||
import ListTable from '@/components/ListTable'
|
||||
export default {
|
||||
name: 'GenericListPage',
|
||||
components: {
|
||||
Page, ListTable
|
||||
},
|
||||
props: {
|
||||
...ListTable.props,
|
||||
helpMessage: {
|
||||
type: String,
|
||||
default: null
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -7,3 +7,4 @@ export { default as BaseDetailPage } from './BaseDetailPage'
|
||||
export { default as SubMenuPage } from './SubMenuPage'
|
||||
export { default as Footer } from './Footer'
|
||||
export { default as IBox } from './IBox'
|
||||
export { default as GenericListPage } from './GenericListPage'
|
||||
|
||||
@@ -69,15 +69,15 @@ export const constantRoutes = [
|
||||
path: 'users/create',
|
||||
component: () => import('@/views/users/UserEdit.vue'), // Parent router-view
|
||||
name: 'UserCreate',
|
||||
hidden: true,
|
||||
meta: { title: 'UserCreate' },
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: 'users/:id',
|
||||
component: () => import('@/views/users/UserDetail.vue'), // Parent router-view
|
||||
name: 'UserDetail',
|
||||
hidden: true,
|
||||
meta: { title: 'UserDetail', activeMenu: '/users/users' },
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: 'groups',
|
||||
@@ -85,27 +85,27 @@ export const constantRoutes = [
|
||||
name: 'UserGroupList',
|
||||
meta: { title: 'UserGroupList' }
|
||||
},
|
||||
{
|
||||
path: 'groups/create',
|
||||
component: () => import('@/views/users/UserGroupEdit.vue'), // Parent router-view
|
||||
name: 'UserGroupEdit',
|
||||
meta: { title: 'UserGroupEdit' },
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: 'groups/:id/update',
|
||||
component: () => import('@/views/users/UserGroupEdit.vue'), // Parent router-view
|
||||
name: 'UserGroupEdit',
|
||||
hidden: true,
|
||||
meta: { title: 'UserGroupEdit' },
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: 'groups/:id',
|
||||
component: () => import('@/views/users/UserGroupDetail/index.vue'), // Parent router-view
|
||||
name: 'UserGroupDetail',
|
||||
hidden: true,
|
||||
meta: { title: 'UserGroupDetail', activeMenu: '/users/groups' },
|
||||
hidden: true
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'groups/create',
|
||||
component: () => import('@/views/users/UserCreate.vue'), // Parent router-view
|
||||
name: 'UserGroupCreate',
|
||||
hidden: true,
|
||||
meta: { title: 'UserGroupCreate' }
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -195,3 +195,11 @@ td .el-button.el-button--mini {
|
||||
font-weight: 600;
|
||||
background-color: inherit;
|
||||
}
|
||||
|
||||
.el-table .ascending .sort-caret.ascending {
|
||||
border-bottom-color: #676a6c;
|
||||
}
|
||||
|
||||
.el-table .descending .sort-caret.descending {
|
||||
border-top-color: #676a6c;
|
||||
}
|
||||
|
||||
@@ -53,9 +53,9 @@ service.interceptors.response.use(
|
||||
const res = response.data
|
||||
|
||||
// if the custom code is not 20000, it is judged as an error.
|
||||
if (response.status !== 200 && response.status !== 201) {
|
||||
if (response.status < 200 || response.status > 300) {
|
||||
Message({
|
||||
message: res.message || 'Error',
|
||||
message: res.message || res.error || 'Error',
|
||||
type: 'error',
|
||||
duration: 5 * 1000
|
||||
})
|
||||
|
||||
@@ -1,36 +1,27 @@
|
||||
<template>
|
||||
<Page>
|
||||
<template>
|
||||
<el-alert type="success"> 这里是一个成功的文案 </el-alert>
|
||||
<el-card>
|
||||
<ListTable :table-config="tableConfig" :more-actions="moreActions" />
|
||||
</el-card>
|
||||
</template>
|
||||
</Page>
|
||||
<GenericListPage :table-config="tableConfig" :header-actions="headerActions" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Page } from '@/layout/components'
|
||||
import ListTable from '@/components/ListTable'
|
||||
import { GenericListPage } from '@/layout/components'
|
||||
import DetailFormatter from '@/components/DataTable/formatters/DetailFormatter'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Page,
|
||||
ListTable
|
||||
GenericListPage
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
tableConfig: {
|
||||
url: '/api/v1/users/groups/',
|
||||
columns: [
|
||||
{
|
||||
type: 'selection'
|
||||
},
|
||||
{
|
||||
prop: 'name',
|
||||
label: this.$tc('Name'),
|
||||
key: 'name',
|
||||
link: 'UserGroupDetail',
|
||||
sortable: true
|
||||
formatter: DetailFormatter,
|
||||
sortable: true,
|
||||
route: 'UserDetail'
|
||||
},
|
||||
{
|
||||
prop: 'users_amount',
|
||||
@@ -40,25 +31,20 @@ export default {
|
||||
{
|
||||
prop: 'comment',
|
||||
label: this.$tc('Comment'),
|
||||
key: 'comment'
|
||||
key: 'comment',
|
||||
showOverflowTooltip: true
|
||||
}
|
||||
],
|
||||
// 写路由名字,table组件会自动传作为参数
|
||||
action: {
|
||||
hasEdit: 'UserGroupEdit',
|
||||
newClick: 'UserGroupEdit'
|
||||
tableActions: {
|
||||
hasEdit: true,
|
||||
editRoute: '404'
|
||||
}
|
||||
},
|
||||
moreActions: [
|
||||
{
|
||||
title: this.$tc('Delete selected'),
|
||||
name: 'deleteSelected'
|
||||
},
|
||||
{
|
||||
title: this.$tc('Update selected'),
|
||||
name: 'updateSelected'
|
||||
}
|
||||
]
|
||||
headerActions: {
|
||||
createRoute: 'UserGroupCreate'
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,11 +27,7 @@ export default {
|
||||
key: 'prop',
|
||||
align: 'center'
|
||||
},
|
||||
extraPaginationAttrs: {
|
||||
background: true,
|
||||
pagerCount: 5,
|
||||
pageSizes: [10, 100]
|
||||
},
|
||||
|
||||
extraButtons: [
|
||||
{
|
||||
type: 'primary',
|
||||
@@ -52,14 +48,16 @@ export default {
|
||||
}
|
||||
],
|
||||
columns: [
|
||||
{ type: 'selection' },
|
||||
{
|
||||
type: 'selection',
|
||||
align: 'center'
|
||||
},
|
||||
// Bug
|
||||
// 应该让我插入Slot,使这个用户名可点击
|
||||
{
|
||||
prop: 'name',
|
||||
label: this.$t('users.name'),
|
||||
sortable: true, // 可排序
|
||||
type: 'link',
|
||||
sortable: true // 可排序
|
||||
// url: 'UserDetail' // 第一个函数指定 路由Template
|
||||
},
|
||||
{
|
||||
|
||||
@@ -9090,6 +9090,11 @@ vue-router@3.0.6:
|
||||
version "3.0.6"
|
||||
resolved "https://registry.yarnpkg.com/vue-router/-/vue-router-3.0.6.tgz#2e4f0f9cbb0b96d0205ab2690cfe588935136ac3"
|
||||
|
||||
vue-select@^3.9.5:
|
||||
version "3.9.5"
|
||||
resolved "https://registry.yarnpkg.com/vue-select/-/vue-select-3.9.5.tgz#d70a3815c2cd9ad3eae75adf47dab6f787b30f98"
|
||||
integrity sha512-r392oaLYepNxY+uY1EN7r05VPOqSWGEfZ3LtJ3NqhrRbWCpWQ5EPSMN3QL80HdN3H+o1ueQA9P58K1vgGZ5P3Q==
|
||||
|
||||
vue-style-loader@^4.1.0:
|
||||
version "4.1.2"
|
||||
resolved "https://registry.yarnpkg.com/vue-style-loader/-/vue-style-loader-4.1.2.tgz#dedf349806f25ceb4e64f3ad7c0a44fba735fcf8"
|
||||
|
||||
Reference in New Issue
Block a user