| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360 |
- <template>
- <div class="table-container">
- <div class="flex justify-between table-header">
- <div class="flex-center">
- <!-- 详情里面的表格左侧带有筛选区域的插槽 -->
- <slot name="left-search"></slot>
- <el-button v-if="handleBtnRole('add')" type="primary" @click="$emit('handleAdd')">
- + 添加
- </el-button>
- <el-button v-if="handleBtnRole('import')" @click="handleImport">
- 导入
- </el-button>
- <el-button v-if="handleBtnRole('export')" :loading="exportLoading" @click="handleExport">
- 导出
- </el-button>
- <!-- 左侧其他按钮插槽 -->
- <slot name="left"></slot>
- </div>
- <div class="flex-center">
- <!-- 右侧区域插槽 -->
- <slot name="right"></slot>
- <el-button link @click="openShowList" v-if="rightBtn.includes('list')">
- <SvgIcon iconClass="list-check" /> 列表
- </el-button>
- <!-- 如果是邮件的表格的话,分页组件放在这里 -->
- <pagination style="margin: 0;" v-if="isPagination && isEmail" layout="total, sizes, prev, pager, next"
- v-model:total="total" v-model:page="queryParams.pageIndex" v-model:limit="queryParams.pageSize"
- @pagination="getList" />
- </div>
- </div>
- <el-table
- ref="singleTableRef"
- v-loading="loading"
- :data="pageData"
- height="100%"
- @selection-change="selectionChange"
- @current-change="handleCurrentChange"
- :highlight-current-row="isCurrentChange"
- @sort-change="sortChange"
- >
- <el-table-column type="selection" width="40" align="center" v-if="isCheckbox" :selectable="selectable" />
- <template v-for="(item, index) in tableColumn">
- <el-table-column v-if="item.show" :key="index" :label="item.label" :prop="item.prop" :width="item.width"
- :sortable="item.sortable ? 'custom' : false" :show-overflow-tooltip="item.showOverflowTooltip" :sort-orders="['descending', 'ascending', null]">
- <!-- 自定义列模板 -->
- <template #default="scope" v-if="item.render || item.toFixed">
- <template v-if="item.toFixed">
- <span>{{ scope.row[item.prop] ? scope.row[item.prop].toFixed(2) : '' }}</span>
- </template>
- <component v-if="item.label != '操作'" :is="item.render" :column="scope.row" :index="scope.$index" />
- <template v-else>
- <component :is="item.render" :column="scope.row" :index="scope.$index" />
- <el-button link v-if="handleBtnRole('edit')" type="primary"
- @click="$emit('handleEdit', scope.row)">编辑</el-button>
- <el-button link v-if="handleBtnRole('remove')" type="danger"
- @click="handleDel(scope.row[tableParams.keyId])">删除</el-button>
- </template>
- </template>
- <template #header v-if="item.headerQuestionFilled">
- <div class="flex">
- <el-popover placement="top" :width="item.headerQuestionFilled.width"
- :content="item.headerQuestionFilled.content">
- <template #reference>
- <div>
- <span>{{ item.label }}</span>
- <i-ep-QuestionFilled style="margin-left: 5px;vertical-align: text-bottom;" />
- </div>
- </template>
- </el-popover>
- </div>
- </template>
- </el-table-column>
- </template>
- </el-table>
- <pagination v-if="isPagination && !isEmail" layout="total, sizes, prev, pager, next" v-model:total="total"
- v-model:page="queryParams.pageIndex" v-model:limit="queryParams.pageSize" @pagination="getList" />
- </div>
- <!-- 右侧列表弹窗 -->
- <listSort ref="listSortRef" :defaultColumn="defaultColumn" :cloumnCode="tableParams.cloumnCode"
- @changeList="changeList" />
- <!-- 导入弹窗 -->
- <fileImport ref="fileImportRef" @refresh="getData" />
- </template>
- <script setup lang="ts">
- import { tableTypes, columnTypes } from './types'
- import SvgIcon from '../SvgIcon/index.vue'
- import listSort from './components/listSort.vue'
- import fileImport from './components/fileImport.vue'
- import { listExport } from '@/api/public'
- import { AxiosResponse } from 'axios';
- import auth from '@/plugins/auth'
- import downloadPlugins from '@/plugins/download'
- import { userHobit } from '@/store/modules/userHobit'
- const userHobitStore = userHobit()
- const emits = defineEmits(['handleAdd', 'export', 'selectionChange', 'handleEdit', 'currentChange', 'sortChange'])
- const router = useRouter();
- const props = defineProps({
- // 表格参数,包括column、url跟查询参数,必传
- tableParams: {
- type: Object,
- required: true
- },
- // 是否有复选框
- isCheckbox: {
- type: Boolean,
- default: true
- },
- // 按钮权限,默认空数组,根据权限可传新增、导入、导出、编辑、删除按钮进来
- btnRole: {
- type: Array as () => { type: string, hasPermi: string }[] || [],
- default: () => { return [] }
- },
- // 右侧按钮区域,默认列表,没有时传空数组
- rightBtn: {
- type: Array as () => string[] || [],
- default: () => {
- return ['list']
- }
- },
- // 是否有操作栏
- isOperation: {
- type: Boolean,
- default: true
- },
- // 是否分页
- isPagination: {
- type: Boolean,
- default: true
- },
- // 是否是邮件里面使用,是的话分页组件位置有变化
- isEmail: {
- type: Boolean,
- default: false
- },
- // 是否有单选功能,有的话点击高亮
- isCurrentChange: {
- type: Boolean,
- default: false
- },
- // 表格数据
- tableData: {
- type: Array
- }
- })
- const loading = ref(false)
- const exportLoading = ref(false)
- const pageList = ref([])
- const pageData = computed(() => {
- return props.tableData || pageList.value
- })
- const queryParams = reactive<PageQuery>({
- pageIndex: 1,
- pageSize: 10,
- commonQueryOrderBy: undefined,
- sortMethod: undefined
- })
- const deepClone = (source: any) => {
- let targetObj: any = source.constructor === Array ? [] : {};
- for (let key in source) {
- if (source.hasOwnProperty(key)) {
- // 只拷贝自身的属性,不拷贝原型的属性
- if (source[key] && typeof source[key] === "object") {
- // 元素为引用数据类型
- targetObj[key] = source[key].constructor === Array ? [] : {};
- targetObj[key] = deepClone(source[key]);
- } else {
- // 元素为基本数据类型
- targetObj[key] = source[key];
- }
- }
- }
- return targetObj;
- }
- const total = ref(0)
- // const tableColumn = ref(props.tableParams.tableColumn)
- const tableColumn = ref()
- const { tableParams } = toRefs(props)
- const defaultColumn = deepClone(tableParams.value.tableColumn)
- userHobitStore.sortCloumn(tableParams.value.cloumnCode, props.tableParams.tableColumn).then(sortListColumn => {
- tableColumn.value = sortListColumn
- })
- // console.log(tableColumn.value, "sortListColumn")
- // 查询表格数据
- const getList = () => {
- let params = props.tableParams.queryParams
- if(props.isPagination) {
- params = Object.assign(queryParams, props.tableParams.queryParams)
- }
- params.scopeMenuId = props.tableParams.menuId
- loading.value = true
- props.tableParams.listFn(params).then((res: AxiosResponse) => {
- pageList.value = res.result.records;
- total.value = Number(res.result.total) || 0;
- }).finally(() => {
- loading.value = false;
- })
- }
- const selectable = (row) => {
- if(props.tableParams.selectableKey) {
- return row[props.tableParams.selectableKey] == props.tableParams.selectableValue
- }
- return true
- }
- // 按钮权限判断
- const handleBtnRole = (type: string) => {
- let detailRole = props.btnRole.find(a => a.type == type)
- if(detailRole){
- return auth.hasPermi(detailRole.hasPermi)
- }
- return false
- }
- // 复选框数据变化
- const selectionData = ref([])
- const selectionChange = (val: any) => {
- selectionData.value = val
- emits('selectionChange', selectionData.value)
- }
- const handleCurrentChange = (val) => {
- emits('currentChange', val)
- }
- // 右侧列表操作
- const listSortRef = ref()
- const openShowList = () => {
- listSortRef.value.open(tableColumn.value)
- }
- const changeList = (list: any) => {
- tableColumn.value = list
- }
- // 导入操作
- const fileImportRef = ref()
- const handleImport = () => {
- fileImportRef.value.open(props.tableParams.importCode, props.tableParams.importType)
- }
- // 导出操作
- const handleExport = () => {
- if(pageData.value.length == 0) {
- ElMessage.error('无数据可导出')
- return false
- }
- let params = JSON.parse(JSON.stringify(props.tableParams.queryParams))
- params.pageSize = 9999
- params.pageIndex = 1
- exportLoading.value = true
- listExport({ templateCode: props.tableParams.exportCode, ...params }).then(res => {
- try {
- downloadPlugins.download('export', res)
- }catch {
- ElMessage.error('导出失败,请稍后再试')
- }
- exportLoading.value = false
- })
- }
- // 删除操作
- const handleDel = (id: string | number) => {
- ElMessageBox.confirm(
- '是否确认删除当前数据?',
- '确认提示',
- { type: 'warning', confirmButtonText: '提交', }
- ).then(() => {
- props.tableParams.delFn!(id).then((res: AxiosResponse) => {
- if(res.success) {
- ElMessage.success('删除成功')
- getData()
- }else{
- ElMessage.error('删除失败')
- }
- })
- }).catch(() => {})
- }
- const getData = () => {
- queryParams.pageIndex = 1
- getList()
- }
- const singleTableRef = ref()
- const setCurrent = (row) => {
- singleTableRef.value?.setCurrentRow(row)
- }
- const sortChange = (val) => {
- let props = val.prop.indexOf('.') != -1 ? val.prop.split('.')[1] : val.prop
- queryParams.commonQueryOrderBy = val.order ? props : undefined
- queryParams.sortMethod = val.order ? (val.order == 'ascending' ? 'asc' : 'desc') : undefined
- if(!val.order && tableParams.value.commonQueryOrderBy){
- queryParams.commonQueryOrderBy = tableParams.value.commonQueryOrderBy
- queryParams.sortMethod = tableParams.value.sortMethod || 'desc'
- }
- getList()
- }
- onMounted(() => {
- if(!props.tableData) {
- nextTick(() => {
- if(tableParams.value.commonQueryOrderBy) {
- queryParams.commonQueryOrderBy = tableParams.value.commonQueryOrderBy
- queryParams.sortMethod = tableParams.value.sortMethod || 'desc'
- }
- getList()
- })
- }
- })
- defineExpose({
- getData,
- setCurrent,
- handleExport
- })
- </script>
- <style lang="scss" scoped>
- .table-container{
- display: flex;
- flex-direction: column;
- height: 100%;
- }
- .table-header{
- :deep(.el-button){
- padding: 5px 9px;
- min-width: 56px;
- border-radius: 2px;
- }
- }
- .el-table{
- border: var(--el-table-border);
- border-bottom: 0;
- margin-top: 15px;
- :deep(.el-table__header){
- th{
- background-color: #F8FAFC;
- color: #262626;
- }
- }
- }
- .pagination{
- padding: 30px 0 0;
- :deep(.el-pagination){
- justify-content: flex-end;
- }
- }
- </style>
|