JeecgBoot 2.3 里程碑版本发布,支持微服务和单体自由切换、提供新行编辑表格JVXETable

This commit is contained in:
zhangdaiscott
2020-09-13 18:23:23 +08:00
parent 65d1e6a879
commit 7f30a186df
533 changed files with 187550 additions and 36942 deletions

View File

@ -38,7 +38,7 @@
<a-input placeholder="h3gSbecd"/>
</a-form-item>
<a-form-item
label="密码"
label="密码"
:required="false"
>
<a-input placeholder="密码"/>

View File

@ -5,43 +5,39 @@
<div class="account-settings-info-left">
<a-menu
:mode="device == 'mobile' ? 'horizontal' : 'inline'"
:default-selected-keys="['settings']"
:style="{ border: '0', width: device == 'mobile' ? '560px' : 'auto'}"
:defaultSelectedKeys="defaultSelectedKeys"
type="inner"
@openChange="onOpenChange"
>
<a-menu-item key="/account/settings/base">
<router-link :to="{ name: 'account-settings-base' }">
<a-menu-item key="settings">
<a @click="settingsClick()">
基本设置
</router-link>
</a>
</a-menu-item>
<a-menu-item key="/account/settings/security">
<router-link :to="{ name: 'account-settings-security' }">
安全设置
</router-link>
<a-menu-item key="security">
<a @click="securityClick()">安全设置</a>
</a-menu-item>
<a-menu-item key="/account/settings/custom">
<router-link :to="{ name: 'account-settings-custom' }">
个性化
</router-link>
<a-menu-item key="custom">
<a @click="customClick()"> 个性化</a>
</a-menu-item>
<a-menu-item key="/account/settings/binding">
<router-link :to="{ name: 'account-settings-binding' }">
账户绑定
</router-link>
<a-menu-item key="binding">
<a @click="bindingClick()">账户绑定</a>
</a-menu-item>
<a-menu-item key="/account/settings/notification">
<router-link :to="{ name: 'account-settings-notification' }">
新消息通知
</router-link>
<a-menu-item key="notification">
<a @click="notificationClick()">新消息通知</a>
</a-menu-item>
</a-menu>
</div>
<div class="account-settings-info-right">
<div class="account-settings-info-title">
<span>{{ $route.meta.title }}</span>
<span>{{ title }}</span>
</div>
<route-view></route-view>
<security ref="security" v-if="security"></security>
<base-setting ref="baseSetting" v-if="baseSetting"></base-setting>
<custom ref="custom" v-if="custom"></custom>
<notification ref="notification" v-if="notification"></notification>
<binding ref="binding" v-if="binding"></binding>
</div>
</div>
</a-card>
@ -52,11 +48,20 @@
import PageLayout from '@/components/page/PageLayout'
import RouteView from "@/components/layouts/RouteView"
import { mixinDevice } from '@/utils/mixin.js'
import security from './Security'
import baseSetting from './BaseSetting'
import custom from './Custom'
import notification from './Notification'
import binding from './Binding'
export default {
components: {
RouteView,
PageLayout
PageLayout,
security,
baseSetting,
custom,
notification,
binding
},
mixins: [mixinDevice],
data () {
@ -85,7 +90,13 @@
fixedNumber: [1, 1]
},
pageTitle: ''
pageTitle: '',
title:"基本设置",
security:false,
baseSetting:true,
custom:false,
notification:false,
binding:false
}
},
created () {
@ -101,7 +112,49 @@
updateMenu () {
let routes = this.$route.matched.concat()
this.defaultSelectedKeys = [ routes.pop().path ]
},
//update-begin--Author:wangshuai Date:20200729 for聚合路由错误 issues#1441--------------------
settingsClick(){
this.security=false
this.custom=false
this.notification=false
this.binding=false
this.baseSetting=true
this.title="基本设置"
},
securityClick(){
this.baseSetting=false
this.custom=false;
this.notification=false
this.binding=false
this.security=true
this.title="安全设置"
},
notificationClick(){
this.security=false
this.custom=false
this.baseSetting=false
this.binding=false
this.notification=true
this.title="新消息通知"
},
bindingClick(){
this.security=false
this.baseSetting=false
this.notification=false;
this.custom=false;
this.binding=true
this.title="账号绑定"
},
customClick(){
this.security=false
this.baseSetting=false
this.notification=false;
this.binding=false
this.custom=true;
this.title="个性化"
}
//update-end--Author:wangshuai Date:20200729 for聚合路由错误 issues#1441--------------------
},
}
</script>

View File

@ -0,0 +1,33 @@
<template>
<a-card :bordered="false">
<a-tabs>
<a-tab-pane tab="基础示例" key="1" forceRender>
<j-vxe-demo1/>
</a-tab-pane>
<a-tab-pane tab="高级示例" key="2" forceRender>
<j-vxe-demo2/>
</a-tab-pane>
</a-tabs>
</a-card>
</template>
<script>
import JVxeDemo1 from '@views/jeecg/JVxeDemo/JVxeDemo1'
import JVxeDemo2 from '@views/jeecg/JVxeDemo/JVxeDemo2'
export default {
name: 'JVXETableDemo',
components: {JVxeDemo2, JVxeDemo1},
data() {
return {}
},
methods: {},
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,304 @@
<template>
<j-vxe-table
ref="vTable"
toolbar
row-number
row-selection
drag-sort
keep-source
:height="580"
:loading="loading"
:dataSource="dataSource"
:columns="columns"
style="margin-top: 8px;"
@valueChange="handleValueChange"
>
<template v-slot:toolbarSuffix>
<a-button @click="handleTableCheck">表单验证</a-button>
<a-tooltip placement="top" title="获取值,忽略表单验证" :autoAdjustOverflow="true">
<a-button @click="handleTableGet">获取值</a-button>
</a-tooltip>
<a-tooltip placement="top" title="模拟加载1000条数据" :autoAdjustOverflow="true">
<a-button @click="handleTableSet">设置值</a-button>
</a-tooltip>
</template>
<template v-slot:action="props">
<a @click="handleCK(props)">查看</a>
<a-divider type="vertical"/>
<a-popconfirm title="确定删除吗?" @confirm="handleDL(props)">
<a>删除</a>
</a-popconfirm>
</template>
</j-vxe-table>
</template>
<script>
import moment from 'moment'
import { pushIfNotExist, randomNumber, randomUUID } from '@/utils/util'
import { JVXETypes } from '@/components/jeecg/JVxeTable'
export default {
name: 'JVxeDemo1',
data() {
return {
loading: false,
columns: [
{
title: '不可编辑',
key: 'normal',
type: JVXETypes.normal,
width: '180px',
fixed: 'left',
defaultValue: 'normal-new',
},
{
title: '单行文本',
key: 'input',
type: JVXETypes.input,
width: '180px',
defaultValue: '',
placeholder: '请输入${title}',
validateRules: [
{
required: true, // 必填
message: '请输入${title}' // 显示的文本
},
{
pattern: /^[a-z|A-Z][a-z|A-Z\d_-]*$/, // 正则
message: '${title}必须以字母开头可包含数字下划线横杠'
},
{
unique: true,
message: '${title}不能重复'
},
{
handler({cellValue, row, column}, callback, target) {
// cellValue 当前校验的值
// callback(flag, message) 方法必须执行且只能执行一次
// flag = 是否通过了校验,不填写或者填写 null 代表不进行任何操作
// message = 提示的类型,默认使用配置的 message
// target 行编辑的实例对象
if (cellValue === 'abc') {
callback(false, '${title}不能是abc') // false = 未通过校验
} else {
callback(true) // true = 通过验证
}
},
message: '${title}默认提示'
}
]
},
{
title: '多行文本',
key: 'textarea',
type: JVXETypes.textarea,
width: '200px',
},
{
title: '数字',
key: 'number',
type: JVXETypes.inputNumber,
width: '80px',
defaultValue: 32,
// 【统计列】sum = 求和、average = 平均值
statistics: ['sum', 'average'],
},
{
title: '下拉框',
key: 'select',
type: JVXETypes.select,
width: '180px',
// 下拉选项
options: [
{title: 'String', value: 'string'},
{title: 'Integer', value: 'int'},
{title: 'Double', value: 'double'},
{title: 'Boolean', value: 'boolean'}
],
allowInput: true,
placeholder: '请选择'
},
{
title: '下拉框_字典',
key: 'select_dict',
type: JVXETypes.select,
width: '180px',
options: [],
dictCode: 'sex',
placeholder: '请选择',
},
{
title: '下拉框_多选',
key: 'select_multiple',
type: JVXETypes.selectMultiple,
width: '180px',
options: [
{title: 'String', value: 'string'},
{title: 'Integer', value: 'int'},
{title: 'Double', value: 'double'},
{title: 'Boolean', value: 'boolean'}
],
defaultValue: ['int', 'boolean'], // 多个默认项
// defaultValue: 'string,double,int', // 也可使用这种方式
placeholder: '多选',
},
{
title: '下拉框_搜索',
key: 'select_search',
type: JVXETypes.selectSearch,
width: '180px',
options: [
{title: 'String', value: 'string'},
{title: 'Integer', value: 'int'},
{title: 'Double', value: 'double'},
{title: 'Boolean', value: 'boolean'}
],
},
{
title: '日期时间',
key: 'datetime',
type: JVXETypes.datetime,
width: '200px',
defaultValue: '2019-4-30 14:52:22',
placeholder: '请选择',
},
{
title: '复选框',
key: 'checkbox',
type: JVXETypes.checkbox,
width: '100px',
customValue: ['Y', 'N'], // true ,false
defaultChecked: false,
},
{
title: '操作',
key: 'action',
type: JVXETypes.slot,
fixed: 'right',
minWidth: '100px',
align: 'center',
slotName: 'action',
}
],
dataSource: [],
}
},
created() {
this.randomPage(0, 20, true)
},
methods: {
handleCK(props) {
this.$message.success('请在控制台查看输出')
// 参数介绍:
// props.value 当前单元格的值
// props.row 当前行的数据
// props.rowId 当前行ID
// props.rowIndex 当前行下标
// props.column 当前列的配置
// props.columnIndex 当前列下标
// props.$table vxe实例可以调用vxe内置方法
// props.target JVXE实例可以调用JVXE内置方法
// props.caseId JVXE实例唯一ID
// props.scrolling 是否正在滚动
// props.triggerChange 触发change事件用于更改slot的值
console.log('查看: ', {props})
},
handleDL(props) {
// 调用删除方法
props.target.removeRows(props.row)
},
handleValueChange(event) {
console.log('handleValueChange.event: ', event)
},
/** 表单验证 */
handleTableCheck() {
this.$refs.vTable.validateTable().then(errMap => {
if (errMap) {
console.log('表单验证未通过', {errMap})
this.$message.error('验证未通过请在控制台查看详细')
} else {
this.$message.success('验证通过')
}
})
},
/** 获取值,忽略表单验证 */
handleTableGet() {
const values = this.$refs.vTable.getTableData()
console.log('获取值:', {values})
this.$message.success('获取值成功请看控制台输出')
},
/** 模拟加载1000条数据 */
handleTableSet() {
this.randomPage(1, 1000, true)
},
/* 随机生成数据 */
randomPage(current, pageSize, loading = false) {
if (loading) {
this.loading = true
}
let randomDatetime = () => {
let time = randomNumber(1000, 9999999999999)
return moment(new Date(time)).format('YYYY-MM-DD HH:mm:ss')
}
let limit = (current - 1) * pageSize
let options = ['string', 'int', 'double', 'boolean']
let begin = Date.now()
let values = []
for (let i = 0; i < pageSize; i++) {
values.push({
id: randomUUID(),
normal: `normal-${(limit + i) + 1}`,
input: `text-${(limit + i) + 1}`,
textarea: `textarea-${(limit + i) + 1}`,
number: randomNumber(0, 233),
select: options[randomNumber(0, 3)],
select_dict: randomNumber(1, 2).toString(),
select_multiple: (() => {
let length = randomNumber(1, 4)
let arr = []
for (let j = 0; j < length; j++) {
pushIfNotExist(arr, options[randomNumber(0, 3)])
}
return arr
})(),
select_search: options[randomNumber(0, 3)],
datetime: randomDatetime(),
checkbox: ['Y', 'N'][randomNumber(0, 1)]
})
}
this.dataSource = values
let end = Date.now()
let diff = end - begin
if (loading && diff < pageSize) {
setTimeout(() => {
this.loading = false
}, pageSize - diff)
}
}
}
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,184 @@
<template>
<j-vxe-table
ref="vTable"
toolbar
row-number
row-selection
keep-source
:height="484"
:loading="loading"
:dataSource="dataSource"
:columns="columns"
:pagination="pagination"
style="margin-top: 8px;"
@pageChange="handlePageChange"
>
<template v-slot:toolbarSuffix>
<a-button @click="handleTableGet">获取值</a-button>
</template>
</j-vxe-table>
</template>
<script>
import moment from 'moment'
import { randomNumber, randomUUID } from '@/utils/util'
import { JVXETypes } from '@/components/jeecg/JVxeTable'
export default {
name: 'JVxeDemo2',
data() {
return {
loading: false,
columns: [
{
title: '下拉框_字典表搜索',
key: 'select_dict_search',
type: JVXETypes.selectDictSearch,
width: '200px',
// 【字典表配置信息】:数据库表名,显示字段名,存储字段名
dict: 'sys_user,realname,username',
},
{
title: 'JPopup',
key: 'popup',
type: JVXETypes.popup,
width: '180px',
popupCode: 'demo',
field: 'name,sex,age',
orgFields: 'name,sex,age',
destFields: 'popup,popup_sex,popup_age'
},
{
title: 'JP-性别',
key: 'popup_sex',
type: JVXETypes.select,
dictCode: 'sex',
disabled: true,
width: '100px',
},
{
title: 'JP-年龄',
key: 'popup_age',
type: JVXETypes.normal,
width: '80px',
},
{
title: '进度条',
key: 'progress',
type: JVXETypes.progress,
minWidth: '120px'
},
{
title: '单选',
key: 'radio',
type: JVXETypes.radio,
width: '130px',
options: [
{text: '男', value: '1'},
{text: '女', value: '2'},
],
// 允许清除选择(再点一次取消选择)
allowClear: true
},
{
title: '上传',
key: 'upload',
type: JVXETypes.upload,
width: '180px',
btnText: '点击上传',
token: true,
responseName: 'message',
action: window._CONFIG['domianURL'] + '/sys/common/upload'
},
{
title: '图片上传',
key: 'image',
type: JVXETypes.image,
width: '180px',
token: true,
},
{
title: '文件上传',
key: 'file',
type: JVXETypes.file,
width: '180px',
token: true,
},
],
dataSource: [],
pagination: {
current: 1,
pageSize: 10,
pageSizeOptions: ['10', '20', '30', '100', '200'],
total: 1000,
},
}
},
created() {
this.randomPage(this.pagination.current, this.pagination.pageSize, true)
},
methods: {
// 当分页参数变化时触发的事件
handlePageChange(event) {
// 重新赋值
this.pagination.current = event.current
this.pagination.pageSize = event.pageSize
// 查询数据
this.randomPage(event.current, event.pageSize, true)
},
/** 获取值,忽略表单验证 */
handleTableGet() {
const values = this.$refs.vTable.getTableData()
console.log('获取值:', {values})
this.$message.success('获取值成功请看控制台输出')
},
/* 随机生成数据 */
randomPage(current, pageSize, loading = false) {
if (loading) {
this.loading = true
}
let randomDatetime = () => {
let time = randomNumber(1000, 9999999999999)
return moment(new Date(time)).format('YYYY-MM-DD HH:mm:ss')
}
let limit = (current - 1) * pageSize
let begin = Date.now()
let values = []
for (let i = 0; i < pageSize; i++) {
let radio = randomNumber(0, 2)
values.push({
id: randomUUID(),
select_dict_search: ['', 'admin', '', 'jeecg', ''][randomNumber(0, 4)],
progress: randomNumber(0, 100),
radio: radio ? radio.toString() : null
})
}
this.dataSource = values
let end = Date.now()
let diff = end - begin
if (loading && diff < pageSize) {
setTimeout(() => {
this.loading = false
}, pageSize - diff)
}
}
}
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,234 @@
<template>
<a-card title="即时保存示例" :bordered="false">
<!--
即时保存大体思路
1. JVxeTable 上必须加 keep-source 属性
2. 监听 edit-closed事件这个事件是在编辑完成后触发
3. 在这个事件里面判断数据是否更改如果更改了就调用接口进行保存操作
-->
<j-vxe-table
toolbar
:toolbarConfig="toolbarConfig"
row-number
row-selection
keep-source
async-remove
:height="340"
:loading="loading"
:columns="columns"
:dataSource="dataSource"
:pagination="pagination"
@save="handleTableSave"
@remove="handleTableRemove"
@edit-closed="handleEditClosed"
@pageChange="handlePageChange"
@selectRowChange="handleSelectRowChange"
/>
</a-card>
</template>
<script>
import { getAction, postAction, putAction } from '@api/manage'
import { JVXETypes } from '@/components/jeecg/JVxeTable'
// 即时保存示例
export default {
name: 'JSBCDemo',
data() {
return {
// 工具栏的按钮配置
toolbarConfig: {
// add 新增按钮remove 删除按钮clearSelection 清空选择按钮
btn: ['add', 'save', 'remove', 'clearSelection']
},
// 是否正在加载
loading: false,
// 分页器参数
pagination: {
// 当前页码
current: 1,
// 每页的条数
pageSize: 200,
// 可切换的条数
pageSizeOptions: ['10', '20', '30', '100', '200'],
// 数据总数目前并不知道真实的总数所以先填写0在后台查出来后再赋值
total: 0,
},
// 选择的行
selectedRows: [],
// 数据源,控制表格的数据
dataSource: [],
// 列配置,控制表格显示的列
columns: [
{key: 'num', title: '序号', width: '80px'},
{
// 字段key跟后台数据的字段名匹配
key: 'ship_name',
// 列的标题
title: '船名',
// 列的宽度
width: '180px',
// 如果加上了该属性就代表当前单元格是可编辑的type就是表单的类型input就是简单的输入框
type: JVXETypes.input
},
{key: 'call', title: '呼叫', width: '80px', type: JVXETypes.input},
{key: 'len', title: '长', width: '80px', type: JVXETypes.input},
{key: 'ton', title: '吨', width: '120px', defaultValue: 233, type: JVXETypes.input},
{key: 'payer', title: '付款方', width: '120px', defaultValue: '张三', type: JVXETypes.input},
{key: 'count', title: '数', width: '40px'},
{
key: 'company',
title: '公司',
// 最小宽度,与宽度不同的是,这个不是固定的宽度,如果表格有多余的空间,会平均分配给设置了 minWidth 的列
// 如果要做占满表格的列可以这么写
minWidth: '180px',
type: JVXETypes.input
},
{key: 'trend', title: '动向', width: '120px', type: JVXETypes.input},
],
// 查询url地址
url: {
getData: '/mock/vxe/getData',
// 模拟保存单行数据(即时保存)
saveRow: '/mock/vxe/immediateSaveRow',
// 模拟保存整个表格的数据
saveAll: '/mock/vxe/immediateSaveAll',
},
}
},
created() {
this.loadData()
},
methods: {
// 加载数据
loadData() {
// 封装查询条件
let formData = {
pageNo: this.pagination.current,
pageSize: this.pagination.pageSize
}
// 调用查询数据接口
this.loading = true
getAction(this.url.getData, formData).then(res => {
if (res.success) {
// 后台查询回来的 total数据总数量
this.pagination.total = res.result.total
// 将查询的数据赋值给 dataSource
this.dataSource = res.result.records
// 重置选择
this.selectedRows = []
} else {
this.$error({title: '主表查询失败', content: res.message})
}
}).finally(() => {
// 这里是无论成功或失败都会执行的方法在这里关闭loading
this.loading = false
})
},
// 【整体保存】点击保存按钮时触发的事件
handleTableSave({$table, target}) {
// 校验整个表格
$table.validate().then((errMap) => {
// 校验通过
if (!errMap) {
// 获取所有数据
let tableData = target.getTableData()
console.log('当前保存的数据是', tableData)
// 获取新增的数据
let newData = target.getNewData()
console.log('-- 新增的数据', newData)
// 获取删除的数据
let deleteData = target.getDeleteData()
console.log('-- 删除的数据', deleteData)
// 【模拟保存】
this.loading = true
postAction(this.url.saveAll, tableData).then(res => {
if (res.success) {
this.$message.success(`保存成功`)
} else {
this.$message.warn(`保存失败` + res.message)
}
}).finally(() => {
this.loading = false
})
}
})
},
// 触发单元格删除事件
handleTableRemove(event) {
// 把 event.deleteRows 传给后台进行删除(注意:这里不会传递前端逻辑新增的数据,因为不需要请求后台删除)
console.log('待删除的数据: ', event.deleteRows)
// 也可以只传ID因为可以根据ID删除
let deleteIds = event.deleteRows.map(row => row.id)
console.log('待删除的数据ids: ', deleteIds)
// 模拟请求后台删除
this.loading = true
window.setTimeout(() => {
this.loading = false
this.$message.success('删除成功')
// 假设后台返回删除成功,必须要调用 confirmRemove() 方法,才会真正在表格里移除(会同时删除选中的逻辑新增的数据)
event.confirmRemove()
}, 1000)
},
// 单元格编辑完成之后触发的事件
handleEditClosed(event) {
let {$table, row, column} = event
let field = column.property
let cellValue = row[field]
// 判断单元格值是否被修改
if ($table.isUpdateByRow(row, field)) {
// 校验当前行
$table.validate(row).then((errMap) => {
// 校验通过
if (!errMap) {
// 【模拟保存】
let hideLoading = this.$message.loading(`正在保存"${column.title}"`, 0)
console.log('即时保存数据', row)
putAction(this.url.saveRow, row).then(res => {
if (res.success) {
this.$message.success(`"${column.title}"保存成功`)
// 局部更新单元格为已保存状态
$table.reloadRow(row, null, field)
} else {
this.$message.warn(`"${column.title}"保存失败` + res.message)
}
}).finally(() => {
hideLoading()
})
}
})
}
},
// 当分页参数变化时触发的事件
handlePageChange(event) {
// 重新赋值
this.pagination.current = event.current
this.pagination.pageSize = event.pageSize
// 查询数据
this.loadData()
},
// 当选择的行变化时触发的事件
handleSelectRowChange(event) {
this.selectedRows = event.selectedRows
},
},
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,278 @@
<template>
<a-card title="弹出子表示例" :bordered="false">
<!--
弹出子表大体思路
1. 必须要有 click-row-show-sub-form 属性如果该属性设为false那么就不会弹出子表
2. 必须要有 sub-form 插槽用于规定弹出子表的内容
3. highlight-current-row 属性可有可无如果有则点击一行的时候该行会背景色会常亮
-->
<!--
弹出详细信息既有主表的数据也有子表的大体思路
1. 必须要有 click-row-show-main-form 属性如果该属性设为false那么就不会弹出详细信息
2. 必须要有 main-form 插槽用于规定弹出子表的内容
3. 可选 click-row-show-sub-form 属性如果有该属性就会显示子表否者不显示
-->
<j-vxe-table
toolbar
row-number
row-selection
highlight-current-row
click-row-show-sub-form
click-row-show-main-form
:height="750"
:loading="loading"
:columns="columns"
:dataSource="dataSource"
@detailsConfirm="handleDetailsConfirm"
>
<!-- 主表单 -->
<template v-slot:mainForm="{row}">
<template v-if="row">
<a-form-model
ref="form2"
:model="row"
:rules="rules"
:label-col="labelCol"
:wrapper-col="wrapperCol"
>
<a-row :gutter="8">
<a-col :span="8">
<a-form-model-item label="ID" prop="id">
<a-input v-model="row.id" disabled/>
</a-form-model-item>
</a-col>
<a-col :span="8">
<a-form-model-item label="序号" prop="num">
<a-input v-model="row.num"/>
</a-form-model-item>
</a-col>
<a-col :span="8">
<a-form-model-item label="船名" prop="ship_name">
<a-input v-model="row.ship_name"/>
</a-form-model-item>
</a-col>
<a-col :span="8">
<a-form-model-item label="呼叫" prop="call">
<a-input v-model="row.call"/>
</a-form-model-item>
</a-col>
<a-col :span="8">
<a-form-model-item label="" prop="len">
<a-input v-model="row.len"/>
</a-form-model-item>
</a-col>
<a-col :span="8">
<a-form-model-item label="" prop="ton">
<a-input v-model="row.ton"/>
</a-form-model-item>
</a-col>
<a-col :span="8">
<a-form-model-item label="付款方" prop="payer">
<a-input v-model="row.payer"/>
</a-form-model-item>
</a-col>
<a-col :span="8">
<a-form-model-item label="" prop="count">
<a-input v-model="row.count"/>
</a-form-model-item>
</a-col>
<a-col :span="8">
<a-form-model-item label="公司" prop="company">
<a-input v-model="row.company"/>
</a-form-model-item>
</a-col>
<a-col :span="8">
<a-form-model-item label="动向" prop="trend">
<a-input v-model="row.trend"/>
</a-form-model-item>
</a-col>
</a-row>
</a-form-model>
</template>
</template>
<!-- 子表单 -->
<template v-slot:subForm="{row}">
<template v-if="loadSubData(row)">
<j-vxe-table
ref="subFormTable"
height="auto"
:max-height="350"
:loading="subTable.loading"
:columns="subTable.columns"
:dataSource="subTable.dataSource"
/>
</template>
</template>
</j-vxe-table>
</a-card>
</template>
<script>
import { getAction } from '@api/manage'
import { JVXETypes } from '@/components/jeecg/JVxeTable'
// 弹出子表示例
export default {
name: 'PopupSubTable',
data() {
return {
loading: false,
dataSource: [],
columns: [
{key: 'num', title: '序号', width: '80px'},
{key: 'ship_name', title: '船名', width: '180px', type: JVXETypes.input},
{key: 'call', title: '呼叫', width: '80px'},
{key: 'len', title: '长', width: '80px'},
{key: 'ton', title: '吨', width: '120px'},
{key: 'payer', title: '付款方', width: '120px'},
{key: 'count', title: '数', width: '40px'},
{
key: 'company',
title: '公司',
minWidth: '180px',
// 是否点击显示详细信息
// 只有当前单元格不能编辑的时候才能生效
// 如果不设的话,点击就只弹出子表,不会弹出主表的详细信息
showDetails: true
},
{key: 'trend', title: '动向', width: '120px'},
],
// 子表的信息
subTable: {
currentRowId: null,
loading: false,
pagination: {current: 1, pageSize: 200, pageSizeOptions: ['100', '200'], total: 0},
selectedRows: [],
dataSource: [],
columns: [
{key: 'dd_num', title: '调度序号', width: '120px'},
{key: 'tug', title: '拖轮', width: '180px', type: JVXETypes.input},
{key: 'work_start_time', title: '作业开始时间', width: '180px', type: JVXETypes.input},
{key: 'work_stop_time', title: '作业结束时间', width: '180px', type: JVXETypes.input},
{key: 'type', title: '船舶分类', width: '120px', type: JVXETypes.input},
{key: 'port_area', title: '所属港区', minWidth: '120px', type: JVXETypes.input},
],
},
// 查询url地址
url: {
getData: '/mock/vxe/getData',
},
// 主表form表单字段
mainForm: {
id: '',
num: '',
ship_name: '',
call: '',
len: '',
ton: '',
payer: '',
count: '',
company: '',
trend: '',
},
// form表单 col
labelCol: {span: 4},
wrapperCol: {span: 20},
rules: {
num: [
{required: true, message: '必须输入序号'},
],
},
}
},
created() {
this.loadData()
},
methods: {
log: console.log,
// 加载数据
loadData() {
// 封装查询条件
let formData = {pageNo: 1, pageSize: 30}
// 调用查询数据接口
this.loading = true
getAction(this.url.getData, formData).then(res => {
if (res.success) {
// 将查询的数据赋值给 dataSource
this.dataSource = res.result.records
// 重置选择
this.selectedRows = []
} else {
this.$error({title: '主表查询失败', content: res.message})
}
}).finally(() => {
// 这里是无论成功或失败都会执行的方法在这里关闭loading
this.loading = false
})
},
// 查询子表数据
loadSubData(row) {
if (row) {
// 这里一定要做限制,限制不能重复查询,否者会出现死循环
if (this.subTable.currentRowId === row.id) {
return true
}
this.subTable.currentRowId = row.id
let formData = {pageNo: 1, pageSize: 30, parentId: row.id}
this.subTable.loading = true
getAction(this.url.getData, formData).then(res => {
if (res.success) {
// 将查询的数据赋值给 dataSource
this.subTable.dataSource = res.result.records
} else {
this.$error({title: '主表查询失败', content: res.message})
}
}).finally(() => {
// 这里是无论成功或失败都会执行的方法在这里关闭loading
this.subTable.loading = false
})
return true
} else {
return false
}
},
// 详细信息里点了确认按钮
handleDetailsConfirm({row, $table, callback}) {
console.log('保存的数据', row)
// 校验当前行
$table.validate(row).then((errMap) => {
// 校验通过
if (!errMap) {
// 校验子表,如果需要的话,可以操作下面这个对象:
// this.$refs.subFormTable
callback(true)
this.loading = true
setTimeout(() => {
this.loading = false
this.$message.success('保存成功')
}, 1000)
} else {
callback(false)
this.$message.warn('校验失败')
}
})
},
},
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,119 @@
<template>
<a-card title="无痕刷新示例" :bordered="false">
<div style="margin-bottom: 8px;">
<span>启用数据变动特效</span>
<a-switch v-model="reloadEffect"/>
</div>
<!--
即时保存大体思路
1. 该功能依赖于即时保存功能请先看即时保存示例
2. 必须要有 socket-reload 属性且设为 true
3. 必须要有 socket-key 属性该属性为当前表格的唯一标识
系统会自动更新所有 socket-key 相同的表格
4. 在局部保存 edit-closed 事件中
保存成功后调用 socketSendUpdateRow 方法将当前 row 传递过去即可 见第 108
-->
<j-vxe-table
ref="table"
row-number
row-selection
keep-source
socket-reload
socket-key="demo-socket-reload"
:reload-effect="reloadEffect"
:height="340"
:loading="loading"
:columns="columns"
:dataSource="dataSource"
@edit-closed="handleEditClosed"
/>
</a-card>
</template>
<script>
import { getAction } from '@api/manage'
import { JVXETypes } from '@/components/jeecg/JVxeTable'
// 无痕刷新示例
export default {
name: 'SocketReload',
data() {
return {
loading: false,
dataSource: [],
columns: [
{key: 'num', title: '序号', width: '80px'},
{key: 'ship_name', title: '船名', width: '180px', type: JVXETypes.input},
{key: 'call', title: '呼叫', width: '80px', type: JVXETypes.input},
{key: 'len', title: '长', width: '80px', type: JVXETypes.input},
{key: 'ton', title: '吨', width: '120px', type: JVXETypes.input},
{key: 'payer', title: '付款方', width: '120px', type: JVXETypes.input},
{key: 'count', title: '数', width: '40px'},
{key: 'company', title: '公司', minWidth: '180px', type: JVXETypes.input},
{key: 'trend', title: '动向', width: '120px', type: JVXETypes.input},
],
// 查询url地址
url: {
getData: '/mock/vxe/getData',
},
// 是否启用日历刷新效果
reloadEffect: false,
}
},
created() {
this.loadData()
},
methods: {
// 加载数据
loadData() {
let formData = {pageNo: 1, pageSize: 200}
this.loading = true
getAction(this.url.getData, formData).then(res => {
if (res.success) {
this.dataSource = res.result.records
} else {
this.$error({title: '主表查询失败', content: res.message})
}
}).finally(() => {
this.loading = false
})
},
// 单元格编辑完成之后触发的事件
handleEditClosed(event) {
let {$table, row, column} = event
let field = column.property
let cellValue = row[field]
// 判断单元格值是否被修改
if ($table.isUpdateByRow(row, field)) {
// 校验当前行
$table.validate(row).then((errMap) => {
// 校验通过
if (!errMap) {
// 【模拟保存】(此处需要替换成真实的请求)
let hideLoading = this.$message.loading(`正在保存"${column.title}"`, 0)
setTimeout(() => {
hideLoading()
this.$message.success(`"${column.title}"保存成功`)
// 局部更新单元格为已保存状态
$table.reloadRow(row, null, field)
// 发送更新消息
this.$refs.table.socketSendUpdateRow(row)
}, 555)
}
})
}
},
},
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,308 @@
<template>
<a-card :bordered="false">
<j-vxe-table
toolbar
:toolbarConfig="toolbarConfig"
row-number
row-selection
row-selection-type="radio"
highlight-current-row
click-select-row
:height="tableHeight"
:loading="table1.loading"
:columns="table1.columns"
:dataSource="table1.dataSource"
:pagination="table1.pagination"
:expand-config="expandConfig"
style="margin-bottom: 8px"
@pageChange="handleTable1PageChange"
@selectRowChange="handleTable1SelectRowChange"
></j-vxe-table>
<a-tabs v-show="subTabs.show" :class="{'sub-tabs':true, 'un-expand': !subTabs.expand}">
<a-tab-pane tab="子表1" key="1">
<j-vxe-table
toolbar
row-number
row-selection
height="auto"
:maxHeight="350"
:loading="table2.loading"
:columns="table2.columns"
:dataSource="table2.dataSource"
:pagination="table2.pagination"
@pageChange="handleTable2PageChange"
@selectRowChange="handleTable2SelectRowChange"
/>
</a-tab-pane>
<a-tab-pane tab="子表2" key="2">
<h1>这里是子表2</h1>
<h1>这里是子表2</h1>
<h1>这里是子表2</h1>
<h1>这里是子表2</h1>
<h1>这里是子表2</h1>
<h1>这里是子表2</h1>
</a-tab-pane>
</a-tabs>
</a-card>
</template>
<script>
import { JVXETypes } from '@/components/jeecg/JVxeTable'
import { getAction } from '@api/manage'
export default {
name: 'ErpTemplate',
data() {
return {
toolbarConfig: {
// prefix 前缀suffix 后缀
slot: ['prefix', 'suffix'],
// add 新增按钮remove 删除按钮clearSelection 清空选择按钮
btn: ['add', 'remove', 'clearSelection']
},
expandConfig: {
// 是否只能同时展开一行
accordion: true
},
// 子表 tabs
subTabs: {
show: false,
// 是否展开
expand: true,
// 是否自动展开
autoExpand: true,
},
table1: {
// 是否正在加载
loading: false,
// 分页器参数
pagination: {
// 当前页码
current: 1,
// 每页的条数
pageSize: 200,
// 可切换的条数
pageSizeOptions: ['10', '20', '30', '100', '200'],
// 数据总数目前并不知道真实的总数所以先填写0在后台查出来后再赋值
total: 0,
showTotal: (total, range) => {
// 此处为 jsx 语法
let text = <span>{range[0] + '-' + range[1] + ' 共 ' + total + ' 条'}</span>
// 判断子表是否显示,如果显示就渲染展开收起按钮
if (this.subTabs.show) {
let expand = (<span>
<a-button type="link" onClick={this.handleToggleTabs}>
<a-icon type={this.subTabs.expand ? 'up' : 'down'}/>
<span>{this.subTabs.expand ? '收起' : '展开'}</span>
</a-button>
<a-checkbox vModel={this.subTabs.autoExpand}>自动展开</a-checkbox>
</span>)
// 返回多个dom用数组
return [expand, text]
} else {
// 直接返回单个dom
return text
}
},
},
// 选择的行
selectedRows: [],
// 数据源,控制表格的数据
dataSource: [],
// 列配置,控制表格显示的列
columns: [
{key: 'num', title: '序号', width: '80px'},
{
// 字段key跟后台数据的字段名匹配
key: 'ship_name',
// 列的标题
title: '船名',
// 列的宽度
width: '180px',
// 如果加上了该属性就代表当前单元格是可编辑的type就是表单的类型input就是简单的输入框
type: JVXETypes.input
},
{key: 'call', title: '呼叫', width: '990px', type: JVXETypes.input},
{key: 'len', title: '长', width: '80px', type: JVXETypes.inputNumber},
{key: 'ton', title: '吨', width: '120px', type: JVXETypes.inputNumber},
{key: 'payer', title: '付款方', width: '120px', type: JVXETypes.input},
{key: 'count', title: '数', width: '40px'},
{
key: 'company',
title: '公司',
// 最小宽度,与宽度不同的是,这个不是固定的宽度,如果表格有多余的空间,会平均分配给设置了 minWidth 的列
// 如果要做占满表格的列可以这么写
minWidth: '180px',
type: JVXETypes.input
},
{key: 'trend', title: '动向', width: '120px', type: JVXETypes.input},
],
},
// 子级表的配置信息 (配置和主表的完全一致,就不写冗余的注释了)
table2: {
currentRowId: null,
loading: false,
pagination: {current: 1, pageSize: 10, pageSizeOptions: ['5', '10', '20', '30'], total: 0},
selectedRows: [],
dataSource: [],
columns: [
{key: 'dd_num', title: '调度序号', width: '120px'},
{key: 'tug', title: '拖轮', width: '180px', type: JVXETypes.input},
{key: 'work_start_time', title: '作业开始时间', width: '180px', type: JVXETypes.input},
{key: 'work_stop_time', title: '作业结束时间', width: '180px', type: JVXETypes.input},
{key: 'type', title: '船舶分类', width: '120px', type: JVXETypes.input},
{key: 'port_area', title: '所属港区', width: '120px', type: JVXETypes.input},
],
},
currentSubRow: null,
// 查询url地址
url: {
getData: '/mock/vxe/getData',
},
}
},
computed: {
tableHeight() {
let {show, expand} = this.subTabs
return show ? (expand ? 350 : 482) : 482
},
},
created() {
this.loadTable1Data()
},
methods: {
// 加载table1【主表】的数据
loadTable1Data() {
// 封装查询条件
let formData = {
pageNo: this.table1.pagination.current,
pageSize: this.table1.pagination.pageSize
}
// 调用查询数据接口
this.table1.loading = true
getAction(this.url.getData, formData).then(res => {
if (res.success) {
// 后台查询回来的 total数据总数量
this.table1.pagination.total = res.result.total
// 将查询的数据赋值给 dataSource
this.table1.dataSource = res.result.records
// 重置选择
this.table1.selectedRows = []
} else {
this.$error({title: '主表查询失败', content: res.message})
}
}).finally(() => {
// 这里是无论成功或失败都会执行的方法在这里关闭loading
this.table1.loading = false
})
},
// 查询子表数据
loadSubData(row) {
if (row) {
// 这里一定要做限制,限制不能重复查询,否者会出现死循环
if (this.table2.currentRowId === row.id) {
return true
}
this.table2.currentRowId = row.id
this.loadTable2Data()
return true
} else {
return false
}
},
// 查询子表数据
loadTable2Data() {
let table2 = this.table2
let formData = {
parentId: table2.currentRowId,
pageNo: this.table2.pagination.current,
pageSize: this.table2.pagination.pageSize
}
table2.loading = true
getAction(this.url.getData, formData).then(res => {
if (res.success) {
// 将查询的数据赋值给 dataSource
table2.selectedRows = []
table2.dataSource = res.result.records
table2.pagination.total = res.result.total
} else {
this.$error({title: '子表查询失败', content: res.message})
}
}).finally(() => {
// 这里是无论成功或失败都会执行的方法在这里关闭loading
table2.loading = false
})
},
// table1【主表】当选择的行变化时触发的事件
handleTable1SelectRowChange(event) {
this.table1.selectedRows = event.selectedRows
this.subTabs.show = true
if (this.subTabs.autoExpand) {
this.subTabs.expand = true
}
this.loadSubData(event.selectedRows[0])
},
// table2【子表】当选择的行变化时触发的事件
handleTable2SelectRowChange(event) {
this.table2.selectedRows = event.selectedRows
},
handleTable1PageChange(event) {
// 重新赋值
this.table1.pagination.current = event.current
this.table1.pagination.pageSize = event.pageSize
// 查询数据
this.loadTable1Data()
},
// 当table2【子表】分页参数变化时触发的事件
handleTable2PageChange(event) {
// 重新赋值
this.table2.pagination.current = event.current
this.table2.pagination.pageSize = event.pageSize
// 查询数据
this.loadTable2Data()
},
// 展开或收起子表tabs
handleToggleTabs() {
this.subTabs.expand = !this.subTabs.expand
},
},
}
</script>
<style lang="less" scoped>
.sub-tabs {
&.un-expand {
/deep/ .ant-tabs-content {
height: 0 !important;
}
/deep/ .ant-tabs-bar {
border-color: transparent !important;
}
/deep/ .ant-tabs-ink-bar {
background-color: transparent !important;
}
/deep/ .ant-tabs-tab {
display: none !important;
}
}
}
</style>

View File

@ -0,0 +1,42 @@
<template>
<a-card :bordered="false">
<a-tabs>
<a-tab-pane tab="ERP布局模板" key="erp">
<erp-template/>
</a-tab-pane>
<a-tab-pane tab="布局模板1" key="1">
<template1/>
</a-tab-pane>
<a-tab-pane tab="布局模板2" key="2">
<template2/>
</a-tab-pane>
<a-tab-pane tab="布局模板3" key="3">
<template3/>
</a-tab-pane>
<a-tab-pane tab="布局模板4" key="4">
<template4/>
</a-tab-pane>
<a-tab-pane tab="布局模板5" key="5">
<template5/>
</a-tab-pane>
</a-tabs>
</a-card>
</template>
<script>
import Template1 from './Template1'
import Template2 from './Template2'
import Template3 from './Template3'
import Template4 from './Template4'
import Template5 from './Template5'
import ErpTemplate from './ErpTemplate'
export default {
name: 'LayoutDemo',
components: {Template5, Template4, Template3, Template2, Template1, ErpTemplate}
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,330 @@
<template>
<a-card :bordered="false">
<a-row :gutter="8">
<!-- 这里是父级节点 -->
<a-col :span="24" style="margin-bottom: 4px;">
<j-vxe-table
toolbar
row-number
row-selection
click-select-row
highlight-current-row
:radio-config="{highlight: false}"
:checkbox-config="{highlight: false}"
:height="340"
:loading="table1.loading"
:columns="table1.columns"
:dataSource="table1.dataSource"
:pagination="table1.pagination"
@pageChange="handleTable1PageChange"
@selectRowChange="handleTable1SelectRowChange"
/>
</a-col>
<!-- 这里是子级节点 -->
<a-col :span="12">
<j-vxe-table
toolbar
row-number
row-selection
click-select-row
highlight-current-row
:radio-config="{highlight: false}"
:checkbox-config="{highlight: false}"
:height="340"
:loading="table2.loading"
:columns="table2.columns"
:dataSource="table2.dataSource"
:pagination="table2.pagination"
@pageChange="handleTable2PageChange"
@selectRowChange="handleTable2SelectRowChange"
>
</j-vxe-table>
</a-col>
<!-- 这里是孙级节点 -->
<a-col :span="12">
<j-vxe-table
toolbar
row-number
row-selection
:height="340"
:loading="table3.loading"
:columns="table3.columns"
:dataSource="table3.dataSource"
:pagination="table3.pagination"
@pageChange="handleTable3PageChange"
>
</j-vxe-table>
</a-col>
</a-row>
</a-card>
</template>
<script>
import { getAction } from '@api/manage'
import { JVXETypes } from '@/components/jeecg/JVxeTable'
// 【多种布局模板】上面父、左下子、右下孙
export default {
name: 'Template1',
data() {
return {
table1: {
// 是否正在加载
loading: false,
// 分页器参数
pagination: {
// 当前页码
current: 1,
// 每页的条数
pageSize: 200,
// 可切换的条数
pageSizeOptions: ['10', '20', '30', '100', '200'],
// 数据总数目前并不知道真实的总数所以先填写0在后台查出来后再赋值
total: 0,
},
// 最后选中的行
lastRow: null,
// 选择的行
selectedRows: [],
// 数据源,控制表格的数据
dataSource: [],
// 列配置,控制表格显示的列
columns: [
{key: 'num', title: '序号', width: '80px'},
{
// 字段key跟后台数据的字段名匹配
key: 'ship_name',
// 列的标题
title: '船名',
// 列的宽度
width: '180px',
// 如果加上了该属性就代表当前单元格是可编辑的type就是表单的类型input就是简单的输入框
type: JVXETypes.input,
formatter({cellValue, row, column}) {
let foo = ''
if (row.company === '佧伒侾佯有限公司') {
foo += '-233'
}
return cellValue + foo
},
},
{key: 'call', title: '呼叫', width: '80px', type: JVXETypes.input},
{key: 'len', title: '长', width: '80px', type: JVXETypes.inputNumber},
{key: 'ton', title: '吨', width: '120px', type: JVXETypes.inputNumber},
{key: 'payer', title: '付款方', width: '120px', type: JVXETypes.input},
{key: 'count', title: '数', width: '40px'},
{
key: 'company',
title: '公司',
// 最小宽度,与宽度不同的是,这个不是固定的宽度,如果表格有多余的空间,会平均分配给设置了 minWidth 的列
// 如果要做占满表格的列可以这么写
minWidth: '180px',
type: JVXETypes.input
},
{key: 'trend', title: '动向', width: '120px', type: JVXETypes.input},
],
},
// 子级表的配置信息 (配置和主表的完全一致,就不写冗余的注释了)
table2: {
loading: false,
pagination: {current: 1, pageSize: 200, pageSizeOptions: ['100', '200'], total: 0},
// 最后选中的行
lastRow: null,
selectedRows: [],
dataSource: [],
columns: [
{key: 'dd_num', title: '调度序号', width: '120px'},
{key: 'tug', title: '拖轮', width: '180px', type: JVXETypes.input},
{key: 'work_start_time', title: '作业开始时间', width: '180px', type: JVXETypes.input},
{key: 'work_stop_time', title: '作业结束时间', width: '180px', type: JVXETypes.input},
{key: 'type', title: '船舶分类', width: '120px', type: JVXETypes.input},
{key: 'port_area', title: '所属港区', width: '120px', type: JVXETypes.input},
],
},
// 孙级表的配置信息 (配置和主表的完全一致,就不写冗余的注释了)
table3: {
loading: false,
pagination: {current: 1, pageSize: 200, pageSizeOptions: ['100', '200'], total: 0},
selectedRows: [],
dataSource: [],
columns: [
{key: 'dd_num', title: '调度序号', width: '120px'},
{key: 'tug', title: '拖轮', width: '120px', type: JVXETypes.input},
{key: 'power', title: '马力', width: '120px', type: JVXETypes.input},
{key: 'nature', title: '性质', width: '120px', type: JVXETypes.input},
{key: 'departure_time', title: '发船时间', width: '180px', type: JVXETypes.input},
],
},
// 查询url地址
url: {
getData: '/mock/vxe/getData',
},
}
},
// 监听器
watch: {
// 监听table1 【主表】选择的数据发生了变化
['table1.lastRow'](row) {
this.loadTable2Data()
},
// 监听table2 【子表】选择的数据发生了变化
['table2.lastRow']() {
this.loadTable3Data()
},
},
created() {
this.loadTable1Data()
},
methods: {
// 加载table1【主表】的数据
loadTable1Data() {
// 封装查询条件
let formData = {
pageNo: this.table1.pagination.current,
pageSize: this.table1.pagination.pageSize
}
// 调用查询数据接口
this.table1.loading = true
getAction(this.url.getData, formData).then(res => {
if (res.success) {
// 后台查询回来的 total数据总数量
this.table1.pagination.total = res.result.total
// 将查询的数据赋值给 dataSource
this.table1.dataSource = res.result.records
// 重置选择
this.table1.selectedRows = []
} else {
this.$error({title: '主表查询失败', content: res.message})
}
}).finally(() => {
// 这里是无论成功或失败都会执行的方法在这里关闭loading
this.table1.loading = false
})
},
// 当table1【主表】分页参数变化时触发的事件
handleTable1PageChange(event) {
// 重新赋值
this.table1.pagination.current = event.current
this.table1.pagination.pageSize = event.pageSize
// 查询数据
this.loadTable1Data()
},
// table1【主表】当选择的行变化时触发的事件
handleTable1SelectRowChange(event) {
this.handleTableSelectRowChange(this.table1, event)
},
// 加载table2【子表】的数据根据主表的id进行查询
loadTable2Data() {
// 如果主表没有选择,则不查询
let selectedRows = this.table1.selectedRows
if (!selectedRows || selectedRows.length === 0) {
this.table2.pagination.total = 0
this.table2.dataSource = []
this.table2.selectedRows = []
return
} else if (this.table1.lastRow == null) {
this.table1.lastRow = selectedRows[selectedRows.length - 1]
}
let formData = {
parentId: this.table1.lastRow.id,
pageNo: this.table2.pagination.current,
pageSize: this.table2.pagination.pageSize
}
this.table2.loading = true
getAction(this.url.getData, formData).then(res => {
if (res.success) {
this.table2.pagination.total = res.result.total
this.table2.dataSource = res.result.records
this.table2.selectedRows = []
} else {
this.$error({title: '子表查询失败', content: res.message})
}
}).finally(() => {
this.table2.loading = false
})
},
// table2【子表】当选择的行变化时触发的事件
handleTable2SelectRowChange(event) {
this.handleTableSelectRowChange(this.table2, event)
},
// 当table2【子表】分页参数变化时触发的事件
handleTable2PageChange(event) {
// 重新赋值
this.table2.pagination.current = event.current
this.table2.pagination.pageSize = event.pageSize
// 查询数据
this.loadTable2Data()
},
// 加载table3【孙表】的数据根据子表的id进行查询
loadTable3Data() {
// 如果主表没有选择,则不查询
let selectedRows = this.table2.selectedRows
if (!selectedRows || selectedRows.length === 0) {
this.table3.pagination.total = 0
this.table3.dataSource = []
this.table3.selectedRows = []
return
} else if (this.table2.lastRow == null) {
this.table2.lastRow = selectedRows[selectedRows.length - 1]
}
let formData = {
parentId: this.table2.lastRow.id,
pageNo: this.table3.pagination.current,
pageSize: this.table3.pagination.pageSize
}
this.table3.loading = true
getAction(this.url.getData, formData).then(res => {
if (res.success) {
this.table3.pagination.total = res.result.total
this.table3.dataSource = res.result.records
} else {
this.$error({title: '子表查询失败', content: res.message})
}
}).finally(() => {
this.table3.loading = false
})
},
// 当table3【孙表】分页参数变化时触发的事件
handleTable3PageChange(event) {
// 重新赋值
this.table3.pagination.current = event.current
this.table3.pagination.pageSize = event.pageSize
// 查询数据
this.loadTable3Data()
},
/** 公共方法:处理表格选中变化事件 */
handleTableSelectRowChange(table, event) {
let {row, action, selectedRows, $table} = event
// 获取最后一个选中的
let lastSelected = selectedRows[selectedRows.length - 1]
if (action === 'selected') {
table.lastRow = row
} else if (action === 'selected-all') {
// 取消全选
if (selectedRows.length === 0) {
table.lastRow = null
} else if (!table.lastRow) {
table.lastRow = lastSelected
}
} else if (action === 'unselected' && row === table.lastRow) {
table.lastRow = lastSelected
}
$table.setCurrentRow(table.lastRow)
table.selectedRows = selectedRows
},
}
}
</script>
<style lang="less">
</style>

View File

@ -0,0 +1,260 @@
<template>
<a-card :bordered="false">
<a-row :gutter="8">
<!-- 左侧父 -->
<a-col :span="12">
<j-vxe-table
toolbar
row-number
row-selection
click-select-row
highlight-current-row
:radio-config="{highlight: false}"
:checkbox-config="{highlight: false}"
:height="790"
:loading="table1.loading"
:columns="table1.columns"
:dataSource="table1.dataSource"
:pagination="table1.pagination"
@pageChange="handleTable1PageChange"
@selectRowChange="handleTable1SelectRowChange"
/>
</a-col>
<a-col :span="12">
<!-- 左侧选择的数据展示在这里 -->
<j-vxe-table
row-number
:height="381"
:columns="table1.columns"
:dataSource="table1.selectedRows"
style="margin: 40px 0 8px;"
/>
<!-- 右下子 -->
<j-vxe-table
toolbar
row-number
row-selection
click-select-row
:height="361"
:loading="table2.loading"
:columns="table2.columns"
:dataSource="table2.dataSource"
:pagination="table2.pagination"
@pageChange="handleTable2PageChange"
@selectRowChange="handleTable2SelectRowChange"
/>
</a-col>
</a-row>
</a-card>
</template>
<script>
import { getAction } from '@api/manage'
import { JVXETypes } from '@/components/jeecg/JVxeTable'
// 【多种布局模板】 左边选择后,记录选到右侧,右侧是父、子
export default {
name: 'Template2',
data() {
return {
table1: {
// 是否正在加载
loading: false,
// 分页器参数
pagination: {
// 当前页码
current: 1,
// 每页的条数
pageSize: 200,
// 可切换的条数
pageSizeOptions: ['10', '20', '30', '100', '200'],
// 数据总数目前并不知道真实的总数所以先填写0在后台查出来后再赋值
total: 0,
},
// 最后选中的行
lastRow: null,
// 选择的行
selectedRows: [],
// 数据源,控制表格的数据
dataSource: [],
// 列配置,控制表格显示的列
columns: [
{key: 'num', title: '序号', width: '80px'},
{
// 字段key跟后台数据的字段名匹配
key: 'ship_name',
// 列的标题
title: '船名',
// 列的宽度
width: '180px',
// 如果加上了该属性就代表当前单元格是可编辑的type就是表单的类型input就是简单的输入框
type: JVXETypes.input
},
{key: 'call', title: '呼叫', width: '80px', type: JVXETypes.input},
{key: 'len', title: '长', width: '80px', type: JVXETypes.input},
{key: 'ton', title: '吨', width: '120px', type: JVXETypes.input},
{key: 'payer', title: '付款方', width: '120px', type: JVXETypes.input},
{key: 'count', title: '数', width: '40px'},
{
key: 'company',
title: '公司',
// 最小宽度,与宽度不同的是,这个不是固定的宽度,如果表格有多余的空间,会平均分配给设置了 minWidth 的列
// 如果要做占满表格的列可以这么写
minWidth: '180px',
type: JVXETypes.input
},
{key: 'trend', title: '动向', width: '120px', type: JVXETypes.input},
],
},
// 子级表的配置信息 (配置和主表的完全一致,就不写冗余的注释了)
table2: {
loading: false,
pagination: {current: 1, pageSize: 200, pageSizeOptions: ['100', '200'], total: 0},
selectedRows: [],
dataSource: [],
columns: [
{key: 'dd_num', title: '调度序号', width: '120px'},
{key: 'tug', title: '拖轮', width: '180px', type: JVXETypes.input},
{key: 'work_start_time', title: '作业开始时间', width: '180px', type: JVXETypes.input},
{key: 'work_stop_time', title: '作业结束时间', width: '180px', type: JVXETypes.input},
{key: 'type', title: '船舶分类', width: '120px', type: JVXETypes.input},
{key: 'port_area', title: '所属港区', width: '120px', type: JVXETypes.input},
],
},
// 查询url地址
url: {
getData: '/mock/vxe/getData',
},
}
},
// 监听器
watch: {
// 监听table1 【主表】选择的数据发生了变化
['table1.lastRow']() {
this.loadTable2Data()
},
},
created() {
this.loadTable1Data()
},
methods: {
// 加载table1【主表】的数据
loadTable1Data() {
// 封装查询条件
let formData = {
pageNo: this.table1.pagination.current,
pageSize: this.table1.pagination.pageSize
}
// 调用查询数据接口
this.table1.loading = true
getAction(this.url.getData, formData).then(res => {
if (res.success) {
// 后台查询回来的 total数据总数量
this.table1.pagination.total = res.result.total
// 将查询的数据赋值给 dataSource
this.table1.dataSource = res.result.records
// 重置选择
this.table1.selectedRows = []
} else {
this.$error({title: '主表查询失败', content: res.message})
}
}).finally(() => {
// 这里是无论成功或失败都会执行的方法在这里关闭loading
this.table1.loading = false
})
},
// 加载table2【子表】的数据根据主表的id进行查询
loadTable2Data() {
// 如果主表没有选择,则不查询
let selectedRows = this.table1.selectedRows
if (!selectedRows || selectedRows.length === 0) {
this.table2.pagination.total = 0
this.table2.dataSource = []
this.table2.selectedRows = []
return
} else if (this.table1.lastRow == null) {
this.table1.lastRow = selectedRows[selectedRows.length - 1]
}
let formData = {
parentId: this.table1.lastRow.id,
pageNo: this.table2.pagination.current,
pageSize: this.table2.pagination.pageSize
}
this.table2.loading = true
getAction(this.url.getData, formData).then(res => {
if (res.success) {
this.table2.pagination.total = res.result.total
this.table2.dataSource = res.result.records
this.table2.selectedRows = []
} else {
this.$error({title: '子表查询失败', content: res.message})
}
}).finally(() => {
this.table2.loading = false
})
},
// table1【主表】当选择的行变化时触发的事件
handleTable1SelectRowChange(event) {
this.handleTableSelectRowChange(this.table1, event)
},
// table2【子表】当选择的行变化时触发的事件
handleTable2SelectRowChange(event) {
this.table2.selectedRows = event.selectedRows
},
// 当table1【主表】分页参数变化时触发的事件
handleTable1PageChange(event) {
// 重新赋值
this.table1.pagination.current = event.current
this.table1.pagination.pageSize = event.pageSize
// 查询数据
this.loadTable1Data()
},
// 当table2【子表】分页参数变化时触发的事件
handleTable2PageChange(event) {
// 重新赋值
this.table2.pagination.current = event.current
this.table2.pagination.pageSize = event.pageSize
// 查询数据
this.loadTable2Data()
},
/** 公共方法:处理表格选中变化事件 */
handleTableSelectRowChange(table, event) {
let {row, action, selectedRows, $table} = event
// 获取最后一个选中的
let lastSelected = selectedRows[selectedRows.length - 1]
if (action === 'selected') {
table.lastRow = row
} else if (action === 'selected-all') {
// 取消全选
if (selectedRows.length === 0) {
table.lastRow = null
} else if (!table.lastRow) {
table.lastRow = lastSelected
}
} else if (action === 'unselected' && row === table.lastRow) {
table.lastRow = lastSelected
}
$table.setCurrentRow(table.lastRow)
table.selectedRows = selectedRows
},
}
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,245 @@
<template>
<a-card :bordered="false">
<a-row :gutter="8">
<a-col :span="12">
<!-- 左上父 -->
<j-vxe-table
toolbar
row-number
row-selection
click-select-row
highlight-current-row
:radio-config="{highlight: false}"
:checkbox-config="{highlight: false}"
:height="357"
:loading="table1.loading"
:columns="table1.columns"
:dataSource="table1.dataSource"
:pagination="table1.pagination"
style="margin-bottom: 8px;"
@pageChange="handleTable1PageChange"
@selectRowChange="handleTable1SelectRowChange"
/>
<!-- 左下子 -->
<j-vxe-table
toolbar
row-number
row-selection
click-select-row
:height="356"
:loading="table2.loading"
:columns="table2.columns"
:dataSource="table2.dataSource"
:pagination="table2.pagination"
@pageChange="handleTable2PageChange"
/>
</a-col>
<!-- 左侧父选择的数据展示在这里 -->
<a-col :span="12">
<j-vxe-table
row-number
:height="800"
:columns="table1.columns"
:dataSource="table1.selectedRows"
style="margin-top: 40px;"
/>
</a-col>
</a-row>
</a-card>
</template>
<script>
import { getAction } from '@api/manage'
import { JVXETypes } from '@/components/jeecg/JVxeTable'
// 【多种布局模板】左侧上边是主表、下边是子表,右侧是选中数据
export default {
name: 'Template3',
components: {},
data() {
return {
// 主表的配置信息
table1: {
// 是否正在加载
loading: false,
// 分页器参数
pagination: {
// 当前页码
current: 1,
// 每页的条数
pageSize: 200,
// 可切换的条数
pageSizeOptions: ['10', '20', '30', '100', '200'],
// 数据总数目前并不知道真实的总数所以先填写0在后台查出来后再赋值
total: 0,
},
// 最后选中的行
lastRow: null,
// 选择的行
selectedRows: [],
// 数据源,控制表格的数据
dataSource: [],
// 列配置,控制表格显示的列
columns: [
{key: 'num', title: '序号', width: '80px'},
{
// 字段key跟后台数据的字段名匹配
key: 'ship_name',
// 列的标题
title: '船名',
// 列的宽度
width: '180px',
// 如果加上了该属性就代表当前单元格是可编辑的type就是表单的类型input就是简单的输入框
type: JVXETypes.input
},
{key: 'call', title: '呼叫', width: '80px', type: JVXETypes.input},
{key: 'len', title: '长', width: '80px', type: JVXETypes.input},
{key: 'ton', title: '吨', width: '120px', type: JVXETypes.input},
{key: 'payer', title: '付款方', width: '120px', type: JVXETypes.input},
{key: 'count', title: '数', width: '40px'},
{key: 'company', title: '公司', width: '180px', type: JVXETypes.input},
{key: 'trend', title: '动向', width: '120px', type: JVXETypes.input},
],
},
// 子表的配置信息 (配置和主表的完全一致,就不写冗余的注释了)
table2: {
loading: false,
pagination: {current: 1, pageSize: 200, pageSizeOptions: ['100', '200'], total: 0},
dataSource: [],
columns: [
{key: 'dd_num', title: '调度序号', width: '120px'},
{key: 'tug', title: '拖轮', width: '180px', type: JVXETypes.input},
{key: 'work_start_time', title: '作业开始时间', width: '180px', type: JVXETypes.input},
{key: 'work_stop_time', title: '作业结束时间', width: '180px', type: JVXETypes.input},
{key: 'type', title: '船舶分类', width: '120px', type: JVXETypes.input},
{key: 'port_area', title: '所属港区', width: '120px', type: JVXETypes.input},
],
},
// 查询url地址
url: {
getData: '/mock/vxe/getData',
},
}
},
// 监听器
watch: {
// 监听table1 【主表】选择的数据发生了变化
['table1.lastRow'](row) {
this.loadTable2Data()
},
},
created() {
this.loadTable1Data()
},
methods: {
// 加载table1主表的数据
loadTable1Data() {
// 封装查询条件
let formData = {
pageNo: this.table1.pagination.current,
pageSize: this.table1.pagination.pageSize
}
// 调用查询数据接口
this.table1.loading = true
getAction(this.url.getData, formData).then(res => {
if (res.success) {
// 后台查询回来的 total数据总数量
this.table1.pagination.total = res.result.total
// 将查询的数据赋值给 dataSource
this.table1.dataSource = res.result.records
} else {
this.$error({title: '主表查询失败', content: res.message})
}
}).finally(() => {
// 这里是无论成功或失败都会执行的方法在这里关闭loading
this.table1.loading = false
})
},
// 加载table2子表的数据根据主表的id进行查询
loadTable2Data() {
// 如果主表没有选择,则不查询
let selectedRows = this.table1.selectedRows
if (!selectedRows || selectedRows.length === 0) {
this.table2.pagination.total = 0
this.table2.dataSource = []
return
} else if (this.table1.lastRow == null) {
this.table1.lastRow = selectedRows[selectedRows.length - 1]
}
let formData = {
parentId: this.table1.lastRow.id,
pageNo: this.table2.pagination.current,
pageSize: this.table2.pagination.pageSize
}
this.table2.loading = true
getAction(this.url.getData, formData).then(res => {
if (res.success) {
this.table2.pagination.total = res.result.total
this.table2.dataSource = res.result.records
} else {
this.$error({title: '子表查询失败', content: res.message})
}
}).finally(() => {
this.table2.loading = false
})
},
// table1【主表】当分页参数变化时触发的事件
handleTable1PageChange(event) {
// 重新赋值
this.table1.pagination.current = event.current
this.table1.pagination.pageSize = event.pageSize
// 查询数据
this.loadTable1Data()
// 分页后重置选择
this.table1.selectedRows = []
this.loadTable2Data()
},
// table2【子表】当分页参数变化时触发的事件
handleTable2PageChange(event) {
// 重新赋值
this.table1.pagination.current = event.current
this.table1.pagination.pageSize = event.pageSize
// 查询数据
this.loadTable2Data()
},
// table1【主表】当选择的行变化时触发的事件
handleTable1SelectRowChange(event) {
this.handleTableSelectRowChange(this.table1, event)
},
/** 公共方法:处理表格选中变化事件 */
handleTableSelectRowChange(table, event) {
let {row, action, selectedRows, $table} = event
// 获取最后一个选中的
let lastSelected = selectedRows[selectedRows.length - 1]
if (action === 'selected') {
table.lastRow = row
} else if (action === 'selected-all') {
// 取消全选
if (selectedRows.length === 0) {
table.lastRow = null
} else if (!table.lastRow) {
table.lastRow = lastSelected
}
} else if (action === 'unselected' && row === table.lastRow) {
table.lastRow = lastSelected
}
$table.setCurrentRow(table.lastRow)
table.selectedRows = selectedRows
},
},
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,347 @@
<template>
<a-card :bordered="false">
<a-row :gutter="8">
<a-col :span="12">
<!-- 左上父 -->
<j-vxe-table
toolbar
row-number
row-selection
click-select-row
highlight-current-row
:radio-config="{highlight: false}"
:checkbox-config="{highlight: false}"
:height="340"
:loading="table1.loading"
:columns="table1.columns"
:dataSource="table1.dataSource"
:pagination="table1.pagination"
style="margin-bottom: 8px;"
@pageChange="handleTable1PageChange"
@selectRowChange="handleTable1SelectRowChange"
/>
<!-- 左下子 -->
<j-vxe-table
toolbar
row-number
row-selection
click-select-row
:height="350"
:loading="table2.loading"
:columns="table2.columns"
:dataSource="table2.dataSource"
:pagination="table2.pagination"
@pageChange="handleTable2PageChange"
/>
</a-col>
<!-- 左侧父选择的数据展示在这里 -->
<a-col :span="12">
<!-- 右上父 -->
<j-vxe-table
row-number
row-selection
click-select-row
highlight-current-row
:radio-config="{highlight: false}"
:checkbox-config="{highlight: false}"
:height="340"
:columns="table1.columns"
:dataSource="table1.selectedRows"
style="margin: 40px 0 8px;"
@selectRowChange="handleTable3SelectRowChange"
/>
<!-- 右下子 -->
<j-vxe-table
toolbar
row-number
row-selection
click-select-row
:height="350"
:loading="table4.loading"
:columns="table4.columns"
:dataSource="table4.dataSource"
:pagination="table4.pagination"
style="margin: 48px 0 0;"
/>
</a-col>
</a-row>
</a-card>
</template>
<script>
import { getAction } from '@api/manage'
import { JVXETypes } from '@/components/jeecg/JVxeTable'
export default {
name: 'Template4',
data() {
return {
table1: {
// 是否正在加载
loading: false,
// 分页器参数
pagination: {
// 当前页码
current: 1,
// 每页的条数
pageSize: 200,
// 可切换的条数
pageSizeOptions: ['10', '20', '30', '100', '200'],
// 数据总数目前并不知道真实的总数所以先填写0在后台查出来后再赋值
total: 0,
},
// 最后选中的行
lastRow: null,
// 选择的行
selectedRows: [],
// 数据源,控制表格的数据
dataSource: [],
// 列配置,控制表格显示的列
columns: [
{key: 'num', title: '序号', width: '80px'},
{
// 字段key跟后台数据的字段名匹配
key: 'ship_name',
// 列的标题
title: '船名',
// 列的宽度
width: '180px',
// 如果加上了该属性就代表当前单元格是可编辑的type就是表单的类型input就是简单的输入框
type: JVXETypes.input
},
{key: 'call', title: '呼叫', width: '80px', type: JVXETypes.input},
{key: 'len', title: '长', width: '80px', type: JVXETypes.input},
{key: 'ton', title: '吨', width: '120px', type: JVXETypes.input},
{key: 'payer', title: '付款方', width: '120px', type: JVXETypes.input},
{key: 'count', title: '数', width: '40px'},
{
key: 'company',
title: '公司',
// 最小宽度,与宽度不同的是,这个不是固定的宽度,如果表格有多余的空间,会平均分配给设置了 minWidth 的列
// 如果要做占满表格的列可以这么写
minWidth: '180px',
type: JVXETypes.input
},
{key: 'trend', title: '动向', width: '120px', type: JVXETypes.input},
],
},
// 子级表的配置信息 (配置和主表的完全一致,就不写冗余的注释了)
table2: {
loading: false,
pagination: {current: 1, pageSize: 200, pageSizeOptions: ['100', '200'], total: 0},
selectedRows: [],
dataSource: [],
columns: [
{key: 'dd_num', title: '调度序号', width: '120px'},
{key: 'tug', title: '拖轮', width: '180px', type: JVXETypes.input},
{key: 'work_start_time', title: '作业开始时间', width: '180px', type: JVXETypes.input},
{key: 'work_stop_time', title: '作业结束时间', width: '180px', type: JVXETypes.input},
{key: 'type', title: '船舶分类', width: '120px', type: JVXETypes.input},
{key: 'port_area', title: '所属港区', width: '120px', type: JVXETypes.input},
],
},
table3: {
// 最后选中的行
lastRow: null,
// 选择的行
selectedRows: [],
},
table4: {
loading: false,
pagination: {current: 1, pageSize: 200, pageSizeOptions: ['100', '200'], total: 0},
selectedRows: [],
dataSource: [],
columns: [
{key: 'dd_num', title: '调度序号', width: '120px'},
{key: 'tug', title: '拖轮', width: '180px', type: JVXETypes.input},
{key: 'work_start_time', title: '作业开始时间', width: '180px', type: JVXETypes.input},
{key: 'work_stop_time', title: '作业结束时间', width: '180px', type: JVXETypes.input},
{key: 'type', title: '船舶分类', width: '120px', type: JVXETypes.input},
{key: 'port_area', title: '所属港区', width: '120px', type: JVXETypes.input},
],
},
// 查询url地址
url: {
getData: '/mock/vxe/getData',
},
}
},
// 监听器
watch: {
// 监听table1 左上【主表】选择的数据发生了变化
['table1.lastRow']() {
this.loadTable2Data()
},
// 监听table3 右上【主表】选择的数据发生了变化
['table3.lastRow']() {
this.loadTable4Data()
},
},
created() {
this.loadTable1Data()
},
methods: {
// 加载table1左上【主表】的数据
loadTable1Data() {
// 封装查询条件
let formData = {
pageNo: this.table1.pagination.current,
pageSize: this.table1.pagination.pageSize
}
// 调用查询数据接口
this.table1.loading = true
getAction(this.url.getData, formData).then(res => {
if (res.success) {
// 后台查询回来的 total数据总数量
this.table1.pagination.total = res.result.total
// 将查询的数据赋值给 dataSource
this.table1.dataSource = res.result.records
// 重置选择
this.table1.selectedRows = []
} else {
this.$error({title: '主表查询失败', content: res.message})
}
}).finally(() => {
// 这里是无论成功或失败都会执行的方法在这里关闭loading
this.table1.loading = false
})
},
// 当table1左上【主表】分页参数变化时触发的事件
handleTable1PageChange(event) {
// 重新赋值
this.table1.pagination.current = event.current
this.table1.pagination.pageSize = event.pageSize
// 查询数据
this.loadTable1Data()
},
// table1左上【主表】当选择的行变化时触发的事件
handleTable1SelectRowChange(event) {
this.handleTableSelectRowChange(this.table1, event)
},
// 加载table2左下【子表】的数据根据主表的id进行查询
loadTable2Data() {
// 如果主表没有选择,则不查询
let selectedRows = this.table1.selectedRows
if (!selectedRows || selectedRows.length === 0) {
this.table2.pagination.total = 0
this.table2.dataSource = []
this.table2.selectedRows = []
return
} else if (this.table1.lastRow == null) {
this.table1.lastRow = selectedRows[selectedRows.length - 1]
}
let formData = {
parentId: this.table1.lastRow.id,
pageNo: this.table2.pagination.current,
pageSize: this.table2.pagination.pageSize
}
this.table2.loading = true
getAction(this.url.getData, formData).then(res => {
if (res.success) {
this.table2.pagination.total = res.result.total
this.table2.dataSource = res.result.records
this.table2.selectedRows = []
} else {
this.$error({title: '子表查询失败', content: res.message})
}
}).finally(() => {
this.table2.loading = false
})
},
// 当table2左下【子表】分页参数变化时触发的事件
handleTable2PageChange(event) {
// 重新赋值
this.table2.pagination.current = event.current
this.table2.pagination.pageSize = event.pageSize
// 查询数据
this.loadTable2Data()
},
// table3右上【主表】当选择的行变化时触发的事件
handleTable3SelectRowChange(event) {
this.handleTableSelectRowChange(this.table3, event)
},
// 加载table4右下【子表】的数据根据主表的id进行查询
loadTable4Data() {
let parentIds = []
// 如果主表没有选择,则不查询
let selectedRows = this.table3.selectedRows
if (!selectedRows || selectedRows.length === 0) {
this.table4.pagination.total = 0
this.table4.dataSource = []
this.table4.selectedRows = []
return
} else if (this.table3.lastRow == null) {
this.table3.lastRow = selectedRows[selectedRows.length - 1]
}
let formData = {
parentId: this.table3.lastRow.id,
pageNo: this.table4.pagination.current,
pageSize: this.table4.pagination.pageSize
}
this.table4.loading = true
getAction(this.url.getData, formData).then(res => {
if (res.success) {
this.table4.pagination.total = res.result.total
this.table4.dataSource = res.result.records
this.table4.selectedRows = []
} else {
this.$error({title: '子表查询失败', content: res.message})
}
}).finally(() => {
this.table4.loading = false
})
},
// 当table4右下【子表】分页参数变化时触发的事件
handleTable4PageChange(event) {
// 重新赋值
this.table4.pagination.current = event.current
this.table4.pagination.pageSize = event.pageSize
// 查询数据
this.loadTable4Data()
},
/** 公共方法:处理表格选中变化事件 */
handleTableSelectRowChange(table, event) {
let {row, action, selectedRows, $table} = event
// 获取最后一个选中的
let lastSelected = selectedRows[selectedRows.length - 1]
if (action === 'selected') {
table.lastRow = row
} else if (action === 'selected-all') {
// 取消全选
if (selectedRows.length === 0) {
table.lastRow = null
} else if (!table.lastRow) {
table.lastRow = lastSelected
}
} else if (action === 'unselected' && row === table.lastRow) {
table.lastRow = lastSelected
}
$table.setCurrentRow(table.lastRow)
table.selectedRows = selectedRows
},
}
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,224 @@
<template>
<a-card :bordered="false">
<a-row :gutter="8">
<a-col :span="6">
<!-- 加上 show-line 属性后展开收起图标自动变成 +- 样式 -->
<a-tree
class="template-5-tree"
:tree-data="treeData"
show-icon
show-line
:expandedKeys="treeExpandedKeys"
:selectedKeys="[pagination.current]"
@expand="handleTreeExpand"
@select="handleTreeSelect"
>
<!-- 自定义子节点图标 -->
<a-icon slot="myIcon" type="unordered-list" style="color:#0c8fcf;"/>
</a-tree>
</a-col>
<a-col :span="18">
<j-vxe-table
row-number
row-selection
:height="750"
:loading="loading"
:columns="columns"
:dataSource="dataSource"
:pagination="pagination"
@pageChange="handleTablePageChange"
/>
</a-col>
</a-row>
</a-card>
</template>
<script>
import { getAction } from '@api/manage'
import { JVXETypes } from '@/components/jeecg/JVxeTable'
// 【多种布局模板】左侧为树,右侧为行编辑
export default {
name: 'Template5',
data() {
return {
// 是否正在加载
loading: false,
// 分页器参数
pagination: {
// 当前页码
current: 1,
// 每页的条数
pageSize: 50,
// 可切换的条数
pageSizeOptions: ['50'],
// 数据总数目前并不知道真实的总数所以先填写0在后台查出来后再赋值
total: 0,
},
// 选择的行
selectedRows: [],
// 数据源,控制表格的数据
dataSource: [],
// 列配置,控制表格显示的列
columns: [
{key: 'num', title: '序号', width: '80px'},
{
// 字段key跟后台数据的字段名匹配
key: 'ship_name',
// 列的标题
title: '船名',
// 列的宽度
width: '180px',
// 如果加上了该属性就代表当前单元格是可编辑的type就是表单的类型input就是简单的输入框
type: JVXETypes.input
},
{key: 'call', title: '呼叫', width: '80px', type: JVXETypes.input},
{key: 'len', title: '长', width: '80px', type: JVXETypes.input},
{key: 'ton', title: '吨', width: '120px', type: JVXETypes.input},
{key: 'payer', title: '付款方', width: '120px', type: JVXETypes.input},
{key: 'count', title: '数', width: '40px'},
{
key: 'company',
title: '公司',
// 最小宽度,与宽度不同的是,这个不是固定的宽度,如果表格有多余的空间,会平均分配给设置了 minWidth 的列
// 如果要做占满表格的列可以这么写
minWidth: '180px',
type: JVXETypes.input
},
{key: 'trend', title: '动向', width: '120px', type: JVXETypes.input},
],
// 树的数据,这里模拟分页固定数据,实际情况应该是后台查出来的数据
treeData: [
// 第1级数据
{
title: '1-10页',
key: '1-10',
// 第2级数据
children: [
{title: '第 1 页', key: 1, slots: {icon: 'myIcon'}},
{title: '第 2 页', key: 2, slots: {icon: 'myIcon'}},
{
title: '第 3 页',
key: 3,
slots: {icon: 'myIcon'},
// 第3级数据
children: [
{title: '第 333 页', key: 333, slots: {icon: 'myIcon'}},
{title: '第 444 页', key: 444, slots: {icon: 'myIcon'}},
{title: '第 555 页', key: 555, slots: {icon: 'myIcon'}},
// 第4第5级以此类推加上 children 属性即可
],
},
{title: '第 4 页', key: 4, slots: {icon: 'myIcon'}},
{title: '第 5 页', key: 5, slots: {icon: 'myIcon'}},
{title: '第 6 页', key: 6, slots: {icon: 'myIcon'}},
{title: '第 7 页', key: 7, slots: {icon: 'myIcon'}},
{title: '第 8 页', key: 8, slots: {icon: 'myIcon'}},
{title: '第 9 页', key: 9, slots: {icon: 'myIcon'}},
{title: '第 10 页', key: 10, slots: {icon: 'myIcon'}},
],
slots: {icon: 'myIcon'},
},
{
title: '11-20页',
key: '11-20',
children: [
{title: '第 11 页', key: 11, slots: {icon: 'myIcon'}},
{title: '第 12 页', key: 12, slots: {icon: 'myIcon'}},
{title: '第 13 页', key: 13, slots: {icon: 'myIcon'}},
{title: '第 14 页', key: 14, slots: {icon: 'myIcon'}},
{title: '第 15 页', key: 15, slots: {icon: 'myIcon'}},
{title: '第 16 页', key: 16, slots: {icon: 'myIcon'}},
{title: '第 17 页', key: 17, slots: {icon: 'myIcon'}},
{title: '第 18 页', key: 18, slots: {icon: 'myIcon'}},
{title: '第 19 页', key: 19, slots: {icon: 'myIcon'}},
{title: '第 20 页', key: 20, slots: {icon: 'myIcon'}},
],
slots: {icon: 'myIcon'},
},
],
// 树展开的列,默认 1-10
treeExpandedKeys: ['1-10'],
// 查询url地址
url: {
getData: '/mock/vxe/getData',
},
}
},
created() {
this.loadData()
},
methods: {
// 加载行编辑的数据
loadData() {
// 封装查询条件
let formData = {
pageNo: this.pagination.current,
pageSize: this.pagination.pageSize
}
// 调用查询数据接口
this.loading = true
getAction(this.url.getData, formData).then(res => {
if (res.success) {
// 后台查询回来的 total数据总数量
this.pagination.total = res.result.total
// 将查询的数据赋值给 dataSource
this.dataSource = res.result.records
// 重置选择
this.selectedRows = []
} else {
this.$error({title: '主表查询失败', content: res.message})
}
}).finally(() => {
// 这里是无论成功或失败都会执行的方法在这里关闭loading
this.loading = false
})
},
handleTablePageChange(event) {
// 重新赋值
this.pagination.current = event.current
this.pagination.pageSize = event.pageSize
// 查询数据
this.loadData()
// 判断树展开的key
if (event.current <= 10) {
this.treeExpandedKeys = ['1-10']
} else {
this.treeExpandedKeys = ['11-20']
}
},
// 树被选择触发的事件
handleTreeSelect(selectedKeys) {
let key = selectedKeys[0]
if (typeof key === 'string') {
// 控制树展开为当前选择的列
this.treeExpandedKeys = selectedKeys
} else {
this.pagination.current = key
this.loadData()
}
},
// 树被选择触发的事件
handleTreeExpand(expandedKeys) {
this.treeExpandedKeys = expandedKeys
},
},
}
</script>
<style lang="less">
/** 隐藏文件小图标 */
.template-5-tree.ant-tree {
li span.ant-tree-switcher.ant-tree-switcher-noop {
display: none;
}
}
</style>

View File

@ -81,10 +81,10 @@
<a-row :gutter="24">
<a-col :span="12">
<a-form-item label="选择部门 自定义返回值">
<j-select-depart v-decorator="['departId']" :trigger-change="true" customReturnField="departName"></j-select-depart>
<j-select-depart v-model="orgCodes" :trigger-change="true" customReturnField="orgCode" :multi="true"></j-select-depart>
</a-form-item>
</a-col>
<a-col :span="12">选中的部门ID(v-decorator):{{ getDepartIdValue() }}</a-col>
<a-col :span="12">选中的部门Code(v-decorator):{{ orgCodes }}</a-col>
</a-row>
<a-row :gutter="24">
@ -110,7 +110,7 @@
<a-row :gutter="24">
<a-col :span="12">
<a-form-item label="选择用户">
<j-select-multi-user v-model="multiUser" ></j-select-multi-user>
<j-select-multi-user v-model="multiUser" :query-config="selectUserQueryConfig"/>
</a-form-item>
</a-col>
<a-col :span="12">选中的用户(v-model):{{ multiUser }}</a-col>
@ -285,7 +285,7 @@
<a-row :gutter="24">
<a-col :span="12">
<a-form-item label="分类字典树">
<j-category-select v-model="formData.selectCategory" pcode="A01"/>
<j-category-select v-model="formData.selectCategory" pcode="A01" :multiple="true"/>
</a-form-item>
</a-col>
<a-col :span="12">选中的值(v-model){{ formData.selectCategory }}</a-col>
@ -419,7 +419,7 @@
<a-row :gutter="24">
<a-col :span="12">
<a-form-item label="JPopup示例">
<j-popup v-model="formData.jPopup" code="demo" field="name" orgFields="name" destFields="name"/>
<j-popup v-model="formData.jPopup" code="demo" field="name" orgFields="name" destFields="name" :multi="true"/>
</a-form-item>
</a-col>
<a-col :span="12">选择的值(v-model){{ formData.jPopup }}</a-col>
@ -492,7 +492,8 @@
sex: 1
},
form: this.$form.createForm(this),
departId: '4f1765520d6346f9bd9c79e2479e5b12,57197590443c44f083d42ae24ef26a2c',
departId: '57197590443c44f083d42ae24ef26a2c,a7d7e77e06c84325a40932163adcdaa6',
orgCodes: 'A02A01,A02A02',
userIds: 'admin',
multiUser: 'admin,jeecg',
jcheckbox: {
@ -577,6 +578,10 @@ sayHi('hello, world!')`
value:"3"
}],
// 选择用户查询条件配置
selectUserQueryConfig: [
{key: 'phone', label: '电话'},
],
}
},
computed: {
@ -595,6 +600,9 @@ sayHi('hello, world!')`
getDepartIdValue() {
return this.form.getFieldValue('departId')
},
getOrgCodesValue() {
return this.form.getFieldValue('orgCodes')
},
changeMe() {
console.log('you so ... , change Me')
},

View File

@ -1,11 +1,12 @@
<template>
<a-card :bordered="false">
<a-table
rowKey="id"
rowKey="rowIndex"
bordered
:columns="columns"
:dataSource="dataSource"
:pagination="false"
:pagination="ipagination"
@change="handleTableChange"
>
</a-table>
</a-card>
@ -43,21 +44,49 @@
dataIndex: 'updateTime',
},
],
/* 分页参数 */
ipagination:{
current: 1,
pageSize: 10,
pageSizeOptions: ['10', '20', '30'],
showTotal: (total, range) => {
return range[0] + "-" + range[1] + "" + total + ""
},
showQuickJumper: true,
showSizeChanger: true,
total: 0
},
dataSource: [
{ name: '张三', point: 23, level: 3, updateTime: '2019-8-14' },
{ id:"1",name: '张三', point: 23, level: 3, updateTime: '2019-8-14' },
{ name: '小王', point: 6, level: 1, updateTime: '2019-8-13' },
{ name: '李四', point: 53, level: 8, updateTime: '2019-8-12' },
{ name: '小红', point: 44, level: 5, updateTime: '2019-8-11' },
{ name: '王五', point: 97, level: 10, updateTime: '2019-8-10' },
{ name: '小明', point: 33, level: 2, updateTime: '2019-8-10' },
]
{ name: '小张', point: 33, level: 2, updateTime: '2019-8-10' },
{ name: '小六', point: 33, level: 2, updateTime: '2019-8-10' },
{ name: '小五', point: 33, level: 2, updateTime: '2019-8-10' },
{ name: '小赵', point: 33, level: 2, updateTime: '2019-8-10' },
{ name: '李华', point: 33, level: 2, updateTime: '2019-8-10' },
{ name: '小康', point: 33, level: 2, updateTime: '2019-8-10' },
{ name: '小鹿', point: 33, level: 2, updateTime: '2019-8-10' },
],
newArr:[],
newDataSource:[],
}
},
mounted() {
this.tableAddTotalRow(this.columns, this.dataSource)
// this.tableAddTotalRow(this.columns, this.dataSource)
/*新增分页合计方法*/
this.newDataSource=this.dataSource
this.dataHandling(this.ipagination.pageSize-1)
},
watch:{
'ipagination.pageSize':function(val) {
this.dataHandling(val-1)
}
},
methods: {
/** 表格增加合计行 */
tableAddTotalRow(columns, dataSource) {
let numKey = 'rowIndex'
@ -80,8 +109,52 @@
})
dataSource.push(totalRow)
},
handleTableChange(pagination, filters, sorter) {
this.ipagination = pagination;
},
/*如果分页走这个方法*/
dataHandling(num) {
this.newArr=[];
let arrLength = this.newDataSource.length; // 数组长度;
let index = 0;
for (let i = 0; i < arrLength; i++) {
if (i % num === 0 && i !== 0) {
this.newArr.push(this.newDataSource.slice(index, i));
index = i;
}
if ((i + 1) === arrLength) {
this.newArr.push(this.newDataSource.slice(index, (i + 1)));
}
}
var arrs=this.newArr;
for (let i =0;i<arrs.length;i++){
let arr = arrs[i];
let newArr= { };
newArr.name="-";
newArr.updateTime="-";
newArr.rowIndex="合计"
var level=0;
var point=0;
for (let j=0;j<arr.length;j++){
level+=arr[j].level;
point+=arr[j].point;
}
newArr.level=level;
newArr.point=point;
arrs[i].push(newArr);
}
var newDataSource=[];
for (let i =0;i<arrs.length;i++){
let arr = arrs[i];
for(var j in arr){
newDataSource.push(arr[j]);
}
}
console.log(this.dataSource)
this.dataSource = Object.values(newDataSource);
console.log(this.dataSource)
}
}
}
</script>

View File

@ -91,6 +91,7 @@
<a-icon type="down"/>
</a-button>
</a-dropdown>
<j-super-query :fieldList="superQueryFieldList" @handleSuperQuery="handleSuperQuery"/>
</div>
<!-- table区域-begin -->
@ -119,9 +120,9 @@
</template>
<span slot="action" slot-scope="text, record">
<a @click="handleEdit(record)" >编辑</a>
<a @click="handleEdit(record)">编辑</a>
<a-divider type="vertical" />
<a-divider type="vertical"/>
<a-dropdown>
<a class="ant-dropdown-link">
@ -188,6 +189,7 @@
import SysUserAgentModal from "./modules/SysUserAgentModal";
import JInput from '@/components/jeecg/JInput'
import UserRecycleBinModal from './modules/UserRecycleBinModal'
import JSuperQuery from '@/components/jeecg/JSuperQuery'
export default {
name: "UserList",
@ -197,7 +199,8 @@
UserModal,
PasswordModal,
JInput,
UserRecycleBinModal
UserRecycleBinModal,
JSuperQuery
},
data() {
return {
@ -261,6 +264,12 @@
width: 180,
dataIndex: 'orgCodeTxt'
},
{
title: '负责部门',
align: "center",
width: 180,
dataIndex: 'departIds_dictText'
},
{
title: '状态',
align: "center",
@ -276,6 +285,11 @@
}
],
superQueryFieldList: [
{ type: 'input', value: 'username', text: '用户账号', },
{ type: 'input', value: 'realname', text: '用户姓名', },
{ type: 'select', value: 'sex', text: '性别', dictCode: 'sex' },
],
url: {
syncUser: "/process/extActProcess/doSyncUser",
list: "/sys/user/list",

View File

@ -16,12 +16,12 @@
<a-input placeholder="请输入用户账号" v-decorator="[ 'username', {}]" :readOnly="true"/>
</a-form-item>
<a-form-item label="密码" :labelCol="labelCol" :wrapperCol="wrapperCol" hasFeedback >
<a-input type="password" placeholder="请输入登密码" v-decorator="[ 'password', validatorRules.password]" />
<a-form-item label="密码" :labelCol="labelCol" :wrapperCol="wrapperCol" hasFeedback >
<a-input type="password" placeholder="请输入登密码" v-decorator="[ 'password', validatorRules.password]" />
</a-form-item>
<a-form-item label="确认密码" :labelCol="labelCol" :wrapperCol="wrapperCol" hasFeedback >
<a-input type="password" @blur="handleConfirmBlur" placeholder="请重新输入登密码" v-decorator="[ 'confirmpassword', validatorRules.confirmpassword]"/>
<a-input type="password" @blur="handleConfirmBlur" placeholder="请重新输入登密码" v-decorator="[ 'confirmpassword', validatorRules.confirmpassword]"/>
</a-form-item>
</a-form>
@ -51,7 +51,7 @@
},
confirmpassword:{
rules: [{
required: true, message: '请重新输入登密码!',
required: true, message: '请重新输入登密码!',
}, {
validator: this.compareToFirstPassword,
}],

View File

@ -27,12 +27,12 @@
</a-form-item>
<template v-if="!model.id">
<a-form-item label="密码" :labelCol="labelCol" :wrapperCol="wrapperCol" >
<a-input type="password" placeholder="请输入登密码" v-decorator="[ 'password']" />
<a-form-item label="密码" :labelCol="labelCol" :wrapperCol="wrapperCol" >
<a-input type="password" placeholder="请输入登密码" v-decorator="[ 'password']" />
</a-form-item>
<a-form-item label="确认密码" :labelCol="labelCol" :wrapperCol="wrapperCol" >
<a-input type="password" @blur="handleConfirmBlur" placeholder="请重新输入登密码" v-decorator="[ 'confirmpassword', validatorRules.confirmpassword]"/>
<a-input type="password" @blur="handleConfirmBlur" placeholder="请重新输入登密码" v-decorator="[ 'confirmpassword', validatorRules.confirmpassword]"/>
</a-form-item>
</template>
@ -51,6 +51,7 @@
<a-form-item label="角色分配" :labelCol="labelCol" :wrapperCol="wrapperCol" v-show="!roleDisabled" >
<a-select
mode="multiple"
:disabled="departDisabled"
style="width: 100%"
placeholder="请选择用户角色"
optionFilterProp = "children"
@ -218,7 +219,7 @@
},
confirmpassword:{
rules: [{
required: true, message: '请重新输入登密码!',
required: true, message: '请重新输入登密码!',
}, {
validator: this.compareToFirstPassword,
}],

View File

@ -5,7 +5,7 @@
:activeKey="customActiveKey"
:tabBarStyle="{ textAlign: 'center', borderBottom: 'unset' }"
@change="handleTabClick">
<a-tab-pane key="tab1" tab="账号密码登">
<a-tab-pane key="tab1" tab="账号密码登">
<a-form-item>
<a-input
size="large"
@ -48,7 +48,7 @@
</a-tab-pane>
<a-tab-pane key="tab2" tab="手机号登">
<a-tab-pane key="tab2" tab="手机号登">
<a-form-item>
<a-input
v-decorator="['mobile',validatorRules.mobile]"
@ -84,7 +84,7 @@
</a-tabs>
<a-form-item>
<a-checkbox v-decorator="['rememberMe', {initialValue: true, valuePropName: 'checked'}]" >自动登</a-checkbox>
<a-checkbox v-decorator="['rememberMe', {initialValue: true, valuePropName: 'checked'}]" >自动登</a-checkbox>
<router-link :to="{ name: 'alteration'}" class="forge-password" style="float: right;">
忘记密码
</router-link>
@ -106,7 +106,7 @@
</a-form-item>
<div class="user-login-other">
<span>其他登方式</span>
<span>其他登方式</span>
<a @click="onThirdLogin('github')" title="github"><a-icon class="item-icon" type="github"></a-icon></a>
<a @click="onThirdLogin('wechat_enterprise')" title="企业微信"><a-icon class="item-icon" type="wechat"></a-icon></a>
<a @click="onThirdLogin('dingtalk')" title="钉钉"><a-icon class="item-icon" type="dingding"></a-icon></a>
@ -195,6 +195,11 @@
console.log("origin",origin);
let token = event.data
//update-begin--Author:wangshuai Date:20200729 for接口在签名校验失败时返回失败的标识码 #1441--------------------
if (token === '登录失败') {
that.$message.warning(token);
}else{
//update-end--Author:wangshuai Date:20200729 for接口在签名校验失败时返回失败的标识码 #1441--------------------
console.log("event.data",token)
that.ThirdLogin(token).then(res=>{
if(res.success){
@ -203,6 +208,7 @@
that.requestFailed(res);
}
})
}
}
window.addEventListener("message", receiveMessage, false);
},
@ -224,7 +230,7 @@
let that = this
let loginParams = {};
that.loginBtn = true;
// 使用账户密码登
// 使用账户密码登
if (that.customActiveKey === 'tab1') {
that.form.validateFields([ 'username', 'password','inputCode', 'rememberMe' ], { force: true }, (err, values) => {
if (!err) {
@ -249,7 +255,7 @@
that.loginBtn = false;
}
})
// 使用手机号登
// 使用手机号登
} else {
that.form.validateFields([ 'mobile', 'captcha', 'rememberMe' ], { force: true }, (err, values) => {
if (!err) {