This commit is contained in:
GGJ
2023-12-29 16:25:34 +08:00
18 changed files with 579 additions and 170 deletions

View File

@@ -1,55 +1,53 @@
<template>
<el-popover
:placement="placement"
trigger="focus"
:hide-after="0"
:width="state.selectorWidth"
:visible="state.popoverVisible"
:placement='placement'
trigger='focus'
:hide-after='0'
:width='state.selectorWidth'
:visible='state.popoverVisible'
>
<div
@mouseover.stop="state.iconSelectorMouseover = true"
@mouseout.stop="state.iconSelectorMouseover = false"
class="icon-selector"
@mouseover.stop='state.iconSelectorMouseover = true'
@mouseout.stop='state.iconSelectorMouseover = false'
class='icon-selector'
>
<transition name="el-zoom-in-center">
<div class="icon-selector-box">
<div class="selector-header">
<div class="selector-title">{{ title ? title : '请选择图标' }}</div>
<!-- <div class="selector-tab">
<transition name='el-zoom-in-center'>
<div class='icon-selector-box'>
<div class='selector-header'>
<div class='selector-title'>{{ title ? title : '请选择图标' }}</div>
<div class='selector-tab'>
<span
:title="'Element Puls ' + 'utils.Icon'"
@click="onChangeTab('ele')"
:class="state.iconType == 'ele' ? 'active' : ''"
>ele</span
>
>ele</span>
<span
:title="'Font Awesome ' + 'utils.Icon'"
@click="onChangeTab('awe')"
:class="state.iconType == 'awe' ? 'active' : ''"
>awe</span
>
<span :title="'utils.Ali iconcont Icon'" @click="onChangeTab('ali')" :class="state.iconType == 'ali' ? 'active' : ''"
>ali</span
>
<span
:title="'utils.Local icon title'"
@click="onChangeTab('local')"
:class="state.iconType == 'local' ? 'active' : ''"
>local</span
>
</div> -->
>awe</span>
<!-- <span :title="'utils.Ali iconcont Icon'" @click="onChangeTab('ali')"-->
<!-- :class="state.iconType == 'ali' ? 'active' : ''"-->
<!-- >ali</span>-->
<!-- <span-->
<!-- :title="'utils.Local icon title'"-->
<!-- @click="onChangeTab('local')"-->
<!-- :class="state.iconType == 'local' ? 'active' : ''"-->
<!-- >local</span-->
<!-- >-->
</div>
</div>
<div class="selector-body">
<el-scrollbar ref="selectorScrollbarRef">
<div v-if="renderFontIconNames.length > 0">
<div class='selector-body'>
<el-scrollbar ref='selectorScrollbarRef'>
<div v-if='renderFontIconNames.length > 0'>
<div
class="icon-selector-item"
:title="item"
@click="onIcon(item)"
v-for="(item, key) in renderFontIconNames"
:key="key"
class='icon-selector-item'
:title='item'
@click='onIcon(item)'
v-for='(item, key) in renderFontIconNames'
:key='key'
>
<Icon :name="item" />
<Icon :name='item' />
</div>
</div>
</el-scrollbar>
@@ -59,37 +57,37 @@
</div>
<template #reference>
<el-input
v-model="state.inputValue"
:size="size"
:disabled="disabled"
placeholder="搜索图标"
ref="selectorInput"
@focus="onInputFocus"
@blur="onInputBlur"
v-model='state.inputValue'
:size='size'
:disabled='disabled'
placeholder='搜索图标'
ref='selectorInput'
@focus='onInputFocus'
@blur='onInputBlur'
:class="'size-' + size"
>
<template #prepend>
<div class="icon-prepend">
<div class='icon-prepend'>
<Icon
:key="'icon' + state.iconKey"
:name="state.prependIcon ? state.prependIcon : state.defaultModelValue"
:name='state.prependIcon ? state.prependIcon : state.defaultModelValue'
/>
<div v-if="showIconName" class="name">
<div v-if='showIconName' class='name'>
{{ state.prependIcon ? state.prependIcon : state.defaultModelValue }}
</div>
</div>
</template>
<template #append>
<Icon @click="onInputRefresh" name="el-icon-RefreshRight" />
<Icon @click='onInputRefresh' name='el-icon-RefreshRight' />
</template>
</el-input>
</template>
</el-popover>
</template>
<script setup lang="ts">
<script setup lang='ts'>
import { reactive, ref, onMounted, nextTick, watch, computed } from 'vue'
import { getElementPlusIconfontNames } from '@/utils/iconfont'
import { getElementPlusIconfontNames,getAwesomeIconfontNames } from '@/utils/iconfont'
import { useEventListener } from '@vueuse/core'
import type { Placement } from 'element-plus'
@@ -104,6 +102,7 @@ interface Props {
modelValue?: string
showIconName?: boolean
}
const props = withDefaults(defineProps<Props>(), {
size: 'default',
disabled: false,
@@ -111,7 +110,7 @@ const props = withDefaults(defineProps<Props>(), {
type: 'ele',
placement: 'bottom',
modelValue: '',
showIconName: false,
showIconName: false
})
const emits = defineEmits<{
@@ -142,7 +141,7 @@ const state: {
inputValue: '',
prependIcon: props.modelValue,
defaultModelValue: props.modelValue || 'fa fa-circle-o',
iconKey: 0, // 给icon标签准备个key以随时使用 h 函数重新生成元素
iconKey: 0 // 给icon标签准备个key以随时使用 h 函数重新生成元素
})
const onInputFocus = () => {
@@ -158,27 +157,27 @@ const onInputRefresh = () => {
state.inputValue = ''
emits('update:modelValue', state.defaultModelValue)
emits('change', state.defaultModelValue)
// }
// const onChangeTab = (name: IconType) => {
// state.iconType = name
// state.fontIconNames = []
// if (name == 'ele') {
// getElementPlusIconfontNames().then((res) => {
// state.fontIconNames = res
// })
// } else if (name == 'awe') {
// getAwesomeIconfontNames().then((res) => {
// state.fontIconNames = res.map((name) => `fa ${name}`)
// })
// } else if (name == 'ali') {
// getIconfontNames().then((res) => {
// state.fontIconNames = res.map((name) => `iconfont ${name}`)
// })
// } else if (name == 'local') {
// getLocalIconfontNames().then((res) => {
// state.fontIconNames = res
// })
// }
}
const onChangeTab = (name: IconType) => {
state.iconType = name
state.fontIconNames = []
if (name == 'ele') {
getElementPlusIconfontNames().then((res) => {
state.fontIconNames = res
})
} else if (name == 'awe') {
getAwesomeIconfontNames().then((res) => {
state.fontIconNames = res.map((name) => `fa ${name}`)
})
} else if (name == 'ali') {
getIconfontNames().then((res) => {
state.fontIconNames = res.map((name) => `iconfont ${name}`)
})
} else if (name == 'local') {
getLocalIconfontNames().then((res) => {
state.fontIconNames = res
})
}
}
const onIcon = (icon: string) => {
state.iconSelectorMouseover = state.popoverVisible = false
@@ -232,35 +231,43 @@ onMounted(() => {
})
</script>
<style scoped lang="scss">
<style scoped lang='scss'>
.size-small {
height: 24px;
}
.size-large {
height: 40px;
}
.size-default {
height: 32px;
}
.icon-prepend {
display: flex;
align-items: center;
justify-content: center;
.name {
padding-left: 5px;
}
}
.selector-header {
display: flex;
align-items: center;
margin-bottom: 12px;
}
.selector-tab {
margin-left: auto;
span {
padding: 0 5px;
cursor: pointer;
user-select: none;
&.active,
&:hover {
color: var(--el-color-primary);
@@ -268,9 +275,11 @@ onMounted(() => {
}
}
}
.selector-body {
height: 250px;
}
.icon-selector-item {
display: inline-block;
padding: 10px 10px 6px 10px;
@@ -279,17 +288,21 @@ onMounted(() => {
border-radius: var(--el-border-radius-base);
cursor: pointer;
font-size: 18px;
.icon {
height: 18px;
width: 18px;
}
&:hover {
border: 1px solid var(--el-color-primary);
}
}
:deep(.el-input-group__prepend) {
padding: 0 10px;
}
:deep(.el-input-group__append) {
padding: 0 10px;
}

View File

@@ -14,7 +14,7 @@ const cascaderProps = {
label: 'name',
value: 'id',
checkStrictly: true,
showAllLevels: false
emitPath: false
}
const dictData = useDictData()
const options = dictData.state.area

View File

@@ -13,6 +13,7 @@ export default defineComponent({
},
setup(props, { slots }) {
const attr = reactive(props.attr)
attr['align'] = attr['align'] ? attr['align'] : 'center'
attr['column-key'] = attr['column-key'] ? attr['column-key'] : attr.prop || uuid()
return () => {
return createVNode(Column, attr, slots.default)

View File

@@ -31,7 +31,7 @@
<!-- datetime -->
<div v-if="field.render == 'datetime'">
{{ !fieldValue ? '-' : timeFormat(fieldValue, field.timeFormat ?? undefined) }}
{{ !fieldValue ? '/' : timeFormat(fieldValue, field.timeFormat ?? undefined) }}
</div>
<!-- color -->

View File

@@ -15,7 +15,7 @@
</div>
</transition>
<div class='table-header ba-scroll-style'>
<div class='table-header ba-scroll-style' v-if='showOperation'>
<slot name='operation'></slot>
<!-- 右侧搜索框和工具按钮 -->
<div class='table-search' v-if='$slots.select'>
@@ -39,11 +39,14 @@ const date = ref([window.XEUtils.toDateString(new Date(), 'yyyy-MM-dd'), window.
interface Props {
// 默认展开
showSelect?: boolean
showOperation?: boolean // 是否显示operation
datePicker?: boolean
}
const props = withDefaults(defineProps<Props>(), {
showSelect: true,
showOperation: true,
datePicker: false
})
if (props.datePicker) {

View File

@@ -1,61 +1,88 @@
<template>
<vxe-table
ref="tableRef"
class="ba-data-table w100"
header-cell-class-name="table-header-cell"
:data="tableStore.table.data"
:border="true"
v-loading="tableStore.table.loading"
ref='tableRef'
class='ba-data-table w100'
header-cell-class-name='table-header-cell'
:data='tableStore.table.data'
:border='true'
v-loading='tableStore.table.loading'
stripe
size="small"
@checkbox-change="onSelectionChange"
v-bind="$attrs"
:column-config="{resizable: true}"
:tree-config="{}"
size='small'
@checkbox-change='onSelectionChange'
v-bind='$attrs'
:column-config='{resizable: true}'
:tree-config='{}'
:row-config='{isCurrent: true, isHover: true}'
>
<!-- Column 组件内部是 el-table-column -->
<Column
:attr="item"
:key="key + '-column'"
v-for="(item, key) in tableStore.table.column"
:tree-node='item.treeNode'
>
<!-- tableStore 预设的列 render 方案 -->
<template v-if="item.render" #default="scope">
<FieldRender
:field="item"
:row="scope.row"
:column="scope.column"
:index="scope.rowIndex"
:key="
key +
'-' +
scope.rowIndex +
'-' +
item.render +
'-' +
(item.field ? '-' + item.field + '-' + scope.row[item.field] : '')
"
/>
</template>
</Column>
<template v-if='isGroup'>
<vxe-table-colgroup
v-if='isGroup'
v-for='(item, index) in tableStore.table.column'
:field='item.field'
:title='item.title'
:key='index'
:min-width='item.width'
show-overflow
align='center'
>
<Column
:attr='child'
:key="key + '-column'"
v-for='(child, key) in item.children'
:tree-node='child.treeNode'
>
<!-- tableStore 预设的列 render 方案 -->
<template v-if='child.render' #default='scope'>
<FieldRender
:field='child'
:row='scope.row'
:column='scope.column'
:index='scope.rowIndex'
:key='child.field+scope.rowIndex'
/>
</template>
</Column>
</vxe-table-colgroup>
</template>
<template v-else>
<Column
:attr='item'
:key="key + '-column'"
v-for='(item, key) in tableStore.table.column'
:tree-node='item.treeNode'
>
<!-- tableStore 预设的列 render 方案 -->
<template v-if='item.render' #default='scope'>
<FieldRender
:field='item'
:row='scope.row'
:column='scope.column'
:index='scope.rowIndex'
:key='item.field+scope.rowIndex'
/>
</template>
</Column>
</template>
</vxe-table>
<div v-if="props.pagination" class="table-pagination">
<div v-if='props.pagination' class='table-pagination'>
<el-pagination
:currentPage="tableStore.table.params!.pageNum"
:page-size="tableStore.table.params!.pageSize"
:page-sizes="pageSizes"
:currentPage='tableStore.table.params!.pageNum'
:page-size='tableStore.table.params!.pageSize'
:page-sizes='pageSizes'
background
:layout="config.layout.shrink ? 'prev, next, jumper' : 'sizes,total, ->, prev, pager, next, jumper'"
:total="tableStore.table.total"
@size-change="onTableSizeChange"
@current-change="onTableCurrentChange"
:total='tableStore.table.total'
@size-change='onTableSizeChange'
@current-change='onTableCurrentChange'
></el-pagination>
</div>
<slot name="footer"></slot>
<slot name='footer'></slot>
</template>
<script setup lang="ts">
<script setup lang='ts'>
import { ref, nextTick, inject, computed } from 'vue'
import type { ElTable, TableInstance } from 'element-plus'
import FieldRender from '@/components/table/fieldRender/index.vue'
@@ -69,9 +96,12 @@ const tableStore = inject('tableStore') as TableStoreClass
interface Props extends /* @vue-ignore */ Partial<InstanceType<typeof ElTable>> {
pagination?: boolean
isGroup?: boolean
}
const props = withDefaults(defineProps<Props>(), {
pagination: true
pagination: true,
isGroup: false
})
const onTableSizeChange = (val: number) => {
@@ -109,16 +139,18 @@ defineExpose({
})
</script>
<style scoped lang="scss">
<style scoped lang='scss'>
.ba-data-table :deep(.el-button + .el-button) {
margin-left: 6px;
}
.ba-data-table :deep(.table-header-cell) .cell {
color: var(--el-text-color-primary);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.table-pagination {
box-sizing: border-box;
width: 100%;