Browse Source

新增加fs-table-select 组件

XueNing 6 months ago
parent
commit
f9c46f0c17

+ 1 - 0
src/components.d.ts

@@ -13,6 +13,7 @@ declare module 'vue' {
     ElEditor: typeof import('./components/form/ElEditor.vue')['default']
     ElEmployees: typeof import('./components/form/ElEmployees.vue')['default']
     Exception: typeof import('./components/Exception.vue')['default']
+    FsTableSelect: typeof import('./components/FsTableSelect/index.vue')['default']
     GlobalAside: typeof import('./components/core/GlobalAside.vue')['default']
     GlobalFooter: typeof import('./components/core/GlobalFooter.vue')['default']
     GlobalHeader: typeof import('./components/core/GlobalHeader.vue')['default']

+ 118 - 0
src/components/FsTableSelect/index.vue

@@ -0,0 +1,118 @@
+<script lang="ts">
+import { tableSelectProps, tableSelectEmits } from './props'
+import { ElPopover } from 'element-plus'
+export default defineComponent({
+  name: 'FsTableSelect',
+  props: tableSelectProps,
+  emits: tableSelectEmits,
+  setup(props, { emit }) {
+    // 是否显示
+    const visible = ref(false)
+    // popover 实例
+    const popoverRef = ref<InstanceType<typeof ElPopover>>()
+
+    // 是否未选中
+    const isEmpty = computed<boolean>(() => {
+      if (!props.multiple) {
+        return props.moduleValue == null || props.moduleValue === ''
+      }
+      return !Array.isArray(props.moduleValue) || !props.moduleValue.length
+    })
+
+    // 是否需要清空图标
+    const closeEnable = computed<boolean>(() => {
+      return props.clearable && !props.disabled && !isEmpty.value
+    })
+
+    /* 打开弹窗 */
+    const onFocus = (e: FocusEvent) => {
+      if (props.automaticDropdown && !visible.value) {
+        visible.value = true
+      }
+      emit('focus', e)
+    }
+
+    const tableData = computed(() => {
+      return props.tableConfig?.datasource.then(res => {
+        return res
+      })
+    })
+
+    /* 关闭弹窗 */
+    const onBlur = (e: FocusEvent) => {
+      emit('blur', e)
+    }
+
+    /* 清除事件 */
+    const onClear = () => {
+      emit('clear')
+    }
+
+    return {
+      popoverRef,
+      visible,
+      tableData,
+      closeEnable,
+      onFocus,
+      onBlur,
+      onClear
+    }
+  }
+})
+</script>
+
+<template>
+  <el-popover
+    ref="popoverRef"
+    v-model:visible="visible"
+    :placement="placement"
+    :width="popperWidth"
+    :popper-class="popperClass"
+    :popper-options="popperOptions"
+    trigger="click"
+    teleported
+  >
+    <template #reference>
+      <div class="table-select-container">
+        <el-input
+          :size="size"
+          :disabled="disabled"
+          :placeholder="placeholder"
+          :readonly="true"
+          :validateEvent="false"
+          :autocomplete="autocomplete"
+          :modelValue="moduleValue"
+          @focus="onFocus"
+          @blur="onBlur"
+        >
+          <template v-if="$slots.prefix" #prefix>
+            <slot name="prefix"></slot>
+          </template>
+          <template #suffix>
+            <div class="select-suffix">
+              <ElIcon v-if="closeEnable" class="select-clear" @click.stop="onClear">
+                <slot name="clearIcon">
+                  <CircleClose />
+                </slot>
+              </ElIcon>
+              <ElIcon>
+                <slot name="suffixIcon" :visible="visible">
+                  <ArrowDown />
+                </slot>
+              </ElIcon>
+            </div>
+          </template>
+        </el-input>
+      </div>
+    </template>
+    <vxe-table :data="tableData">
+      <vxe-column v-for="(item, index) in tableConfig?.column" :key="index" v-bind="item"></vxe-column>
+    </vxe-table>
+  </el-popover>
+</template>
+
+<style scoped lang="scss">
+.table-select-container {
+  width: 100%;
+}
+</style>

+ 76 - 0
src/components/FsTableSelect/props.ts

@@ -0,0 +1,76 @@
+/* eslint-disable @typescript-eslint/no-unused-vars */
+import type { InputProps, PopoverProps } from 'element-plus'
+import type { PropType } from 'vue'
+import type { TableConfig } from './types'
+
+export const tableSelectProps = {
+  // 绑定值
+  moduleValue: {
+    type: [String, Number, Array],
+    default: ''
+  },
+  // 是否多选
+  multiple: Boolean,
+  // 是否禁用
+  disabled: Boolean,
+  // 尺寸
+  size: {
+    type: String as PropType<InputProps['size']>,
+    default: 'default'
+  },
+  // 是否支持清除
+  clearable: Boolean,
+  // input 的 autocomplete 属性
+  autocomplete: String,
+  // value 的属性名
+  valueKey: {
+    type: String,
+    default: 'value'
+  },
+  // label 的属性名
+  labelKey: {
+    type: String,
+    default: 'label'
+  },
+  // 回显数据,用于后段分页显示
+  initValue: [Object, Array],
+  // 气泡位置
+  placement: {
+    type: String,
+    default: 'bottom-start'
+  },
+  // 是否在输入框获得焦点后自动弹出选项菜单
+  automaticDropdown: Boolean,
+  // 占位符
+  placeholder: {
+    type: String,
+    default: '请选择'
+  },
+  // popover 宽度
+  popperWidth: {
+    type: [String, Number],
+    default: 560
+  },
+  // popover 样式
+  popperClass: String,
+  // popover 配置项
+  popperOptions: Object as PropType<PopoverProps['popperOptions']>,
+  // 表格配置
+  tableConfig: {
+    type: Object as PropType<TableConfig>
+  }
+}
+
+export type TableSelectProps = ExtractPropTypes<typeof tableSelectProps>
+
+/**
+ * 事件
+ */
+export const tableSelectEmits = {
+  // 清除按钮点击事件
+  clear: () => true,
+  // 获取焦点事件
+  focus: (_e: FocusEvent) => true,
+  // 失去焦点事件
+  blur: (_e: FocusEvent) => true
+}

+ 18 - 0
src/components/FsTableSelect/types/index.ts

@@ -0,0 +1,18 @@
+/* 多选选中数据文本 */
+export interface TableConfig {
+  column: Array<TableColumn>
+  datasource: Promise<any>
+}
+
+interface TableColumn {
+  // 类型
+  type?: string
+  // 列名
+  prop?: string
+  // 表格宽度
+  width?: number | string
+  // 对齐方式
+  align?: string
+  // 标题
+  title?: string
+}

+ 9 - 0
src/router/asyncRouter.ts

@@ -10,6 +10,15 @@ const asyncRouter: RouteRecordRaw[] = [
       icon: 'House'
     }
   },
+  {
+    path: '/tableSelect',
+    name: 'tableSelect',
+    component: () => import('@/views/tableSelect/index.vue'),
+    meta: {
+      title: '下拉表格',
+      icon: 'Table'
+    }
+  },
 
   // -- APPEND HERE --
   {

+ 6 - 0
src/shims-vue.d.ts

@@ -0,0 +1,6 @@
+declare module '*.vue' {
+  import { DefineComponent } from 'vue'
+  // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types
+  const component: DefineComponent<{}, {}, any>
+  export default component
+}

+ 43 - 0
src/views/tableSelect/index.vue

@@ -0,0 +1,43 @@
+<script setup lang="ts">
+import FsTableSelect from '@/components/FsTableSelect/index.vue'
+import type { TableConfig } from '@/components/FsTableSelect/types'
+
+const data = ref('')
+
+const tableConfig: TableConfig = {
+  column: [
+    {
+      type: 'selection',
+      width: 45,
+      align: 'center'
+    },
+    {
+      title: '#',
+      type: 'seq',
+      width: 45,
+      align: 'center'
+    },
+    {
+      title: '姓名',
+      prop: 'name',
+      align: 'center'
+    },
+    {
+      title: '性别',
+      prop: 'name',
+      align: 'center'
+    }
+  ],
+  datasource: Promise.reject([{ name: '张三', sex: '性别' }])
+}
+</script>
+
+<template>
+  <div class="w-full bg-white p-4">
+    <div class="w-230px">
+      <fs-table-select v-model="data" :tableConfig="tableConfig" clearable />
+    </div>
+  </div>
+</template>
+
+<style scoped></style>