mirror of
https://gitee.com/log4j/pig-ui.git
synced 2024-12-23 05:40:20 +08:00
✨ Introducing new features. 新增 popverInput 、表单动态表格组件
This commit is contained in:
parent
fb002a0ed6
commit
de9ece8096
197
src/components/FormTable/index.vue
Normal file
197
src/components/FormTable/index.vue
Normal file
@ -0,0 +1,197 @@
|
||||
<template>
|
||||
<div class="form-table" ref="scFormTable">
|
||||
<el-table :data="data" ref="table" border stripe :cell-style="{ textAlign: 'center' }" :header-cell-style="{
|
||||
textAlign: 'center',
|
||||
background: 'var(--el-table-row-hover-bg-color)',
|
||||
color: 'var(--el-text-color-primary)',
|
||||
}">
|
||||
<el-table-column type="index" width="50" fixed="left">
|
||||
<template #header>
|
||||
<el-button v-if="!hideAdd" type="primary" icon="el-icon-plus" size="small" circle @click="rowAdd"></el-button>
|
||||
<el-tooltip content="序号" placement="top">
|
||||
#
|
||||
</el-tooltip>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<div :class="['form-table-handle', { 'form-table-handle-delete': !hideDelete }]">
|
||||
<span>{{ scope.$index + 1 }}</span>
|
||||
<el-button v-if="!hideDelete" type="danger" icon="el-icon-delete" size="small" plain circle
|
||||
@click="rowDel(scope.row, scope.$index)"></el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="" width="50" v-if="dragSort">
|
||||
<template #header>
|
||||
<el-icon>
|
||||
<el-tooltip content="拖动排序" placement="top">
|
||||
<WarningFilled />
|
||||
</el-tooltip>
|
||||
</el-icon>
|
||||
</template>
|
||||
<template #default>
|
||||
<div class="move" style="cursor: move;">
|
||||
<el-icon>
|
||||
<Sort />
|
||||
</el-icon>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<slot></slot>
|
||||
<template #empty>
|
||||
{{ placeholder }}
|
||||
</template>
|
||||
</el-table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Sortable from 'sortablejs'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
/**
|
||||
* 表格数据
|
||||
*/
|
||||
modelValue: { type: Array, default: () => [] },
|
||||
/**
|
||||
* 新增行模板
|
||||
*/
|
||||
addTemplate: { type: Object, default: () => {} },
|
||||
/**
|
||||
* 无数据时的提示语
|
||||
*/
|
||||
placeholder: { type: String, default: "暂无数据" },
|
||||
/**
|
||||
* 是否启用拖拽排序
|
||||
*/
|
||||
dragSort: { type: Boolean, default: false },
|
||||
/**
|
||||
* 是否隐藏新增按钮
|
||||
*/
|
||||
hideAdd: { type: Boolean, default: false },
|
||||
/**
|
||||
* 是否隐藏删除按钮
|
||||
*/
|
||||
hideDelete: { type: Boolean, default: false }
|
||||
},
|
||||
data(){
|
||||
return {
|
||||
/**
|
||||
* 表格数据
|
||||
*/
|
||||
data: []
|
||||
}
|
||||
},
|
||||
mounted(){
|
||||
this.data = this.modelValue
|
||||
if(this.dragSort){
|
||||
this.rowDrop()
|
||||
}
|
||||
},
|
||||
watch:{
|
||||
modelValue(){
|
||||
this.data = this.modelValue
|
||||
},
|
||||
data: {
|
||||
handler(){
|
||||
/**
|
||||
* 更新表格数据
|
||||
* @event update:modelValue
|
||||
* @type {Array}
|
||||
*/
|
||||
this.$emit('update:modelValue', this.data);
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* 启用表格行拖拽排序
|
||||
*/
|
||||
rowDrop(){
|
||||
const _this = this
|
||||
const tbody = this.$refs.table.$el.querySelector('.el-table__body-wrapper tbody')
|
||||
Sortable.create(tbody, {
|
||||
handle: ".move",
|
||||
animation: 300,
|
||||
ghostClass: "ghost",
|
||||
onEnd({ newIndex, oldIndex }) {
|
||||
_this.data.splice(newIndex, 0, _this.data.splice(oldIndex, 1)[0])
|
||||
const newArray = _this.data.slice(0)
|
||||
const tmpHeight = _this.$refs.scFormTable.offsetHeight
|
||||
_this.$refs.scFormTable.style.setProperty('height', tmpHeight + 'px')
|
||||
_this.data = []
|
||||
_this.$nextTick(() => {
|
||||
_this.data = newArray
|
||||
_this.$nextTick(() => {
|
||||
_this.$refs.scFormTable.style.removeProperty('height')
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
/**
|
||||
* 新增一行
|
||||
*/
|
||||
rowAdd(){
|
||||
const temp = JSON.parse(JSON.stringify(this.addTemplate))
|
||||
this.data.push(temp)
|
||||
},
|
||||
/**
|
||||
* 删除一行
|
||||
* @param {Object} row - 要删除的行数据
|
||||
* @param {number} index - 要删除的行的索引
|
||||
*/
|
||||
rowDel(row, index){
|
||||
this.data.splice(index, 1)
|
||||
},
|
||||
/**
|
||||
* 插入一行
|
||||
* @param {Object} row - 要插入的行数据,默认为新增行模板
|
||||
*/
|
||||
pushRow(row){
|
||||
const temp = row || JSON.parse(JSON.stringify(this.addTemplate))
|
||||
this.data.push(temp)
|
||||
},
|
||||
/**
|
||||
* 根据索引删除一行
|
||||
* @param {number} index - 要删除的行的索引
|
||||
*/
|
||||
deleteRow(index){
|
||||
this.data.splice(index, 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.form-table {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.form-table .form-table-handle {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.form-table .form-table-handle span {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.form-table .form-table-handle button {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.form-table .hover-row .form-table-handle-delete span {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.form-table .hover-row .form-table-handle-delete button {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.form-table .move {
|
||||
text-align: center;
|
||||
font-size: 14px;
|
||||
margin-top: 3px;
|
||||
}
|
||||
</style>
|
105
src/components/PopoverInput/index.vue
Normal file
105
src/components/PopoverInput/index.vue
Normal file
@ -0,0 +1,105 @@
|
||||
<template>
|
||||
<div @mouseenter="inPopover = true" @mouseleave="inPopover = false">
|
||||
<el-popover placement="top" v-model:visible="visible" :width="width" trigger="contextmenu" class="popover-input"
|
||||
:teleported="teleported" :persistent="false" popper-class="!p-0">
|
||||
<div class="flex p-3" @click.stop="">
|
||||
<div class="popover-input__input mr-[10px] flex-1">
|
||||
<el-select class="flex-1" :size="size" v-if="type == 'select'" v-model="inputValue"
|
||||
:teleported="teleported">
|
||||
<el-option v-for="item in options" :key="item.value" :label="item.label"
|
||||
:value="item.value"></el-option>
|
||||
</el-select>
|
||||
<el-input v-else v-model.trim="inputValue" :maxlength="limit" :show-word-limit="showLimit" :type="type"
|
||||
:size="size" clearable :placeholder="placeholder" />
|
||||
</div>
|
||||
<div class="flex-none popover-input__btns">
|
||||
<el-button link @click="close">取消</el-button>
|
||||
<el-button type="primary" :size="size" @click="handleConfirm">确定</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<template #reference>
|
||||
<div class="inline" @click.stop="handleOpen">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</template>
|
||||
</el-popover>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { useEventListener } from '@vueuse/core'
|
||||
import type { PropType } from 'vue'
|
||||
|
||||
const props = defineProps({
|
||||
value: {
|
||||
type: String
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
default: 'text'
|
||||
},
|
||||
width: {
|
||||
type: [Number, String],
|
||||
default: '300px'
|
||||
},
|
||||
placeholder: String,
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
options: {
|
||||
type: Array as PropType<any[]>,
|
||||
default: () => []
|
||||
},
|
||||
size: {
|
||||
type: String as PropType<'default' | 'small' | 'large'>,
|
||||
default: 'default'
|
||||
},
|
||||
limit: {
|
||||
type: Number,
|
||||
default: 200
|
||||
},
|
||||
showLimit: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
teleported: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
})
|
||||
const emit = defineEmits(['confirm'])
|
||||
const visible = ref(false)
|
||||
const inPopover = ref(false)
|
||||
const inputValue = ref()
|
||||
const handleConfirm = () => {
|
||||
close()
|
||||
emit('confirm', inputValue.value)
|
||||
}
|
||||
const handleOpen = () => {
|
||||
if (props.disabled) {
|
||||
return
|
||||
}
|
||||
visible.value = true
|
||||
}
|
||||
const close = () => {
|
||||
visible.value = false
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.value,
|
||||
(value) => {
|
||||
inputValue.value = value
|
||||
},
|
||||
{
|
||||
immediate: true
|
||||
}
|
||||
)
|
||||
|
||||
useEventListener(document.documentElement, 'click', () => {
|
||||
if (inPopover.value) return
|
||||
close()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss"></style>
|
Loading…
Reference in New Issue
Block a user