10 changed files with 6436 additions and 6 deletions
@ -1,3 +1,4 @@ |
|||||
import BasicForm from './src/BasicForm.vue' |
import BasicForm from './src/BasicForm.vue' |
||||
|
import BasicFormV3 from './src/BasicFormV3.vue' |
||||
|
|
||||
export { BasicForm } |
export { BasicForm,BasicFormV3 } |
||||
|
File diff suppressed because it is too large
@ -0,0 +1,3 @@ |
|||||
|
import SearchTableV3 from './src/SearchTable.vue' |
||||
|
|
||||
|
export { SearchTableV3} |
@ -0,0 +1,324 @@ |
|||||
|
<template> |
||||
|
<Dialog :title="dialogTitle" v-model="searchDialogVisible" :width="dialogWidth"> |
||||
|
<!-- 搜索工作栏 --> |
||||
|
<slot :name="'searchQuery'+formFieldRef"></slot> |
||||
|
<ContentWrap v-if="searchQuery"> |
||||
|
<Search :schema="searchSchema" @search="setSearchParamsRef" @reset="setSearchParamsRef" /> |
||||
|
</ContentWrap> |
||||
|
|
||||
|
<!-- 列表头部 --> |
||||
|
<TableHead |
||||
|
:HeadButttondata="HeadButttondata" |
||||
|
:routeName="routeName" |
||||
|
@searchFormClick="searchFormClick" |
||||
|
@buttonBaseClick="buttonBaseClick" |
||||
|
:allSchemas="allSchemasRef" |
||||
|
/> |
||||
|
<ContentWrap> |
||||
|
<TableV2 |
||||
|
v-clientSearchTable |
||||
|
ref="searchTableRef" |
||||
|
:isCheckStrictly="isCheckStrictly" |
||||
|
:columns="tableColumns" |
||||
|
:data="tableObjectRef.tableList" |
||||
|
:loading="tableObjectRef.loading" |
||||
|
:total="tableObjectRef.total" |
||||
|
v-model:pageSize="tableObjectRef.pageSize" |
||||
|
v-model:currentPage="tableObjectRef.currentPage" |
||||
|
v-model:sort="tableObjectRef.sort" |
||||
|
:searchTableSelectionsList="searchTableSelectionsList" |
||||
|
:selection="true" |
||||
|
:selectionTotal="multipleBol" |
||||
|
:reserveSelection="true" |
||||
|
row-key="id" |
||||
|
@rowClick="rowClick" |
||||
|
/> |
||||
|
<!-- <el-table-v2 style="border: 1px solid red;" |
||||
|
:height="700" |
||||
|
ref="searchTableRef" |
||||
|
v-clientSearchTable |
||||
|
:columns="tableColumns" |
||||
|
:data="tableObjectRef.tableList" |
||||
|
fixed></el-table-v2> --> |
||||
|
</ContentWrap> |
||||
|
<template #footer> |
||||
|
<div class="flex items-center"> |
||||
|
<slot :name="'selectionsActions'+formFieldRef" :selections="searchTableRef?searchTableRef.selections:[]"></slot> |
||||
|
<el-button @click="submitForm" type="primary" :disabled="formLoading">{{ sureText }}</el-button> |
||||
|
<slot name="actionsOther"></slot> |
||||
|
<el-button @click="searchDialogVisible = false">取 消</el-button> |
||||
|
|
||||
|
<slot name="actions"></slot> |
||||
|
</div> |
||||
|
</template> |
||||
|
</Dialog> |
||||
|
</template> |
||||
|
<script setup lang="ts"> |
||||
|
import * as defaultButtons from '@/utils/disposition/defaultButtons' |
||||
|
const props = defineProps({ |
||||
|
showSearchTableQueryFields: { |
||||
|
type: Array, |
||||
|
required: false, |
||||
|
default: [] |
||||
|
}, |
||||
|
hiddenFilterBtnFields:{ |
||||
|
type: Array, |
||||
|
required: false, |
||||
|
default: [] |
||||
|
}, |
||||
|
// true 取消父子关联; false 关联 |
||||
|
isCheckStrictly:{ |
||||
|
type:Boolean, |
||||
|
default:false |
||||
|
}, |
||||
|
sureText:{ |
||||
|
type: String, |
||||
|
required: false, |
||||
|
default:'确 定' |
||||
|
} |
||||
|
}) |
||||
|
const { t } = useI18n() // 国际化 |
||||
|
const message = useMessage() // 消息弹窗 |
||||
|
|
||||
|
const route = useRoute() // 路由信息 |
||||
|
const routeName = ref() |
||||
|
routeName.value = route.name |
||||
|
|
||||
|
const searchDialogVisible = ref(false) // 弹窗的是否展示 |
||||
|
const dialogTitle = ref('') // 弹窗的标题 |
||||
|
const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 |
||||
|
const multipleBol = ref(false) |
||||
|
|
||||
|
// 列表头部按钮 |
||||
|
const HeadButttondata = ref( |
||||
|
multipleBol.value |
||||
|
? [ |
||||
|
defaultButtons.defaultWhenPageBtn(null), // 选择当页 |
||||
|
defaultButtons.defaultUnselectPageBtn(null), // 反选当页 |
||||
|
// defaultButtons.defaultDeselectAllBtn(null), // 取消全选 |
||||
|
defaultButtons.defaultFilterBtn(null) // 筛选 |
||||
|
] |
||||
|
: [ |
||||
|
defaultButtons.defaultFilterBtn(null) // 筛选 |
||||
|
] |
||||
|
) |
||||
|
|
||||
|
/** 打开弹窗 */ |
||||
|
const getListRef = ref() |
||||
|
const setSearchParamsRef = ref() |
||||
|
const tableObjectRef = ref() |
||||
|
const getPage: any = ref() |
||||
|
const searchSchema = ref() |
||||
|
const tableColumns = ref() |
||||
|
const formFieldRef = ref('') |
||||
|
const searchFieldRef = ref() |
||||
|
const typeRef = ref() |
||||
|
const rowRef = ref() |
||||
|
const allSchemasRef = ref() |
||||
|
const searchConditionRef = ref() |
||||
|
const searchTableSelectionsList = ref() //表格弹窗回显的列表 |
||||
|
const searchQuery = ref(false) |
||||
|
const hiddenFilterBtn = ref(false) |
||||
|
const updateData = (list:any)=>{ |
||||
|
tableObjectRef.value.tableList = list |
||||
|
searchTableRef.value.clearSelection() |
||||
|
} |
||||
|
const openData = (titleName: any, tableObject:any ,allSchemas: any,multiple: any) => { |
||||
|
dialogWidth.value = '80%' |
||||
|
multipleBol.value = multiple |
||||
|
HeadButttondata.value = multiple |
||||
|
? [ |
||||
|
defaultButtons.defaultWhenPageBtn(null), // 选择当页 |
||||
|
defaultButtons.defaultUnselectPageBtn(null), // 反选当页 |
||||
|
// defaultButtons.defaultDeselectAllBtn(null), // 取消全选 |
||||
|
// defaultButtons.defaultFilterBtn(null) // 筛选 |
||||
|
] |
||||
|
: [ |
||||
|
// defaultButtons.defaultFilterBtn(null) // 筛选 |
||||
|
] |
||||
|
dialogTitle.value = t(`ts.${titleName}`).replace('ts.', '') |
||||
|
tableObjectRef.value = tableObject |
||||
|
searchDialogVisible.value = true |
||||
|
allSchemasRef.value = allSchemas |
||||
|
searchSchema.value = allSchemas.searchSchema |
||||
|
tableColumns.value = allSchemas.tableColumns |
||||
|
} |
||||
|
const open = (titleName: any, allSchemas: any,getApiPage: any, formField: any, searchField: any,multiple: any, type: any, row: any, searchCondition:any , isCountRequestRe:any,isConcatDetailSchemas=false,detailSchemas: any, searchTableSelections:any) => { |
||||
|
searchQuery.value = props.showSearchTableQueryFields.find(item=>item==formField)?true:false |
||||
|
hiddenFilterBtn.value = props.hiddenFilterBtnFields.find(item=>item==formField)?true:false |
||||
|
|
||||
|
dialogWidth.value = '80%' |
||||
|
multipleBol.value = multiple |
||||
|
|
||||
|
const filterBtns = hiddenFilterBtn.value?[]:[defaultButtons.defaultFilterBtn(null)] |
||||
|
|
||||
|
HeadButttondata.value = multiple?[ |
||||
|
defaultButtons.defaultWhenPageBtn(null), // 选择当页 |
||||
|
defaultButtons.defaultUnselectPageBtn(null), // 反选当页 |
||||
|
// defaultButtons.defaultDeselectAllBtn(null), // 取消全选 |
||||
|
...filterBtns, // 筛选 |
||||
|
]: |
||||
|
[ |
||||
|
...filterBtns, // 筛选 |
||||
|
] |
||||
|
searchDialogVisible.value = true |
||||
|
formFieldRef.value = formField |
||||
|
searchFieldRef.value = searchField |
||||
|
allSchemasRef.value = allSchemas |
||||
|
searchSchema.value = allSchemas.searchSchema |
||||
|
if (isConcatDetailSchemas) { |
||||
|
//主子表合并 |
||||
|
console.log('detailSchemas', detailSchemas) |
||||
|
tableColumns.value = [...allSchemas?.tableColumns, ...detailSchemas?.tableMainColumns].filter( |
||||
|
(item) => item.field !== 'action' |
||||
|
) |
||||
|
} else { |
||||
|
tableColumns.value = allSchemas?.tableColumns.filter((item) => item.field !== 'action') |
||||
|
} |
||||
|
getPage.value = getApiPage |
||||
|
typeRef.value = type |
||||
|
rowRef.value = row |
||||
|
// dialogTitle.value = t('action.' + type) |
||||
|
dialogTitle.value = t(`ts.${titleName}`).replace('ts.', '') |
||||
|
searchTableSelectionsList.value = searchTableSelections |
||||
|
|
||||
|
const { tableObject, tableMethods } = useTable({ |
||||
|
getListApi: getPage.value // 分页接口 |
||||
|
}) |
||||
|
tableObject.pageSize = 200 |
||||
|
tableObjectRef.value = tableObject |
||||
|
searchConditionRef.value = searchCondition |
||||
|
if (searchCondition) tableObjectRef.value.params = searchCondition |
||||
|
|
||||
|
// 获得表格的各种操作 |
||||
|
const { getList, setSearchParams } = tableMethods |
||||
|
setSearchParamsRef.value = setSearchParams |
||||
|
getListRef.value = getList |
||||
|
getList() |
||||
|
} |
||||
|
const dialogWidth = ref('80%') |
||||
|
const changeDialogWidth = (width: any) => { |
||||
|
dialogWidth.value = width |
||||
|
} |
||||
|
const hiddenFilterButton = () => { |
||||
|
HeadButttondata.value = [] |
||||
|
} |
||||
|
|
||||
|
// 筛选提交 |
||||
|
const searchFormClick = (searchData) => { |
||||
|
console.log(99, rowRef.value) |
||||
|
console.log(100, searchData) |
||||
|
console.log(101, searchConditionRef.value) |
||||
|
// 20240104 修改 判断 当前弹窗 是否有条件 如果有条件 需拼接到 筛选中 searchData.filters |
||||
|
// 20240321 修改 判断 searchData 是否有条件 如果有 拼接 |
||||
|
if (searchData.filters) { |
||||
|
if (searchConditionRef.value&&searchConditionRef.value.filters) { |
||||
|
Object.keys(searchConditionRef.value.filters).forEach((key) => { |
||||
|
searchData.filters.push(searchConditionRef.value.filters[key]) |
||||
|
}) |
||||
|
} else if(searchConditionRef.value){ |
||||
|
Object.keys(searchConditionRef.value).forEach((key) => { |
||||
|
searchData.filters.push({ |
||||
|
action: '==', |
||||
|
column: key, |
||||
|
value: searchConditionRef.value[key] |
||||
|
}) |
||||
|
}) |
||||
|
} |
||||
|
} else { |
||||
|
if (searchConditionRef.value.filters) { |
||||
|
searchData.filters = searchConditionRef.value.filters |
||||
|
} else if(searchConditionRef.value){ |
||||
|
searchData.filters = [] |
||||
|
Object.keys(searchConditionRef.value).forEach((key) => { |
||||
|
searchData.filters.push({ |
||||
|
action: '==', |
||||
|
column: key, |
||||
|
value: searchConditionRef.value[key] |
||||
|
}) |
||||
|
}) |
||||
|
} |
||||
|
} |
||||
|
tableObjectRef.value.params = { |
||||
|
isSearch: true, |
||||
|
filters: searchData.filters |
||||
|
} |
||||
|
getListRef.value() // 刷新当前列表 |
||||
|
} |
||||
|
const buttonBaseClick = (val, item) => { |
||||
|
// 设置按钮 |
||||
|
if (val == 'DeselectAll') { |
||||
|
// 取消全选 |
||||
|
searchTableRef.value.clearSelection() |
||||
|
} else if (val == 'UnselectPage') { |
||||
|
// 反选当页 |
||||
|
searchTableRef.value.togglePageSelection() |
||||
|
} else if (val == 'WhenPage') { |
||||
|
// 选择当页 |
||||
|
searchTableRef.value.toggleAllSelection(true) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
defineExpose({ open,openData,updateData,hiddenFilterButton ,changeDialogWidth,searchFormClick}) // 提供 open 方法,用于打开弹窗 |
||||
|
|
||||
|
// Table 组件 ref |
||||
|
const searchTableRef = ref() |
||||
|
|
||||
|
/** 提交表单 */ |
||||
|
const emit = defineEmits(['searchTableSuccess']) // 定义 searchTableSuccess 事件,用于操作成功后的回调 |
||||
|
const submitForm = async () => { |
||||
|
// 提交请求 |
||||
|
formLoading.value = true |
||||
|
const selections = searchTableRef.value.selections |
||||
|
// 如果不是多选的 |
||||
|
if (!multipleBol.value) { |
||||
|
if (selections.length > 1 || selections.length == 0) { |
||||
|
message.warning('请选择一条数据!') |
||||
|
formLoading.value = false |
||||
|
return |
||||
|
} |
||||
|
// 多选 |
||||
|
} else { |
||||
|
if (selections.length == 0) { |
||||
|
message.warning('至少选择一条数据!') |
||||
|
formLoading.value = false |
||||
|
return |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
try { |
||||
|
searchDialogVisible.value = false |
||||
|
// 发送操作成功的事件 |
||||
|
emit( |
||||
|
'searchTableSuccess', |
||||
|
formFieldRef.value, |
||||
|
searchFieldRef.value, |
||||
|
selections, |
||||
|
typeRef.value, |
||||
|
rowRef.value |
||||
|
) |
||||
|
} finally { |
||||
|
formLoading.value = false |
||||
|
} |
||||
|
} |
||||
|
const rowClick = (row: any, column: any, event: Event) => { |
||||
|
|
||||
|
const selected = searchTableRef.value?.elTableRef |
||||
|
?.getSelectionRows() |
||||
|
.some((item) => item.id === row.id) |
||||
|
if (!selected) { |
||||
|
searchTableRef.value?.elTableRef?.toggleRowSelection(row, true) |
||||
|
if(props.isCheckStrictly&&row.children){//取消关联 |
||||
|
row.children.forEach(item => { |
||||
|
searchTableRef.value?.elTableRef?.toggleRowSelection(item, false) |
||||
|
}); |
||||
|
} |
||||
|
} else { |
||||
|
// 取消 |
||||
|
searchTableRef.value?.elTableRef?.toggleRowSelection(row, false) |
||||
|
} |
||||
|
} |
||||
|
</script> |
||||
|
<style scoped lang="scss"> |
||||
|
</style> |
@ -0,0 +1,226 @@ |
|||||
|
|
||||
|
<template> |
||||
|
<div style="height: 400px" v-loading="loading"> |
||||
|
<el-auto-resizer> |
||||
|
<template #default="{ height, width }"> |
||||
|
<el-table-v2 |
||||
|
class="table-v2-container" |
||||
|
row-key="id" |
||||
|
:columns="[selectionColumn,...mColumns]" |
||||
|
:data="mData" |
||||
|
:width="width" |
||||
|
:height="height" |
||||
|
fixed |
||||
|
/> |
||||
|
</template> |
||||
|
</el-auto-resizer> |
||||
|
<div class="mt-15px float-left" style='height:32px;line-height:32px'>已选{{ selections.length }}条数据</div> |
||||
|
<el-pagination v-model:current-page="currentPageRef" v-model:page-size="pageSizeRef" class="float-right mt-15px" layout="total, sizes, prev, pager, next, jumper" :total="total" :page-sizes="[200,500,1000,2000]"/> |
||||
|
|
||||
|
</div> |
||||
|
</template> |
||||
|
<script lang="tsx" setup> |
||||
|
import { ref, unref } from 'vue' |
||||
|
import { ElCheckbox } from 'element-plus' |
||||
|
import type { FunctionalComponent } from 'vue' |
||||
|
import type { CheckboxValueType, Column } from 'element-plus' |
||||
|
import {formatDate } from '@/utils/formatTime' |
||||
|
|
||||
|
|
||||
|
const props = defineProps({ |
||||
|
// 表头 |
||||
|
columns: { |
||||
|
type: Array as PropType<TableColumn[]>, |
||||
|
default: () => [] |
||||
|
}, |
||||
|
data: { |
||||
|
type: Array as PropType<Recordable[]>, |
||||
|
default: () => [] |
||||
|
}, |
||||
|
currentPage: { |
||||
|
type: Number, |
||||
|
default: 1 |
||||
|
}, |
||||
|
pageSize: { |
||||
|
type: Number, |
||||
|
default: 200 |
||||
|
}, |
||||
|
total: { |
||||
|
type: Number, |
||||
|
default: 0 |
||||
|
}, |
||||
|
// 加载状态 |
||||
|
loading: { |
||||
|
type: Boolean, |
||||
|
default: false |
||||
|
}, |
||||
|
}) |
||||
|
const pageSizeRef = ref(props.pageSize) |
||||
|
const currentPageRef = ref(props.currentPage) |
||||
|
watch( |
||||
|
() => props.currentPage, |
||||
|
(val: number) => { |
||||
|
currentPageRef.value = val |
||||
|
} |
||||
|
) |
||||
|
watch( |
||||
|
() => props.pageSize, |
||||
|
(val: number) => { |
||||
|
pageSizeRef.value = val |
||||
|
} |
||||
|
) |
||||
|
watch( |
||||
|
() => pageSizeRef.value, |
||||
|
(val: number) => { |
||||
|
emit('update:pageSize', val) |
||||
|
} |
||||
|
) |
||||
|
watch( |
||||
|
() => currentPageRef.value, |
||||
|
(val: number) => { |
||||
|
emit('update:currentPage', val) |
||||
|
} |
||||
|
) |
||||
|
console.log('columns====',props.columns) |
||||
|
type SelectionCellProps = { |
||||
|
value: boolean |
||||
|
intermediate?: boolean |
||||
|
onChange: (value: CheckboxValueType) => void |
||||
|
} |
||||
|
const SelectionCell: FunctionalComponent<SelectionCellProps> = ({ |
||||
|
value, |
||||
|
intermediate = false, |
||||
|
onChange, |
||||
|
}) => { |
||||
|
return ( |
||||
|
<ElCheckbox |
||||
|
onChange={onChange} |
||||
|
modelValue={value} |
||||
|
indeterminate={intermediate} |
||||
|
/> |
||||
|
) |
||||
|
} |
||||
|
const selectionColumn = ref({ |
||||
|
key: 'selection', |
||||
|
width: 50, |
||||
|
align:'center', |
||||
|
cellRenderer: ({ rowData,rowIndex }) => { |
||||
|
const onChange = (value: CheckboxValueType) => { |
||||
|
console.log('onChange', value) |
||||
|
rowData.checked = value |
||||
|
selections.value = selections.value.filter(item=>item.id!=rowData.id) |
||||
|
if (value) { |
||||
|
selections.value.push(rowData) |
||||
|
} |
||||
|
} |
||||
|
return <SelectionCell value={rowData.checked} onChange={onChange} /> |
||||
|
}, |
||||
|
|
||||
|
headerCellRenderer: () => { |
||||
|
const _data = unref(mData) |
||||
|
const onChange = (value: CheckboxValueType) => |
||||
|
{ |
||||
|
mData.value = _data.map((row) => { |
||||
|
row.checked = value |
||||
|
return row |
||||
|
}) |
||||
|
selections.value = selections.value.filter(item=>mData.value.findIndex(item1=>item1.id==item.id)==-1) |
||||
|
if(value){ |
||||
|
selections.value = [...selections.value,...mData.value] |
||||
|
} |
||||
|
} |
||||
|
const allSelected = _data.every((row) => row.checked) |
||||
|
const containsChecked = _data.some((row) => row.checked) |
||||
|
|
||||
|
return ( |
||||
|
<SelectionCell |
||||
|
value={allSelected} |
||||
|
intermediate={containsChecked && !allSelected} |
||||
|
onChange={onChange} |
||||
|
/> |
||||
|
) |
||||
|
}, |
||||
|
}) |
||||
|
const mColumns = ref(props.columns.map(item=>({ |
||||
|
key: 'id', |
||||
|
dataKey: item['field'], |
||||
|
title: item['label'], |
||||
|
width: 140, |
||||
|
}))) |
||||
|
|
||||
|
const mData = ref([]) |
||||
|
watch(()=>props.data,()=>{ |
||||
|
console.log('selections',selections.value ) |
||||
|
mData.value = props.data.map(item=>({ |
||||
|
...item, |
||||
|
checked: selections.value.find(item1=>item1.id==item.id)?true:false, |
||||
|
createTime:formatDate(item.createTime) |
||||
|
})) |
||||
|
console.log('mData',mData.value) |
||||
|
|
||||
|
}) |
||||
|
|
||||
|
const rowEventHandlers = ({onClick})=>{ |
||||
|
|
||||
|
} |
||||
|
|
||||
|
const selections = ref([]) |
||||
|
// const selections = computed(()=>mData.value.filter(item=>item.checked)) |
||||
|
// 切换全选/不全选 |
||||
|
const toggleAllSelection = (isAll)=>{ |
||||
|
if(isAll){ |
||||
|
//全选 |
||||
|
mData.value.forEach((row) => { |
||||
|
row.checked = isAll |
||||
|
}) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
const togglePageSelection = (isAll)=>{ |
||||
|
mData.value.forEach((row) => { |
||||
|
row.checked = !row.checked |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
|
||||
|
defineExpose({ selections,toggleAllSelection,togglePageSelection }) |
||||
|
|
||||
|
const emit = defineEmits(['update:pageSize','update:currentPage']) |
||||
|
|
||||
|
console.log('props.data',props.data) |
||||
|
console.log('mData',mData.value) |
||||
|
// const columns = generateColumns(10) |
||||
|
// const data = generateData(columns, 200) |
||||
|
|
||||
|
</script> |
||||
|
<style lang="scss" scoped> |
||||
|
.table-v2-container { |
||||
|
border: 1px solid #ebeef5; |
||||
|
::v-deep(.el-table-v2__header-cell) { |
||||
|
border-right: 1px solid #ebeef5; |
||||
|
text-align: center; |
||||
|
&:last-child{ |
||||
|
border-right: none; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
::v-deep(.el-table-v2__header-cell-text) { |
||||
|
width: 100%; |
||||
|
} |
||||
|
::v-deep(.el-table-v2__row-cell) { |
||||
|
text-align: center; |
||||
|
border-right: 1px solid #ebeef5; |
||||
|
&:last-child{ |
||||
|
border-right: none; |
||||
|
} |
||||
|
} |
||||
|
::v-deep(.el-table-v2__cell-text) { |
||||
|
width: 100%; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
||||
|
} |
||||
|
|
||||
|
|
||||
|
</style> |
File diff suppressed because it is too large
File diff suppressed because it is too large
Loading…
Reference in new issue