123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521 |
- <template>
- <div class="header-actions" v-if="getActionList.length != 0">
- <div class="overflow-box">
- <el-button
- v-for="(item, index) in getActionList"
- :key="index"
- :type="item.type || 'primary'"
- :plain="item.plain || false"
- v-bind="getHeaderActions(item)"
- @click="item.action"
- :disabled="item.disabled || false"
- >
- {{ item.text }}
- </el-button>
- </div>
- </div>
- <div class="table-list-container by-table">
- <!-- v-if="!hideHeader" -->
- <header v-if="false" class="header">
- <h2>{{ title }}</h2>
- </header>
- <div class="by-search" v-if="!hideSearch">
- <div style="display: flex;">
- <div class="by-dropdown" v-for="i in selectConfigCopy" :key="i.prop" style="margin-right:10px">
- <div class="by-dropdown-title">
- {{ i.label }}<i class="el-icon-caret-bottom el-icon--right"></i>
- </div>
- <ul class="by-dropdown-lists">
- <li @click="searchItemSelct('all',i)">全部</li>
- <li v-for="j in i.data" :key="j.value" @click="searchItemSelct(j,i)">{{ j.label }}</li>
- </ul>
- </div>
- </div>
-
- <div style="display: flex">
- <el-input
- placeholder="请输入关键字"
- suffix-icon="search"
- size="mini"
- v-model="keywrod"
- @keyup.enter="searchFn"
- >
- </el-input>
- <el-button
- type="primary"
- style="margin-left: 10px"
- size="default"
- @click="searchFn"
- >搜索</el-button
- >
- <div class="more-icon"><i class="el-icon-wind-power"></i></div>
- <div class="more-icon">
- <i class="el-icon-notebook-2"></i>
- </div>
- </div>
- </div>
- <component :is="containerTag">
- <div class="filter-form-container">
- <slot />
- </div>
- <el-table
- ref="hocElTable"
- v-loading="loading"
- :data="source"
- v-if="!hideTable"
- style="width: 100%"
- v-bind="$attrs"
- v-on="tableEvents"
- row-key="id"
- :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
- >
- <el-table-column
- v-for="(item, index) in config"
- :key="index"
- v-bind="getAttrsValue(item)"
- :type="item.type || ''"
- >
-
-
- <template #default="scope" v-if="!item.type">
- <slot :name="item.attrs.slot" :item="scope.row" v-if="item.attrs.slot">
- 插槽占位符
- </slot>
- <div v-else-if="isFunction(getValue(scope, item))">
-
- <component
- :is="
- renderTypeList[getMatchRenderFunction(item)]
- .target
- "
- :cell-list="getValue(scope, item)()"
- :row="scope.row"
- :parent="getParent"
- @click="
- ($event) => {
- handleNativeClick(
- getAttrsValue(item),
- $event,
- item
- )
- }
- "
- />
- </div>
- <div v-else>
- {{ getValue(scope, item) }}
- </div>
- </template>
- </el-table-column>
- </el-table>
- <el-row
- v-if="!hidePagination"
- class="table-pagination"
- justify="end"
- type="flex"
- >
- <el-pagination
- background
- layout="total, sizes, prev, pager, next, jumper"
- :current-page="getPagination.pageNum"
- :page-size="getPagination.pageSize"
- :total="getPagination.total"
- @size-change="handleSizeChange"
- @current-change="handlePageChange"
- />
- </el-row>
- </component>
- </div>
- </template>
-
- <script>
- import { isFunction as isFn, isBoolean } from './type'
- import ElementsMapping from './ElementsMapping'
- import ComponentsMapping from './ComponentsMapping'
- import { computed, defineComponent, getCurrentInstance, ref } from 'vue'
- import expand from './expand'
- export default defineComponent({
- name: 'Table',
- components: {
- ElementsMapping,
- ComponentsMapping,
- },
- props: {
- hideSearch: {
- type: Boolean,
- default: false,
- },
- hideTable: {
- type: Boolean,
- default: false,
- },
- //顶部搜索下拉配置
- selectConfig:{
- type: Array,
- default() {
- return []
- },
- },
- // 获取表格元数据时携带的参数
- filterParams: {
- type: Object,
- default() {
- return {}
- },
- },
- // 表格加载 loading
- loading: {
- type: Boolean,
- default: false,
- },
- // 表格名称
- title: {
- type: String,
- default: '',
- },
- // 表格元数据
- source: {
- type: Array,
- required: true,
- default() {
- return []
- },
- },
- searchConfig: {
- type: Object,
- default() {
- return {
- keyword: '',
- }
- },
- },
- // 指定外层容器的渲染组件
- containerTag: {
- type: String,
- default: 'div',
- },
- // 是否隐藏表头
- hideHeader: {
- type: Boolean,
- default: false,
- },
- // 是否隐藏分页
- hidePagination: {
- type: Boolean,
- default: false,
- },
- // 分页配置
- pagination: {
- type: Object,
- default() {
- return {}
- },
- },
- // 表格配置文件
- config: {
- type: Array,
- default() {
- return []
- },
- },
- // 表头右上方的按钮组
- actionList: {
- type: Array,
- default() {
- return [{ text: '', action: () => {} }]
- },
- },
- // element table 原生事件
- tableEvents: {
- type: Object,
- default() {
- return {}
- },
- },
- searchKey: {
- type: String,
- default: 'keyword',
- },
- },
- setup(props) {
-
- const { proxy } = getCurrentInstance()
- const keywrod = ref('')
- const selectConfigCopy = computed(()=>{
- return props.selectConfig.map((item)=>{
- item.labelCopy = item.label
- return item
- })
-
- })
- console.log(selectConfigCopy)
- const getAttrsValue = (item) => {
- const { attrs } = item
- const result = {
- ...attrs,
- }
- delete result.prop
- return result
- }
- const renderTypeList = ref({
- render: {},
- renderHTML: {
- target: 'elements-mapping',
- },
- renderComponent: {
- target: 'components-mapping',
- },
- })
- const getParent = computed(() => {
- return proxy.$parent
- })
- const getPagination = computed(() => {
- const params = {
- pageNum: 1,
- pageSize: 10,
- total: 0,
- }
- return Object.assign({}, params, props.pagination)
- })
- const getActionList = computed(() => {
- return props.actionList
- .slice()
- .reverse()
- .filter((it) => it.text)
- })
- const getValue = (scope, configItem) => {
- const prop = configItem.attrs.prop
- const renderName = getMatchRenderFunction(configItem)
- const renderObj = renderTypeList.value[renderName]
- if (renderObj && isFunction(configItem[renderName])) {
- return renderObj.target
- ? getRenderValue(scope, configItem, {
- name: renderName,
- type: 'bind',
- })
- : getRenderValue(scope, configItem)
- }
- return scope.row[prop]
- }
- const getRenderValue = (
- scope,
- item,
- fn = { name: 'render', type: 'call' }
- ) => {
- const prop = item.attrs.prop
- const propValue = prop && scope.row[prop]
- scope.row.$index = scope.$index
- const args = propValue !== undefined ? propValue : scope.row
-
- return item[fn.name][fn.type](getParent.value, args)
- }
- // 匹配 render 开头的函数
- const getMatchRenderFunction = (obj) => {
- return Object.keys(obj).find((key) => {
- const matchRender = key.match(/^render.*/)
- return matchRender && matchRender[0]
- })
- }
- const isFunction = (fn) => {
- return isFn(fn)
- }
- const searchFn = (val) => {
- console.log(props)
- proxy.$emit(
- 'getList',
- Object.assign(props.filterParams, { [props.searchKey]: keywrod.value })
- )
- }
- const handlePageChange = (val) => {
- proxy.$emit(
- 'getList',
- Object.assign(props.filterParams, { pageNum: val })
- )
- }
- const handleSizeChange = (val) => {
- proxy.$emit(
- 'getList',
- Object.assign(props.filterParams, { pageSize: val })
- )
- }
- const getHeaderActions = (item) => {
- return {
- ...item.attrs,
- }
- }
- const stopBubbles = (e) => {
- const event = e || window.event
- if (event && event.stopPropagation) {
- event.stopPropagation()
- } else {
- event.cancelBubble = true
- }
- }
- const handleNativeClick = ({ isBubble }, e,item) => {
- // 考虑到单元格内渲染了组件,并且组件自身可能含有点击事件,故添加了阻止冒泡机制
- // 若指定 isBubble 为 false,则当前单元格恢复冒泡机制
- if (isBoolean(isBubble) && !isBubble) return
- stopBubbles(e)
- }
- //下拉搜索相关
-
- const searchItemSelct = ((item,i) => {
- if(item == 'all') {
- i.label = '全部'
- proxy.$emit(
- 'getList',
- Object.assign(props.filterParams, { [i.prop]: '' })
- )
- return
- }
- i.label = item.label
- console.log(item,i)
- proxy.$emit(
- 'getList',
- Object.assign(props.filterParams, { [i.prop]: item.value })
- )
- })
- return {
- getParent,
- getPagination,
- renderTypeList,
- getActionList,
- getAttrsValue,
- getValue,
- getRenderValue,
- getMatchRenderFunction,
- isFunction,
- handlePageChange,
- handleSizeChange,
- getHeaderActions,
- stopBubbles,
- handleNativeClick,
- keywrod,
- searchFn,
- searchItemSelct,
- selectConfigCopy
- }
- },
- })
- </script>
- <style>
- .table-list-container th {
- color: #333 !important;
- }
- .by-table td .el-button+.el-button{
- margin-left: 0!important;
- }
- .by-table td .el-button{
- background: none!important;
- margin: 0!important;
- padding:8px 6px!important;
- }
- </style>
- <style lang="scss" scoped>
- .by-search {
- display: flex;
- justify-content: space-between;
- margin-bottom: 10px;
- }
- .by-dropdown {
- width: 106px;
- position: relative;
- text-align: left;
- height: 32px;
- z-index: 100;
- padding:0 10px;
- transition: all 0.5s ease;
- cursor: pointer;
- line-height: 32px;
- .by-dropdown-title {
- font-size: 14px;
- background-color: #fff;
-
- }
- ul {
- position: absolute;
- left: 0;
- right: 0;
- top: 32px;
- padding: 0;
- margin: 0;
- z-index: 100;
- display: none;
- li {
- list-style: none;
- font-size: 12px;
- height: 30px;
- padding: 0 10px;
- }
- li:hover {
- background-color: #eff6ff;
- color: #0084ff;
- }
- }
- }
- .by-dropdown::before {
- display: block;
- width: 1px;
- content: ' ';
- position: absolute;
- height: 14px;
- top: 8px;
- background-color: #ddd;
- right: 0;
- z-index: 101;
- }
- .by-dropdown:hover {
- background: #ffffff;
-
- border-radius: 2px 2px 2px 2px;
- opacity: 1;
- ul {
- background: #ffffff;
- box-shadow: 0px 2px 16px 1px rgba(0, 0, 0, 0.06);
- border-radius: 2px 2px 2px 2px;
- opacity: 1;
- display: block;
- text-align: left;
- }
- }
- .header-actions {
- flex: 1;
- overflow-x: auto;
- padding: 20px;
- background: #fff;
- margin-bottom: 20px;
- .overflow-box {
-
- :deep() .el-button:nth-child(1) {
- margin-left: 10px;
- }
- }
- }
- .table-list-container {
- background: #fff;
- padding: 13px 20px 20px;
- .table-pagination {
- padding-top: 20px;
- }
- .header {
- display: flex;
- padding-bottom: 20px;
- }
- .el-table {
- :deep() th {
- font-size: 14px;
- }
- :deep() td {
- font-size: 14px;
- }
- }
- }
- </style>
|