mirror of
https://github.com/jeecgboot/JeecgBoot.git
synced 2026-02-06 02:25:30 +08:00
前端和后端源码,合并到一个git仓库中,方便用户下载,避免前后端不匹配的问题
This commit is contained in:
57
jeecgboot-vue3/src/views/demo/jeecg/AsyncTreeTable.vue
Normal file
57
jeecgboot-vue3/src/views/demo/jeecg/AsyncTreeTable.vue
Normal file
@ -0,0 +1,57 @@
|
||||
<template>
|
||||
<PageWrapper>
|
||||
<a-card :bordered="false">
|
||||
<BasicTable :loading="loading" :dataSource="dataSource" @register="registerTable" @expand="onExpand" />
|
||||
</a-card>
|
||||
</PageWrapper>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
import { defHttp } from '/@/utils/http/axios';
|
||||
import { PageWrapper } from '/@/components/Page';
|
||||
import { BasicTable, useTable } from '/@/components/Table';
|
||||
|
||||
const url = '/mock/api/asynTreeList';
|
||||
|
||||
const loading = ref<boolean>(false);
|
||||
const dataSource = ref<any[]>([]);
|
||||
const [registerTable, { setLoading }] = useTable({
|
||||
rowKey: 'id',
|
||||
bordered: true,
|
||||
canResize: false,
|
||||
// 树表格
|
||||
isTreeTable: true,
|
||||
showIndexColumn: true,
|
||||
columns: [
|
||||
{ title: '名称', dataIndex: 'name' },
|
||||
{ title: '组件', dataIndex: 'component' },
|
||||
{ title: '排序', dataIndex: 'orderNum' },
|
||||
],
|
||||
});
|
||||
|
||||
async function loadData(params) {
|
||||
loading.value = true;
|
||||
let result = await defHttp.get({ url, params });
|
||||
loading.value = false;
|
||||
return result.map((item) => {
|
||||
if (item.hasChildren) {
|
||||
return { ...item, children: [] };
|
||||
} else {
|
||||
return item;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async function loadRootData() {
|
||||
dataSource.value = await loadData({ id: '0' });
|
||||
}
|
||||
|
||||
loadRootData();
|
||||
|
||||
async function onExpand(isExpand, rowData) {
|
||||
if (isExpand && rowData.hasChildren && rowData.children.length === 0) {
|
||||
rowData.children = await loadData({ id: rowData.id });
|
||||
}
|
||||
}
|
||||
</script>
|
||||
80
jeecgboot-vue3/src/views/demo/jeecg/ImgDragSort.vue
Normal file
80
jeecgboot-vue3/src/views/demo/jeecg/ImgDragSort.vue
Normal file
@ -0,0 +1,80 @@
|
||||
<template>
|
||||
<div>
|
||||
<draggable @end="end" v-model="dataArr" item-key="id" style="display: flex">
|
||||
<template #item="{ element }">
|
||||
<div class="imgDiv">
|
||||
<img :src="element.filePath" preview="index" />
|
||||
</div>
|
||||
</template>
|
||||
<template #footer>
|
||||
<a-button @click="sureChange" type="primary" style="margin-top: 100px">确定</a-button>
|
||||
</template>
|
||||
</draggable>
|
||||
<a-divider>json数据</a-divider>
|
||||
<a-row>
|
||||
<a-col :span="12">
|
||||
<p>拖拽前:</p>
|
||||
<textarea rows="25" style="width: 780px">{{ oldDateSource }}</textarea>
|
||||
</a-col>
|
||||
<a-col :span="12">
|
||||
<p>拖拽后:</p>
|
||||
<textarea rows="25" style="width: 780px">{{ newDateSource }}</textarea>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import draggable from 'vuedraggable';
|
||||
import { defineComponent, ref, unref } from 'vue';
|
||||
|
||||
const mockData = [
|
||||
{ id: '000', sort: 0, filePath: 'https://static.jeecg.com/upload/test/1_1588149743473.jpg' },
|
||||
{ id: '111', sort: 1, filePath: 'https://static.jeecg.com/upload/test/u27356337152749454924fm27gp0_1588149731821.jpg' },
|
||||
{ id: '222', sort: 2, filePath: 'https://static.jeecg.com/upload/test/u24454681402491956848fm27gp0_1588149712663.jpg' },
|
||||
{ id: '333', sort: 3, filePath: 'https://static.jeecg.com/temp/国炬软件logo_1606575029126.png' },
|
||||
{ id: '444', sort: 4, filePath: 'https://static.jeecg.com/upload/test/u8891206113801177793fm27gp0_1588149704459.jpg' },
|
||||
];
|
||||
|
||||
//数据集
|
||||
const dataArr = ref(mockData);
|
||||
//原始数据
|
||||
const oldDateSource = ref(mockData);
|
||||
//更改后的数据
|
||||
const newDateSource = ref([]);
|
||||
|
||||
/**
|
||||
* 拖动结束事件
|
||||
* @param evt
|
||||
*/
|
||||
function end(evt) {
|
||||
console.log('拖动前的位置' + evt.oldIndex);
|
||||
console.log('拖动后的位置' + evt.newIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* 确认更改事件
|
||||
* @param evt
|
||||
*/
|
||||
function sureChange() {
|
||||
for (let i = 0; i < unref(dataArr).length; i++) {
|
||||
dataArr.value[i].sort = i;
|
||||
}
|
||||
newDateSource.value = unref(dataArr);
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.imgDiv {
|
||||
padding: 8px;
|
||||
border: 1px solid #d9d9d9;
|
||||
border-radius: 4px;
|
||||
margin: 0 8px 8px 0;
|
||||
|
||||
img {
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
object-fit: cover;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
170
jeecgboot-vue3/src/views/demo/jeecg/ImgTurnPage.vue
Normal file
170
jeecgboot-vue3/src/views/demo/jeecg/ImgTurnPage.vue
Normal file
@ -0,0 +1,170 @@
|
||||
<template>
|
||||
<div style="min-width: 800px">
|
||||
<a-row>
|
||||
<!-- 左侧文件树 -->
|
||||
<a-col :span="6">
|
||||
<a-tree
|
||||
showLine
|
||||
:treeData="treeData"
|
||||
:expandedKeys="[expandedKeys[0]]"
|
||||
:selectedKeys="selectedKeys"
|
||||
:style="{ height: '500px', 'border-right': '2px solid #c1c1c1', 'overflow-y': 'auto' }"
|
||||
@expand="onExpand"
|
||||
@select="onSelect"
|
||||
></a-tree>
|
||||
</a-col>
|
||||
|
||||
<!--右侧缩略图-->
|
||||
<a-col :span="18">
|
||||
<a-row style="margin-top: 10px; padding-left: 2%">
|
||||
<a-col :span="24" style="margin-bottom: 10px">
|
||||
<a-button @click="prev" preIcon="ant-design:left-outlined" type="primary">上一页</a-button>
|
||||
<a-button @click="next" preIcon="ant-design:right-outlined" style="margin-left: 8px" type="primary">下一页</a-button>
|
||||
<span style="margin-left: 100px; font-weight: bolder">{{ navName }}</span>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<img :src="imgUrl" preview />
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, unref, onMounted } from 'vue';
|
||||
//mock数据
|
||||
const mockdata = [
|
||||
{
|
||||
title: '第一页',
|
||||
key: '0-0',
|
||||
children: [
|
||||
{
|
||||
title: '1页',
|
||||
key: '0-0-0',
|
||||
imgUrl: 'https://static.jeecg.com/upload/test/1_1588149743473.jpg',
|
||||
},
|
||||
{
|
||||
title: '2页',
|
||||
key: '0-0-1',
|
||||
imgUrl: 'https://static.jeecg.com/upload/test/u27356337152749454924fm27gp0_1588149731821.jpg',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: '第二页',
|
||||
key: '0-1',
|
||||
children: [
|
||||
{
|
||||
title: '1页',
|
||||
key: '0-1-0',
|
||||
imgUrl: 'https://static.jeecg.com/upload/test/u24454681402491956848fm27gp0_1588149712663.jpg',
|
||||
},
|
||||
{
|
||||
title: '2页',
|
||||
key: '0-1-1',
|
||||
imgUrl: 'https://static.jeecg.com/upload/test/u8891206113801177793fm27gp0_1588149704459.jpg',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: '第三页',
|
||||
key: '0-2',
|
||||
children: [
|
||||
{
|
||||
title: '1页',
|
||||
key: '0-2-0',
|
||||
imgUrl: 'https://static.jeecg.com/upload/test/1374962_1587621329085.jpg',
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
/**
|
||||
* 左侧树形数据
|
||||
*/
|
||||
const treeData = ref(mockdata);
|
||||
//选中的key
|
||||
const selectedKeys = ref([]);
|
||||
//展开的key
|
||||
const expandedKeys = ref([]);
|
||||
const sort = ref(0);
|
||||
//图片链接
|
||||
const imgUrl = ref('');
|
||||
//页码标题
|
||||
const navName = ref('');
|
||||
//图片集合
|
||||
const imgList = ref([]);
|
||||
|
||||
onMounted(getImgList);
|
||||
|
||||
/**
|
||||
* 加载图片集合
|
||||
*/
|
||||
function getImgList() {
|
||||
var count = 0;
|
||||
for (var i = 0; i < unref(treeData).length; i++) {
|
||||
for (var j = 0; j < unref(treeData)[i].children.length; j++) {
|
||||
imgList.value.push({
|
||||
key: unref(treeData)[i].children[j].key,
|
||||
pkey: unref(treeData)[i].key,
|
||||
sort: count++,
|
||||
imgUrl: unref(treeData)[i].children[j].imgUrl,
|
||||
navName: unref(treeData)[i].title + '/' + unref(treeData)[i].children[j].title,
|
||||
});
|
||||
}
|
||||
}
|
||||
setValue(imgList.value[unref(sort)]);
|
||||
}
|
||||
/**
|
||||
* 节点选中事件
|
||||
*/
|
||||
function onSelect(selectedKeys, info) {
|
||||
for (var i = 0; i < unref(imgList).length; i++) {
|
||||
if (unref(imgList)[i].key === selectedKeys[0]) {
|
||||
sort.value = unref(imgList)[i].sort;
|
||||
setValue(unref(imgList)[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 节点展开事件
|
||||
*/
|
||||
function onExpand(expandedKey) {
|
||||
expandedKeys.value = [];
|
||||
if (expandedKey !== null && expandedKey !== '') {
|
||||
expandedKeys.value[0] = expandedKey[1];
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 上一页
|
||||
*/
|
||||
function prev() {
|
||||
if (unref(sort) === 0) {
|
||||
sort.value = unref(imgList).length - 1;
|
||||
} else {
|
||||
sort.value = sort.value - 1;
|
||||
}
|
||||
setValue(unref(imgList)[unref(sort)]);
|
||||
}
|
||||
/**
|
||||
* 下一页
|
||||
*/
|
||||
function next() {
|
||||
if (unref(sort) === unref(imgList).length - 1) {
|
||||
sort.value = 0;
|
||||
} else {
|
||||
sort.value = unref(sort) + 1;
|
||||
}
|
||||
setValue(unref(imgList)[unref(sort)]);
|
||||
}
|
||||
|
||||
// 设置受控节点值
|
||||
function setValue(value) {
|
||||
selectedKeys.value = [];
|
||||
imgUrl.value = value.imgUrl;
|
||||
selectedKeys.value[0] = value.key;
|
||||
expandedKeys.value[0] = value.pkey;
|
||||
navName.value = value.navName;
|
||||
}
|
||||
</script>
|
||||
243
jeecgboot-vue3/src/views/demo/jeecg/InnerExpandTable.vue
Normal file
243
jeecgboot-vue3/src/views/demo/jeecg/InnerExpandTable.vue
Normal file
@ -0,0 +1,243 @@
|
||||
<template>
|
||||
<a-card :bordered="false">
|
||||
<BasicTable @register="registerTable" :expandedRowKeys="expandedRowKeys" :rowSelection="rowSelection" @expand="handleExpand">
|
||||
<template #tableTitle>
|
||||
<a-button type="primary" @click="handleAdd" preIcon="ant-design:plus-outlined"> 新增</a-button>
|
||||
</template>
|
||||
<template #expandedRowRender>
|
||||
<BasicTable bordered size="middle" rowKey="id" :canResize="false" :columns="innerColumns" :dataSource="innerData" :pagination="false">
|
||||
</BasicTable>
|
||||
</template>
|
||||
<!--操作栏-->
|
||||
<template #action="{ record }">
|
||||
<TableAction :actions="getTableAction(record)" />
|
||||
</template>
|
||||
</BasicTable>
|
||||
<JVxeTableModal @register="registerModal" @success="reload()"></JVxeTableModal>
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
import { defHttp } from '/@/utils/http/axios';
|
||||
import { BasicTable, useTable, TableAction } from '/@/components/Table';
|
||||
import { useModal } from '/@/components/Modal';
|
||||
import JVxeTableModal from '/@/views/demo/vextable/jvxetable/JVxeTableModal.vue';
|
||||
//接口url
|
||||
const url = {
|
||||
list: '/test/order/orderList',
|
||||
delete: '/test/order/delete',
|
||||
deleteBatch: '/test/order/deleteBatch',
|
||||
customerListByMainId: '/test/order/listOrderCustomerByMainId',
|
||||
};
|
||||
// 展开key
|
||||
const expandedRowKeys = ref<any[]>([]);
|
||||
// 选择key
|
||||
const checkedKeys = ref<any[]>([]);
|
||||
// 子表数据
|
||||
const innerData = ref<any[]>([]);
|
||||
// 主表表头
|
||||
const columns = [
|
||||
{
|
||||
title: '订单号',
|
||||
align: 'center',
|
||||
dataIndex: 'orderCode',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: '订单类型',
|
||||
align: 'center',
|
||||
dataIndex: 'ctype',
|
||||
width: 100,
|
||||
customRender: ({ text }) => {
|
||||
let re = '';
|
||||
if (text === '1') {
|
||||
re = '国内订单';
|
||||
} else if (text === '2') {
|
||||
re = '国际订单';
|
||||
}
|
||||
return re;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '订单日期',
|
||||
align: 'center',
|
||||
width: 100,
|
||||
dataIndex: 'orderDate',
|
||||
},
|
||||
{
|
||||
title: '订单金额',
|
||||
align: 'center',
|
||||
dataIndex: 'orderMoney',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: '订单备注',
|
||||
align: 'center',
|
||||
dataIndex: 'content',
|
||||
width: 100,
|
||||
},
|
||||
];
|
||||
// 子表表头
|
||||
const innerColumns = [
|
||||
{
|
||||
title: '客户名',
|
||||
align: 'center',
|
||||
width: 100,
|
||||
dataIndex: 'name',
|
||||
key: 'name',
|
||||
},
|
||||
{
|
||||
title: '性别',
|
||||
align: 'center',
|
||||
dataIndex: 'sex',
|
||||
customRender: function (text) {
|
||||
//console.log(typeof text )
|
||||
//console.log(text)
|
||||
if (text.value == '1') {
|
||||
return '男';
|
||||
} else if (text.value == '2') {
|
||||
return '女';
|
||||
} else {
|
||||
return text;
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '身份证号码',
|
||||
align: 'center',
|
||||
dataIndex: 'idcard',
|
||||
},
|
||||
{
|
||||
title: '电话',
|
||||
dataIndex: 'telphone',
|
||||
align: 'center',
|
||||
},
|
||||
];
|
||||
const list = (params) => defHttp.get({ url: url.list, params });
|
||||
const [registerModal, { openModal }] = useModal();
|
||||
const [registerTable, { reload }] = useTable({
|
||||
columns,
|
||||
api: list,
|
||||
rowKey: 'id',
|
||||
striped: true,
|
||||
useSearchForm: false,
|
||||
showTableSetting: true,
|
||||
clickToRowSelect: false,
|
||||
bordered: true,
|
||||
actionColumn: {
|
||||
width: 110,
|
||||
title: '操作',
|
||||
dataIndex: 'action',
|
||||
slots: { customRender: 'action' },
|
||||
fixed: undefined,
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* 选择列配置
|
||||
*/
|
||||
const rowSelection = {
|
||||
type: 'checkbox',
|
||||
columnWidth: 30,
|
||||
selectedRowKeys: checkedKeys,
|
||||
onChange: onSelectChange,
|
||||
};
|
||||
|
||||
/**
|
||||
* 选择事件
|
||||
*/
|
||||
function onSelectChange(selectedRowKeys: (string | number)[]) {
|
||||
checkedKeys.value = selectedRowKeys;
|
||||
}
|
||||
/**
|
||||
* 展开事件
|
||||
* */
|
||||
function handleExpand(expanded, record) {
|
||||
expandedRowKeys.value = [];
|
||||
innerData.value = [];
|
||||
if (expanded === true) {
|
||||
expandedRowKeys.value.push(record.id);
|
||||
defHttp.get({ url: url.customerListByMainId, params: { orderId: record.id } }, { isTransformResponse: false }).then((res) => {
|
||||
if (res.success) {
|
||||
innerData.value = res.result.records;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 新增事件
|
||||
*/
|
||||
function handleAdd() {
|
||||
openModal(true, {
|
||||
isUpdate: false,
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 编辑事件
|
||||
*/
|
||||
function handleEdit(record) {
|
||||
openModal(true, {
|
||||
record,
|
||||
isUpdate: true,
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 删除事件
|
||||
*/
|
||||
function handleDelete(record) {
|
||||
defHttp.delete({ url: url.delete, data: { id: record.id } }, { joinParamsToUrl: true }).then(() => {
|
||||
reload();
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 操作栏
|
||||
*/
|
||||
function getTableAction(record) {
|
||||
return [
|
||||
{
|
||||
label: '编辑',
|
||||
onClick: handleEdit.bind(null, record),
|
||||
},
|
||||
{
|
||||
label: '删除',
|
||||
popConfirm: {
|
||||
title: '是否确认删除',
|
||||
confirm: handleDelete.bind(null, record),
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
</script>
|
||||
<style scoped>
|
||||
.ant-card-body .table-operator {
|
||||
margin-bottom: 18px;
|
||||
}
|
||||
|
||||
.ant-table-tbody .ant-table-row td {
|
||||
padding-top: 15px;
|
||||
padding-bottom: 15px;
|
||||
}
|
||||
|
||||
.anty-row-operator button {
|
||||
margin: 0 5px;
|
||||
}
|
||||
|
||||
.ant-btn-danger {
|
||||
background-color: #ffffff;
|
||||
}
|
||||
|
||||
.ant-modal-cust-warp {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.ant-modal-cust-warp .ant-modal-body {
|
||||
height: calc(100% - 110px) !important;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.ant-modal-cust-warp .ant-modal-content {
|
||||
height: 90% !important;
|
||||
overflow-y: hidden;
|
||||
}
|
||||
</style>
|
||||
67
jeecgboot-vue3/src/views/demo/jeecg/JCodeEditDemo.vue
Normal file
67
jeecgboot-vue3/src/views/demo/jeecg/JCodeEditDemo.vue
Normal file
@ -0,0 +1,67 @@
|
||||
<template>
|
||||
<BasicForm
|
||||
:labelWidth="200"
|
||||
:schemas="schemas"
|
||||
:showResetButton="false"
|
||||
:showSubmitButton="false"
|
||||
:actionColOptions="{ span: 24 }"
|
||||
@submit="handleSubmit"
|
||||
@reset="handleReset"
|
||||
style="height: 800px"
|
||||
>
|
||||
<template #jCodeEdit="{ model, field }">
|
||||
<JCodeEditor v-model:value="model[field]" mode="js" height="300px" :fullScreen="true" />
|
||||
</template>
|
||||
</BasicForm>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, unref, ref } from 'vue';
|
||||
import { BasicForm, FormSchema, JCodeEditor } from '/@/components/Form';
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
import { optionsListApi } from '/@/api/demo/select';
|
||||
import { useDebounceFn } from '@vueuse/core';
|
||||
|
||||
const schemas: FormSchema[] = [
|
||||
{
|
||||
field: 'field1',
|
||||
component: 'JCodeEditor',
|
||||
label: '代码编辑器',
|
||||
required: true,
|
||||
slot: 'jCodeEdit',
|
||||
colProps: {
|
||||
span: 15,
|
||||
},
|
||||
defaultValue: 'Hello JeecgBoot',
|
||||
},
|
||||
];
|
||||
|
||||
export default defineComponent({
|
||||
components: { BasicForm, JCodeEditor },
|
||||
setup() {
|
||||
const check = ref(null);
|
||||
const { createMessage } = useMessage();
|
||||
const keyword = ref<string>('');
|
||||
const searchParams = computed<Recordable>(() => {
|
||||
return { keyword: unref(keyword) };
|
||||
});
|
||||
|
||||
function onSearch(value: string) {
|
||||
keyword.value = value;
|
||||
}
|
||||
|
||||
return {
|
||||
schemas,
|
||||
optionsListApi,
|
||||
onSearch: useDebounceFn(onSearch, 300),
|
||||
searchParams,
|
||||
handleReset: () => {
|
||||
keyword.value = '';
|
||||
},
|
||||
handleSubmit: (values: any) => {
|
||||
createMessage.success('click search,values:' + JSON.stringify(values));
|
||||
},
|
||||
check,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
99
jeecgboot-vue3/src/views/demo/jeecg/JEditorDemo.vue
Normal file
99
jeecgboot-vue3/src/views/demo/jeecg/JEditorDemo.vue
Normal file
@ -0,0 +1,99 @@
|
||||
<template>
|
||||
<div class="p-4">
|
||||
<div class="p-4 bg-white">
|
||||
<a-button-group class="j-table-operator">
|
||||
<a-button type="primary" @click="setDis(0)">启用</a-button>
|
||||
<a-button type="primary" @click="setDis(1)">禁用</a-button>
|
||||
<a-button type="primary" @click="getValues()">校验表单并获取值</a-button>
|
||||
<a-button type="primary" @click="setValues()">设置值</a-button>
|
||||
</a-button-group>
|
||||
|
||||
<BasicForm @register="register" @submit="handleSubmit" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
export default {
|
||||
title: '富文本 | Markdown',
|
||||
name: 'MarkdownDemo',
|
||||
};
|
||||
</script>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { FormSchema, useForm, BasicForm } from '/@/components/Form';
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
|
||||
const { createMessage, createSuccessModal } = useMessage();
|
||||
|
||||
const schemas: FormSchema[] = [
|
||||
{
|
||||
field: 'name',
|
||||
component: 'Input',
|
||||
label: '姓名',
|
||||
required: true,
|
||||
defaultValue: 'zhangsan',
|
||||
},
|
||||
{
|
||||
field: 'tinymce',
|
||||
component: 'JEditor',
|
||||
label: '富文本',
|
||||
defaultValue: 'defaultValue',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
field: 'markdown',
|
||||
component: 'JMarkdownEditor',
|
||||
label: 'Markdown',
|
||||
defaultValue: '# 张三',
|
||||
required: true,
|
||||
componentProps: {
|
||||
height: 300,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const [register, { setProps, validate, setFieldsValue }] = useForm({
|
||||
labelWidth: 120,
|
||||
schemas: schemas,
|
||||
actionColOptions: {
|
||||
span: 24,
|
||||
},
|
||||
compact: true,
|
||||
showResetButton: false,
|
||||
showSubmitButton: false,
|
||||
showAdvancedButton: false,
|
||||
disabled: false,
|
||||
});
|
||||
|
||||
function handleSubmit(values) {
|
||||
console.log(values);
|
||||
}
|
||||
|
||||
function setDis(flag) {
|
||||
setProps({ disabled: !!flag });
|
||||
}
|
||||
|
||||
async function getValues() {
|
||||
try {
|
||||
const values = await validate();
|
||||
console.log(values);
|
||||
createSuccessModal({
|
||||
title: '校验通过',
|
||||
content: `${JSON.stringify(values)}`,
|
||||
});
|
||||
} catch (error) {
|
||||
createMessage.warning('检验不通过');
|
||||
}
|
||||
}
|
||||
|
||||
function setValues() {
|
||||
setFieldsValue({
|
||||
name: 'LiSi',
|
||||
markdown: '# 李四',
|
||||
tinymce: '<p><strong><span style="font-size: 18pt;">张<span style="color: #e03e2d;">三</span>丰</span></strong></p>',
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
84
jeecgboot-vue3/src/views/demo/jeecg/JUploadDemo.vue
Normal file
84
jeecgboot-vue3/src/views/demo/jeecg/JUploadDemo.vue
Normal file
@ -0,0 +1,84 @@
|
||||
<template>
|
||||
<a-button-group class="j-table-operator">
|
||||
<a-button type="primary" @click="setDisabled(0)">启用</a-button>
|
||||
<a-button type="primary" @click="setDisabled(1)">禁用</a-button>
|
||||
<a-button type="primary" @click="showUploadModal">文件弹窗</a-button>
|
||||
</a-button-group>
|
||||
<BasicForm @register="register" @submit="handleSubmit" />
|
||||
<JUploadModal v-model:value="uploadModalValue" @register="registerModel" />
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
import { FormSchema, useForm, BasicForm } from '/@/components/Form';
|
||||
import { UploadTypeEnum } from '/@/components/Form/src/jeecg/components/JUpload';
|
||||
import { JUploadModal } from '/@/components/Form/src/jeecg/components/JUpload';
|
||||
import { useModal } from '/@/components/Modal';
|
||||
|
||||
const uploadModalValue = ref('');
|
||||
|
||||
const schemas: FormSchema[] = [
|
||||
{
|
||||
field: 'uploadFile',
|
||||
component: 'JUpload',
|
||||
helpMessage: '无限制上传',
|
||||
label: '上传文件',
|
||||
},
|
||||
{
|
||||
field: 'uploadFileMax',
|
||||
component: 'JUpload',
|
||||
helpMessage: '最多上传3个文件',
|
||||
label: '上传文件(3)',
|
||||
componentProps: { maxCount: 3 },
|
||||
},
|
||||
{
|
||||
field: 'uploadImage',
|
||||
component: 'JUpload',
|
||||
label: '上传图片',
|
||||
helpMessage: '无限制上传',
|
||||
componentProps: {
|
||||
fileType: UploadTypeEnum.image,
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'uploadImageMax',
|
||||
component: 'JUpload',
|
||||
label: '上传图片(1)',
|
||||
helpMessage: '最多上传1张图片',
|
||||
componentProps: {
|
||||
fileType: UploadTypeEnum.image,
|
||||
maxCount: 1,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const [registerModel, { openModal }] = useModal();
|
||||
|
||||
const [register, { setProps, validate, setFieldsValue }] = useForm({
|
||||
labelWidth: 120,
|
||||
schemas: schemas,
|
||||
actionColOptions: {
|
||||
span: 24,
|
||||
},
|
||||
compact: true,
|
||||
showResetButton: false,
|
||||
showSubmitButton: false,
|
||||
showAdvancedButton: false,
|
||||
disabled: false,
|
||||
});
|
||||
|
||||
function handleSubmit(values) {
|
||||
console.log(values);
|
||||
}
|
||||
|
||||
function setDisabled(flag) {
|
||||
setProps({ disabled: !!flag });
|
||||
}
|
||||
|
||||
function showUploadModal() {
|
||||
openModal(true, {
|
||||
maxCount: 9,
|
||||
fileType: UploadTypeEnum.image,
|
||||
});
|
||||
}
|
||||
</script>
|
||||
403
jeecgboot-vue3/src/views/demo/jeecg/JVxeTableDemo/JVxeDemo1.vue
Normal file
403
jeecgboot-vue3/src/views/demo/jeecg/JVxeTableDemo/JVxeDemo1.vue
Normal file
@ -0,0 +1,403 @@
|
||||
<template>
|
||||
<a-space>
|
||||
<a-button @click="onToggleLoading">切换加载</a-button>
|
||||
<a-button @click="onToggleDisabled">切换禁用</a-button>
|
||||
</a-space>
|
||||
<!--这种使用场景得用height,用maxHeight底层有问题-->
|
||||
<JVxeTable
|
||||
ref="tableRef"
|
||||
stripe
|
||||
toolbar
|
||||
rowNumber
|
||||
rowSelection
|
||||
rowExpand
|
||||
resizable
|
||||
asyncRemove
|
||||
clickSelectRow
|
||||
:height="480"
|
||||
:checkboxConfig="{ range: true }"
|
||||
:disabledRows="{ input: ['text--16', 'text--18'] }"
|
||||
:loading="loading"
|
||||
:disabled="disabled"
|
||||
:columns="columns"
|
||||
:dataSource="dataSource"
|
||||
@removed="onJVxeRemove"
|
||||
@valueChange="handleValueChange"
|
||||
@blur="handleBlur"
|
||||
:custom="true"
|
||||
>
|
||||
<template #toolbarSuffix>
|
||||
<a-button @click="handleTableCheck">表单验证</a-button>
|
||||
<a-tooltip placement="top" title="获取值,忽略表单验证" :autoAdjustOverflow="true">
|
||||
<a-button @click="onGetData">获取数据</a-button>
|
||||
</a-tooltip>
|
||||
<a-tooltip placement="top" title="模拟加载1000条数据" :autoAdjustOverflow="true">
|
||||
<a-button @click="handleTableSet">设置值</a-button>
|
||||
</a-tooltip>
|
||||
<a-button @click="onGetSelData">获取选中数据</a-button>
|
||||
<a-button @click="onClearSel">清空选中</a-button>
|
||||
<a-button @click="onDelFirst">删除第一行数据</a-button>
|
||||
<a-button @click="onDelSel">删除选中数据</a-button>
|
||||
</template>
|
||||
|
||||
<template #expandContent="props">
|
||||
<div style="padding: 20px">
|
||||
<span>Hello! My name is: {{ props.row.input }}!</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #myAction="props">
|
||||
<a @click="onLookRow(props)">查看</a>
|
||||
<a-divider type="vertical" />
|
||||
<Popconfirm title="确定删除吗?" @confirm="onDeleteRow(props)">
|
||||
<a>删除</a>
|
||||
</Popconfirm>
|
||||
</template>
|
||||
</JVxeTable>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
// noinspection ES6UnusedImports
|
||||
import { Popconfirm } from 'ant-design-vue';
|
||||
import { JVxeTypes, JVxeColumn, JVxeTableInstance } from '/@/components/jeecg/JVxeTable/types';
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
import { random } from 'lodash-es';
|
||||
import { buildUUID } from '/@/utils/uuid';
|
||||
import dayjs from 'dayjs';
|
||||
import { pushIfNotExist } from '/@/utils/common/compUtils';
|
||||
|
||||
const { createMessage } = useMessage();
|
||||
const tableRef = ref<JVxeTableInstance>();
|
||||
const loading = ref(false);
|
||||
const disabled = ref(false);
|
||||
const columns = ref<JVxeColumn[]>([
|
||||
{
|
||||
title: 'ID',
|
||||
key: 'id',
|
||||
type: JVxeTypes.hidden,
|
||||
},
|
||||
{
|
||||
title: '不可编辑',
|
||||
key: 'noEdit',
|
||||
type: JVxeTypes.normal,
|
||||
width: 180,
|
||||
defaultValue: 'noEdit-new',
|
||||
},
|
||||
{
|
||||
title: '单行文本',
|
||||
key: 'input',
|
||||
type: JVxeTypes.input,
|
||||
width: 180,
|
||||
defaultValue: '',
|
||||
placeholder: '请输入${title}',
|
||||
validateRules: [
|
||||
{
|
||||
required: true, // 必填
|
||||
message: '请输入${title}', // 显示的文本
|
||||
},
|
||||
{
|
||||
pattern: /^[a-z|A-Z][a-z|A-Z\d_-]*$/, // 正则
|
||||
message: '必须以字母开头,可包含数字、下划线、横杠',
|
||||
},
|
||||
{
|
||||
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: 200,
|
||||
},
|
||||
{
|
||||
title: '数字',
|
||||
key: 'number',
|
||||
type: JVxeTypes.inputNumber,
|
||||
width: 80,
|
||||
defaultValue: 32,
|
||||
// 【统计列】sum = 求和、average = 平均值
|
||||
statistics: ['sum', 'average'],
|
||||
},
|
||||
{
|
||||
title: '下拉框',
|
||||
key: 'select',
|
||||
type: JVxeTypes.select,
|
||||
width: 180,
|
||||
// 下拉选项
|
||||
options: [
|
||||
{ title: 'String', value: 'string' },
|
||||
{ title: 'Integer', value: 'int' },
|
||||
{ title: 'Double', value: 'double' },
|
||||
{ title: 'Boolean', value: 'boolean' },
|
||||
],
|
||||
// allowInput: true,
|
||||
allowSearch: true,
|
||||
placeholder: '请选择',
|
||||
},
|
||||
{
|
||||
title: '下拉框_字典',
|
||||
key: 'select_dict',
|
||||
type: JVxeTypes.select,
|
||||
width: 180,
|
||||
options: [],
|
||||
dictCode: 'sex',
|
||||
placeholder: '请选择',
|
||||
},
|
||||
{
|
||||
title: '下拉框_多选',
|
||||
key: 'select_multiple',
|
||||
type: JVxeTypes.selectMultiple,
|
||||
width: 205,
|
||||
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: 180,
|
||||
options: [
|
||||
{ title: 'String', value: 'string' },
|
||||
{ title: 'Integer', value: 'int' },
|
||||
{ title: 'Double', value: 'double' },
|
||||
{ title: 'Boolean', value: 'boolean' },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: '日期时间',
|
||||
key: 'datetime',
|
||||
type: JVxeTypes.datetime,
|
||||
width: 200,
|
||||
defaultValue: '2019-04-30 14:52:22',
|
||||
placeholder: '请选择',
|
||||
},
|
||||
{
|
||||
title: '时间',
|
||||
key: 'time',
|
||||
type: JVxeTypes.time,
|
||||
width: 200,
|
||||
defaultValue: '14:52:22',
|
||||
placeholder: '请选择',
|
||||
},
|
||||
{
|
||||
title: '复选框',
|
||||
key: 'checkbox',
|
||||
type: JVxeTypes.checkbox,
|
||||
width: 100,
|
||||
customValue: ['Y', 'N'], // true ,false
|
||||
defaultChecked: false,
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
type: JVxeTypes.slot,
|
||||
fixed: 'right',
|
||||
minWidth: 120,
|
||||
align: 'center',
|
||||
slotName: 'myAction',
|
||||
},
|
||||
]);
|
||||
const dataSource = ref<any[]>([]);
|
||||
|
||||
/* 随机生成数据 */
|
||||
function randomPage(current, pageSize, isLoading = false) {
|
||||
if (isLoading) {
|
||||
loading.value = true;
|
||||
}
|
||||
|
||||
let randomDatetime = () => {
|
||||
let time = random(1000, 9999999999999);
|
||||
return dayjs(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: any[] = [];
|
||||
for (let i = 0; i < pageSize; i++) {
|
||||
values.push({
|
||||
id: buildUUID(),
|
||||
noEdit: `noEdit-${limit + i + 1}`,
|
||||
input: `text-${limit + i + 1}`,
|
||||
textarea: `textarea-${limit + i + 1}`,
|
||||
number: random(0, 233),
|
||||
select: options[random(0, 3)],
|
||||
select_dict: random(1, 2).toString(),
|
||||
select_multiple: (() => {
|
||||
let length = random(1, 4);
|
||||
let arr = [];
|
||||
for (let j = 0; j < length; j++) {
|
||||
pushIfNotExist(arr, options[random(0, 3)]);
|
||||
}
|
||||
return arr.join(',');
|
||||
})(),
|
||||
select_search: options[random(0, 3)],
|
||||
datetime: randomDatetime(),
|
||||
checkbox: ['Y', 'N'][random(0, 1)],
|
||||
});
|
||||
}
|
||||
|
||||
dataSource.value = values;
|
||||
let end = Date.now();
|
||||
let diff = end - begin;
|
||||
|
||||
if (isLoading && diff < pageSize) {
|
||||
setTimeout(() => (loading.value = false), pageSize - diff);
|
||||
}
|
||||
}
|
||||
|
||||
randomPage(0, 20, true);
|
||||
|
||||
function onLookRow(props) {
|
||||
createMessage.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 });
|
||||
}
|
||||
|
||||
// async function onDeleteRow(props) {
|
||||
// // 同步调用删除方法
|
||||
// const res = await tableRef.value?.removeRows(props.row);
|
||||
// if (res && res.rows.length > 0) {
|
||||
// createMessage.success('删除成功');
|
||||
// }
|
||||
// }
|
||||
|
||||
async function onDeleteRow(props) {
|
||||
// 异步调用删除方法
|
||||
const res = await tableRef.value?.removeRows(props.row, true);
|
||||
console.log('删除成功~', res);
|
||||
}
|
||||
|
||||
function handleValueChange(event) {
|
||||
console.log('handleValueChange.event: ', event);
|
||||
}
|
||||
|
||||
// update-begin--author:liaozhiyang---date:20230817---for:【issues/636】JVxeTable加上blur事件
|
||||
function handleBlur(event){
|
||||
console.log("blur",event);
|
||||
}
|
||||
// update-end--author:liaozhiyang---date:20230817---for:【issues/636】JVxeTable加上blur事件
|
||||
/** 表单验证 */
|
||||
function handleTableCheck() {
|
||||
tableRef.value!.validateTable().then((errMap) => {
|
||||
if (errMap) {
|
||||
console.log('表单验证未通过:', { errMap });
|
||||
createMessage.error('验证未通过,请在控制台查看详细');
|
||||
} else {
|
||||
createMessage.success('验证通过');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/** 获取值,忽略表单验证 */
|
||||
function onGetData() {
|
||||
const values = tableRef.value!.getTableData();
|
||||
console.log('获取值:', { values });
|
||||
createMessage.success('获取值成功,请看控制台输出');
|
||||
}
|
||||
|
||||
/** 模拟加载1000条数据 */
|
||||
function handleTableSet() {
|
||||
randomPage(1, 1000, true);
|
||||
}
|
||||
|
||||
function onDelFirst() {
|
||||
const xTable = tableRef.value!.getXTable();
|
||||
const record = xTable.getTableData().fullData[0];
|
||||
tableRef.value!.removeRows(record);
|
||||
}
|
||||
|
||||
function onDelSel() {
|
||||
const xTable = tableRef.value!.getXTable();
|
||||
xTable.removeCheckboxRow();
|
||||
}
|
||||
|
||||
function onGetSelData() {
|
||||
createMessage.info('请看控制台');
|
||||
console.log(tableRef.value!.getSelectionData());
|
||||
}
|
||||
|
||||
function onClearSel() {
|
||||
tableRef.value!.clearSelection();
|
||||
}
|
||||
|
||||
function onToggleLoading() {
|
||||
loading.value = !loading.value;
|
||||
}
|
||||
|
||||
function onToggleDisabled() {
|
||||
disabled.value = !disabled.value;
|
||||
}
|
||||
|
||||
function doDelete(deleteRows) {
|
||||
let rowId;
|
||||
return new Promise((resolve) => {
|
||||
if (Array.isArray(deleteRows)) {
|
||||
rowId = deleteRows.filter((row) => row.id);
|
||||
} else {
|
||||
rowId = deleteRows.id;
|
||||
}
|
||||
console.log('删除 rowId: ', rowId);
|
||||
setTimeout(() => resolve(true), 1500);
|
||||
});
|
||||
}
|
||||
|
||||
/** 异步删除示例 */
|
||||
async function onJVxeRemove(event) {
|
||||
const hideLoading = createMessage.loading('删除中…', 0);
|
||||
try {
|
||||
// 1. 向后台传递 event.deleteRows 以删除
|
||||
let flag = await doDelete(event.deleteRows);
|
||||
if (flag) {
|
||||
// 注:如果启用了表格的 loading 状态,则必须先停止再删除,否则会导致无法从表格上删除数据
|
||||
// 2. 调用 event.confirmRemove 方法确认删除成功
|
||||
// await tableRef.value!.removeSelection();
|
||||
await event.confirmRemove()
|
||||
createMessage.success('删除成功!');
|
||||
} else {
|
||||
// 3. 若删除失败,不调用 event.confirmRemove() 方法就不会删除数据
|
||||
createMessage.warn('删除失败!');
|
||||
}
|
||||
} finally {
|
||||
hideLoading();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
179
jeecgboot-vue3/src/views/demo/jeecg/JVxeTableDemo/JVxeDemo2.vue
Normal file
179
jeecgboot-vue3/src/views/demo/jeecg/JVxeTableDemo/JVxeDemo2.vue
Normal file
@ -0,0 +1,179 @@
|
||||
<template>
|
||||
<JVxeTable
|
||||
ref="tableRef"
|
||||
toolbar
|
||||
row-number
|
||||
row-selection
|
||||
keep-source
|
||||
:height="492"
|
||||
:loading="loading"
|
||||
:dataSource="dataSource"
|
||||
:columns="columns"
|
||||
:pagination="pagination"
|
||||
style="margin-top: 8px"
|
||||
@pageChange="handlePageChange"
|
||||
>
|
||||
<template #toolbarSuffix>
|
||||
<a-button @click="handleTableGet">获取数据</a-button>
|
||||
</template>
|
||||
</JVxeTable>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { reactive, ref } from 'vue';
|
||||
// noinspection ES6UnusedImports
|
||||
import { Popconfirm } from 'ant-design-vue';
|
||||
import { JVxeColumn, JVxeTableInstance, JVxeTypes } from '/@/components/jeecg/JVxeTable/types';
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
import { random } from 'lodash-es';
|
||||
import { buildUUID } from '/@/utils/uuid';
|
||||
import { uploadUrl } from '/@/api/common/api';
|
||||
|
||||
const tableRef = ref<JVxeTableInstance>();
|
||||
const { createMessage } = useMessage();
|
||||
const loading = ref(false);
|
||||
const columns = ref<JVxeColumn[]>([
|
||||
{
|
||||
title: '下拉框_字典表搜索',
|
||||
key: 'select_dict_search',
|
||||
type: JVxeTypes.selectDictSearch,
|
||||
width: 200,
|
||||
async: true, // 异步搜索,默认为 true
|
||||
// 字典表配置信息:数据库表名,显示字段名,存储字段名
|
||||
dict: 'sys_user,realname,username',
|
||||
tipsContent: '请输入查询条件',
|
||||
},
|
||||
{
|
||||
title: 'JPopup',
|
||||
key: 'popup',
|
||||
type: JVxeTypes.popup,
|
||||
width: 180,
|
||||
popupCode: 'demo',
|
||||
// field: 'name,sex,age',
|
||||
// orgFields: 'name,sex,age',
|
||||
// destFields: 'popup,popup_sex,popup_age',
|
||||
fieldConfig: [
|
||||
{ source: 'name', target: 'popup' },
|
||||
{ source: 'sex', target: 'popup_sex' },
|
||||
{ source: 'age', target: 'popup_age' },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'JP-性别',
|
||||
key: 'popup_sex',
|
||||
type: JVxeTypes.select,
|
||||
dictCode: 'sex',
|
||||
disabled: true,
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: 'JP-年龄',
|
||||
key: 'popup_age',
|
||||
type: JVxeTypes.normal,
|
||||
width: 80,
|
||||
},
|
||||
{
|
||||
title: '用户选择',
|
||||
key: 'userSelect',
|
||||
type: JVxeTypes.userSelect,
|
||||
width: 240,
|
||||
},
|
||||
{
|
||||
title: '部门选择',
|
||||
key: 'departSelect',
|
||||
type: JVxeTypes.departSelect,
|
||||
width: 240,
|
||||
},
|
||||
{
|
||||
title: '单选',
|
||||
key: 'radio',
|
||||
type: JVxeTypes.radio,
|
||||
width: 130,
|
||||
options: [
|
||||
{ text: '男', value: '1' },
|
||||
{ text: '女', value: '2' },
|
||||
],
|
||||
// 允许清除选择(再点一次取消选择)
|
||||
allowClear: false,
|
||||
},
|
||||
{
|
||||
title: '上传',
|
||||
key: 'upload',
|
||||
type: JVxeTypes.upload,
|
||||
width: 180,
|
||||
btnText: '点击上传',
|
||||
token: true,
|
||||
responseName: 'message',
|
||||
action: uploadUrl,
|
||||
},
|
||||
{
|
||||
title: '图片上传',
|
||||
key: 'image',
|
||||
type: JVxeTypes.image,
|
||||
width: 180,
|
||||
maxCount: 6,
|
||||
},
|
||||
{
|
||||
title: '文件上传',
|
||||
key: 'file',
|
||||
type: JVxeTypes.file,
|
||||
width: 180,
|
||||
maxCount: 2,
|
||||
},
|
||||
{
|
||||
title: '进度条',
|
||||
key: 'progress',
|
||||
type: JVxeTypes.progress,
|
||||
minWidth: 320,
|
||||
},
|
||||
]);
|
||||
const dataSource = ref<any[]>([]);
|
||||
const pagination = reactive({
|
||||
current: 1,
|
||||
pageSize: 10,
|
||||
pageSizeOptions: ['10', '20', '30', '100', '200'],
|
||||
total: 1000,
|
||||
});
|
||||
|
||||
randomPage(pagination.current, pagination.pageSize, true);
|
||||
|
||||
// 当分页参数变化时触发的事件
|
||||
function handlePageChange(event) {
|
||||
// 重新赋值
|
||||
pagination.current = event.current;
|
||||
pagination.pageSize = event.pageSize;
|
||||
// 查询数据
|
||||
randomPage(event.current, event.pageSize, true);
|
||||
}
|
||||
|
||||
/** 获取值,忽略表单验证 */
|
||||
function handleTableGet() {
|
||||
const values = tableRef.value!.getTableData();
|
||||
console.log('获取值:', { values });
|
||||
createMessage.success('获取值成功,请看控制台输出');
|
||||
}
|
||||
|
||||
/* 随机生成分页数据 */
|
||||
function randomPage(current, pageSize, $loading = false) {
|
||||
if ($loading) {
|
||||
loading.value = true;
|
||||
}
|
||||
let begin = Date.now();
|
||||
let values: any[] = [];
|
||||
for (let i = 0; i < pageSize; i++) {
|
||||
let radio = random(0, 2);
|
||||
values.push({
|
||||
id: buildUUID(),
|
||||
select_dict_search: ['admin', '', 'jeecg'][random(0, 2)],
|
||||
progress: random(0, 100),
|
||||
radio: radio ? radio.toString() : null,
|
||||
});
|
||||
}
|
||||
dataSource.value = values;
|
||||
let end = Date.now();
|
||||
let diff = end - begin;
|
||||
if ($loading && diff < pageSize) {
|
||||
setTimeout(() => (loading.value = false), pageSize - diff);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
129
jeecgboot-vue3/src/views/demo/jeecg/JVxeTableDemo/JVxeDemo3.vue
Normal file
129
jeecgboot-vue3/src/views/demo/jeecg/JVxeTableDemo/JVxeDemo3.vue
Normal file
@ -0,0 +1,129 @@
|
||||
<template>
|
||||
<div>
|
||||
<ol style="border: 1px solid #cccccc; width: 600px; padding: 8px">
|
||||
<li>1. 开启 dragSort 属性之后即可实现上下拖拽排序。</li>
|
||||
<li>2. 使用 sortKey 属性可以自定义排序保存的 key,默认为 orderNum。</li>
|
||||
<li>3. 使用 sortBegin 属性可以自定义排序的起始值,默认为 0。</li>
|
||||
<li>4. sortKey 定义的字段不需要定义在 columns 中也能正常获取到值。</li>
|
||||
<li>5. 当存在 fixed 列时,拖拽排序将会失效,仅能上下排序。</li>
|
||||
</ol>
|
||||
|
||||
<p> 以下示例开启了拖拽排序,排序值保存字段为 sortNum,排序起始值为 3<br /> </p>
|
||||
|
||||
<JVxeTable
|
||||
ref="tableRef1"
|
||||
toolbar
|
||||
dragSort
|
||||
sortKey="sortNum"
|
||||
:sortBegin="3"
|
||||
rowSelection
|
||||
dragSortFixed="none"
|
||||
rowSelectionFixed="none"
|
||||
:maxHeight="580"
|
||||
:columns="table1.columns"
|
||||
:dataSource="table1.data"
|
||||
>
|
||||
<template #toolbarSuffix>
|
||||
<a-button @click="onGetData1">获取数据</a-button>
|
||||
</template>
|
||||
</JVxeTable>
|
||||
|
||||
<br />
|
||||
<p>以下 fixed 表格不支持拖拽排序,仅支持点击上下排序</p>
|
||||
|
||||
<JVxeTable ref="tableRef2" toolbar dragSort rowSelection :maxHeight="580" :columns="table2.columns" :dataSource="table2.data">
|
||||
<template #toolbarSuffix>
|
||||
<a-button @click="onGetData2">获取数据</a-button>
|
||||
</template>
|
||||
</JVxeTable>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, reactive } from 'vue';
|
||||
import { JVxeTypes, JVxeColumn, JVxeTableInstance } from '/@/components/jeecg/JVxeTable/types';
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
|
||||
const tableRef1 = ref<JVxeTableInstance>();
|
||||
const tableRef2 = ref<JVxeTableInstance>();
|
||||
const table1 = reactive({
|
||||
columns: [
|
||||
{
|
||||
title: 'ID',
|
||||
key: 'id',
|
||||
width: 120,
|
||||
type: JVxeTypes.normal,
|
||||
},
|
||||
{
|
||||
title: '姓名',
|
||||
key: 'name',
|
||||
width: 240,
|
||||
type: JVxeTypes.input,
|
||||
defaultValue: 'new name',
|
||||
},
|
||||
{
|
||||
title: '字段长度',
|
||||
key: 'dbLength',
|
||||
width: 2400,
|
||||
type: JVxeTypes.inputNumber,
|
||||
defaultValue: 32,
|
||||
},
|
||||
{
|
||||
title: 'sortNum',
|
||||
key: 'sortNum',
|
||||
width: 120,
|
||||
type: JVxeTypes.normal,
|
||||
},
|
||||
] as JVxeColumn[],
|
||||
data: [
|
||||
{ id: 'uuid-0001', name: '张三', dbLength: 123 },
|
||||
{ id: 'uuid-0002', name: '李四', dbLength: 777 },
|
||||
{ id: 'uuid-0003', name: '王五', dbLength: 666 },
|
||||
{ id: 'uuid-0004', name: '赵六', dbLength: 233 },
|
||||
],
|
||||
});
|
||||
|
||||
const table2 = reactive({
|
||||
columns: [
|
||||
{
|
||||
title: 'ID',
|
||||
key: 'id',
|
||||
width: 320,
|
||||
fixed: 'left',
|
||||
type: JVxeTypes.normal,
|
||||
},
|
||||
{
|
||||
title: '姓名',
|
||||
key: 'name',
|
||||
width: 720,
|
||||
type: JVxeTypes.input,
|
||||
defaultValue: 'new name',
|
||||
},
|
||||
{
|
||||
title: '字段长度',
|
||||
key: 'dbLength',
|
||||
width: 720,
|
||||
type: JVxeTypes.inputNumber,
|
||||
defaultValue: 32,
|
||||
},
|
||||
] as JVxeColumn[],
|
||||
data: [
|
||||
{ id: 'uuid-0001', name: '张三', dbLength: 123 },
|
||||
{ id: 'uuid-0002', name: '李四', dbLength: 777 },
|
||||
{ id: 'uuid-0003', name: '王五', dbLength: 666 },
|
||||
{ id: 'uuid-0004', name: '赵六', dbLength: 233 },
|
||||
],
|
||||
});
|
||||
|
||||
const { createMessage } = useMessage();
|
||||
|
||||
function onGetData1() {
|
||||
createMessage.info('请看控制台');
|
||||
console.log(tableRef1.value!.getTableData());
|
||||
}
|
||||
|
||||
function onGetData2() {
|
||||
createMessage.info('请看控制台');
|
||||
console.log(tableRef2.value!.getTableData());
|
||||
}
|
||||
</script>
|
||||
153
jeecgboot-vue3/src/views/demo/jeecg/JVxeTableDemo/JVxeDemo4.vue
Normal file
153
jeecgboot-vue3/src/views/demo/jeecg/JVxeTableDemo/JVxeDemo4.vue
Normal file
@ -0,0 +1,153 @@
|
||||
<template>
|
||||
<JVxeTable
|
||||
ref="vTable"
|
||||
toolbar
|
||||
rowNumber
|
||||
rowSelection
|
||||
:maxHeight="580"
|
||||
:dataSource="dataSource"
|
||||
:columns="columns"
|
||||
:linkageConfig="linkageConfig"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
import { defHttp } from '/@/utils/http/axios';
|
||||
import { JVxeTypes, JVxeColumn, JVxeLinkageConfig } from '/@/components/jeecg/JVxeTable/types';
|
||||
|
||||
// 联动配置
|
||||
const linkageConfig = ref<JVxeLinkageConfig[]>([
|
||||
{ requestData: requestMockData, key: 's1' },
|
||||
// 可配置多个联动
|
||||
{ requestData: requestMenu, key: 'menu1' },
|
||||
]);
|
||||
|
||||
const columns = ref<JVxeColumn[]>([
|
||||
{
|
||||
title: '性别',
|
||||
key: 'sex',
|
||||
type: JVxeTypes.select,
|
||||
dictCode: 'sex',
|
||||
width: '180px',
|
||||
placeholder: '请选择${title}',
|
||||
},
|
||||
{
|
||||
title: '省/直辖市/自治区',
|
||||
key: 's1',
|
||||
type: JVxeTypes.select,
|
||||
width: '180px',
|
||||
placeholder: '请选择${title}',
|
||||
// 联动字段(即下一级的字段)
|
||||
linkageKey: 's2',
|
||||
},
|
||||
{
|
||||
title: '市',
|
||||
key: 's2',
|
||||
type: JVxeTypes.select,
|
||||
width: '180px',
|
||||
placeholder: '请选择${title}',
|
||||
// 联动字段(即下一级的字段)
|
||||
linkageKey: 's3',
|
||||
},
|
||||
{
|
||||
title: '县/区',
|
||||
key: 's3',
|
||||
type: JVxeTypes.select,
|
||||
width: '180px',
|
||||
options: [],
|
||||
placeholder: '请选择${title}',
|
||||
},
|
||||
{
|
||||
title: '一级菜单',
|
||||
key: 'menu1',
|
||||
type: JVxeTypes.select,
|
||||
width: '180px',
|
||||
placeholder: '请选择${title}',
|
||||
// 联动字段(即下一级的字段)
|
||||
linkageKey: 'menu2',
|
||||
},
|
||||
{
|
||||
title: '二级菜单',
|
||||
key: 'menu2',
|
||||
type: JVxeTypes.select,
|
||||
width: '180px',
|
||||
placeholder: '请选择${title}',
|
||||
// 联动字段(即下一级的字段)
|
||||
linkageKey: 'menu3',
|
||||
},
|
||||
{
|
||||
title: '三级菜单',
|
||||
key: 'menu3',
|
||||
type: JVxeTypes.select,
|
||||
width: '180px',
|
||||
placeholder: '请选择${title}',
|
||||
},
|
||||
]);
|
||||
|
||||
const dataSource = ref([
|
||||
{ sex: '1', s1: '110000', s2: '110100', s3: '110101' },
|
||||
{ sex: '2', s1: '130000', s2: '130300', s3: '130303' },
|
||||
]);
|
||||
|
||||
// 模拟数据
|
||||
const mockData = [
|
||||
{ text: '北京市', value: '110000', parent: '' },
|
||||
{ text: '天津市', value: '120000', parent: '' },
|
||||
{ text: '河北省', value: '130000', parent: '' },
|
||||
{ text: '上海市', value: '310000', parent: '' },
|
||||
|
||||
{ text: '北京市', value: '110100', parent: '110000' },
|
||||
{ text: '天津市市', value: '120100', parent: '120000' },
|
||||
{ text: '石家庄市', value: '130100', parent: '130000' },
|
||||
{ text: '唐山市', value: '130200', parent: '130000' },
|
||||
{ text: '秦皇岛市', value: '130300', parent: '130000' },
|
||||
{ text: '上海市', value: '310100', parent: '310000' },
|
||||
|
||||
{ text: '东城区', value: '110101', parent: '110100' },
|
||||
{ text: '西城区', value: '110102', parent: '110100' },
|
||||
{ text: '朝阳区', value: '110105', parent: '110100' },
|
||||
{ text: '和平区', value: '120101', parent: '120100' },
|
||||
{ text: '河东区', value: '120102', parent: '120100' },
|
||||
{ text: '河西区', value: '120103', parent: '120100' },
|
||||
{ text: '黄浦区', value: '310101', parent: '310100' },
|
||||
{ text: '徐汇区', value: '310104', parent: '310100' },
|
||||
{ text: '长宁区', value: '310105', parent: '310100' },
|
||||
{ text: '长安区', value: '130102', parent: '130100' },
|
||||
{ text: '桥西区', value: '130104', parent: '130100' },
|
||||
{ text: '新华区', value: '130105', parent: '130100' },
|
||||
{ text: '路南区', value: '130202', parent: '130200' },
|
||||
{ text: '路北区', value: '130203', parent: '130200' },
|
||||
{ text: '古冶区', value: '130204', parent: '130200' },
|
||||
{ text: '海港区', value: '130302', parent: '130300' },
|
||||
{ text: '山海关区', value: '130303', parent: '130300' },
|
||||
{ text: '北戴河区', value: '130304', parent: '130300' },
|
||||
];
|
||||
|
||||
/** 模拟从后台查询数据 */
|
||||
function requestMockData(parent) {
|
||||
return new Promise((resolve) => {
|
||||
let data = mockData.filter((i) => i.parent === parent);
|
||||
setTimeout(() => resolve(data), 500);
|
||||
});
|
||||
}
|
||||
|
||||
/** 查询后台真实数据 */
|
||||
async function requestMenu(parent) {
|
||||
let result;
|
||||
// 如果parent为空,则查询第一级菜单
|
||||
if (parent === '') {
|
||||
result = await defHttp.get({
|
||||
url: '/sys/permission/getSystemMenuList',
|
||||
params: {},
|
||||
});
|
||||
} else {
|
||||
result = await defHttp.get({
|
||||
url: '/sys/permission/getSystemSubmenu',
|
||||
params: { parentId: parent },
|
||||
});
|
||||
}
|
||||
// 返回的数据里必须包含 value 和 text 字段
|
||||
return result.map((item) => ({ value: item.id, text: item.name }));
|
||||
}
|
||||
</script>
|
||||
129
jeecgboot-vue3/src/views/demo/jeecg/JVxeTableDemo/JVxeDemo5.vue
Normal file
129
jeecgboot-vue3/src/views/demo/jeecg/JVxeTableDemo/JVxeDemo5.vue
Normal file
@ -0,0 +1,129 @@
|
||||
<template>
|
||||
<div>
|
||||
<b>键盘操作快捷键:</b>
|
||||
<div style="border: 1px solid #cccccc; padding: 8px; width: 740px">
|
||||
<pre>
|
||||
F2 | 如果存在,激活单元格为编辑状态
|
||||
Esc | 如果存在,取消单元格编辑状态
|
||||
↑ | 如果存在,则移动到上面的单元格
|
||||
↓ | 如果存在,则移动到下面的单元格
|
||||
← | 如果存在,则移动到左边的单元格
|
||||
→ | 如果存在,则移动到右边的单元格
|
||||
Tab | 如果存在,则移动到右边单元格;如果移动到最后一列,则从下一行开始移到,以此循环
|
||||
Shift + Tab | 如果存在,则移动到左边单元格,如果移动到第一列,则从上一行开始移到,以此循环
|
||||
Enter | 如果存在,取消单元格编辑并移动到下面的单元格
|
||||
Shift + Enter | 如果存在,取消单元格编辑并移动到上面的单元格</pre
|
||||
>
|
||||
</div>
|
||||
|
||||
<JVxeTable ref="tableRef" stripe toolbar rowNumber rowSelection keyboardEdit :columns="columns" :dataSource="dataSource"> </JVxeTable>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { ref, onMounted, nextTick, defineComponent } from 'vue';
|
||||
import { Popconfirm } from 'ant-design-vue';
|
||||
import { JVxeTypes, JVxeColumn, JVxeTableInstance } from '/@/components/jeecg/JVxeTable/types';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'JVxeDemo5',
|
||||
components: { [Popconfirm.name]: Popconfirm },
|
||||
setup() {
|
||||
const tableRef = ref<JVxeTableInstance>();
|
||||
const columns = ref<JVxeColumn[]>([
|
||||
{
|
||||
title: '单行文本',
|
||||
key: 'input',
|
||||
type: JVxeTypes.input,
|
||||
width: 220,
|
||||
defaultValue: '',
|
||||
placeholder: '请输入${title}',
|
||||
},
|
||||
{
|
||||
title: '多行文本',
|
||||
key: 'textarea',
|
||||
type: JVxeTypes.textarea,
|
||||
width: 240,
|
||||
},
|
||||
{
|
||||
title: '数字',
|
||||
key: 'number',
|
||||
type: JVxeTypes.inputNumber,
|
||||
width: 120,
|
||||
defaultValue: 32,
|
||||
},
|
||||
{
|
||||
title: '日期时间',
|
||||
key: 'datetime',
|
||||
type: JVxeTypes.datetime,
|
||||
width: 240,
|
||||
defaultValue: '2019-04-30 14:51:22',
|
||||
placeholder: '请选择',
|
||||
},
|
||||
{
|
||||
title: '时间',
|
||||
key: 'time',
|
||||
type: JVxeTypes.time,
|
||||
width: 220,
|
||||
defaultValue: '14:52:22',
|
||||
placeholder: '请选择',
|
||||
},
|
||||
{
|
||||
title: '下拉框',
|
||||
key: 'select',
|
||||
type: JVxeTypes.select,
|
||||
width: 220,
|
||||
// 下拉选项
|
||||
options: [
|
||||
{ title: 'String', value: 'string' },
|
||||
{ title: 'Integer', value: 'int' },
|
||||
{ title: 'Double', value: 'double' },
|
||||
{ title: 'Boolean', value: 'boolean' },
|
||||
],
|
||||
// allowInput: true,
|
||||
allowSearch: true,
|
||||
placeholder: '请选择',
|
||||
},
|
||||
{
|
||||
title: '复选框',
|
||||
key: 'checkbox',
|
||||
type: JVxeTypes.checkbox,
|
||||
// width: 100,
|
||||
customValue: ['Y', 'N'], // true ,false
|
||||
defaultChecked: false,
|
||||
},
|
||||
]);
|
||||
const dataSource = ref([]);
|
||||
|
||||
function handleView(props) {
|
||||
// 参数介绍:
|
||||
// props.value 当前单元格的值
|
||||
// props.row 当前行的数据
|
||||
// props.rowId 当前行ID
|
||||
// props.rowIndex 当前行下标
|
||||
// props.column 当前列的配置
|
||||
// props.columnIndex 当前列下标
|
||||
// props.$table vxe-table实例,可以调用vxe-table内置方法
|
||||
// props.scrolling 是否正在滚动
|
||||
// props.reloadEffect 是否开启了数据刷新特效
|
||||
// props.triggerChange 触发change事件,用于更改slot的值
|
||||
console.log('props: ', props);
|
||||
}
|
||||
|
||||
function handleDelete({ row }) {
|
||||
// 使用实例:删除当前操作的行
|
||||
tableRef.value?.removeRows(row);
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
console.log(tableRef.value);
|
||||
await nextTick();
|
||||
// 默认添加五行数据
|
||||
tableRef.value!.addRows([{ input: 'input_1' }, { input: 'input_2' }, { input: 'input_3' }, { input: 'input_4' }, { input: 'input_5' }], {
|
||||
setActive: false,
|
||||
});
|
||||
});
|
||||
|
||||
return { tableRef, columns, dataSource, handleView, handleDelete };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
@ -0,0 +1,224 @@
|
||||
<template>
|
||||
<a-card title="即时保存示例" :bordered="false">
|
||||
<!--
|
||||
【即时保存大体思路】:
|
||||
1. JVxeTable 上必须加 keep-source 属性
|
||||
2. 监听 edit-closed事件,这个事件是在编辑完成后触发
|
||||
3. 在这个事件里面判断数据是否更改,如果更改了就调用接口进行保存操作
|
||||
-->
|
||||
<JVxeTable
|
||||
toolbar
|
||||
:toolbarConfig="toolbarConfig"
|
||||
rowNumber
|
||||
rowSelection
|
||||
keepSource
|
||||
asyncRemove
|
||||
:height="340"
|
||||
:loading="loading"
|
||||
:columns="columns"
|
||||
:dataSource="dataSource"
|
||||
:pagination="pagination"
|
||||
@save="handleTableSave"
|
||||
@removed="handleTableRemove"
|
||||
@edit-closed="handleEditClosed"
|
||||
@pageChange="handlePageChange"
|
||||
@selectRowChange="handleSelectRowChange"
|
||||
/>
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
// 即时保存示例
|
||||
import { reactive, ref } from 'vue';
|
||||
import { defHttp } from '/@/utils/http/axios';
|
||||
import { JVxeColumn, JVxeTypes } from '/@/components/jeecg/JVxeTable/types';
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
|
||||
const { createMessage } = useMessage();
|
||||
// 工具栏的按钮配置
|
||||
const toolbarConfig = reactive({
|
||||
// add 新增按钮;remove 删除按钮;clearSelection 清空选择按钮
|
||||
btn: ['add', 'save', 'remove', 'clearSelection'],
|
||||
});
|
||||
// 是否正在加载
|
||||
const loading = ref(false);
|
||||
// 分页器参数
|
||||
const pagination = reactive({
|
||||
// 当前页码
|
||||
current: 1,
|
||||
// 每页的条数
|
||||
pageSize: 200,
|
||||
// 可切换的条数
|
||||
pageSizeOptions: ['10', '20', '30', '100', '200'],
|
||||
// 数据总数(目前并不知道真实的总数,所以先填写0,在后台查出来后再赋值)
|
||||
total: 0,
|
||||
});
|
||||
// 选择的行
|
||||
const selectedRows = ref<Recordable[]>([]);
|
||||
// 数据源,控制表格的数据
|
||||
const dataSource = ref<Recordable[]>([]);
|
||||
// 列配置,控制表格显示的列
|
||||
const columns = ref<JVxeColumn[]>([
|
||||
{ key: 'num', title: '序号', width: 80, type: JVxeTypes.normal },
|
||||
{
|
||||
// 字段key,跟后台数据的字段名匹配
|
||||
key: 'ship_name',
|
||||
// 列的标题
|
||||
title: '船名',
|
||||
// 列的宽度
|
||||
width: 180,
|
||||
// 如果加上了该属性,就代表当前单元格是可编辑的,type就是表单的类型,input就是简单的输入框
|
||||
type: JVxeTypes.input,
|
||||
},
|
||||
{ key: 'call', title: '呼叫', width: 80, type: JVxeTypes.input },
|
||||
{ key: 'len', title: '长', width: 80, type: JVxeTypes.input },
|
||||
{ key: 'ton', title: '吨', width: 120, defaultValue: 233, type: JVxeTypes.input },
|
||||
{ key: 'payer', title: '付款方', width: 120, defaultValue: '张三', type: JVxeTypes.input },
|
||||
{ key: 'count', title: '数', width: 40, type: JVxeTypes.normal },
|
||||
{
|
||||
key: 'company',
|
||||
title: '公司',
|
||||
// 最小宽度,与宽度不同的是,这个不是固定的宽度,如果表格有多余的空间,会平均分配给设置了 minWidth 的列
|
||||
// 如果要做占满表格的列可以这么写
|
||||
minWidth: 180,
|
||||
type: JVxeTypes.input,
|
||||
},
|
||||
{ key: 'trend', title: '动向', width: 120, type: JVxeTypes.input },
|
||||
]);
|
||||
|
||||
// 查询url地址
|
||||
enum Api {
|
||||
getData = '/mock/vxe/getData',
|
||||
// 模拟保存单行数据(即时保存)
|
||||
saveRow = '/mock/vxe/immediateSaveRow',
|
||||
// 模拟保存整个表格的数据
|
||||
saveAll = '/mock/vxe/immediateSaveAll',
|
||||
}
|
||||
|
||||
loadData();
|
||||
|
||||
// 加载数据
|
||||
async function loadData() {
|
||||
loading.value = true;
|
||||
// 调用查询数据接口
|
||||
await defHttp
|
||||
.get({
|
||||
// 请求地址
|
||||
url: Api.getData,
|
||||
// 封装查询条件
|
||||
params: {
|
||||
pageNo: pagination.current,
|
||||
pageSize: pagination.pageSize,
|
||||
},
|
||||
})
|
||||
.then((result) => {
|
||||
// 后台查询回来的 total,数据总数量
|
||||
pagination.total = result.total;
|
||||
// 将查询的数据赋值给 dataSource
|
||||
dataSource.value = result.records;
|
||||
// 重置选择
|
||||
selectedRows.value = [];
|
||||
})
|
||||
.finally(() => {
|
||||
// 这里是无论成功或失败都会执行的方法,在这里关闭loading
|
||||
loading.value = false;
|
||||
});
|
||||
}
|
||||
|
||||
// 【整体保存】点击保存按钮时触发的事件
|
||||
function 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);
|
||||
// 【模拟保存】
|
||||
loading.value = true;
|
||||
defHttp
|
||||
.post({
|
||||
url: Api.saveAll,
|
||||
params: tableData,
|
||||
})
|
||||
.then(() => {
|
||||
createMessage.success(`保存成功!`);
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 触发单元格删除事件
|
||||
function handleTableRemove(event) {
|
||||
// 把 event.deleteRows 传给后台进行删除(注意:这里不会传递前端逻辑新增的数据,因为不需要请求后台删除)
|
||||
console.log('待删除的数据: ', event.deleteRows);
|
||||
// 也可以只传ID,因为可以根据ID删除
|
||||
let deleteIds = event.deleteRows.map((row) => row.id);
|
||||
console.log('待删除的数据ids: ', deleteIds);
|
||||
|
||||
// 模拟请求后台删除
|
||||
loading.value = true;
|
||||
window.setTimeout(() => {
|
||||
loading.value = false;
|
||||
createMessage.success('删除成功');
|
||||
// 假设后台返回删除成功,必须要调用 confirmRemove() 方法,才会真正在表格里移除(会同时删除选中的逻辑新增的数据)
|
||||
event.confirmRemove();
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
// 单元格编辑完成之后触发的事件
|
||||
function handleEditClosed(event) {
|
||||
let { $table, row, column } = event;
|
||||
let field = column.property;
|
||||
// 判断单元格值是否被修改
|
||||
if ($table.isUpdateByRow(row, field)) {
|
||||
// 校验当前行
|
||||
$table.validate(row).then((errMap) => {
|
||||
// 校验通过
|
||||
if (!errMap) {
|
||||
// 【模拟保存】
|
||||
let hideLoading = createMessage.loading(`正在保存"${column.title}"`, 0);
|
||||
console.log('即时保存数据:', row);
|
||||
defHttp
|
||||
.put({
|
||||
url: Api.saveRow,
|
||||
params: row,
|
||||
})
|
||||
.then((res) => {
|
||||
createMessage.success(`"${column.title}"保存成功!`);
|
||||
// 局部更新单元格为已保存状态
|
||||
$table.reloadRow(row, null, field);
|
||||
})
|
||||
.finally(() => {
|
||||
hideLoading();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 当分页参数变化时触发的事件
|
||||
function handlePageChange(event) {
|
||||
// 重新赋值
|
||||
pagination.current = event.current;
|
||||
pagination.pageSize = event.pageSize;
|
||||
// 查询数据
|
||||
loadData();
|
||||
}
|
||||
|
||||
// 当选择的行变化时触发的事件
|
||||
function handleSelectRowChange(event) {
|
||||
selectedRows.value = event.selectedRows;
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
@ -0,0 +1,244 @@
|
||||
<template>
|
||||
<a-card title="弹出子表示例" :bordered="false">
|
||||
<!--
|
||||
【弹出子表大体思路】
|
||||
1. 必须要有 clickRowShowSubForm 属性,如果该属性设为false,那么就不会弹出子表
|
||||
2. 必须要有 subForm 插槽,用于规定弹出子表的内容
|
||||
3. highlightCurrentRow 属性可有可无,如果有则点击一行的时候,该行会背景色会常亮
|
||||
-->
|
||||
<!--
|
||||
【弹出详细信息大体思路】
|
||||
1. 必须要有 clickRowShowMainForm 属性,如果该属性设为false,那么就不会弹出详细信息
|
||||
2. 必须要有 mainForm 插槽,用于规定弹出的内容
|
||||
-->
|
||||
<JVxeTable
|
||||
toolbar
|
||||
rowNumber
|
||||
rowSelection
|
||||
highlightCurrentRow
|
||||
clickRowShowSubForm
|
||||
clickRowShowMainForm
|
||||
:height="750"
|
||||
:loading="loading"
|
||||
:columns="columns"
|
||||
:dataSource="dataSource"
|
||||
@detailsConfirm="handleDetailsConfirm"
|
||||
>
|
||||
<!-- 主表单 -->
|
||||
<template #mainForm="{ row }">
|
||||
<template v-if="row">
|
||||
<a-form ref="form2" :model="row" :rules="rules" :label-col="labelCol" :wrapper-col="wrapperCol">
|
||||
<a-row :gutter="8">
|
||||
<a-col :span="8">
|
||||
<a-form-item label="ID" name="id">
|
||||
<a-input v-model:value="row.id" disabled />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="8">
|
||||
<a-form-item label="序号" name="num">
|
||||
<a-input v-model:value="row.num" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="8">
|
||||
<a-form-item label="船名" name="ship_name">
|
||||
<a-input v-model:value="row.ship_name" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="8">
|
||||
<a-form-item label="呼叫" name="call">
|
||||
<a-input v-model:value="row.call" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="8">
|
||||
<a-form-item label="长" name="len">
|
||||
<a-input v-model:value="row.len" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="8">
|
||||
<a-form-item label="吨" name="ton">
|
||||
<a-input v-model:value="row.ton" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="8">
|
||||
<a-form-item label="付款方" name="payer">
|
||||
<a-input v-model:value="row.payer" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="8">
|
||||
<a-form-item label="数" name="count">
|
||||
<a-input v-model:value="row.count" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="8">
|
||||
<a-form-item label="公司" name="company">
|
||||
<a-input v-model:value="row.company" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="8">
|
||||
<a-form-item label="动向" name="trend">
|
||||
<a-input v-model:value="row.trend" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-form>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<!-- 子表单 -->
|
||||
<template #subForm="{ row }">
|
||||
<template v-if="loadSubData(row)">
|
||||
<JVxeTable
|
||||
ref="subFormTable"
|
||||
height="auto"
|
||||
:max-height="350"
|
||||
:loading="subTable.loading"
|
||||
:columns="subTable.columns"
|
||||
:dataSource="subTable.dataSource"
|
||||
/>
|
||||
</template>
|
||||
</template>
|
||||
</JVxeTable>
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
// 弹出子表示例
|
||||
import { reactive, ref } from 'vue';
|
||||
import { defHttp } from '/@/utils/http/axios';
|
||||
import { JVxeColumn, JVxeTypes } from '/@/components/jeecg/JVxeTable/types';
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
|
||||
const { createMessage } = useMessage();
|
||||
const loading = ref(false);
|
||||
const dataSource = ref([]);
|
||||
const columns = ref<JVxeColumn[]>([
|
||||
{ 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' },
|
||||
]);
|
||||
const selectedRows = ref([]);
|
||||
// 子表的信息
|
||||
const subTable = reactive({
|
||||
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 },
|
||||
] as JVxeColumn[],
|
||||
});
|
||||
|
||||
// form表单 col
|
||||
const labelCol = reactive({ span: 4 });
|
||||
const wrapperCol = reactive({ span: 20 });
|
||||
const rules = reactive({
|
||||
num: [{ required: true, message: '必须输入序号' }],
|
||||
});
|
||||
|
||||
// 查询url地址
|
||||
enum Api {
|
||||
getData = '/mock/vxe/getData',
|
||||
}
|
||||
|
||||
loadData();
|
||||
|
||||
// 加载数据
|
||||
function loadData() {
|
||||
// 封装查询条件
|
||||
// 调用查询数据接口
|
||||
loading.value = true;
|
||||
defHttp
|
||||
.get({
|
||||
url: Api.getData,
|
||||
params: {
|
||||
pageNo: 1,
|
||||
pageSize: 30,
|
||||
},
|
||||
})
|
||||
.then((result) => {
|
||||
// 将查询的数据赋值给 dataSource
|
||||
dataSource.value = result.records;
|
||||
// 重置选择
|
||||
selectedRows.value = [];
|
||||
})
|
||||
.finally(() => {
|
||||
// 这里是无论成功或失败都会执行的方法,在这里关闭loading
|
||||
loading.value = false;
|
||||
});
|
||||
}
|
||||
|
||||
// 查询子表数据
|
||||
function loadSubData(row) {
|
||||
if (row) {
|
||||
// 这里一定要做限制,限制不能重复查询,否者会出现死循环
|
||||
if (subTable.currentRowId === row.id) {
|
||||
return true;
|
||||
}
|
||||
subTable.currentRowId = row.id;
|
||||
subTable.loading = true;
|
||||
defHttp
|
||||
.get({
|
||||
url: Api.getData,
|
||||
params: {
|
||||
pageNo: 1,
|
||||
pageSize: 30,
|
||||
parentId: row.id,
|
||||
},
|
||||
})
|
||||
.then((result) => {
|
||||
// 将查询的数据赋值给 dataSource
|
||||
subTable.dataSource = result.records;
|
||||
})
|
||||
.finally(() => {
|
||||
// 这里是无论成功或失败都会执行的方法,在这里关闭loading
|
||||
subTable.loading = false;
|
||||
});
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 详细信息里点了确认按钮
|
||||
function handleDetailsConfirm({ row, $table, callback }) {
|
||||
console.log('保存的数据:', row);
|
||||
// 校验当前行
|
||||
$table.validate(row).then((errMap) => {
|
||||
// 校验通过
|
||||
if (!errMap) {
|
||||
// 校验子表,如果需要的话,可以操作下面这个对象:
|
||||
callback(true);
|
||||
loading.value = true;
|
||||
setTimeout(() => {
|
||||
loading.value = false;
|
||||
createMessage.success('保存成功');
|
||||
}, 1000);
|
||||
} else {
|
||||
callback(false);
|
||||
createMessage.warn('校验失败');
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
@ -0,0 +1,126 @@
|
||||
<template>
|
||||
<a-card title="无痕刷新示例" :bordered="false">
|
||||
<div style="margin-bottom: 8px">
|
||||
<span>启用数据变动特效:</span>
|
||||
<a-switch v-model:checked="reloadEffect" />
|
||||
</div>
|
||||
|
||||
<!--
|
||||
【无痕刷新大体思路】:
|
||||
1. 该功能依赖于【即时保存】功能,请先看即时保存示例
|
||||
2. 必须要有 socket-reload 属性,且设为 true
|
||||
3. 必须要有 socket-key 属性,该属性为当前表格的唯一标识,
|
||||
系统会自动更新所有 socket-key 相同的表格
|
||||
4. 在局部保存 edit-closed 事件中,
|
||||
保存成功后调用 socketSendUpdateRow 方法,将当前 row 传递过去即可 (见第 102 行)
|
||||
-->
|
||||
<JVxeTable
|
||||
ref="tableRef"
|
||||
rowNumber
|
||||
rowSelection
|
||||
keepSource
|
||||
socketReload
|
||||
socketKey="demo-socket-reload"
|
||||
:reloadEffect="reloadEffect"
|
||||
:height="340"
|
||||
:loading="loading"
|
||||
:columns="columns"
|
||||
:dataSource="dataSource"
|
||||
@valueChange="onValueChange"
|
||||
@edit-closed="handleEditClosed"
|
||||
/>
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
// 无痕刷新示例
|
||||
import { ref } from 'vue';
|
||||
import { defHttp } from '/@/utils/http/axios';
|
||||
import { JVxeColumn, JVxeTableInstance, JVxeTypes } from '/@/components/jeecg/JVxeTable/types';
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
|
||||
const { createMessage } = useMessage();
|
||||
const tableRef = ref<JVxeTableInstance>();
|
||||
// 是否启用日历刷新效果
|
||||
const reloadEffect = ref(true);
|
||||
const loading = ref(false);
|
||||
const dataSource = ref<Recordable[]>([]);
|
||||
const columns = ref<JVxeColumn[]>([
|
||||
{ key: 'num', title: '序号', width: 80 },
|
||||
{ key: 'enabled', title: '启用', width: 80, type: JVxeTypes.checkbox },
|
||||
{ key: 'ship_name', title: '船名', width: 180, type: JVxeTypes.input },
|
||||
{ key: 'call', title: '呼叫', width: 80, type: JVxeTypes.input },
|
||||
{ key: 'len', title: '长', width: 80, type: JVxeTypes.input },
|
||||
{ key: 'ton', title: '吨', width: 120, type: JVxeTypes.input },
|
||||
{ key: 'payer', title: '付款方', width: 120, type: JVxeTypes.input },
|
||||
{ key: 'count', title: '数', width: 40 },
|
||||
{ key: 'company', title: '公司', minWidth: 180, type: JVxeTypes.input },
|
||||
{ key: 'trend', title: '动向', width: 120, type: JVxeTypes.input },
|
||||
]);
|
||||
|
||||
// 查询url地址
|
||||
enum Api {
|
||||
getData = '/mock/vxe/getData',
|
||||
}
|
||||
|
||||
loadData();
|
||||
|
||||
// 加载数据
|
||||
function loadData() {
|
||||
loading.value = true;
|
||||
defHttp
|
||||
.get({
|
||||
url: Api.getData,
|
||||
params: { pageNo: 1, pageSize: 200 },
|
||||
})
|
||||
.then((result) => {
|
||||
dataSource.value = result.records;
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
}
|
||||
|
||||
/** 单元格值变化时触发的事件 */
|
||||
function onValueChange(event) {
|
||||
switch (event.type) {
|
||||
// 所有不能触发 editClosed 事件的组件,都需要定义在这里,可以安装你自己的业务需求来完善此处的case
|
||||
case JVxeTypes.radio:
|
||||
case JVxeTypes.checkbox:
|
||||
doSendUpdateRow(event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 单元格编辑完成之后触发的事件
|
||||
function handleEditClosed(event) {
|
||||
doSendUpdateRow(event);
|
||||
}
|
||||
|
||||
// 发送变更行请求
|
||||
function doSendUpdateRow(event) {
|
||||
let { $table, row, column } = event;
|
||||
let field = column.property;
|
||||
// 判断单元格值是否被修改
|
||||
if ($table.isUpdateByRow(row, field)) {
|
||||
// 校验当前行
|
||||
$table.validate(row).then((errMap) => {
|
||||
// 校验通过
|
||||
if (!errMap) {
|
||||
// 【模拟保存】(此处需要替换成真实的请求)
|
||||
let hideLoading = createMessage.loading(`正在保存"${column.title}"`, 0);
|
||||
setTimeout(() => {
|
||||
hideLoading();
|
||||
createMessage.success(`"${column.title}"保存成功!`);
|
||||
// 局部更新单元格为已保存状态
|
||||
$table.reloadRow(row, null, field);
|
||||
// 发送更新消息
|
||||
tableRef.value?.socketSendUpdateRow(row);
|
||||
}, 555);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
40
jeecgboot-vue3/src/views/demo/jeecg/JVxeTableDemo/index.vue
Normal file
40
jeecgboot-vue3/src/views/demo/jeecg/JVxeTableDemo/index.vue
Normal file
@ -0,0 +1,40 @@
|
||||
<template>
|
||||
<PageWrapper>
|
||||
<a-card :bordered="false">
|
||||
<template #title>
|
||||
<span>
|
||||
JVXETable是专门为大数据和各种ERP风格的复杂操作研发的的高性能表格组件,底层采用vxe-table组件,可以完美弥补antd默认table性能不足问题。
|
||||
<a href="https://help.jeecg.com/component/JVxeTable.html">API文档</a>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<a-tabs defaultActiveKey="1">
|
||||
<a-tab-pane tab="基础示例" key="1">
|
||||
<JVxeDemo1 />
|
||||
</a-tab-pane>
|
||||
<a-tab-pane tab="高级示例" key="2">
|
||||
<JVxeDemo2 />
|
||||
</a-tab-pane>
|
||||
<a-tab-pane tab="排序示例" key="3">
|
||||
<JVxeDemo3 />
|
||||
</a-tab-pane>
|
||||
<a-tab-pane tab="联动示例" key="4">
|
||||
<JVxeDemo4 />
|
||||
</a-tab-pane>
|
||||
<a-tab-pane tab="键盘操作" key="5">
|
||||
<JVxeDemo5 />
|
||||
</a-tab-pane>
|
||||
</a-tabs>
|
||||
</a-card>
|
||||
</PageWrapper>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
// noinspection ES6UnusedImports
|
||||
import { PageWrapper } from '/@/components/Page';
|
||||
import JVxeDemo1 from './JVxeDemo1.vue';
|
||||
import JVxeDemo2 from './JVxeDemo2.vue';
|
||||
import JVxeDemo3 from './JVxeDemo3.vue';
|
||||
import JVxeDemo4 from './JVxeDemo4.vue';
|
||||
import JVxeDemo5 from './JVxeDemo5.vue';
|
||||
</script>
|
||||
@ -0,0 +1,319 @@
|
||||
<template>
|
||||
<a-card :bordered="false">
|
||||
<JVxeTable
|
||||
toolbar
|
||||
:toolbarConfig="toolbarConfig"
|
||||
rowNumber
|
||||
rowSelection
|
||||
rowSelectionType="radio"
|
||||
clickSelectRow
|
||||
highlightCurrentRow
|
||||
:height="tableHeight"
|
||||
:loading="table1.loading"
|
||||
:columns="table1.columns"
|
||||
:dataSource="table1.dataSource"
|
||||
:pagination="table1.pagination"
|
||||
:expandConfig="expandConfig"
|
||||
style="margin-bottom: 8px"
|
||||
@pageChange="handleTable1PageChange"
|
||||
@selectRowChange="handleTable1SelectRowChange"
|
||||
></JVxeTable>
|
||||
|
||||
<a-tabs v-show="subTabs.show" :class="{ 'sub-tabs': true, 'un-expand': !subTabs.expand }">
|
||||
<a-tab-pane tab="子表1" key="1">
|
||||
<JVxeTable
|
||||
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 { h } from 'vue';
|
||||
import { defHttp } from '/@/utils/http/axios';
|
||||
import { JVxeTypes } from '/@/components/jeecg/JVxeTable/types';
|
||||
import { Button, Checkbox } from 'ant-design-vue';
|
||||
import { UpOutlined, DownOutlined } from '@ant-design/icons-vue';
|
||||
|
||||
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 = h('span', `${range[0]}-${range[1]} 共 ${total} 条`);
|
||||
// 判断子表是否显示,如果显示就渲染展开收起按钮
|
||||
if (this.subTabs.show) {
|
||||
let expand = h('span', {}, [
|
||||
h(
|
||||
Button,
|
||||
{
|
||||
type: 'link',
|
||||
onClick: this.handleToggleTabs,
|
||||
},
|
||||
() => [this.subTabs.expand ? h(UpOutlined) : h(DownOutlined), h('span', {}, this.subTabs.expand ? '收起' : '展开')]
|
||||
),
|
||||
h(
|
||||
Checkbox,
|
||||
{
|
||||
// h 写法不支持 v-model , 所以需要手动赋值
|
||||
checked: this.subTabs.autoExpand,
|
||||
'onUpdate:checked': (checked) => (this.subTabs.autoExpand = checked),
|
||||
},
|
||||
() => '自动展开'
|
||||
),
|
||||
]);
|
||||
// 返回多个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;
|
||||
defHttp
|
||||
.get({
|
||||
url: this.url.getData,
|
||||
params: formData,
|
||||
})
|
||||
.then((result) => {
|
||||
// 后台查询回来的 total,数据总数量
|
||||
this.table1.pagination.total = result.total;
|
||||
// 将查询的数据赋值给 dataSource
|
||||
this.table1.dataSource = result.records;
|
||||
// 重置选择
|
||||
this.table1.selectedRows = [];
|
||||
})
|
||||
.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;
|
||||
defHttp
|
||||
.get({
|
||||
url: this.url.getData,
|
||||
params: formData,
|
||||
})
|
||||
.then((result) => {
|
||||
// 将查询的数据赋值给 dataSource
|
||||
table2.selectedRows = [];
|
||||
table2.dataSource = result.records;
|
||||
table2.pagination.total = result.total;
|
||||
})
|
||||
.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-nav) {
|
||||
border-color: transparent !important;
|
||||
}
|
||||
|
||||
:deep(.ant-tabs-ink-bar) {
|
||||
background-color: transparent !important;
|
||||
}
|
||||
|
||||
:deep(.ant-tabs-tab) {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,332 @@
|
||||
<template>
|
||||
<a-card :bordered="false">
|
||||
<a-row :gutter="8">
|
||||
<!-- 这里是父级节点 -->
|
||||
<a-col :span="24" style="margin-bottom: 4px">
|
||||
<JVxeTable
|
||||
toolbar
|
||||
rowNumber
|
||||
rowSelection
|
||||
clickSelectRow
|
||||
highlightCurrentRow
|
||||
:radioConfig="{ highlight: false }"
|
||||
:checkboxConfig="{ 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">
|
||||
<JVxeTable
|
||||
toolbar
|
||||
rowNumber
|
||||
rowSelection
|
||||
clickSelectRow
|
||||
highlightCurrentRow
|
||||
:radioConfig="{ highlight: false }"
|
||||
:checkboxConfig="{ highlight: false }"
|
||||
:height="340"
|
||||
:loading="table2.loading"
|
||||
:columns="table2.columns"
|
||||
:dataSource="table2.dataSource"
|
||||
:pagination="table2.pagination"
|
||||
@pageChange="handleTable2PageChange"
|
||||
@selectRowChange="handleTable2SelectRowChange"
|
||||
>
|
||||
</JVxeTable>
|
||||
</a-col>
|
||||
<!-- 这里是孙级节点 -->
|
||||
<a-col :span="12">
|
||||
<JVxeTable
|
||||
toolbar
|
||||
rowNumber
|
||||
rowSelection
|
||||
:height="340"
|
||||
:loading="table3.loading"
|
||||
:columns="table3.columns"
|
||||
:dataSource="table3.dataSource"
|
||||
:pagination="table3.pagination"
|
||||
@pageChange="handleTable3PageChange"
|
||||
>
|
||||
</JVxeTable>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { defHttp } from '/@/utils/http/axios';
|
||||
import { JVxeTypes } from '/@/components/jeecg/JVxeTable/types';
|
||||
|
||||
// 【多种布局模板】上面父、左下子、右下孙
|
||||
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;
|
||||
defHttp
|
||||
.get({
|
||||
url: this.url.getData,
|
||||
params: formData,
|
||||
})
|
||||
.then((result) => {
|
||||
// 后台查询回来的 total,数据总数量
|
||||
this.table1.pagination.total = result.total;
|
||||
// 将查询的数据赋值给 dataSource
|
||||
this.table1.dataSource = result.records;
|
||||
// 重置选择
|
||||
this.table1.selectedRows = [];
|
||||
})
|
||||
.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;
|
||||
defHttp
|
||||
.get({
|
||||
url: this.url.getData,
|
||||
params: formData,
|
||||
})
|
||||
.then((result) => {
|
||||
this.table2.pagination.total = result.total;
|
||||
this.table2.dataSource = result.records;
|
||||
this.table2.selectedRows = [];
|
||||
})
|
||||
.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;
|
||||
defHttp
|
||||
.get({
|
||||
url: this.url.getData,
|
||||
params: formData,
|
||||
})
|
||||
.then((result) => {
|
||||
this.table3.pagination.total = result.total;
|
||||
this.table3.dataSource = result.records;
|
||||
})
|
||||
.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>
|
||||
@ -0,0 +1,249 @@
|
||||
<template>
|
||||
<a-card :bordered="false">
|
||||
<a-row :gutter="8">
|
||||
<!-- 左侧父 -->
|
||||
<a-col :span="12">
|
||||
<JVxeTable
|
||||
toolbar
|
||||
rowNumber
|
||||
rowSelection
|
||||
clickSelectRow
|
||||
highlightCurrentRow
|
||||
:radioConfig="{ highlight: false }"
|
||||
:checkboxConfig="{ 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">
|
||||
<!-- 左侧选择的数据展示在这里 -->
|
||||
<JVxeTable rowNumber :height="375" :columns="table1.columns" :dataSource="table1.selectedRows" style="margin: 52px 0 8px" />
|
||||
|
||||
<!-- 右下子 -->
|
||||
<JVxeTable
|
||||
toolbar
|
||||
rowNumber
|
||||
rowSelection
|
||||
clickSelectRow
|
||||
:height="355"
|
||||
: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 { defHttp } from '/@/utils/http/axios';
|
||||
import { JVxeTypes } from '/@/components/jeecg/JVxeTable/types';
|
||||
|
||||
// 【多种布局模板】 左边选择后,记录选到右侧,右侧是父、子
|
||||
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;
|
||||
defHttp
|
||||
.get({
|
||||
url: this.url.getData,
|
||||
params: formData,
|
||||
})
|
||||
.then((result) => {
|
||||
// 后台查询回来的 total,数据总数量
|
||||
this.table1.pagination.total = result.total;
|
||||
// 将查询的数据赋值给 dataSource
|
||||
this.table1.dataSource = result.records;
|
||||
// 重置选择
|
||||
this.table1.selectedRows = [];
|
||||
})
|
||||
.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;
|
||||
defHttp
|
||||
.get({
|
||||
url: this.url.getData,
|
||||
params: formData,
|
||||
})
|
||||
.then((result) => {
|
||||
this.table2.pagination.total = result.total;
|
||||
this.table2.dataSource = result.records;
|
||||
this.table2.selectedRows = [];
|
||||
})
|
||||
.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>
|
||||
@ -0,0 +1,237 @@
|
||||
<template>
|
||||
<a-card :bordered="false">
|
||||
<a-row :gutter="8">
|
||||
<a-col :span="12">
|
||||
<!-- 左上父 -->
|
||||
<JVxeTable
|
||||
toolbar
|
||||
rowNumber
|
||||
rowSelection
|
||||
clickSelectRow
|
||||
highlightCurrentRow
|
||||
:radioConfig="{ highlight: false }"
|
||||
:checkboxConfig="{ highlight: false }"
|
||||
:height="357"
|
||||
:loading="table1.loading"
|
||||
:columns="table1.columns"
|
||||
:dataSource="table1.dataSource"
|
||||
:pagination="table1.pagination"
|
||||
style="margin-bottom: 8px"
|
||||
@pageChange="handleTable1PageChange"
|
||||
@selectRowChange="handleTable1SelectRowChange"
|
||||
/>
|
||||
|
||||
<!-- 左下子 -->
|
||||
<JVxeTable
|
||||
toolbar
|
||||
rowNumber
|
||||
rowSelection
|
||||
clickSelectRow
|
||||
:height="356"
|
||||
:loading="table2.loading"
|
||||
:columns="table2.columns"
|
||||
:dataSource="table2.dataSource"
|
||||
:pagination="table2.pagination"
|
||||
@pageChange="handleTable2PageChange"
|
||||
/>
|
||||
</a-col>
|
||||
<!-- 左侧父选择的数据展示在这里 -->
|
||||
<a-col :span="12">
|
||||
<JVxeTable rowNumber :height="812" :columns="table1.columns" :dataSource="table1.selectedRows" style="margin-top: 52px" />
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { defHttp } from '/@/utils/http/axios';
|
||||
import { JVxeTypes } from '/@/components/jeecg/JVxeTable/types';
|
||||
|
||||
// 【多种布局模板】左侧上边是主表、下边是子表,右侧是选中数据
|
||||
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;
|
||||
defHttp
|
||||
.get({
|
||||
url: this.url.getData,
|
||||
params: formData,
|
||||
})
|
||||
.then((result) => {
|
||||
// 后台查询回来的 total,数据总数量
|
||||
this.table1.pagination.total = result.total;
|
||||
// 将查询的数据赋值给 dataSource
|
||||
this.table1.dataSource = result.records;
|
||||
})
|
||||
.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;
|
||||
defHttp
|
||||
.get({
|
||||
url: this.url.getData,
|
||||
params: formData,
|
||||
})
|
||||
.then((result) => {
|
||||
this.table2.pagination.total = result.total;
|
||||
this.table2.dataSource = result.records;
|
||||
})
|
||||
.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>
|
||||
@ -0,0 +1,340 @@
|
||||
<template>
|
||||
<a-card :bordered="false">
|
||||
<a-row :gutter="8">
|
||||
<a-col :span="12">
|
||||
<!-- 左上父 -->
|
||||
<JVxeTable
|
||||
toolbar
|
||||
rowNumber
|
||||
rowSelection
|
||||
clickSelectRow
|
||||
highlightCurrentRow
|
||||
:radioConfig="{ highlight: false }"
|
||||
:checkboxConfig="{ highlight: false }"
|
||||
:height="340"
|
||||
:loading="table1.loading"
|
||||
:columns="table1.columns"
|
||||
:dataSource="table1.dataSource"
|
||||
:pagination="table1.pagination"
|
||||
style="margin-bottom: 8px"
|
||||
@pageChange="handleTable1PageChange"
|
||||
@selectRowChange="handleTable1SelectRowChange"
|
||||
/>
|
||||
<!-- 左下子 -->
|
||||
<JVxeTable
|
||||
toolbar
|
||||
rowNumber
|
||||
rowSelection
|
||||
clickSelectRow
|
||||
:height="350"
|
||||
:loading="table2.loading"
|
||||
:columns="table2.columns"
|
||||
:dataSource="table2.dataSource"
|
||||
:pagination="table2.pagination"
|
||||
@pageChange="handleTable2PageChange"
|
||||
/>
|
||||
</a-col>
|
||||
<!-- 左侧父选择的数据展示在这里 -->
|
||||
<a-col :span="12">
|
||||
<!-- 右上父 -->
|
||||
<JVxeTable
|
||||
rowNumber
|
||||
rowSelection
|
||||
clickSelectRow
|
||||
highlightCurrentRow
|
||||
:radioConfig="{ highlight: false }"
|
||||
:checkboxConfig="{ highlight: false }"
|
||||
:height="340"
|
||||
:columns="table1.columns"
|
||||
:dataSource="table1.selectedRows"
|
||||
style="margin: 52px 0 8px"
|
||||
@selectRowChange="handleTable3SelectRowChange"
|
||||
/>
|
||||
<!-- 右下子 -->
|
||||
<JVxeTable
|
||||
toolbar
|
||||
rowNumber
|
||||
rowSelection
|
||||
clickSelectRow
|
||||
: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 { defHttp } from '/@/utils/http/axios';
|
||||
import { JVxeTypes } from '/@/components/jeecg/JVxeTable/types';
|
||||
|
||||
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;
|
||||
defHttp
|
||||
.get({
|
||||
url: this.url.getData,
|
||||
params: formData,
|
||||
})
|
||||
.then((result) => {
|
||||
// 后台查询回来的 total,数据总数量
|
||||
this.table1.pagination.total = result.total;
|
||||
// 将查询的数据赋值给 dataSource
|
||||
this.table1.dataSource = result.records;
|
||||
// 重置选择
|
||||
this.table1.selectedRows = [];
|
||||
})
|
||||
.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;
|
||||
defHttp
|
||||
.get({
|
||||
url: this.url.getData,
|
||||
params: formData,
|
||||
})
|
||||
.then((result) => {
|
||||
this.table2.pagination.total = result.total;
|
||||
this.table2.dataSource = result.records;
|
||||
this.table2.selectedRows = [];
|
||||
})
|
||||
.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;
|
||||
defHttp
|
||||
.get({
|
||||
url: this.url.getData,
|
||||
params: formData,
|
||||
})
|
||||
.then((result) => {
|
||||
this.table4.pagination.total = result.total;
|
||||
this.table4.dataSource = result.records;
|
||||
this.table4.selectedRows = [];
|
||||
})
|
||||
.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>
|
||||
@ -0,0 +1,221 @@
|
||||
<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">
|
||||
<JVxeTable
|
||||
rowNumber
|
||||
rowSelection
|
||||
:height="750"
|
||||
:loading="loading"
|
||||
:columns="columns"
|
||||
:dataSource="dataSource"
|
||||
:pagination="pagination"
|
||||
@pageChange="handleTablePageChange"
|
||||
/>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { defHttp } from '/@/utils/http/axios';
|
||||
import { JVxeTypes } from '/@/components/jeecg/JVxeTable/types';
|
||||
|
||||
// 【多种布局模板】左侧为树,右侧为行编辑
|
||||
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;
|
||||
defHttp
|
||||
.get({
|
||||
url: this.url.getData,
|
||||
params: formData,
|
||||
})
|
||||
.then((result) => {
|
||||
// 后台查询回来的 total,数据总数量
|
||||
this.pagination.total = result.total;
|
||||
// 将查询的数据赋值给 dataSource
|
||||
this.dataSource = result.records;
|
||||
// 重置选择
|
||||
this.selectedRows = [];
|
||||
})
|
||||
.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>
|
||||
@ -0,0 +1,35 @@
|
||||
<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 lang="ts" setup>
|
||||
import Template1 from './Template1.vue';
|
||||
import Template2 from './Template2.vue';
|
||||
import Template3 from './Template3.vue';
|
||||
import Template4 from './Template4.vue';
|
||||
import Template5 from './Template5.vue';
|
||||
import ErpTemplate from './ErpTemplate.vue';
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
157
jeecgboot-vue3/src/views/demo/jeecg/JeecgComponents.vue
Normal file
157
jeecgboot-vue3/src/views/demo/jeecg/JeecgComponents.vue
Normal file
@ -0,0 +1,157 @@
|
||||
<template>
|
||||
<BasicForm
|
||||
ref="formElRef"
|
||||
:class="'jee-select-demo-form'"
|
||||
:labelCol="{ span: 6 }"
|
||||
:wrapperCol="{ span: 14 }"
|
||||
:showResetButton="false"
|
||||
:showSubmitButton="false"
|
||||
:schemas="schemas"
|
||||
:actionColOptions="{ span: 24 }"
|
||||
@submit="handleSubmit"
|
||||
@reset="handleReset"
|
||||
style="height: 100%"
|
||||
>
|
||||
<template #jAreaLinkage="{ model, field }">
|
||||
<JAreaLinkage v-model:value="model[field]" :showArea="true" :showAll="false" />
|
||||
</template>
|
||||
<template #jAreaLinkage1="{ model, field }">
|
||||
<JAreaLinkage :disabled="isDisabledAuth(['demo.dbarray'])" v-model:value="model[field]" :showArea="true" :showAll="false" />
|
||||
</template>
|
||||
<template #JPopup="{ model, field }">
|
||||
<JPopup v-model:value="model[field]" :formElRef="formElRef" code="report_user" :fieldConfig="[{ source: 'username', target: 'pop1' }]" />
|
||||
</template>
|
||||
<template #JAreaSelect="{ model, field }">
|
||||
<JAreaSelect v-model:value="model[field]" />
|
||||
</template>
|
||||
<template #JCheckbox="{ model, field }">
|
||||
<JCheckbox v-model:value="model[field]" dictCode="remindMode" />
|
||||
</template>
|
||||
<template #JInput="{ model, field }">
|
||||
<JInput v-model:value="model[field]" :type="model['jinputtype']" />
|
||||
</template>
|
||||
<template #dargVerify="{ model, field }">
|
||||
<BasicDragVerify v-model:value="model[field]" />
|
||||
</template>
|
||||
<template #superQuery="{ model, field }">
|
||||
<super-query :config="superQueryConfig" @search="(value)=>handleSuperQuery(value, model, field)"/>
|
||||
</template>
|
||||
<template #superQuery1="{ model, field }">
|
||||
<super-query :config="superQueryConfig" @search="(value)=>handleSuperQuery(value, model, field)" :isCustomSave="true" :saveSearchData="saveSearchData" :save="handleSuperQuerySave"/>
|
||||
</template>
|
||||
</BasicForm>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, unref, ref } from 'vue';
|
||||
import { BasicForm, ApiSelect, JAreaLinkage, JPopup, JAreaSelect, FormActionType, JCheckbox, JInput, JEllipsis } from '/@/components/Form';
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
import { optionsListApi } from '/@/api/demo/select';
|
||||
import { useDebounceFn } from '@vueuse/core';
|
||||
import { schemas } from './jeecgComponents.data';
|
||||
import { usePermission } from '/@/hooks/web/usePermission';
|
||||
import { BasicDragVerify } from '/@/components/Verify';
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
BasicForm,
|
||||
ApiSelect,
|
||||
JAreaLinkage,
|
||||
JPopup,
|
||||
JAreaSelect,
|
||||
JCheckbox,
|
||||
JInput,
|
||||
JEllipsis,
|
||||
BasicDragVerify,
|
||||
},
|
||||
name: 'JeecgComponents',
|
||||
setup() {
|
||||
const { isDisabledAuth } = usePermission();
|
||||
const check = ref(null);
|
||||
const formElRef = ref<Nullable<FormActionType>>(null);
|
||||
const { createMessage } = useMessage();
|
||||
const keyword = ref<string>('');
|
||||
const submitButtonOptions = ref({
|
||||
text: '确定',
|
||||
});
|
||||
const searchParams = computed<Recordable>(() => {
|
||||
return { keyword: unref(keyword) };
|
||||
});
|
||||
|
||||
function onSearch(value: string) {
|
||||
keyword.value = value;
|
||||
}
|
||||
|
||||
const superQueryConfig = {
|
||||
name:{ title: "名称", view: "text", type: "string", order: 1 },
|
||||
birthday:{ title: "生日", view: "date", type: "string", order: 2 },
|
||||
age:{ title: "年龄", view: "number", type: "number", order: 4 },
|
||||
sex:{ title: "性别", view: "list", type: "string", dictCode: "sex", order: 5 },
|
||||
bpmStatus:{ title: "流程状态", view: "list_multi", type: "string", dictCode: "bpm_status", order: 6 },
|
||||
}
|
||||
function handleSuperQuery(value, model, field){
|
||||
if(value){
|
||||
let str = decodeURI(value.superQueryParams)
|
||||
console.log(str)
|
||||
model[field] = str
|
||||
}
|
||||
}
|
||||
const saveSearchData = ref([
|
||||
{
|
||||
content: '[{"field":"age","rule":"eq","val":14}]',
|
||||
title: '豆蔻年华',
|
||||
type: 'and',
|
||||
},
|
||||
{
|
||||
content: '[{"field":"name","rule":"eq","val":"张三"}]',
|
||||
title: '项目经理',
|
||||
type: 'and',
|
||||
},
|
||||
]);
|
||||
const handleSuperQuerySave = (data) => {
|
||||
// 高级查询保存后的信息
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
// 模拟接口
|
||||
setTimeout(() => {
|
||||
if (Math.random() > 0.5) {
|
||||
console.log('接口成功~');
|
||||
saveSearchData.value = data;
|
||||
resolve();
|
||||
} else {
|
||||
console.log('接口失败~');
|
||||
reject();
|
||||
}
|
||||
}, 1e3);
|
||||
});
|
||||
}
|
||||
return {
|
||||
schemas,
|
||||
formElRef,
|
||||
isDisabledAuth,
|
||||
optionsListApi,
|
||||
submitButtonOptions,
|
||||
onSearch: useDebounceFn(onSearch, 300),
|
||||
searchParams,
|
||||
superQueryConfig,
|
||||
handleSuperQuery,
|
||||
handleReset: () => {
|
||||
keyword.value = '';
|
||||
},
|
||||
handleSubmit: (values: any) => {
|
||||
console.log('values:', values);
|
||||
createMessage.success('click search,values:' + JSON.stringify(values));
|
||||
},
|
||||
check,
|
||||
handleSuperQuerySave,
|
||||
saveSearchData,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
/**update-begin-author:taoyan date:20220324 for: VUEN-351【vue3】展示不全*/
|
||||
.jee-select-demo-form .ant-col-5 {
|
||||
flex: 0 0 159px;
|
||||
max-width: 159px;
|
||||
}
|
||||
/**update-end-author:taoyan date:20220324 for: VUEN-351【vue3】展示不全*/
|
||||
</style>
|
||||
93
jeecgboot-vue3/src/views/demo/jeecg/JeecgPdfView.vue
Normal file
93
jeecgboot-vue3/src/views/demo/jeecg/JeecgPdfView.vue
Normal file
@ -0,0 +1,93 @@
|
||||
<template>
|
||||
<a-card :bordered="false">
|
||||
<a-row>
|
||||
<!-- 左侧文件树 -->
|
||||
<a-col :span="4" class="clName">
|
||||
<a-tree :treeData="treeData" :defaultExpandAll="true" @select="onSelect" style="height: 500px; overflow-y: auto"> </a-tree>
|
||||
</a-col>
|
||||
<!--右侧缩略图-->
|
||||
<a-col :span="18">
|
||||
<div v-for="(file, key) in dataSource" :key="key">
|
||||
<a-col :span="24">
|
||||
<a-divider orientation="left">{{ file.fileName }}</a-divider>
|
||||
</a-col>
|
||||
<!-- 预览区域 -->
|
||||
<a-col :span="24">
|
||||
<template v-if="file.filePdfPath">
|
||||
<div @click="pdfPreview(file.title)">
|
||||
<img style="width: 80px; height: 80px" src="../../../assets/images/pdf4.jpg" />
|
||||
</div>
|
||||
</template>
|
||||
<template v-else> (暂无材料,点击"选择文件"或"扫描上传"上传文件) </template>
|
||||
</a-col>
|
||||
</div>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<div style="display: none">
|
||||
<iframe id="pdfPreviewIframe" :src="url" frameborder="0" width="100%" height="550px" scrolling="auto"></iframe>
|
||||
</div>
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref, unref, onMounted } from 'vue';
|
||||
import { useGlobSetting } from '/@/hooks/setting';
|
||||
import { getToken } from '/@/utils/auth';
|
||||
|
||||
const mockdata = [
|
||||
{
|
||||
id: '1',
|
||||
key: '1',
|
||||
title: '实例.pdf',
|
||||
fileCode: 'shili',
|
||||
fileName: '实例',
|
||||
filePdfPath: '实例',
|
||||
},
|
||||
];
|
||||
|
||||
export default defineComponent({
|
||||
name: 'JeecgPdfView',
|
||||
setup() {
|
||||
const glob = useGlobSetting();
|
||||
const treeData = ref([
|
||||
{
|
||||
title: '所有PDF电子档',
|
||||
key: '0-0',
|
||||
children: mockdata,
|
||||
},
|
||||
]);
|
||||
const dataSource = ref(mockdata);
|
||||
const allData = ref(mockdata);
|
||||
const url = ref(`${glob.domainUrl}/sys/common/pdf/pdfPreviewIframe`);
|
||||
|
||||
/**
|
||||
* 打开iframe窗口
|
||||
* @param title
|
||||
*/
|
||||
function pdfPreview(title) {
|
||||
let iframe = document.getElementById('pdfPreviewIframe');
|
||||
let json = { title: title, token: getToken() };
|
||||
iframe.contentWindow.postMessage(json, '*');
|
||||
}
|
||||
|
||||
// 选择PDF文件
|
||||
function onSelect(selectedKeys, info) {
|
||||
dataSource.value = [];
|
||||
if (selectedKeys[0] === undefined || selectedKeys[0] === '0-0') {
|
||||
dataSource.value = unref(allData);
|
||||
} else {
|
||||
dataSource.value.push(info.node.dataRef);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
url,
|
||||
dataSource,
|
||||
treeData,
|
||||
allData,
|
||||
onSelect,
|
||||
pdfPreview,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
102
jeecgboot-vue3/src/views/demo/jeecg/Native/less/TableExpand.less
Normal file
102
jeecgboot-vue3/src/views/demo/jeecg/Native/less/TableExpand.less
Normal file
@ -0,0 +1,102 @@
|
||||
/** [表格主题样式一] 表格强制列不换行 */
|
||||
.j-table-force-nowrap {
|
||||
td,
|
||||
th {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.ant-table-selection-column {
|
||||
padding: 12px 22px !important;
|
||||
}
|
||||
|
||||
/** 列自适应,弊端会导致列宽失效 */
|
||||
|
||||
&.ant-table-wrapper .ant-table-content {
|
||||
overflow-x: auto;
|
||||
}
|
||||
}
|
||||
|
||||
/** 查询区域通用样式*/
|
||||
.table-page-search-wrapper {
|
||||
.ant-form-inline {
|
||||
.ant-form-item {
|
||||
display: flex;
|
||||
margin-bottom: 24px;
|
||||
margin-right: 0;
|
||||
|
||||
.ant-form-item-control-wrapper {
|
||||
flex: 1 1;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
> .ant-form-item-label {
|
||||
line-height: 32px;
|
||||
padding-right: 8px;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.ant-form-item-control {
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.table-page-search-submitButtons {
|
||||
display: block;
|
||||
margin-bottom: 24px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
/*列表上方操作按钮区域*/
|
||||
.ant-card-body .table-operator {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
/** Button按钮间距 */
|
||||
.table-operator .ant-btn {
|
||||
margin: 0 8px 8px 0;
|
||||
}
|
||||
|
||||
.table-operator .ant-btn-group .ant-btn {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.table-operator .ant-btn-group .ant-btn:last-child {
|
||||
margin: 0 8px 8px 0;
|
||||
}
|
||||
|
||||
/*列表td的padding设置 可以控制列表大小*/
|
||||
.ant-table-tbody .ant-table-row td {
|
||||
padding-top: 15px;
|
||||
padding-bottom: 15px;
|
||||
}
|
||||
|
||||
/*列表页面弹出modal*/
|
||||
.ant-modal-cust-warp {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/*弹出modal Y轴滚动条*/
|
||||
.ant-modal-cust-warp .ant-modal-body {
|
||||
height: calc(100% - 110px) !important;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
/*弹出modal 先有content后有body 故滚动条控制在body上*/
|
||||
.ant-modal-cust-warp .ant-modal-content {
|
||||
height: 90% !important;
|
||||
overflow-y: hidden;
|
||||
}
|
||||
|
||||
/*列表中有图片的加这个样式 参考用户管理*/
|
||||
.anty-img-wrap {
|
||||
height: 25px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.antd-more a {
|
||||
color: #000000;
|
||||
}
|
||||
419
jeecgboot-vue3/src/views/demo/jeecg/Native/one/OneNativeList.vue
Normal file
419
jeecgboot-vue3/src/views/demo/jeecg/Native/one/OneNativeList.vue
Normal file
@ -0,0 +1,419 @@
|
||||
<template>
|
||||
<a-card :bordered="false">
|
||||
<!-- 操作按钮区域 -->
|
||||
<div class="table-operator">
|
||||
<a-button @click="handleAdd" type="primary" preIcon="ant-design:plus">新增</a-button>
|
||||
<!-- <a-button type="primary" preIcon="ant-design:download" @click="handleExportExcel('单表原生列表')">导出</a-button>-->
|
||||
<!-- <j-upload-button type="primary" preIcon="ant-design:import-outlined" @click="handleImportExcel">导入</j-upload-button>-->
|
||||
<a-dropdown v-if="selectedRowKeys.length > 0">
|
||||
<template #overlay>
|
||||
<a-menu>
|
||||
<a-menu-item key="1" @click="batchDel">
|
||||
<Icon icon="ant-design:delete-outlined"></Icon>
|
||||
删除
|
||||
</a-menu-item>
|
||||
</a-menu>
|
||||
</template>
|
||||
<a-button
|
||||
>批量操作
|
||||
<Icon icon="mdi:chevron-down"></Icon>
|
||||
</a-button>
|
||||
</a-dropdown>
|
||||
</div>
|
||||
|
||||
<!-- table区域-begin -->
|
||||
<div>
|
||||
<div class="ant-alert ant-alert-info" style="margin-bottom: 16px">
|
||||
<i class="anticon anticon-info-circle ant-alert-icon"></i> 已选择 <a style="font-weight: 600">{{ selectedRowKeys.length }}</a
|
||||
>项
|
||||
<a style="margin-left: 24px" @click="onClearSelected">清空</a>
|
||||
</div>
|
||||
|
||||
<a-table
|
||||
ref="table"
|
||||
size="middle"
|
||||
:scroll="{ x: true }"
|
||||
bordered
|
||||
rowKey="id"
|
||||
class="j-table-force-nowrap"
|
||||
:columns="columns"
|
||||
:dataSource="dataSource"
|
||||
:pagination="ipagination"
|
||||
:loading="loading"
|
||||
:rowSelection="{ selectedRowKeys: selectedRowKeys, onChange: onSelectChange }"
|
||||
@change="handleTableChange"
|
||||
>
|
||||
<template #bodyCell="{ column, text, record }">
|
||||
<template v-if="column.dataIndex==='tupian'">
|
||||
<span v-if="!text" style="font-size: 12px; font-style: italic">无图片</span>
|
||||
<img v-else :src="getImgView(text)" :preview="record.id" alt="" class="anty-img-wrap" />
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex==='wenjian'">
|
||||
<span v-if="!text" style="font-size: 12px; font-style: italic">无文件</span>
|
||||
<a-button v-else :ghost="true" type="primary" preIcon="ant-design:download" size="small" @click="downloadFile(text)"> 下载 </a-button>
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex==='action'">
|
||||
<a @click="handleEdit(record)">编辑</a>
|
||||
<a-divider type="vertical" />
|
||||
<a-dropdown>
|
||||
<!-- update-begin--author:liaozhiyang---date:20230803---for:【QQYUN-5838】图标改小保持一致 -->
|
||||
<a class="ant-dropdown-link">更多 <Icon icon="mdi-light:chevron-down"></Icon></a>
|
||||
<!-- update-end--author:liaozhiyang---date:20230803---for:【QQYUN-5838】图标改小保持一致 -->
|
||||
<template #overlay>
|
||||
<a-menu class="antd-more">
|
||||
<a-menu-item>
|
||||
<a @click="handleDetail(record)">详情</a>
|
||||
</a-menu-item>
|
||||
<a-menu-item>
|
||||
<Popconfirm title="确定删除吗?" @confirm="() => handleDelete(record.id)">
|
||||
<a>删除</a>
|
||||
</Popconfirm>
|
||||
</a-menu-item>
|
||||
</a-menu>
|
||||
</template>
|
||||
</a-dropdown>
|
||||
</template>
|
||||
<!-- <template v-else-if="column.dataIndex==='htmlSlot'">
|
||||
<div v-html="text"></div>
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex==='pcaSlot'">
|
||||
<div>{{ getAreaTextByCode(text) }}</div>
|
||||
</template> -->
|
||||
</template>
|
||||
</a-table>
|
||||
</div>
|
||||
<OneNativeModal ref="oneProtogenesisModal" @ok="handleSuccess"></OneNativeModal>
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import '../less/TableExpand.less';
|
||||
import { onMounted, ref, reactive } from 'vue';
|
||||
import { defHttp } from '/@/utils/http/axios';
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
import { filterMultiDictText } from '/@/utils/dict/JDictSelectUtil.js';
|
||||
import { getAreaTextByCode } from '/@/components/Form/src/utils/Area';
|
||||
import OneNativeModal from './components/OneNativeModal.vue';
|
||||
import { Modal, Popconfirm } from 'ant-design-vue';
|
||||
import { JSelectUserByDept, JDictSelectTag, JSelectDept, JSearchSelect } from '/@/components/Form';
|
||||
import Icon from '/@/components/Icon/index';
|
||||
import { filterObj, getFileAccessHttpUrl } from '/@/utils/common/compUtils';
|
||||
import { loadCategoryData } from '/@/api/common/api';
|
||||
import { getToken } from '/@/utils/auth';
|
||||
import { useMethods } from '/@/hooks/system/useMethods';
|
||||
import { downloadFile } from '/@/utils/common/renderUtils';
|
||||
import { initDictOptions } from '/@/utils/dict';
|
||||
|
||||
const { handleExportXls, handleImportXls } = useMethods();
|
||||
const modalVisible = ref<boolean>(false);
|
||||
const queryParam = ref<any>({});
|
||||
const loading = ref<boolean>(false);
|
||||
const dictOptions = ref<any>([]);
|
||||
const oneProtogenesisModal = ref();
|
||||
const tokenHeader = { 'X-Access-Token': getToken() };
|
||||
//表头
|
||||
const columns = ref<any>([
|
||||
{
|
||||
title: '文本',
|
||||
align: 'center',
|
||||
dataIndex: 'name',
|
||||
},
|
||||
{
|
||||
title: '字典下拉',
|
||||
align: 'center',
|
||||
dataIndex: 'xiala',
|
||||
customRender: ({ text }) => (text ? filterMultiDictText(dictOptions.value['xiala'], text) : ''),
|
||||
},
|
||||
{
|
||||
title: '字典单选',
|
||||
align: 'center',
|
||||
dataIndex: 'danxuan',
|
||||
customRender: ({ text }) => (text ? filterMultiDictText(dictOptions.value['danxuan'], text) : ''),
|
||||
},
|
||||
{
|
||||
title: '字典多选',
|
||||
align: 'center',
|
||||
dataIndex: 'duoxuan',
|
||||
customRender: ({ text }) => (text ? filterMultiDictText(dictOptions.value['duoxuan'], text) : ''),
|
||||
},
|
||||
{
|
||||
title: '开关',
|
||||
align: 'center',
|
||||
dataIndex: 'kaiguan',
|
||||
customRender: ({ text }) => (text ? filterMultiDictText(dictOptions.value['kaiguan'], text) : ''),
|
||||
},
|
||||
{
|
||||
title: '日期',
|
||||
align: 'center',
|
||||
dataIndex: 'riqi',
|
||||
customRender: function ({ text }) {
|
||||
return !text ? '' : text.length > 10 ? text.substr(0, 10) : text;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '年月日时分秒',
|
||||
align: 'center',
|
||||
dataIndex: 'nyrsfm',
|
||||
},
|
||||
{
|
||||
title: '时间',
|
||||
align: 'center',
|
||||
dataIndex: 'shijian',
|
||||
},
|
||||
{
|
||||
title: '文件',
|
||||
align: 'center',
|
||||
dataIndex: 'wenjian',
|
||||
},
|
||||
{
|
||||
title: '图片',
|
||||
align: 'center',
|
||||
dataIndex: 'tupian',
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
dataIndex: 'action',
|
||||
align: 'center',
|
||||
fixed: 'right',
|
||||
width: 147,
|
||||
},
|
||||
]);
|
||||
|
||||
const Api = reactive<any>({
|
||||
list: '/test/jeecgDemo/oneNative/list',
|
||||
delete: '/test/jeecgDemo/oneNative/delete',
|
||||
exportXls: '/test/jeecgDemo/oneNative/exportXls',
|
||||
importExcel: 'test/jeecgDemo/oneNative/importExcel',
|
||||
});
|
||||
|
||||
const dataSource = ref<any>([]);
|
||||
const toggleSearchStatus = ref<boolean>(false);
|
||||
const ipagination = ref<any>({
|
||||
current: 1,
|
||||
pageSize: 10,
|
||||
pageSizeOptions: ['10', '20', '30'],
|
||||
showTotal: (total, range) => {
|
||||
return range[0] + '-' + range[1] + ' 共' + total + '条';
|
||||
},
|
||||
showQuickJumper: true,
|
||||
showSizeChanger: true,
|
||||
total: 0,
|
||||
});
|
||||
|
||||
const selectedRowKeys = ref<any>([]);
|
||||
const selectionRows = ref<any>([]);
|
||||
const iSorter = ref<any>({ column: 'createTime', order: 'desc' });
|
||||
const iFilters = ref<any>({});
|
||||
const { createMessage } = useMessage();
|
||||
|
||||
/**
|
||||
* 复选框选中事件
|
||||
* @param rowKeys
|
||||
* @param rows
|
||||
*/
|
||||
function onSelectChange(rowKeys, rows) {
|
||||
selectedRowKeys.value = rowKeys;
|
||||
selectionRows.value = rows;
|
||||
}
|
||||
|
||||
/**
|
||||
* 表格改变事件
|
||||
*/
|
||||
function handleTableChange({ pagination, filters, sorter }) {
|
||||
ipagination.value = pagination;
|
||||
iSorter.value = sorter;
|
||||
iFilters.value = { ...filters };
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增
|
||||
*/
|
||||
function handleAdd() {
|
||||
oneProtogenesisModal.value.disableSubmit = false;
|
||||
oneProtogenesisModal.value.add();
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除选中行
|
||||
*/
|
||||
function onClearSelected() {
|
||||
selectedRowKeys.value = [];
|
||||
selectionRows.value = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除
|
||||
*/
|
||||
function batchDel() {
|
||||
Modal.confirm({
|
||||
title: '确认删除',
|
||||
content: '是否删除选中数据',
|
||||
okText: '确认',
|
||||
cancelText: '取消',
|
||||
onOk: () => {
|
||||
defHttp.delete({ url: Api.delete, data: { ids: selectedRowKeys.value } }, { joinParamsToUrl: true }).then(() => {
|
||||
handleSuccess();
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出excel
|
||||
*/
|
||||
function handleExportExcel(title) {
|
||||
let paramsForm = getQueryParams();
|
||||
if (selectedRowKeys.value && selectedRowKeys.value.length > 0) {
|
||||
paramsForm['selections'] = selectedRowKeys.join(',');
|
||||
}
|
||||
handleExportXls(title, Api.exportXls, filterObj(paramsForm));
|
||||
}
|
||||
|
||||
/**
|
||||
* 导入excel
|
||||
*/
|
||||
function handleImportExcel(file) {
|
||||
handleImportXls(file, Api.importExcel, '').then(() => {
|
||||
handleSuccess();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取查询参数
|
||||
*/
|
||||
function getQueryParams() {
|
||||
let params = Object.assign(queryParam.value, iSorter.value, iFilters.value);
|
||||
params.field = getQueryField();
|
||||
params.pageNo = ipagination.value.current;
|
||||
params.pageSize = ipagination.value.pageSize;
|
||||
return filterObj(params);
|
||||
}
|
||||
|
||||
/**
|
||||
* 字段权限控制
|
||||
*/
|
||||
function getQueryField() {
|
||||
let str = 'id,';
|
||||
columns.value.forEach(function (value) {
|
||||
str += ',' + value.dataIndex;
|
||||
});
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化数据
|
||||
*/
|
||||
function loadData(arg?) {
|
||||
if (arg === 1) {
|
||||
ipagination.value.current = 1;
|
||||
}
|
||||
loading.value = true;
|
||||
let params = getQueryParams();
|
||||
defHttp
|
||||
.get({ url: Api.list, params }, { isTransformResponse: false })
|
||||
.then((res) => {
|
||||
if (res.success) {
|
||||
dataSource.value = res.result.records;
|
||||
if (res.result && res.result.total) {
|
||||
ipagination.value.total = res.result.total;
|
||||
} else {
|
||||
ipagination.value.total = 0;
|
||||
}
|
||||
} else {
|
||||
createMessage.warning(res.message);
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
}
|
||||
|
||||
//查询
|
||||
function searchQuery() {
|
||||
loadData(1);
|
||||
selectedRowKeys.value = [];
|
||||
selectionRows.value = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询区域展开关闭
|
||||
*/
|
||||
function handleToggleSearch() {
|
||||
toggleSearchStatus.value = !toggleSearchStatus.value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置按钮
|
||||
*/
|
||||
function searchReset() {
|
||||
queryParam.value = {};
|
||||
loadData(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取预览图片
|
||||
*/
|
||||
function getImgView(text) {
|
||||
if (text && text.indexOf(',') > 0) {
|
||||
text = text.substring(0, text.indexOf(','));
|
||||
}
|
||||
return getFileAccessHttpUrl(text);
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑
|
||||
* @param record
|
||||
*/
|
||||
function handleEdit(record) {
|
||||
oneProtogenesisModal.value.disableSubmit = false;
|
||||
oneProtogenesisModal.value.edit(record);
|
||||
}
|
||||
|
||||
/**
|
||||
* 详情
|
||||
* @param record
|
||||
*/
|
||||
function handleDetail(record) {
|
||||
oneProtogenesisModal.value.disableSubmit = true;
|
||||
oneProtogenesisModal.value.edit(record);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除
|
||||
* @param id
|
||||
*/
|
||||
function handleDelete(id) {
|
||||
defHttp.delete({ url: Api.delete, data: { ids: id } }, { joinParamsToUrl: true }).then((res) => {
|
||||
handleSuccess();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化字典选项
|
||||
*/
|
||||
async function initDictConfig() {
|
||||
dictOptions.value['flzds'] = await loadCategoryData({ code: 'B01' });
|
||||
dictOptions.value['xiala'] = await initDictOptions('sex');
|
||||
dictOptions.value['danxuan'] = await initDictOptions('sex');
|
||||
dictOptions.value['duoxuan'] = await initDictOptions('urgent_level');
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存表单后回调事件
|
||||
*/
|
||||
function handleSuccess() {
|
||||
selectedRowKeys.value = [];
|
||||
selectionRows.value = [];
|
||||
loadData(1);
|
||||
}
|
||||
onMounted(() => {
|
||||
dictOptions.value['kaiguan'] = [
|
||||
{ text: '是', value: '1' },
|
||||
{ text: '否', value: '2' },
|
||||
];
|
||||
//初始加载页面
|
||||
loadData();
|
||||
//初始化字典选项
|
||||
initDictConfig();
|
||||
});
|
||||
</script>
|
||||
@ -0,0 +1,455 @@
|
||||
<template>
|
||||
<a-spin :spinning="confirmLoading">
|
||||
<a-form class="antd-modal-form" ref="formRef" :model="formState" :rules="validatorRules">
|
||||
<a-row>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="文本" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.name">
|
||||
<a-input v-model:value="formState.name" placeholder="请输入文本"></a-input>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="密码" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.miMa">
|
||||
<a-input-password v-model:value="formState.miMa" placeholder="请输入密码" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="字典下拉" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.xiala">
|
||||
<JDictSelectTag type="select" v-model:value="formState.xiala" dictCode="sex" placeholder="请选择字典下拉" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="字典单选" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.danxuan">
|
||||
<JDictSelectTag type="radio" v-model:value="formState.danxuan" dictCode="sex" placeholder="请选择字典单选" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="字典多选" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.duoxuan">
|
||||
<JCheckbox v-model:value="formState.duoxuan" dictCode="urgent_level" placeholder="请选择字典多选" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="开关" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.kaiguan">
|
||||
<JSwitch v-model:value="formState.kaiguan" :options="['1', '0']"></JSwitch>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="日期" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.riqi">
|
||||
<a-date-picker placeholder="请选择日期" format="YYYY-MM-DD" valueFormat="YYYY-MM-DD" v-model:value="formState.riqi" style="width: 100%" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="年月日时分秒" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.nyrsfm">
|
||||
<a-date-picker show-time v-model:value="formState.nyrsfm" style="width: 100%" valueFormat="YYYY-MM-DD HH:mm:ss" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="时间" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.shijian">
|
||||
<TimePicker placeholder="请选择时间" v-model:value="formState.shijian" style="width: 100%" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="文件" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.wenjian">
|
||||
<JUpload v-model:value="formState.wenjian"></JUpload>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="图片" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.tupian">
|
||||
<JImageUpload :fileMax="2" v-model:value="formState.tupian"></JImageUpload>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="多行文本框" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.dhwb">
|
||||
<a-textarea v-model:value="formState.dhwb" rows="4" placeholder="请输入多行文本框" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="字典表下拉搜索框" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.xlss">
|
||||
<JSearchSelect v-model:value="formState.xlss" dict="sys_user,realname,username" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="popup弹窗" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.popup">
|
||||
<JPopup
|
||||
v-model:value="formState.popup"
|
||||
:fieldConfig="[
|
||||
{ source: 'name', target: 'popup' },
|
||||
{ source: 'id', target: 'popback' },
|
||||
]"
|
||||
code="report_user"
|
||||
:multi="true"
|
||||
:setFieldsValue="setFieldsValue"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="popback" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.popback">
|
||||
<a-input v-model:value="formState.popback" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="分类字典树" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.flzds">
|
||||
<JCategorySelect
|
||||
@change="(value) => handleFormChange('flzds', value)"
|
||||
v-model:value="formState.flzds"
|
||||
pcode="B02"
|
||||
placeholder="请选择分类字典树"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="部门选择" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.bmxz">
|
||||
<JSelectDept v-model:value="formState.bmxz" :multi="true" type="array" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="用户选择" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.yhxz">
|
||||
<JSelectUserByDept v-model:value="formState.yhxz" :multi="true" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="富文本" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.fwb">
|
||||
<JEditor v-model:value="formState.fwb" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="markdown" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.markdownString">
|
||||
<JMarkdownEditor v-model:value="formState.markdownString"></JMarkdownEditor>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="省市区JAreaSelect" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.shq">
|
||||
<JAreaSelect v-model:value="formState.shq" placeholder="请输入省市区" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
|
||||
<a-col :span="24">
|
||||
<a-form-item label="省市区JAreaLinkage" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.jssq">
|
||||
<JAreaLinkage v-model:value="formState.jssq" placeholder="请输入省市区" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
|
||||
<a-col :span="24">
|
||||
<a-form-item label="JInputPop" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.ldzje">
|
||||
<JInputPop
|
||||
v-model:value="formState.ldzje"
|
||||
placeholder="请输入JInputPop"
|
||||
@change="(value) => handleFormChange('ldzje', value)"
|
||||
></JInputPop>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="JSelectInput" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.ldzjs">
|
||||
<JSelectInput
|
||||
v-model:value="formState.ldzjs"
|
||||
placeholder="请选择JSelectInput"
|
||||
:options="ldzjsOptions"
|
||||
@change="(value) => handleFormChange('ldzjs', value)"
|
||||
></JSelectInput>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="下拉多选" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.zddtjxl">
|
||||
<JSelectMultiple v-model:value="formState.zddtjxl" placeholder="请选择下拉多选" dictCode="sex"></JSelectMultiple>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="用户" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.yongHu">
|
||||
<JSelectUser v-model:value="formState.yongHu" placeholder="请选择用户"></JSelectUser>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="职务" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.zhiWu">
|
||||
<JSelectPosition
|
||||
v-model:value="formState.zhiWu"
|
||||
placeholder="请选择职务"
|
||||
@change="(value) => handleFormChange('zhiWu', value)"
|
||||
></JSelectPosition>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="角色" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.jueSe">
|
||||
<JSelectRole v-model:value="formState.jueSe" placeholder="请选择角色" @change="(value) => handleFormChange('jueSe', value)"></JSelectRole>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="自定义树" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.zdys">
|
||||
<JTreeSelect
|
||||
ref="treeSelect"
|
||||
placeholder="请选择自定义树"
|
||||
v-model:value="formState.zdys"
|
||||
dict="sys_category,name,id"
|
||||
pidValue="0"
|
||||
loadTriggleChange
|
||||
>
|
||||
</JTreeSelect>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
|
||||
<a-col :span="24">
|
||||
<a-form-item label="数值" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.yuanjia">
|
||||
<a-input-number v-model:value="formState.yuanjia" placeholder="请输入double类型" style="width: 100%" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="输入2到10位的字母" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.ywzz">
|
||||
<a-input v-model:value="formState.ywzz" placeholder="请输入2到10位的字母"></a-input>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="JTreeDict" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.zdbxl">
|
||||
<JTreeDict
|
||||
v-model:value="formState.zdbxl"
|
||||
placeholder="请选择JTreeDict"
|
||||
@change="(value) => handleFormChange('zdbxl', value)"
|
||||
></JTreeDict>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="JCodeEditor" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.zdmrz">
|
||||
<JCodeEditor
|
||||
v-model:value="formState.zdmrz"
|
||||
placeholder="请输入JCodeEditor"
|
||||
@change="(value) => handleFormChange('zdmrz', value)"
|
||||
></JCodeEditor>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="参数" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.jsonParam">
|
||||
<JAddInput v-model:value="formState.jsonParam" placeholder="参数"></JAddInput>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-form>
|
||||
</a-spin>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, reactive, nextTick } from 'vue';
|
||||
import { defHttp } from '/@/utils/http/axios';
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
import dayjs from 'dayjs';
|
||||
import { TimePicker, Form } from 'ant-design-vue';
|
||||
import JCheckbox from '/@/components/Form/src/jeecg/components/JCheckbox.vue';
|
||||
import JDictSelectTag from '/@/components/Form/src/jeecg/components/JDictSelectTag.vue';
|
||||
import JSwitch from '/@/components/Form/src/jeecg/components/JSwitch.vue';
|
||||
import JUpload from '/@/components/Form/src/jeecg/components/JUpload/JUpload.vue';
|
||||
import JImageUpload from '/@/components/Form/src/jeecg/components/JImageUpload.vue';
|
||||
import JSearchSelect from '/@/components/Form/src/jeecg/components/JSearchSelect.vue';
|
||||
import JPopup from '/@/components/Form/src/jeecg/components/JPopup.vue';
|
||||
import JCategorySelect from '/@/components/Form/src/jeecg/components/JCategorySelect.vue';
|
||||
import JSelectUserByDept from '/@/components/Form/src/jeecg/components/JSelectUserByDept.vue';
|
||||
import JEditor from '/@/components/Form/src/jeecg/components/JEditor.vue';
|
||||
import JMarkdownEditor from '/@/components/Form/src/jeecg/components/JMarkdownEditor.vue';
|
||||
import JTreeSelect from '/@/components/Form/src/jeecg/components/JTreeSelect.vue';
|
||||
import JInputPop from '/@/components/Form/src/jeecg/components/JInputPop.vue';
|
||||
import JSelectInput from '/@/components/Form/src/jeecg/components/JSelectInput.vue';
|
||||
import JSelectPosition from '/@/components/Form/src/jeecg/components/JSelectPosition.vue';
|
||||
import JSelectMultiple from '/@/components/Form/src/jeecg/components/JSelectMultiple.vue';
|
||||
import JInput from '/@/components/Form/src/jeecg/components/JInput.vue';
|
||||
import JSelectDept from '/@/components/Form/src/jeecg/components/JSelectDept.vue';
|
||||
import JSelectUser from '/@/components/Form/src/jeecg/components/JSelectUser.vue';
|
||||
import JAreaSelect from '/@/components/Form/src/jeecg/components/JAreaSelect.vue';
|
||||
import JAreaLinkage from '/@/components/Form/src/jeecg/components/JAreaLinkage.vue';
|
||||
import JSelectRole from '/@/components/Form/src/jeecg/components/JSelectRole.vue';
|
||||
import JTreeDict from '/@/components/Form/src/jeecg/components/JTreeDict.vue';
|
||||
import JCodeEditor from '/@/components/Form/src/jeecg/components/JCodeEditor.vue';
|
||||
import JAddInput from '/@/components/Form/src/jeecg/components/JAddInput.vue';
|
||||
import { getValueType } from '/@/utils';
|
||||
|
||||
const emit = defineEmits(['register', 'ok']);
|
||||
//update-begin---author:wangshuai ---date:20220616 for:报表示例验证修改--------------
|
||||
const formState = reactive<Record<string, any>>({
|
||||
name: '',
|
||||
miMa: '',
|
||||
ywzz: '',
|
||||
xiala: '',
|
||||
danxuan: '',
|
||||
duoxuan: '',
|
||||
riqi: '',
|
||||
shijian: '',
|
||||
wenjian: '',
|
||||
tupian: '',
|
||||
dhwb: '',
|
||||
xlss: '',
|
||||
popup: '',
|
||||
flzds: '',
|
||||
yhxz: '',
|
||||
fwb: '',
|
||||
shq: '',
|
||||
ldzje: '',
|
||||
ldzjs: '',
|
||||
zddtjxl: '',
|
||||
yongHu: '',
|
||||
zhiWu: '',
|
||||
jueSe: '',
|
||||
zdys: '',
|
||||
jssq: '',
|
||||
zdbxl: '',
|
||||
zdmrz: '',
|
||||
jsonParam: '',
|
||||
bmxz: '',
|
||||
yuanjia: '',
|
||||
nyrsfm: '',
|
||||
});
|
||||
//update-end---author:wangshuai ---date:20220616 for:报表示例验证修改--------------
|
||||
const { createMessage } = useMessage();
|
||||
const formRef = ref();
|
||||
const useForm = Form.useForm;
|
||||
const url = reactive<any>({
|
||||
duplicateCheck: '/sys/duplicate/check',
|
||||
add: '/test/jeecgDemo/oneNative/add',
|
||||
edit: '/test/jeecgDemo/oneNative/edit',
|
||||
});
|
||||
const labelCol = ref<any>({ xs: { span: 24 }, sm: { span: 5 } });
|
||||
const wrapperCol = ref<any>({ xs: { span: 24 }, sm: { span: 16 } });
|
||||
const confirmLoading = ref<boolean>(false);
|
||||
//表单验证
|
||||
const validatorRules = {
|
||||
name: [{ required: false, message: '请输入文本!' }],
|
||||
miMa: [{ required: false, message: '请输入密码!' }],
|
||||
ywzz: [{ required: false }, { pattern: '^[a-z|A-Z]{2,10}$', message: '不符合校验规则!' }],
|
||||
xiala: [{ required: false, message: '请选择下拉组件!' }],
|
||||
danxuan: [{ required: false, message: '请选择单选组件!' }],
|
||||
duoxuan: [{ required: false, message: '请选择多选组件!' }],
|
||||
riqi: [{ required: false, message: '请选择日期!' }],
|
||||
shijian: [{ required: false, message: '请选择时间!' }],
|
||||
wenjian: [{ required: false, message: '请上传文件!' }],
|
||||
tupian: [{ required: false, message: '请上传图片!' }],
|
||||
dhwb: [{ required: false, message: '请填写多行文本!' }],
|
||||
xlss: [{ required: false, message: '请选择字典下拉搜索!' }],
|
||||
popup: [{ required: false, message: '请选择popup弹窗!' }],
|
||||
flzds: [{ required: false, message: '请选择分类字典树!' }],
|
||||
yhxz: [{ required: false, message: '请选择用户!' }],
|
||||
fwb: [{ required: false, message: '请填写富文本!' }],
|
||||
shq: [{ required: false, message: '请选择省市级!' }],
|
||||
ldzje: [{ required: false, message: '请输入JInputPop!' }],
|
||||
ldzjs: [{ required: false, message: '请选择下拉输入框!' }],
|
||||
zddtjxl: [{ required: false, message: '请选择多选输入框!' }],
|
||||
yongHu: [{ required: false, message: '请选择用户!' }],
|
||||
zhiWu: [{ required: false, message: '请选择职务!' }],
|
||||
jueSe: [{ required: false, message: '请选择角色!' }],
|
||||
zdys: [{ required: false, message: '请选择自定义树!' }],
|
||||
jssq: [{ required: false, message: '请选择三级联动!' }],
|
||||
zdbxl: [{ required: false, message: '请选择JTreeDict!' }],
|
||||
zdmrz: [{ required: false, message: '请输入JCodeEditor!' }],
|
||||
jsonParam: [{ required: false, message: '请输入参数!' }],
|
||||
bmxz: [{ required: false, message: '请选择部门!' }],
|
||||
yuanjia: [{ required: false, message: '请输入数值!' }],
|
||||
nyrsfm: [{ required: false, message: '请选择年月日时分秒!' }],
|
||||
};
|
||||
//update-begin---author:wangshuai ---date:20220616 for:报表示例验证修改------------
|
||||
const { resetFields, validate, validateInfos } = useForm(formState, validatorRules, { immediate: false });
|
||||
//update-end---author:wangshuai ---date:20220616 for:报表示例验证修改------------
|
||||
const ldzjsOptions = ref([
|
||||
{ label: '男', value: '1' },
|
||||
{ label: '女', value: '2' },
|
||||
]);
|
||||
|
||||
/**
|
||||
* 新增
|
||||
*/
|
||||
function add() {
|
||||
edit({});
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑
|
||||
*/
|
||||
function edit(record) {
|
||||
nextTick(() => {
|
||||
resetFields();
|
||||
//赋值
|
||||
Object.assign(formState, record);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 提交数据
|
||||
*/
|
||||
async function submitForm() {
|
||||
// 触发表单验证
|
||||
//update-begin---author:wangshuai ---date:20220616 for:报表示例验证修改------------
|
||||
await validate();
|
||||
confirmLoading.value = true;
|
||||
let httpurl = '';
|
||||
let method = '';
|
||||
//时间格式化
|
||||
let model = formState;
|
||||
if (!model.id) {
|
||||
httpurl += url.add;
|
||||
method = 'post';
|
||||
} else {
|
||||
httpurl += url.edit;
|
||||
method = 'put';
|
||||
}
|
||||
//循环数据如果是数组
|
||||
for (let data in formState) {
|
||||
//如果该数据是数组并且是字符串类型
|
||||
if (formState[data] instanceof Array) {
|
||||
let valueType = getValueType(formRef.value.getProps, data);
|
||||
//如果是字符串类型的需要变成以逗号分割的字符串
|
||||
if (valueType === 'string') {
|
||||
formState[data] = formState[data].join(',');
|
||||
}
|
||||
}
|
||||
}
|
||||
defHttp
|
||||
.request(
|
||||
{
|
||||
url: httpurl,
|
||||
params: model,
|
||||
method: method,
|
||||
},
|
||||
{ isTransformResponse: false }
|
||||
)
|
||||
.then((res) => {
|
||||
if (res.success) {
|
||||
createMessage.success(res.message);
|
||||
emit('ok');
|
||||
} else {
|
||||
createMessage.warning(res.message);
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
confirmLoading.value = false;
|
||||
});
|
||||
//update-end---author:wangshuai ---date:20220616 for:报表示例验证修改--------------
|
||||
}
|
||||
|
||||
/**
|
||||
* popup成功回调事件
|
||||
*/
|
||||
function popupHandleSuccess(values) {
|
||||
Object.assign(formState, values);
|
||||
}
|
||||
|
||||
/**
|
||||
* popup组件值改变事件
|
||||
*/
|
||||
function setFieldsValue(map) {
|
||||
Object.keys(map).map((key) => {
|
||||
formState[key] = map[key];
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 值改变事件触发
|
||||
* @param key
|
||||
* @param value
|
||||
*/
|
||||
function handleFormChange(key, value) {
|
||||
formState[key] = value;
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
add,
|
||||
edit,
|
||||
submitForm,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.antd-modal-form {
|
||||
padding: 24px 24px 24px 24px;
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,65 @@
|
||||
<template>
|
||||
<BasicModal
|
||||
:title="title"
|
||||
:width="width"
|
||||
:visible="visible"
|
||||
:height="600"
|
||||
@ok="handleOk"
|
||||
:okButtonProps="{ class: { 'jee-hidden': disableSubmit } }"
|
||||
@cancel="handleCancel"
|
||||
cancelText="关闭"
|
||||
>
|
||||
<OneNativeForm ref="realForm" @ok="submitCallback" :disabled="disableSubmit"></OneNativeForm>
|
||||
</BasicModal>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, nextTick } from 'vue';
|
||||
import OneNativeForm from './OneNativeForm.vue';
|
||||
import { BasicModal } from '/@/components/Modal';
|
||||
|
||||
const title = ref<string>('');
|
||||
const width = ref<number>(800);
|
||||
const visible = ref<boolean>(false);
|
||||
const disableSubmit = ref<boolean>(false);
|
||||
const realForm = ref();
|
||||
const emit = defineEmits(['register', 'ok']);
|
||||
|
||||
function add() {
|
||||
title.value = '新增';
|
||||
visible.value = true;
|
||||
nextTick(() => {
|
||||
realForm.value.add();
|
||||
});
|
||||
}
|
||||
|
||||
function edit(record) {
|
||||
title.value = disableSubmit.value ? '详情' : '编辑';
|
||||
visible.value = true;
|
||||
nextTick(() => {
|
||||
realForm.value.edit(record);
|
||||
});
|
||||
}
|
||||
|
||||
function handleOk() {
|
||||
realForm.value.submitForm();
|
||||
}
|
||||
|
||||
function submitCallback() {
|
||||
handleCancel();
|
||||
emit('ok');
|
||||
}
|
||||
|
||||
function handleCancel() {
|
||||
visible.value = false;
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
add,
|
||||
edit,
|
||||
disableSubmit,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
</style>
|
||||
202
jeecgboot-vue3/src/views/demo/jeecg/PrintDemo.vue
Normal file
202
jeecgboot-vue3/src/views/demo/jeecg/PrintDemo.vue
Normal file
@ -0,0 +1,202 @@
|
||||
<template>
|
||||
<PageWrapper>
|
||||
<a-card :bordered="false" class="j-print-demo">
|
||||
<div style="text-align: right">
|
||||
<a-button type="primary" ghost @click="onPrint">打印</a-button>
|
||||
</div>
|
||||
<section ref="print" id="printContent">
|
||||
<div style="text-align: center">
|
||||
<p style="font-size: 24px; font-weight: 800">打印测试表单</p>
|
||||
</div>
|
||||
<!--签字-->
|
||||
<a-col :md="24" :sm="24">
|
||||
<div class="sign" style="text-align: center; height: inherit">
|
||||
<a-col :span="24">
|
||||
<span>打印人员:</span>
|
||||
<a-input style="width: 30%" v-model:value="model.printer" />
|
||||
<span style="margin-left: 12.5%">打印日期:</span>
|
||||
<a-input style="width: 30%" v-model:value="model.printTime" />
|
||||
</a-col>
|
||||
<a-col :span="24"> </a-col>
|
||||
<a-col :span="24" style="margin-top: 20px">
|
||||
<span>打印内容:</span>
|
||||
<a-input style="width: 80%" v-model:value="model.printContent" />
|
||||
</a-col>
|
||||
<a-col :span="24" style="margin-top: 20px">
|
||||
<span>打印目的1:</span>
|
||||
<a-input style="width: 80%" v-model:value="model.printReason" />
|
||||
</a-col>
|
||||
<a-col :span="24" style="margin-top: 20px">
|
||||
<span>打印目的2:</span>
|
||||
<a-input style="width: 80%" v-model:value="model.printReason" />
|
||||
</a-col>
|
||||
<a-col :span="24" style="margin-top: 20px">
|
||||
<span>打印目的3:</span>
|
||||
<a-input style="width: 80%" v-model:value="model.printReason" />
|
||||
</a-col>
|
||||
<a-col :span="24" style="margin-top: 20px">
|
||||
<span>打印目的4:</span>
|
||||
<a-input style="width: 80%" v-model:value="model.printReason" />
|
||||
</a-col>
|
||||
<a-col :span="24" style="margin-top: 20px">
|
||||
<span>打印目的5:</span>
|
||||
<a-input style="width: 80%" v-model:value="model.printReason" />
|
||||
</a-col>
|
||||
<a-col :span="24" style="margin-top: 20px">
|
||||
<span>打印目的6:</span>
|
||||
<a-input style="width: 80%" v-model:value="model.printReason" />
|
||||
</a-col>
|
||||
<a-col :span="24" style="margin-top: 20px">
|
||||
<span>打印目的7:</span>
|
||||
<a-input style="width: 80%" v-model:value="model.printReason" />
|
||||
</a-col>
|
||||
<a-col :span="24" style="margin-top: 20px">
|
||||
<span>打印目的8:</span>
|
||||
<a-input style="width: 80%" v-model:value="model.printReason" />
|
||||
</a-col>
|
||||
<a-col :span="24" style="margin-top: 20px">
|
||||
<span>打印目的9:</span>
|
||||
<a-input style="width: 80%" v-model:value="model.printReason" />
|
||||
</a-col>
|
||||
<a-col :span="24" style="margin-top: 20px">
|
||||
<span>打印目的10:</span>
|
||||
<a-input style="width: 80%" v-model:value="model.printReason" />
|
||||
</a-col>
|
||||
<a-col :span="24" style="margin-top: 20px">
|
||||
<span>打印目的11:</span>
|
||||
<a-input style="width: 80%" v-model:value="model.printReason" />
|
||||
</a-col>
|
||||
<a-col :span="24" style="margin-top: 20px">
|
||||
<span>打印目的12:</span>
|
||||
<a-input style="width: 80%" v-model:value="model.printReason" />
|
||||
</a-col>
|
||||
<a-col :span="24" style="margin-top: 20px">
|
||||
<span>打印目的13:</span>
|
||||
<a-input style="width: 80%" v-model:value="model.printReason" />
|
||||
</a-col>
|
||||
<a-col :span="24" style="margin-top: 20px">
|
||||
<span>打印目的14:</span>
|
||||
<a-input style="width: 80%" v-model:value="model.printReason" />
|
||||
</a-col>
|
||||
<a-col style="margin-top: 20px" :span="24">
|
||||
<span>打印图片:</span>
|
||||
<br />
|
||||
<a-upload
|
||||
action="/jsonplaceholder.typicode.com/posts/"
|
||||
listType="picture-card"
|
||||
:fileList="model.fileList"
|
||||
@preview="handlePreview"
|
||||
@change="handleChange"
|
||||
>
|
||||
<div v-if="model.fileList.length < 3">
|
||||
<Icon icon="ant-design:plus-outlined" />
|
||||
<div class="ant-upload-text">Upload</div>
|
||||
</div>
|
||||
</a-upload>
|
||||
<a-modal :open="previewVisible" :footer="null" @cancel="previewVisible = false">
|
||||
<img alt="example" style="width: 100%" :src="previewImage" />
|
||||
</a-modal>
|
||||
</a-col>
|
||||
</div>
|
||||
</a-col>
|
||||
</section>
|
||||
</a-card>
|
||||
</PageWrapper>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { ref, reactive } from 'vue';
|
||||
import { PageWrapper } from '/@/components/Page';
|
||||
import Icon from '/@/components/Icon/src/Icon.vue';
|
||||
import { printJS } from '/@/hooks/web/usePrintJS';
|
||||
|
||||
export default {
|
||||
name: 'PrintDemo',
|
||||
components: { PageWrapper, Icon },
|
||||
props: {
|
||||
reBizCode: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
setup() {
|
||||
const model = reactive({
|
||||
printer: '张三',
|
||||
printTime: '2021-12-31 23:59:59',
|
||||
printContent: '打印内容:这是一个打印测试!',
|
||||
printReason: '做一个打印测试',
|
||||
fileList: [
|
||||
{
|
||||
uid: '-1',
|
||||
name: 'xxx.png',
|
||||
status: 'done',
|
||||
url: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png',
|
||||
},
|
||||
{
|
||||
uid: '-2',
|
||||
name: 'pic1.png',
|
||||
status: 'done',
|
||||
url: 'https://www.gizbot.com/img/2016/11/whatsapp-error-lead-image-08-1478607387.jpg',
|
||||
},
|
||||
],
|
||||
});
|
||||
const previewImage = ref('');
|
||||
const previewVisible = ref(false);
|
||||
|
||||
function onPrint() {
|
||||
printJS({
|
||||
printable: '#printContent',
|
||||
type: 'html',
|
||||
});
|
||||
}
|
||||
|
||||
function handlePreview(file) {
|
||||
previewImage.value = file.url || file.thumbUrl;
|
||||
previewVisible.value = true;
|
||||
}
|
||||
|
||||
function handleChange({ fileList }) {
|
||||
model.fileList = fileList;
|
||||
}
|
||||
|
||||
return {
|
||||
model,
|
||||
previewImage,
|
||||
previewVisible,
|
||||
onPrint,
|
||||
handlePreview,
|
||||
handleChange,
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.j-print-demo .ant-card-body {
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
margin-bottom: 1%;
|
||||
border: 0 solid black;
|
||||
min-width: 800px;
|
||||
color: #000000 !important;
|
||||
}
|
||||
|
||||
.sign .ant-input {
|
||||
font-weight: bolder;
|
||||
text-align: center;
|
||||
border-left-width: 0 !important;
|
||||
border-top-width: 0 !important;
|
||||
border-right-width: 0 !important;
|
||||
outline: none !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
/* you can make up upload button and sample style by using stylesheets */
|
||||
.ant-upload-select-picture-card i {
|
||||
font-size: 32px;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.ant-upload-select-picture-card .ant-upload-text {
|
||||
margin-top: 8px;
|
||||
color: #666;
|
||||
}
|
||||
</style>
|
||||
59
jeecgboot-vue3/src/views/demo/jeecg/TableTotal.vue
Normal file
59
jeecgboot-vue3/src/views/demo/jeecg/TableTotal.vue
Normal file
@ -0,0 +1,59 @@
|
||||
<template>
|
||||
<PageWrapper>
|
||||
<a-card :bordered="false">
|
||||
<BasicTable @register="registerTable" />
|
||||
</a-card>
|
||||
</PageWrapper>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { PageWrapper } from '/@/components/Page';
|
||||
import { BasicTable, useTable } from '/@/components/Table';
|
||||
import { mapTableTotalSummary } from '/@/utils/common/compUtils';
|
||||
|
||||
const [registerTable] = useTable({
|
||||
rowKey: 'id',
|
||||
bordered: true,
|
||||
canResize: false,
|
||||
columns: [
|
||||
{ title: '姓名', dataIndex: 'name' },
|
||||
{ title: '贡献点', dataIndex: 'point' },
|
||||
{ title: '等级', dataIndex: 'level' },
|
||||
{ title: '更新时间', dataIndex: 'updateTime' },
|
||||
],
|
||||
dataSource: [
|
||||
{ id: 0, name: '张三', point: 23, level: 3, updateTime: '2019-8-14' },
|
||||
{ id: 1, name: '小鹿', point: 33, level: 9, updateTime: '2019-8-10' },
|
||||
{ id: 2, name: '小王', point: 6, level: 1, updateTime: '2019-8-13' },
|
||||
{ id: 3, name: '李四', point: 53, level: 8, updateTime: '2019-8-12' },
|
||||
{ id: 4, name: '小红', point: 44, level: 5, updateTime: '2019-8-11' },
|
||||
{ id: 5, name: '王五', point: 97, level: 10, updateTime: '2019-8-10' },
|
||||
{ id: 6, name: '小明', point: 33, level: 2, updateTime: '2019-8-10' },
|
||||
{ id: 7, name: '小张', point: 33, level: 4, updateTime: '2019-8-10' },
|
||||
{ id: 8, name: '小六', point: 33, level: 2, updateTime: '2019-8-10' },
|
||||
{ id: 9, name: '小五', point: 33, level: 7, updateTime: '2019-8-10' },
|
||||
{ id: 10, name: '小赵', point: 33, level: 2, updateTime: '2019-8-10' },
|
||||
{ id: 11, name: '李华', point: 33, level: 8, updateTime: '2019-8-10' },
|
||||
{ id: 12, name: '小康', point: 33, level: 5, updateTime: '2019-8-10' },
|
||||
],
|
||||
// 显示底部合计
|
||||
showSummary: true,
|
||||
// 底部合计计算方法
|
||||
summaryFunc: onSummary,
|
||||
});
|
||||
|
||||
function onSummary(tableData: Recordable[]) {
|
||||
// 可用工具方法自动计算合计
|
||||
const totals = mapTableTotalSummary(tableData, ['point', 'level']);
|
||||
return [
|
||||
totals,
|
||||
{
|
||||
_row: '平均',
|
||||
_index: '平均',
|
||||
// 计算平均值
|
||||
point: (totals.point / tableData.length).toFixed(2),
|
||||
level: (totals.level / tableData.length).toFixed(0),
|
||||
},
|
||||
];
|
||||
}
|
||||
</script>
|
||||
@ -0,0 +1,165 @@
|
||||
<template>
|
||||
<div>
|
||||
<!--表格-->
|
||||
<BasicTable @register="registerTable" :rowSelection="rowSelection" :searchInfo="searchInfo">
|
||||
<!--插槽:table标题-->
|
||||
<template #tableTitle>
|
||||
<a-button type="primary" preIcon="ant-design:plus-outlined" @click="handleCreate"> 新增</a-button>
|
||||
<a-dropdown v-if="selectedRowKeys.length > 0">
|
||||
<template #overlay>
|
||||
<a-menu>
|
||||
<a-menu-item key="1" @click="batchHandleDelete">
|
||||
<Icon icon="ant-design:delete-outlined"></Icon>
|
||||
删除
|
||||
</a-menu-item>
|
||||
</a-menu>
|
||||
</template>
|
||||
<a-button
|
||||
>批量操作
|
||||
<Icon icon="mdi:chevron-down"></Icon>
|
||||
</a-button>
|
||||
</a-dropdown>
|
||||
</template>
|
||||
<!--操作栏-->
|
||||
<template #action="{ record }">
|
||||
<TableAction :actions="getTableAction(record)" />
|
||||
</template>
|
||||
</BasicTable>
|
||||
<!-- 表单区域 -->
|
||||
<JeecgOrderCustomerModal @register="registerModal" @success="handleSuccess"></JeecgOrderCustomerModal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
//ts语法
|
||||
import type { ComputedRef } from 'vue';
|
||||
import { ref, computed, unref, watch, inject } from 'vue';
|
||||
import { BasicTable, TableAction } from '/@/components/Table';
|
||||
import JeecgOrderCustomerModal from './components/JeecgOrderCustomerModal.vue';
|
||||
import { useListPage } from '/@/hooks/system/useListPage';
|
||||
import { useModal } from '/@/components/Modal';
|
||||
import { customColumns } from './erplist.data';
|
||||
import { customList, deleteCustomer, deleteBatchCustomer } from './erplist.api';
|
||||
import { isEmpty } from '/@/utils/is';
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
//接收主表id
|
||||
const orderId = inject<ComputedRef<string>>(
|
||||
'orderId',
|
||||
computed(() => '')
|
||||
);
|
||||
//提示弹窗
|
||||
const $message = useMessage();
|
||||
//弹窗model
|
||||
const [registerModal, { openModal }] = useModal();
|
||||
const searchInfo = {};
|
||||
// 列表页面公共参数、方法
|
||||
const { prefixCls, tableContext } = useListPage({
|
||||
tableProps: {
|
||||
api: getCustomList,
|
||||
tableSetting:{
|
||||
cacheKey:'customer'
|
||||
},
|
||||
columns: customColumns,
|
||||
canResize: false,
|
||||
useSearchForm: false,
|
||||
actionColumn: {
|
||||
width: 180,
|
||||
},
|
||||
pagination: {
|
||||
current: 1,
|
||||
pageSize: 5,
|
||||
pageSizeOptions: ['5', '10', '20'],
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
//注册table数据
|
||||
const [registerTable, { reload, setSelectedRowKeys }, { rowSelection, selectedRowKeys }] = tableContext;
|
||||
|
||||
watch(orderId, () => {
|
||||
searchInfo['orderId'] = unref(orderId);
|
||||
reload();
|
||||
// 主表id变化时,清空子表的选中状态
|
||||
setSelectedRowKeys([]);
|
||||
});
|
||||
|
||||
async function getCustomList(params) {
|
||||
let { orderId } = params;
|
||||
// 主表Id为空时,不查询子表数据,直接返回空数组
|
||||
if (orderId == null || isEmpty(orderId)) {
|
||||
return [];
|
||||
}
|
||||
return await customList(params);
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增事件
|
||||
*/
|
||||
function handleCreate() {
|
||||
console.log('orderId=====》', orderId);
|
||||
if (isEmpty(unref(orderId))) {
|
||||
$message.createMessage.warning('请选择一个订单信息');
|
||||
return;
|
||||
}
|
||||
openModal(true, {
|
||||
isUpdate: false,
|
||||
showFooter: true,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑事件
|
||||
*/
|
||||
async function handleEdit(record: Recordable) {
|
||||
openModal(true, {
|
||||
record,
|
||||
isUpdate: true,
|
||||
showFooter: true,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除事件
|
||||
*/
|
||||
async function handleDelete(record) {
|
||||
await deleteCustomer({ id: record.id }, reload);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除事件
|
||||
*/
|
||||
async function batchHandleDelete() {
|
||||
await deleteBatchCustomer({ ids: selectedRowKeys.value }, () => {
|
||||
selectedRowKeys.value = [];
|
||||
reload();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 成功回调
|
||||
*/
|
||||
function handleSuccess() {
|
||||
reload();
|
||||
}
|
||||
|
||||
/**
|
||||
* 操作栏
|
||||
*/
|
||||
function getTableAction(record) {
|
||||
return [
|
||||
{
|
||||
label: '编辑',
|
||||
onClick: handleEdit.bind(null, record),
|
||||
},
|
||||
{
|
||||
label: '删除',
|
||||
popConfirm: {
|
||||
title: '是否确认删除',
|
||||
confirm: handleDelete.bind(null, record),
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
@ -0,0 +1,164 @@
|
||||
<template>
|
||||
<div>
|
||||
<!--表格-->
|
||||
<BasicTable @register="registerTable" :rowSelection="rowSelection" :searchInfo="searchInfo">
|
||||
<!--插槽:table标题-->
|
||||
<template #tableTitle>
|
||||
<a-button type="primary" preIcon="ant-design:plus-outlined" @click="handleCreate"> 新增</a-button>
|
||||
<a-dropdown v-if="selectedRowKeys.length > 0">
|
||||
<template #overlay>
|
||||
<a-menu>
|
||||
<a-menu-item key="1" @click="batchHandleDelete">
|
||||
<Icon icon="ant-design:delete-outlined"></Icon>
|
||||
删除
|
||||
</a-menu-item>
|
||||
</a-menu>
|
||||
</template>
|
||||
<a-button
|
||||
>批量操作
|
||||
<Icon icon="mdi:chevron-down"></Icon>
|
||||
</a-button>
|
||||
</a-dropdown>
|
||||
</template>
|
||||
<!--操作栏-->
|
||||
<template #action="{ record }">
|
||||
<TableAction :actions="getTableAction(record)" />
|
||||
</template>
|
||||
</BasicTable>
|
||||
<!-- 表单区域 -->
|
||||
<JeecgOrderTicketModal @register="registerModal" @success="handleSuccess"></JeecgOrderTicketModal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
//ts语法
|
||||
import type { ComputedRef } from 'vue';
|
||||
import { ref, computed, unref, watch, inject } from 'vue';
|
||||
import { BasicTable, TableAction } from '/@/components/Table';
|
||||
import JeecgOrderTicketModal from './components/JeecgOrderTicketModal.vue';
|
||||
import { useListPage } from '/@/hooks/system/useListPage';
|
||||
import { useModal } from '/@/components/Modal';
|
||||
import { ticketColumns } from './erplist.data';
|
||||
import { ticketList, deleteTicket, deleteBatchTicket } from './erplist.api';
|
||||
import { isEmpty } from '/@/utils/is';
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
//接收主表id
|
||||
const orderId = inject<ComputedRef<string>>(
|
||||
'orderId',
|
||||
computed(() => '')
|
||||
);
|
||||
//提示弹窗
|
||||
const $message = useMessage();
|
||||
//弹窗model
|
||||
const [registerModal, { openModal }] = useModal();
|
||||
const searchInfo = {};
|
||||
// 列表页面公共参数、方法
|
||||
const { prefixCls, tableContext } = useListPage({
|
||||
tableProps: {
|
||||
api: getTicketList,
|
||||
tableSetting:{
|
||||
cacheKey:'ticket'
|
||||
},
|
||||
columns: ticketColumns,
|
||||
canResize: false,
|
||||
useSearchForm: false,
|
||||
actionColumn: {
|
||||
width: 180,
|
||||
},
|
||||
pagination: {
|
||||
current: 1,
|
||||
pageSize: 5,
|
||||
pageSizeOptions: ['5', '10', '20'],
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
//注册table数据
|
||||
const [registerTable, { reload, setSelectedRowKeys }, { rowSelection, selectedRowKeys }] = tableContext;
|
||||
|
||||
watch(orderId, () => {
|
||||
searchInfo['orderId'] = unref(orderId);
|
||||
reload();
|
||||
// 主表id变化时,清空子表的选中状态
|
||||
setSelectedRowKeys([]);
|
||||
});
|
||||
|
||||
async function getTicketList(params) {
|
||||
let { orderId } = params;
|
||||
// 主表Id为空时,不查询子表数据,直接返回空数组
|
||||
if (orderId == null || isEmpty(orderId)) {
|
||||
return [];
|
||||
}
|
||||
return await ticketList(params);
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增事件
|
||||
*/
|
||||
function handleCreate() {
|
||||
if (isEmpty(unref(orderId))) {
|
||||
$message.createMessage.warning('请选择一个订单信息');
|
||||
return;
|
||||
}
|
||||
openModal(true, {
|
||||
isUpdate: false,
|
||||
showFooter: true,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑事件
|
||||
*/
|
||||
async function handleEdit(record: Recordable) {
|
||||
openModal(true, {
|
||||
record,
|
||||
isUpdate: true,
|
||||
showFooter: true,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除事件
|
||||
*/
|
||||
async function handleDelete(record) {
|
||||
await deleteTicket({ id: record.id }, reload);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除事件
|
||||
*/
|
||||
async function batchHandleDelete() {
|
||||
await deleteBatchTicket({ ids: selectedRowKeys.value }, () => {
|
||||
selectedRowKeys.value = [];
|
||||
reload();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 成功回调
|
||||
*/
|
||||
function handleSuccess() {
|
||||
reload();
|
||||
}
|
||||
|
||||
/**
|
||||
* 操作栏
|
||||
*/
|
||||
function getTableAction(record) {
|
||||
return [
|
||||
{
|
||||
label: '编辑',
|
||||
onClick: handleEdit.bind(null, record),
|
||||
},
|
||||
{
|
||||
label: '删除',
|
||||
popConfirm: {
|
||||
title: '是否确认删除',
|
||||
confirm: handleDelete.bind(null, record),
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
@ -0,0 +1,57 @@
|
||||
<template>
|
||||
<BasicModal v-bind="$attrs" @register="registerModal" :title="getTitle" @ok="handleSubmit" :width="700">
|
||||
<BasicForm @register="registerForm" />
|
||||
</BasicModal>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed, unref, inject } from 'vue';
|
||||
import { BasicModal, useModalInner } from '/@/components/Modal';
|
||||
import { BasicForm, useForm } from '/@/components/Form/index';
|
||||
import { customerFormSchema } from '../erplist.data';
|
||||
import { saveOrUpdateCustomer } from '../erplist.api';
|
||||
//接收主表id
|
||||
const orderId = inject('orderId') || '';
|
||||
// 声明Emits
|
||||
const emit = defineEmits(['success', 'register']);
|
||||
const isUpdate = ref(true);
|
||||
//表单配置
|
||||
const [registerForm, { resetFields, setFieldsValue, validate }] = useForm({
|
||||
labelWidth: 150,
|
||||
schemas: customerFormSchema,
|
||||
showActionButtonGroup: false,
|
||||
});
|
||||
//表单赋值
|
||||
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
|
||||
//重置表单
|
||||
await resetFields();
|
||||
setModalProps({ confirmLoading: false });
|
||||
isUpdate.value = !!data?.isUpdate;
|
||||
if (unref(isUpdate)) {
|
||||
//表单赋值
|
||||
await setFieldsValue({
|
||||
...data.record,
|
||||
});
|
||||
}
|
||||
});
|
||||
//设置标题
|
||||
const getTitle = computed(() => (!unref(isUpdate) ? '新增' : '编辑'));
|
||||
|
||||
//表单提交事件
|
||||
async function handleSubmit() {
|
||||
try {
|
||||
const values = await validate();
|
||||
setModalProps({ confirmLoading: true });
|
||||
if (unref(orderId)) {
|
||||
values.orderId = unref(orderId);
|
||||
}
|
||||
//提交表单
|
||||
await saveOrUpdateCustomer(values, isUpdate.value);
|
||||
//关闭弹窗
|
||||
closeModal();
|
||||
//刷新列表
|
||||
emit('success');
|
||||
} finally {
|
||||
setModalProps({ confirmLoading: false });
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@ -0,0 +1,52 @@
|
||||
<template>
|
||||
<BasicModal v-bind="$attrs" @register="registerModal" :title="getTitle" @ok="handleSubmit" :width="700">
|
||||
<BasicForm @register="registerForm" />
|
||||
</BasicModal>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed, unref } from 'vue';
|
||||
import { BasicModal, useModalInner } from '/@/components/Modal';
|
||||
import { BasicForm, useForm } from '/@/components/Form/index';
|
||||
import { formSchema } from '../erplist.data';
|
||||
import { saveOrUpdate } from '../erplist.api';
|
||||
// 声明Emits
|
||||
const emit = defineEmits(['success', 'register']);
|
||||
const isUpdate = ref(true);
|
||||
//表单配置
|
||||
const [registerForm, { resetFields, setFieldsValue, validate }] = useForm({
|
||||
labelWidth: 150,
|
||||
schemas: formSchema,
|
||||
showActionButtonGroup: false,
|
||||
});
|
||||
//表单赋值
|
||||
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
|
||||
//重置表单
|
||||
await resetFields();
|
||||
setModalProps({ confirmLoading: false });
|
||||
isUpdate.value = !!data?.isUpdate;
|
||||
if (unref(isUpdate)) {
|
||||
//表单赋值
|
||||
await setFieldsValue({
|
||||
...data.record,
|
||||
});
|
||||
}
|
||||
});
|
||||
//设置标题
|
||||
const getTitle = computed(() => (!unref(isUpdate) ? '新增' : '编辑'));
|
||||
|
||||
//表单提交事件
|
||||
async function handleSubmit() {
|
||||
try {
|
||||
const values = await validate();
|
||||
setModalProps({ confirmLoading: true });
|
||||
//提交表单
|
||||
await saveOrUpdate(values, isUpdate.value);
|
||||
//关闭弹窗
|
||||
closeModal();
|
||||
//刷新列表
|
||||
emit('success');
|
||||
} finally {
|
||||
setModalProps({ confirmLoading: false });
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@ -0,0 +1,57 @@
|
||||
<template>
|
||||
<BasicModal v-bind="$attrs" @register="registerModal" :title="getTitle" @ok="handleSubmit" :width="500" :minHeight="20" :maxHeight="20">
|
||||
<BasicForm @register="registerForm" />
|
||||
</BasicModal>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed, unref, inject } from 'vue';
|
||||
import { BasicModal, useModalInner } from '/@/components/Modal';
|
||||
import { BasicForm, useForm } from '/@/components/Form/index';
|
||||
import { ticketFormSchema } from '../erplist.data';
|
||||
import { saveOrUpdateTicket } from '../erplist.api';
|
||||
//接收主表id
|
||||
const orderId = inject('orderId');
|
||||
// 声明Emits
|
||||
const emit = defineEmits(['success', 'register']);
|
||||
const isUpdate = ref(true);
|
||||
//表单配置
|
||||
const [registerForm, { resetFields, setFieldsValue, validate }] = useForm({
|
||||
labelWidth: 150,
|
||||
schemas: ticketFormSchema,
|
||||
showActionButtonGroup: false,
|
||||
});
|
||||
//表单赋值
|
||||
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
|
||||
//重置表单
|
||||
await resetFields();
|
||||
setModalProps({ confirmLoading: false });
|
||||
isUpdate.value = !!data?.isUpdate;
|
||||
if (unref(isUpdate)) {
|
||||
//表单赋值
|
||||
await setFieldsValue({
|
||||
...data.record,
|
||||
});
|
||||
}
|
||||
});
|
||||
//设置标题
|
||||
const getTitle = computed(() => (!unref(isUpdate) ? '新增' : '编辑'));
|
||||
|
||||
//表单提交事件
|
||||
async function handleSubmit() {
|
||||
try {
|
||||
const values = await validate();
|
||||
setModalProps({ confirmLoading: true });
|
||||
if (unref(orderId)) {
|
||||
values.orderId = unref(orderId);
|
||||
}
|
||||
//提交表单
|
||||
await saveOrUpdateTicket(values, isUpdate.value);
|
||||
//关闭弹窗
|
||||
closeModal();
|
||||
//刷新列表
|
||||
emit('success');
|
||||
} finally {
|
||||
setModalProps({ confirmLoading: false });
|
||||
}
|
||||
}
|
||||
</script>
|
||||
139
jeecgboot-vue3/src/views/demo/jeecg/erplist/erplist.api.ts
Normal file
139
jeecgboot-vue3/src/views/demo/jeecg/erplist/erplist.api.ts
Normal file
@ -0,0 +1,139 @@
|
||||
import { defHttp } from '/@/utils/http/axios';
|
||||
import { Modal } from 'ant-design-vue';
|
||||
|
||||
enum Api {
|
||||
list = '/test/order/orderList',
|
||||
save = '/test/order/add',
|
||||
edit = '/test/order/edit',
|
||||
deleteOne = '/test/order/delete',
|
||||
deleteBatch = '/test/order/deleteBatch',
|
||||
customList = '/test/order/listOrderCustomerByMainId',
|
||||
saveCustomer = '/test/order/addCustomer',
|
||||
editCustomer = '/test/order/editCustomer',
|
||||
deleteCustomer = '/test/order/deleteCustomer',
|
||||
deleteBatchCustomer = '/test/order/deleteBatchCustomer',
|
||||
ticketList = '/test/order/listOrderTicketByMainId',
|
||||
saveTicket = '/test/order/addTicket',
|
||||
editTicket = '/test/order/editTicket',
|
||||
deleteTicket = '/test/order/deleteTicket',
|
||||
deleteBatchTicket = '/test/order/deleteBatchTicket',
|
||||
}
|
||||
|
||||
/**
|
||||
* 列表接口
|
||||
* @param params
|
||||
*/
|
||||
export const list = (params) => defHttp.get({ url: Api.list, params });
|
||||
|
||||
/**
|
||||
* 删除
|
||||
*/
|
||||
export const deleteOne = (params, handleSuccess) => {
|
||||
return defHttp.delete({ url: Api.deleteOne, params }, { joinParamsToUrl: true }).then(() => {
|
||||
handleSuccess();
|
||||
});
|
||||
};
|
||||
/**
|
||||
* 批量删除
|
||||
* @param params
|
||||
*/
|
||||
export const batchDelete = (params, handleSuccess) => {
|
||||
Modal.confirm({
|
||||
title: '确认删除',
|
||||
content: '是否删除选中数据',
|
||||
okText: '确认',
|
||||
cancelText: '取消',
|
||||
onOk: () => {
|
||||
return defHttp.delete({ url: Api.deleteBatch, data: params }, { joinParamsToUrl: true }).then(() => {
|
||||
handleSuccess();
|
||||
});
|
||||
},
|
||||
});
|
||||
};
|
||||
/**
|
||||
* 保存或者更新
|
||||
* @param params
|
||||
*/
|
||||
export const saveOrUpdate = (params, isUpdate) => {
|
||||
let url = isUpdate ? Api.edit : Api.save;
|
||||
return defHttp.post({ url: url, params });
|
||||
};
|
||||
|
||||
/**
|
||||
* 列表接口
|
||||
* @param params
|
||||
*/
|
||||
export const customList = (params) => defHttp.get({ url: Api.customList, params });
|
||||
|
||||
/**
|
||||
* 删除
|
||||
*/
|
||||
export const deleteCustomer = (params, handleSuccess) => {
|
||||
return defHttp.delete({ url: Api.deleteCustomer, params }, { joinParamsToUrl: true }).then(() => {
|
||||
handleSuccess();
|
||||
});
|
||||
};
|
||||
/**
|
||||
* 批量删除
|
||||
* @param params
|
||||
*/
|
||||
export const deleteBatchCustomer = (params, handleSuccess) => {
|
||||
Modal.confirm({
|
||||
title: '确认删除',
|
||||
content: '是否删除选中数据',
|
||||
okText: '确认',
|
||||
cancelText: '取消',
|
||||
onOk: () => {
|
||||
return defHttp.delete({ url: Api.deleteBatchCustomer, data: params }, { joinParamsToUrl: true }).then(() => {
|
||||
handleSuccess();
|
||||
});
|
||||
},
|
||||
});
|
||||
};
|
||||
/**
|
||||
* 保存或者更新
|
||||
* @param params
|
||||
*/
|
||||
export const saveOrUpdateCustomer = (params, isUpdate) => {
|
||||
let url = isUpdate ? Api.editCustomer : Api.saveCustomer;
|
||||
return defHttp.post({ url: url, params });
|
||||
};
|
||||
/**
|
||||
* 列表接口
|
||||
* @param params
|
||||
*/
|
||||
export const ticketList = (params) => defHttp.get({ url: Api.ticketList, params });
|
||||
|
||||
/**
|
||||
* 删除
|
||||
*/
|
||||
export const deleteTicket = (params, handleSuccess) => {
|
||||
return defHttp.delete({ url: Api.deleteTicket, params }, { joinParamsToUrl: true }).then(() => {
|
||||
handleSuccess();
|
||||
});
|
||||
};
|
||||
/**
|
||||
* 批量删除
|
||||
* @param params
|
||||
*/
|
||||
export const deleteBatchTicket = (params, handleSuccess) => {
|
||||
Modal.confirm({
|
||||
title: '确认删除',
|
||||
content: '是否删除选中数据',
|
||||
okText: '确认',
|
||||
cancelText: '取消',
|
||||
onOk: () => {
|
||||
return defHttp.delete({ url: Api.deleteBatchTicket, data: params }, { joinParamsToUrl: true }).then(() => {
|
||||
handleSuccess();
|
||||
});
|
||||
},
|
||||
});
|
||||
};
|
||||
/**
|
||||
* 保存或者更新
|
||||
* @param params
|
||||
*/
|
||||
export const saveOrUpdateTicket = (params, isUpdate) => {
|
||||
let url = isUpdate ? Api.editTicket : Api.saveTicket;
|
||||
return defHttp.post({ url: url, params });
|
||||
};
|
||||
238
jeecgboot-vue3/src/views/demo/jeecg/erplist/erplist.data.ts
Normal file
238
jeecgboot-vue3/src/views/demo/jeecg/erplist/erplist.data.ts
Normal file
@ -0,0 +1,238 @@
|
||||
import { BasicColumn } from '/@/components/Table';
|
||||
import { FormSchema } from '/@/components/Table';
|
||||
import { render } from '/@/utils/common/renderUtils';
|
||||
|
||||
export const columns: BasicColumn[] = [
|
||||
{
|
||||
title: '订单号',
|
||||
dataIndex: 'orderCode',
|
||||
width: 260,
|
||||
},
|
||||
{
|
||||
title: '订单类型',
|
||||
dataIndex: 'ctype',
|
||||
width: 160,
|
||||
customRender: ({ text }) => {
|
||||
return text == '1' ? '国内订单' : text == '2' ? '国际订单' : '';
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '订单日期',
|
||||
dataIndex: 'orderDate',
|
||||
width: 300,
|
||||
},
|
||||
{
|
||||
title: '订单金额',
|
||||
width: 200,
|
||||
dataIndex: 'orderMoney',
|
||||
},
|
||||
{
|
||||
title: '订单备注',
|
||||
width: 200,
|
||||
dataIndex: 'content',
|
||||
},
|
||||
];
|
||||
|
||||
export const searchFormSchema: FormSchema[] = [
|
||||
{
|
||||
label: '订单号',
|
||||
field: 'orderCode',
|
||||
component: 'Input',
|
||||
colProps: { span: 6 },
|
||||
},
|
||||
{
|
||||
label: '订单类型',
|
||||
field: 'ctype',
|
||||
component: 'Select',
|
||||
componentProps: {
|
||||
options: [
|
||||
{
|
||||
label: '国内订单',
|
||||
value: '1',
|
||||
key: '1',
|
||||
},
|
||||
{
|
||||
label: '国际订单',
|
||||
value: '2',
|
||||
key: '2',
|
||||
},
|
||||
],
|
||||
},
|
||||
colProps: { span: 6 },
|
||||
},
|
||||
];
|
||||
|
||||
export const formSchema: FormSchema[] = [
|
||||
{
|
||||
label: '',
|
||||
field: 'id',
|
||||
component: 'Input',
|
||||
show: false,
|
||||
},
|
||||
{
|
||||
label: '订单号',
|
||||
field: 'orderCode',
|
||||
component: 'Input',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
label: '订单类型',
|
||||
field: 'ctype',
|
||||
component: 'Select',
|
||||
componentProps: {
|
||||
options: [
|
||||
{
|
||||
label: '国内订单',
|
||||
value: '1',
|
||||
key: '1',
|
||||
},
|
||||
{
|
||||
label: '国际订单',
|
||||
value: '2',
|
||||
key: '2',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '订单日期',
|
||||
field: 'orderDate',
|
||||
component: 'DatePicker',
|
||||
componentProps: {
|
||||
valueFormat: 'YYYY-MM-DD hh:mm:ss',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '订单金额',
|
||||
field: 'orderMoney',
|
||||
component: 'InputNumber',
|
||||
},
|
||||
{
|
||||
label: '订单备注',
|
||||
field: 'content',
|
||||
component: 'Input',
|
||||
},
|
||||
];
|
||||
|
||||
export const customColumns: BasicColumn[] = [
|
||||
{
|
||||
title: '客户名',
|
||||
dataIndex: 'name',
|
||||
width: 260,
|
||||
},
|
||||
{
|
||||
title: '性别',
|
||||
dataIndex: 'sex',
|
||||
width: 100,
|
||||
customRender: ({ text }) => {
|
||||
return render.renderDict(text, 'sex');
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '身份证号',
|
||||
dataIndex: 'idcard',
|
||||
width: 300,
|
||||
},
|
||||
{
|
||||
title: '电话',
|
||||
width: 200,
|
||||
dataIndex: 'telphone',
|
||||
},
|
||||
];
|
||||
|
||||
export const customerFormSchema: FormSchema[] = [
|
||||
{
|
||||
label: '',
|
||||
field: 'id',
|
||||
component: 'Input',
|
||||
show: false,
|
||||
},
|
||||
{
|
||||
label: '客户姓名',
|
||||
field: 'name',
|
||||
component: 'Input',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
label: '性别',
|
||||
field: 'sex',
|
||||
component: 'JDictSelectTag',
|
||||
componentProps: {
|
||||
dictCode: 'sex',
|
||||
placeholder: '请选择性别',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '身份证号码',
|
||||
field: 'idcard',
|
||||
component: 'Input',
|
||||
},
|
||||
{
|
||||
label: '身份证扫描件',
|
||||
field: 'idcardPic',
|
||||
component: 'JImageUpload',
|
||||
componentProps: {
|
||||
fileMax: 2,
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '联系方式',
|
||||
field: 'telphone',
|
||||
component: 'Input',
|
||||
rules: [{ required: false, pattern: /^1[3456789]\d{9}$/, message: '手机号码格式有误' }],
|
||||
},
|
||||
{
|
||||
label: 'orderId',
|
||||
field: 'orderId',
|
||||
component: 'Input',
|
||||
show: false,
|
||||
},
|
||||
];
|
||||
|
||||
export const ticketColumns: BasicColumn[] = [
|
||||
{
|
||||
title: '航班号',
|
||||
dataIndex: 'ticketCode',
|
||||
},
|
||||
{
|
||||
title: '航班时间',
|
||||
dataIndex: 'tickectDate',
|
||||
},
|
||||
{
|
||||
title: '创建人',
|
||||
dataIndex: 'createBy',
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
dataIndex: 'createTime',
|
||||
},
|
||||
];
|
||||
|
||||
export const ticketFormSchema: FormSchema[] = [
|
||||
{
|
||||
label: '',
|
||||
field: 'id',
|
||||
component: 'Input',
|
||||
show: false,
|
||||
},
|
||||
{
|
||||
label: '航班号',
|
||||
field: 'ticketCode',
|
||||
component: 'Input',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
label: '航班时间',
|
||||
field: 'tickectDate',
|
||||
component: 'DatePicker',
|
||||
componentProps: {
|
||||
valueFormat: 'YYYY-MM-DD',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: 'orderId',
|
||||
field: 'orderId',
|
||||
component: 'Input',
|
||||
show: false,
|
||||
},
|
||||
];
|
||||
163
jeecgboot-vue3/src/views/demo/jeecg/erplist/index.vue
Normal file
163
jeecgboot-vue3/src/views/demo/jeecg/erplist/index.vue
Normal file
@ -0,0 +1,163 @@
|
||||
<template>
|
||||
<div>
|
||||
<!--主表表格-->
|
||||
<BasicTable @register="registerTable" :rowSelection="rowSelection">
|
||||
<!--插槽:table标题-->
|
||||
<template #tableTitle>
|
||||
<a-button type="primary" preIcon="ant-design:plus-outlined" @click="handleCreate"> 新增</a-button>
|
||||
<a-dropdown v-if="selectedRowKeys.length > 0">
|
||||
<template #overlay>
|
||||
<a-menu>
|
||||
<a-menu-item key="1" @click="batchHandleDelete">
|
||||
<Icon icon="ant-design:delete-outlined"></Icon>
|
||||
删除
|
||||
</a-menu-item>
|
||||
</a-menu>
|
||||
</template>
|
||||
<a-button
|
||||
>批量操作
|
||||
<Icon icon="mdi:chevron-down"></Icon>
|
||||
</a-button>
|
||||
</a-dropdown>
|
||||
</template>
|
||||
<!--操作栏-->
|
||||
<template #action="{ record }">
|
||||
<TableAction :actions="getTableAction(record)" />
|
||||
</template>
|
||||
</BasicTable>
|
||||
<!--子表表格tab-->
|
||||
<a-tabs defaultActiveKey="1" style="margin: 10px">
|
||||
<a-tab-pane tab="客户信息" key="1">
|
||||
<JeecgOrderCustomerList />
|
||||
</a-tab-pane>
|
||||
<a-tab-pane tab="机票信息" key="2" forceRender>
|
||||
<JeecgOrderTicketList />
|
||||
</a-tab-pane>
|
||||
</a-tabs>
|
||||
</div>
|
||||
<!-- 表单区域 -->
|
||||
<JeecgOrderModal @register="registerModal" @success="handleSuccess"></JeecgOrderModal>
|
||||
</template>
|
||||
|
||||
<script lang="ts" name="tab-list" setup>
|
||||
//ts语法
|
||||
import { ref, computed, unref, watch, provide } from 'vue';
|
||||
import { BasicTable, TableAction } from '/@/components/Table';
|
||||
import { useListPage } from '/@/hooks/system/useListPage';
|
||||
import { useModal } from '/@/components/Modal';
|
||||
import JeecgOrderModal from './components/JeecgOrderModal.vue';
|
||||
import JeecgOrderCustomerList from './JeecgOrderCustomerList.vue';
|
||||
import JeecgOrderTicketList from './JeecgOrderTicketList.vue';
|
||||
import { columns, searchFormSchema } from './erplist.data';
|
||||
import { list, deleteOne, batchDelete } from './erplist.api';
|
||||
|
||||
//弹窗model
|
||||
const [registerModal, { openModal }] = useModal();
|
||||
|
||||
// 列表页面公共参数、方法
|
||||
const { tableContext } = useListPage({
|
||||
tableProps: {
|
||||
api: list,
|
||||
tableSetting:{
|
||||
cacheKey:'erp_main'
|
||||
},
|
||||
columns: columns,
|
||||
canResize: false,
|
||||
rowSelection: { type: 'radio' },
|
||||
formConfig: {
|
||||
schemas: searchFormSchema,
|
||||
},
|
||||
actionColumn: {
|
||||
width: 180,
|
||||
},
|
||||
pagination: {
|
||||
current: 1,
|
||||
pageSize: 5,
|
||||
pageSizeOptions: ['5', '10', '20'],
|
||||
},
|
||||
},
|
||||
});
|
||||
//注册table数据
|
||||
const [registerTable, { reload, updateTableDataRecord }, { rowSelection, selectedRowKeys }] = tableContext;
|
||||
|
||||
const orderId = computed(() => (unref(selectedRowKeys).length > 0 ? unref(selectedRowKeys)[0] : ''));
|
||||
//下发 orderId,子组件接收
|
||||
provide('orderId', orderId);
|
||||
|
||||
/**
|
||||
* 新增事件
|
||||
*/
|
||||
function handleCreate() {
|
||||
openModal(true, {
|
||||
isUpdate: false,
|
||||
showFooter: true,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑事件
|
||||
*/
|
||||
async function handleEdit(record: Recordable) {
|
||||
openModal(true, {
|
||||
record,
|
||||
isUpdate: true,
|
||||
showFooter: true,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 详情
|
||||
*/
|
||||
async function handleDetail(record: Recordable) {
|
||||
openModal(true, {
|
||||
record,
|
||||
isUpdate: true,
|
||||
showFooter: false,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除事件
|
||||
*/
|
||||
async function handleDelete(record) {
|
||||
await deleteOne({ id: record.id }, reload);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除事件
|
||||
*/
|
||||
async function batchHandleDelete() {
|
||||
await batchDelete({ ids: selectedRowKeys.value }, () => {
|
||||
selectedRowKeys.value = [];
|
||||
reload();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 成功回调
|
||||
*/
|
||||
function handleSuccess() {
|
||||
reload();
|
||||
}
|
||||
|
||||
/**
|
||||
* 操作栏
|
||||
*/
|
||||
function getTableAction(record) {
|
||||
return [
|
||||
{
|
||||
label: '编辑',
|
||||
onClick: handleEdit.bind(null, record),
|
||||
},
|
||||
{
|
||||
label: '删除',
|
||||
popConfirm: {
|
||||
title: '是否确认删除',
|
||||
confirm: handleDelete.bind(null, record),
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
54
jeecgboot-vue3/src/views/demo/jeecg/index.vue
Normal file
54
jeecgboot-vue3/src/views/demo/jeecg/index.vue
Normal file
@ -0,0 +1,54 @@
|
||||
<template>
|
||||
<div class="p-4">
|
||||
<a-card :bordered="false" style="height: 100%">
|
||||
<a-tabs v-model:activeKey="activeKey" @change="tabChange">
|
||||
<a-tab-pane key="JeecgComponents" tab="下拉选择组件"></a-tab-pane>
|
||||
<a-tab-pane key="JCodeEditDemo" tab="代码编辑器" force-render></a-tab-pane>
|
||||
<a-tab-pane key="JEditorDemo" tab="富文本&MakeDown"></a-tab-pane>
|
||||
<a-tab-pane key="ImgDragSort" tab="图片拖拽"></a-tab-pane>
|
||||
<a-tab-pane key="ImgTurnPage" tab="图片翻页"></a-tab-pane>
|
||||
<a-tab-pane key="JeecgPdfView" tab="PDF预览"></a-tab-pane>
|
||||
<a-tab-pane key="JUploadDemo" tab="文件上传"></a-tab-pane>
|
||||
</a-tabs>
|
||||
<component :is="currentComponent"></component>
|
||||
</a-card>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref, computed } from 'vue';
|
||||
import JeecgComponents from './JeecgComponents.vue';
|
||||
import JEditorDemo from './JEditorDemo.vue';
|
||||
import JCodeEditDemo from './JCodeEditDemo.vue';
|
||||
import ImgDragSort from './ImgDragSort.vue';
|
||||
import ImgTurnPage from './ImgTurnPage.vue';
|
||||
import JeecgPdfView from './JeecgPdfView.vue';
|
||||
import JUploadDemo from './JUploadDemo.vue';
|
||||
export default defineComponent({
|
||||
name: 'comp-jeecg-basic',
|
||||
setup() {
|
||||
const activeKey = ref('JeecgComponents');
|
||||
const currentComponent = computed(() => {
|
||||
const componentType = {
|
||||
JeecgComponents: JeecgComponents,
|
||||
JEditorDemo: JEditorDemo,
|
||||
JCodeEditDemo: JCodeEditDemo,
|
||||
ImgDragSort: ImgDragSort,
|
||||
ImgTurnPage: ImgTurnPage,
|
||||
JeecgPdfView: JeecgPdfView,
|
||||
JUploadDemo: JUploadDemo,
|
||||
};
|
||||
return componentType[activeKey.value];
|
||||
});
|
||||
|
||||
//使用component动态切换tab
|
||||
function tabChange(key) {
|
||||
activeKey.value = key;
|
||||
}
|
||||
return {
|
||||
activeKey,
|
||||
currentComponent,
|
||||
tabChange,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
864
jeecgboot-vue3/src/views/demo/jeecg/jeecgComponents.data.ts
Normal file
864
jeecgboot-vue3/src/views/demo/jeecg/jeecgComponents.data.ts
Normal file
@ -0,0 +1,864 @@
|
||||
import { FormSchema, JCronValidator } from '/@/components/Form';
|
||||
import { usePermission } from '/@/hooks/web/usePermission';
|
||||
|
||||
const { isDisabledAuth } = usePermission();
|
||||
export const schemas: FormSchema[] = [
|
||||
{
|
||||
field: 'jdst',
|
||||
component: 'JDictSelectTag',
|
||||
label: '性别下拉',
|
||||
helpMessage: ['component模式'],
|
||||
componentProps: {
|
||||
dictCode: 'sex',
|
||||
},
|
||||
colProps: {
|
||||
span: 12,
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'jdst',
|
||||
component: 'JEllipsis',
|
||||
label: '选中值',
|
||||
colProps: { span: 12 },
|
||||
},
|
||||
{
|
||||
field: 'jdst1',
|
||||
component: 'JDictSelectTag',
|
||||
label: '性别选择',
|
||||
helpMessage: ['component模式'],
|
||||
componentProps: {
|
||||
dictCode: 'sex',
|
||||
type: 'radioButton',
|
||||
},
|
||||
colProps: {
|
||||
span: 12,
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'jdst1',
|
||||
component: 'JEllipsis',
|
||||
label: '选中值',
|
||||
colProps: { span: 12 },
|
||||
},
|
||||
{
|
||||
field: 'jdst2',
|
||||
component: 'JDictSelectTag',
|
||||
label: '字典表下拉',
|
||||
helpMessage: ['component模式'],
|
||||
componentProps: {
|
||||
dictCode: 'sys_user,realname,id',
|
||||
},
|
||||
colProps: {
|
||||
span: 12,
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'jdst2',
|
||||
component: 'JEllipsis',
|
||||
label: '选中值',
|
||||
colProps: { span: 12 },
|
||||
},
|
||||
{
|
||||
field: 'jdst3',
|
||||
component: 'JDictSelectTag',
|
||||
label: '字典表下拉(带条件)',
|
||||
helpMessage: ['component模式'],
|
||||
componentProps: {
|
||||
dictCode: "sys_user,realname,id,username!='admin' order by create_time",
|
||||
},
|
||||
colProps: {
|
||||
span: 12,
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'jdst3',
|
||||
component: 'JEllipsis',
|
||||
label: '选中值',
|
||||
colProps: { span: 12 },
|
||||
},
|
||||
{
|
||||
field: 'jsst',
|
||||
component: 'JSearchSelect',
|
||||
label: '字典搜索(同步)',
|
||||
colProps: { span: 12 },
|
||||
componentProps: {
|
||||
//dict: "sys_depart,depart_name,id",
|
||||
dictOptions: [
|
||||
{
|
||||
text: '选项一',
|
||||
value: '1',
|
||||
},
|
||||
{
|
||||
text: '选项二',
|
||||
value: '2',
|
||||
},
|
||||
{
|
||||
text: '选项三',
|
||||
value: '3',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'jsst',
|
||||
component: 'JEllipsis',
|
||||
label: '选择值',
|
||||
colProps: { span: 12 },
|
||||
},
|
||||
{
|
||||
field: 'jsst2',
|
||||
component: 'JSearchSelect',
|
||||
label: '字典搜索(异步)',
|
||||
colProps: { span: 12 },
|
||||
componentProps: {
|
||||
dict: 'sys_depart,depart_name,id',
|
||||
pageSize: 6,
|
||||
async: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'jsst2',
|
||||
component: 'JEllipsis',
|
||||
label: '选择值',
|
||||
colProps: { span: 12 },
|
||||
},
|
||||
{
|
||||
field: 'xldx',
|
||||
component: 'JDictSelectTag',
|
||||
label: '字典下拉多选',
|
||||
colProps: { span: 12 },
|
||||
componentProps: {
|
||||
dictCode: 'sex',
|
||||
mode: 'multiple',
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'xldx',
|
||||
component: 'JEllipsis',
|
||||
label: '选择值',
|
||||
colProps: { span: 12 },
|
||||
},
|
||||
{
|
||||
field: 'xldx2',
|
||||
component: 'JSelectMultiple',
|
||||
label: '字典下拉多选2',
|
||||
colProps: { span: 12 },
|
||||
componentProps: {
|
||||
dictCode: 'sex',
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'xldx2',
|
||||
component: 'JEllipsis',
|
||||
label: '选择值',
|
||||
colProps: { span: 12 },
|
||||
},
|
||||
{
|
||||
field: 'dxxlk',
|
||||
component: 'JDictSelectTag',
|
||||
label: '字典下拉单选',
|
||||
colProps: { span: 12 },
|
||||
componentProps: {
|
||||
dictCode: 'sex',
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'dxxlk',
|
||||
component: 'JEllipsis',
|
||||
label: '选择值',
|
||||
colProps: { span: 12 },
|
||||
},
|
||||
{
|
||||
label: '可输入下拉',
|
||||
field: 'selectInput',
|
||||
component: 'JSelectInput',
|
||||
componentProps: {
|
||||
options: [
|
||||
{ label: '选项一', value: '1' },
|
||||
{ label: '选项二', value: '2' },
|
||||
{ label: '选项三', value: '3' },
|
||||
],
|
||||
},
|
||||
colProps: { span: 12 },
|
||||
},
|
||||
{
|
||||
field: 'selectInput',
|
||||
component: 'JEllipsis',
|
||||
label: '选择值',
|
||||
colProps: { span: 12 },
|
||||
},
|
||||
{
|
||||
field: 'depart3',
|
||||
component: 'JSelectDept',
|
||||
label: '选择部门—自定义值',
|
||||
helpMessage: ['component模式'],
|
||||
componentProps: { showButton: false, rowKey: 'orgCode', primaryKey: 'orgCode' },
|
||||
colProps: {
|
||||
span: 12,
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'depart3',
|
||||
component: 'JEllipsis',
|
||||
label: '选中部门',
|
||||
colProps: { span: 12 },
|
||||
},
|
||||
{
|
||||
field: 'depart2',
|
||||
component: 'JSelectDept',
|
||||
label: '选择部门',
|
||||
helpMessage: ['component模式'],
|
||||
componentProps: { showButton: false },
|
||||
colProps: {
|
||||
span: 12,
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'depart2',
|
||||
component: 'JEllipsis',
|
||||
label: '选中部门',
|
||||
colProps: { span: 12 },
|
||||
},
|
||||
{
|
||||
field: 'user2',
|
||||
component: 'JSelectUser',
|
||||
label: '用户选择组件',
|
||||
helpMessage: ['component模式'],
|
||||
componentProps: {
|
||||
labelKey: 'realname',
|
||||
rowKey: 'id',
|
||||
showSelected: true,
|
||||
},
|
||||
colProps: {
|
||||
span: 12,
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'user2',
|
||||
component: 'JEllipsis',
|
||||
label: '选中用户',
|
||||
colProps: { span: 12 },
|
||||
},
|
||||
{
|
||||
field: 'user3',
|
||||
component: 'JSelectUserByDept',
|
||||
label: '部门选择用户',
|
||||
helpMessage: ['component模式'],
|
||||
componentProps: {
|
||||
labelKey: 'realname',
|
||||
rowKey: 'username',
|
||||
},
|
||||
colProps: {
|
||||
span: 12,
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'user3',
|
||||
component: 'JEllipsis',
|
||||
label: '选中用户',
|
||||
colProps: { span: 12 },
|
||||
},
|
||||
{
|
||||
field: 'role2',
|
||||
component: 'JSelectRole',
|
||||
label: '角色选择组件',
|
||||
helpMessage: ['component模式'],
|
||||
colProps: {
|
||||
span: 12,
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'role2',
|
||||
component: 'JEllipsis',
|
||||
label: '选中角色',
|
||||
colProps: { span: 12 },
|
||||
},
|
||||
{
|
||||
field: 'position2',
|
||||
component: 'JSelectPosition',
|
||||
label: '职务选择组件',
|
||||
helpMessage: ['component模式'],
|
||||
colProps: { span: 12 },
|
||||
componentProps: { async: true, showSelectTable: true },
|
||||
},
|
||||
{
|
||||
field: 'position2',
|
||||
component: 'JEllipsis',
|
||||
label: '选中职务',
|
||||
colProps: { span: 12 },
|
||||
},
|
||||
{
|
||||
field: 'checkbox1',
|
||||
component: 'JCheckbox',
|
||||
label: 'JCheckbox组件1',
|
||||
helpMessage: ['component模式'],
|
||||
defaultValue: '1,2',
|
||||
componentProps: {
|
||||
options: [
|
||||
{ label: '男', value: '1' },
|
||||
{ label: '女', value: '2' },
|
||||
],
|
||||
},
|
||||
colProps: {
|
||||
span: 12,
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'checkbox1',
|
||||
component: 'JEllipsis',
|
||||
label: '选中值',
|
||||
colProps: { span: 12 },
|
||||
},
|
||||
{
|
||||
field: 'checkbox2',
|
||||
component: 'Input',
|
||||
label: 'JCheckbox组件2',
|
||||
defaultValue: '1',
|
||||
helpMessage: ['插槽模式'],
|
||||
slot: 'JCheckbox',
|
||||
colProps: {
|
||||
span: 12,
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'checkbox2',
|
||||
component: 'JEllipsis',
|
||||
label: '选中值',
|
||||
colProps: { span: 12 },
|
||||
},
|
||||
{
|
||||
field: 'data1',
|
||||
label: '日期选择',
|
||||
component: 'DatePicker',
|
||||
componentProps: {
|
||||
showTime: true,
|
||||
valueFormat: 'YYYY-MM-DD HH:mm:ss',
|
||||
},
|
||||
colProps: {
|
||||
span: 12,
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'data1',
|
||||
component: 'JEllipsis',
|
||||
label: '选中值',
|
||||
colProps: {
|
||||
span: 12,
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'data2',
|
||||
label: '年份范围选择',
|
||||
component: 'RangePicker',
|
||||
componentProps: {
|
||||
picker: 'year',
|
||||
valueFormat: 'YYYY',
|
||||
},
|
||||
colProps: {
|
||||
span: 12,
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'data2',
|
||||
component: 'JEllipsis',
|
||||
label: '选中值',
|
||||
colProps: {
|
||||
span: 12,
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'hk',
|
||||
component: 'Input',
|
||||
label: '滑块验证码',
|
||||
helpMessage: ['插槽模式'],
|
||||
slot: 'dargVerify',
|
||||
colProps: {
|
||||
span: 12,
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'hk',
|
||||
component: 'JEllipsis',
|
||||
label: '选中值',
|
||||
colProps: {
|
||||
span: 12,
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'JTreeDict',
|
||||
component: 'JTreeDict',
|
||||
label: '树字典',
|
||||
helpMessage: ['component模式'],
|
||||
colProps: { span: 12 },
|
||||
},
|
||||
{
|
||||
field: 'JTreeDict',
|
||||
component: 'JEllipsis',
|
||||
label: '选中值',
|
||||
colProps: {
|
||||
span: 12,
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'ts',
|
||||
component: 'JTreeSelect',
|
||||
label: '下拉树选择',
|
||||
helpMessage: ['component模式'],
|
||||
componentProps: {
|
||||
dict: 'sys_permission,name,id',
|
||||
pidField: 'parent_id',
|
||||
hasChildField: 'is_leaf',
|
||||
converIsLeafVal: 0,
|
||||
},
|
||||
colProps: {
|
||||
span: 12,
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'ts',
|
||||
component: 'JEllipsis',
|
||||
label: '选中值',
|
||||
colProps: { span: 12 },
|
||||
},
|
||||
{
|
||||
field: 'ts1',
|
||||
component: 'JTreeSelect',
|
||||
label: '下拉树多选',
|
||||
helpMessage: ['component模式'],
|
||||
componentProps: {
|
||||
dict: 'sys_permission,name,id',
|
||||
pidField: 'parent_id',
|
||||
hasChildField: 'is_leaf',
|
||||
converIsLeafVal: 0,
|
||||
multiple: true,
|
||||
},
|
||||
colProps: {
|
||||
span: 12,
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'ts1',
|
||||
component: 'JEllipsis',
|
||||
label: '选中值',
|
||||
colProps: { span: 12 },
|
||||
},
|
||||
{
|
||||
field: 'category',
|
||||
component: 'JCategorySelect',
|
||||
label: '分类字典树',
|
||||
helpMessage: ['component模式'],
|
||||
defaultValue: '',
|
||||
componentProps: {
|
||||
pcode: 'B01',
|
||||
multiple: true,
|
||||
},
|
||||
colProps: {
|
||||
span: 12,
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'category',
|
||||
component: 'JEllipsis',
|
||||
label: '选中值',
|
||||
colProps: { span: 12 },
|
||||
},
|
||||
{
|
||||
field: 'JEasyCron',
|
||||
component: 'JEasyCron',
|
||||
label: 'JEasyCron',
|
||||
helpMessage: ['component模式'],
|
||||
colProps: { span: 12 },
|
||||
defaultValue: '* * * * * ? *',
|
||||
rules: [{ validator: JCronValidator }],
|
||||
},
|
||||
{
|
||||
field: 'JEasyCron',
|
||||
component: 'JEllipsis',
|
||||
label: '选择值',
|
||||
colProps: { span: 12 },
|
||||
},
|
||||
{
|
||||
field: 'JInput',
|
||||
component: 'JInput',
|
||||
label: '特殊查询组件',
|
||||
helpMessage: ['插槽模式'],
|
||||
slot: 'JInput',
|
||||
colProps: {
|
||||
span: 12,
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'jinputtype',
|
||||
component: 'Select',
|
||||
label: '查询类型',
|
||||
componentProps: {
|
||||
options: [
|
||||
{ value: 'like', label: '模糊(like)' },
|
||||
{ value: 'ne', label: '不等于(ne)' },
|
||||
{ value: 'ge', label: '大于等于(ge)' },
|
||||
{ value: 'le', label: '小于等于(le)' },
|
||||
],
|
||||
},
|
||||
colProps: {
|
||||
span: 6,
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'JInput',
|
||||
component: 'JEllipsis',
|
||||
label: '输入值',
|
||||
colProps: { span: 6 },
|
||||
},
|
||||
{
|
||||
field: 'field1',
|
||||
component: 'Select',
|
||||
label: '省市区选择',
|
||||
helpMessage: ['插槽模式'],
|
||||
slot: 'jAreaLinkage',
|
||||
colProps: {
|
||||
span: 12,
|
||||
},
|
||||
defaultValue: ['130000', '130200'],
|
||||
},
|
||||
{
|
||||
field: 'field1',
|
||||
component: 'JEllipsis',
|
||||
label: '选中值',
|
||||
colProps: {
|
||||
span: 12,
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'field0',
|
||||
component: 'Select',
|
||||
label: '禁用组件(方式一)',
|
||||
helpMessage: ['插槽模式'],
|
||||
slot: 'jAreaLinkage1',
|
||||
colProps: {
|
||||
span: 12,
|
||||
},
|
||||
defaultValue: ['130000', '130200'],
|
||||
},
|
||||
|
||||
{
|
||||
field: 'field0',
|
||||
component: 'JEllipsis',
|
||||
label: '选中值',
|
||||
colProps: {
|
||||
span: 12,
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'field2',
|
||||
component: 'JAreaLinkage',
|
||||
label: '禁用组件(方式二)',
|
||||
helpMessage: ['component模式'],
|
||||
colProps: {
|
||||
span: 12,
|
||||
},
|
||||
dynamicDisabled: ({ values }) => {
|
||||
console.log(values);
|
||||
return isDisabledAuth(['demo.dbarray']);
|
||||
},
|
||||
defaultValue: ['140000', '140300', '140302'],
|
||||
},
|
||||
{
|
||||
field: 'field2',
|
||||
component: 'JEllipsis',
|
||||
label: '选中值',
|
||||
colProps: {
|
||||
span: 12,
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'pca1',
|
||||
component: 'JAreaSelect',
|
||||
label: '省市区级联',
|
||||
helpMessage: ['component模式'],
|
||||
defaultValue: '140302',
|
||||
colProps: {
|
||||
span: 12,
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'pca1',
|
||||
component: 'JEllipsis',
|
||||
label: '选中值',
|
||||
colProps: {
|
||||
span: 12,
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'pop1',
|
||||
component: 'Input',
|
||||
label: 'JPopup示例',
|
||||
helpMessage: ['插槽模式'],
|
||||
slot: 'JPopup',
|
||||
colProps: {
|
||||
span: 12,
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'pop1',
|
||||
component: 'JEllipsis',
|
||||
label: '选中值',
|
||||
colProps: {
|
||||
span: 12,
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'JInputPop',
|
||||
component: 'JInputPop',
|
||||
label: 'JInputPop',
|
||||
helpMessage: ['component模式'],
|
||||
colProps: { span: 12 },
|
||||
},
|
||||
{
|
||||
field: 'JInputPop',
|
||||
component: 'JEllipsis',
|
||||
label: '输入值',
|
||||
colProps: { span: 12 },
|
||||
},
|
||||
{
|
||||
field: 'JTreeDictAsync',
|
||||
component: 'JTreeDict',
|
||||
label: '异步JTreeDict',
|
||||
helpMessage: ['component模式'],
|
||||
colProps: { span: 12 },
|
||||
componentProps: { async: true },
|
||||
},
|
||||
{
|
||||
field: 'JTreeDictAsync',
|
||||
component: 'JEllipsis',
|
||||
label: '选中值',
|
||||
colProps: { span: 12 },
|
||||
},
|
||||
{
|
||||
field: 'JSwitch',
|
||||
component: 'JSwitch',
|
||||
label: 'JSwitch',
|
||||
helpMessage: ['component模式'],
|
||||
colProps: { span: 12 },
|
||||
},
|
||||
{
|
||||
field: 'JSwitch',
|
||||
component: 'JEllipsis',
|
||||
label: '选中值',
|
||||
colProps: { span: 12 },
|
||||
},
|
||||
{
|
||||
field: 'JSwitchSelect',
|
||||
component: 'JSwitch',
|
||||
label: 'JSwitchSelect',
|
||||
helpMessage: ['component模式'],
|
||||
colProps: { span: 12 },
|
||||
componentProps: { query: true },
|
||||
},
|
||||
{
|
||||
field: 'JSwitchSelect',
|
||||
component: 'JEllipsis',
|
||||
label: '选中值',
|
||||
colProps: { span: 12 },
|
||||
},
|
||||
|
||||
{
|
||||
field: 'userSelect2',
|
||||
component: 'UserSelect',
|
||||
label: '高级用户选择',
|
||||
helpMessage: ['component模式'],
|
||||
colProps: { span: 12 },
|
||||
},
|
||||
{
|
||||
field: 'userSelect2',
|
||||
component: 'JEllipsis',
|
||||
label: '选中值',
|
||||
colProps: { span: 12 },
|
||||
},
|
||||
|
||||
{
|
||||
field: 'superQuery',
|
||||
component: 'Input',
|
||||
label: '高级查询',
|
||||
helpMessage: ['插槽模式'],
|
||||
slot: 'superQuery',
|
||||
colProps: { span: 12 },
|
||||
},
|
||||
{
|
||||
field: 'superQuery',
|
||||
component: 'JEllipsis',
|
||||
label: '选中值',
|
||||
colProps: { span: 12 },
|
||||
},
|
||||
{
|
||||
field: 'superQuery1',
|
||||
component: 'Input',
|
||||
label: '高级查询',
|
||||
helpMessage: ['插槽模式-自己保存查询条件'],
|
||||
slot: 'superQuery1',
|
||||
colProps: { span: 12 },
|
||||
},
|
||||
{
|
||||
field: 'superQuery1',
|
||||
component: 'JEllipsis',
|
||||
label: '选中值',
|
||||
colProps: { span: 12 },
|
||||
},
|
||||
{
|
||||
field: 'pop2',
|
||||
component: 'JPopupDict',
|
||||
label: 'JPopupDict示例',
|
||||
colProps: {
|
||||
span: 12,
|
||||
},
|
||||
componentProps:{
|
||||
placeholder: '请选择',
|
||||
dictCode: 'report_user,username,id',
|
||||
multi: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'pop2',
|
||||
component: 'JEllipsis',
|
||||
label: '选中值',
|
||||
colProps: {
|
||||
span: 12,
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'sex',
|
||||
component: 'JDictSelectTag',
|
||||
label: '性别(控制下方课程options)',
|
||||
helpMessage: ['component模式','性别不同,下方课程展示选项不同'],
|
||||
componentProps: {
|
||||
dictCode: 'sex',
|
||||
type: 'radioButton',
|
||||
onChange: (value) => {
|
||||
console.log(value);
|
||||
},
|
||||
},
|
||||
colProps: {
|
||||
span: 12,
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'sex',
|
||||
component: 'JEllipsis',
|
||||
label: '选中值',
|
||||
colProps: { span: 12 },
|
||||
},
|
||||
{
|
||||
field: 'course',
|
||||
component: 'Select',
|
||||
label: '课程',
|
||||
dynamicPropskey: 'options',
|
||||
dynamicPropsVal: ({ model }) => {
|
||||
let options;
|
||||
if (model.sex == 1) {
|
||||
return [
|
||||
{ value: '0', label: 'java - 男' },
|
||||
{ value: '1', label: 'vue - 男' },
|
||||
];
|
||||
} else if (model.sex == 2) {
|
||||
return [
|
||||
{ value: '2', label: '瑜伽 - 女' },
|
||||
{ value: '3', label: '美甲 - 女' },
|
||||
];
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
},
|
||||
componentProps: {
|
||||
disabled: false,
|
||||
},
|
||||
colProps: {
|
||||
span: 12,
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'course',
|
||||
component: 'JEllipsis',
|
||||
label: '选中值',
|
||||
colProps: { span: 12 },
|
||||
},
|
||||
{
|
||||
field: 'field100',
|
||||
component: 'JInputSelect',
|
||||
label: 'JInputSelect',
|
||||
helpMessage: ['component模式'],
|
||||
componentProps: {
|
||||
selectPlaceholder: '可选择系统变量',
|
||||
inputPlaceholder: '请输入',
|
||||
options: [
|
||||
{
|
||||
label: '登录用户账号',
|
||||
value: '${sys_user_code}',
|
||||
},
|
||||
{
|
||||
label: '登录用户名称',
|
||||
value: '${sys_user_name}',
|
||||
},
|
||||
{
|
||||
label: '当前日期',
|
||||
value: '${sys_date}',
|
||||
},
|
||||
{
|
||||
label: '当前时间',
|
||||
value: '${sys_date}',
|
||||
},
|
||||
{
|
||||
label: '登录用户部门',
|
||||
value: '${sys_org_code}',
|
||||
},
|
||||
{
|
||||
label: '用户拥有部门',
|
||||
value: '${sys_multi_org_code}',
|
||||
},
|
||||
{
|
||||
label: '登录用户租户',
|
||||
value: '${tenant_id}',
|
||||
},
|
||||
],
|
||||
},
|
||||
colProps: {
|
||||
span: 12,
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'field100',
|
||||
component: 'JEllipsis',
|
||||
label: '选中值',
|
||||
colProps: { span: 12 },
|
||||
},
|
||||
{
|
||||
field: 'JAreaLinkage',
|
||||
component: 'JAreaLinkage',
|
||||
label: '省市区选择',
|
||||
colProps: {
|
||||
span: 12,
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'JAreaLinkage',
|
||||
component: 'JEllipsis',
|
||||
label: '选中值',
|
||||
colProps: { span: 12 },
|
||||
},
|
||||
|
||||
{
|
||||
field: 'orderAuth',
|
||||
component: 'Input',
|
||||
label: '指令权限',
|
||||
helpMessage: ['有权限右侧的"选中值"可见,否则不可见'],
|
||||
colProps: {
|
||||
span: 12,
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'orderAuth',
|
||||
auth: 'demo:order:auth',
|
||||
component: 'JEllipsis',
|
||||
label: '选中值',
|
||||
colProps: { span: 12 },
|
||||
},
|
||||
|
||||
];
|
||||
@ -0,0 +1,94 @@
|
||||
<template>
|
||||
<BasicModal v-bind="$attrs" @register="registerModal" :title="title" @ok="handleSubmit" width="700px">
|
||||
<BasicForm @register="registerForm" />
|
||||
<!--TODO 子表Tab数据-->
|
||||
</BasicModal>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed, unref } from 'vue';
|
||||
import { BasicModal, useModalInner } from '/@/components/Modal';
|
||||
import { BasicForm, useForm } from '/@/components/Form/index';
|
||||
import { defHttp } from '/@/utils/http/axios';
|
||||
// Emits声明
|
||||
const emit = defineEmits(['register', 'success']);
|
||||
const isUpdate = ref(true);
|
||||
//表单配置
|
||||
const [registerForm, { resetFields, setFieldsValue, validate }] = useForm({
|
||||
labelWidth: 150,
|
||||
schemas: [
|
||||
{
|
||||
field: 'orderCode',
|
||||
label: '订单号',
|
||||
component: 'Input',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
field: 'ctype',
|
||||
label: '订单类型',
|
||||
component: 'Select',
|
||||
componentProps: {
|
||||
options: [
|
||||
{ label: '国内订单', value: '1' },
|
||||
{ label: '国际订单', value: '2' },
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'orderDate',
|
||||
label: '订单日期',
|
||||
component: 'DatePicker',
|
||||
componentProps: {
|
||||
valueFormat: 'YYYY-MM-DD hh:mm:ss',
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'orderMoney',
|
||||
label: '订单金额',
|
||||
component: 'InputNumber',
|
||||
},
|
||||
{
|
||||
field: 'content',
|
||||
label: '订单备注',
|
||||
component: 'Input',
|
||||
},
|
||||
{
|
||||
field: 'id',
|
||||
label: 'id',
|
||||
component: 'Input',
|
||||
show: false,
|
||||
},
|
||||
],
|
||||
showActionButtonGroup: false,
|
||||
});
|
||||
//表单赋值
|
||||
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
|
||||
//重置表单
|
||||
await resetFields();
|
||||
setModalProps({ confirmLoading: false });
|
||||
isUpdate.value = !!data?.isUpdate;
|
||||
if (unref(isUpdate)) {
|
||||
//表单赋值
|
||||
await setFieldsValue({
|
||||
...data.record,
|
||||
});
|
||||
}
|
||||
});
|
||||
//设置标题
|
||||
const title = computed(() => (!unref(isUpdate) ? '新增订单' : '编辑订单'));
|
||||
//表单提交事件
|
||||
async function handleSubmit(v) {
|
||||
try {
|
||||
let values = await validate();
|
||||
setModalProps({ confirmLoading: true });
|
||||
//提交表单
|
||||
let url = unref(isUpdate) ? '/test/order/edit' : '/test/order/add';
|
||||
defHttp.post({ url: url, params: values });
|
||||
//关闭弹窗
|
||||
closeModal();
|
||||
//刷新列表
|
||||
emit('success');
|
||||
} finally {
|
||||
setModalProps({ confirmLoading: false });
|
||||
}
|
||||
}
|
||||
</script>
|
||||
Reference in New Issue
Block a user