Эх сурвалжийг харах

fix: Bs-Ui 增加表格选择器

hanxiaohui 2 сар өмнө
parent
commit
cc1596536a

+ 3 - 3
src/components/BsUi/Form/Form.vue

@@ -27,7 +27,7 @@
                        v-model:value="props.formData[item.field]"
                        v-model:selected-data="props.formData[item.field]"
                        v-model:checked="props.formData[item.field]" v-bind="item.componentProps"
-                       @change="handleFieldChange(item, $event)">
+                       @change="(value, extraProps) => handleFieldChange(item, value, extraProps)">
               <slot>{{ item.componentProps?.buttonText || '' }}</slot>
               <template v-for="slot in item.componentProps.slots" #[slot.slotName]="slotVal">
                 <component :is="slot.customRender(slotVal)" v-bind="slot.slotProps"></component>
@@ -101,10 +101,10 @@ const props = defineProps({
 const emits = defineEmits(['cancel', 'ok', 'change']);
 const slots = useSlots();
 
-const handleFieldChange = (field, value) => {
+const handleFieldChange = (field, value, extraValue = {}) => {
   formRef.value.validateFields([field.field])
   field?.onChange && field?.onChange(value)
-  emits('change', value)
+  emits('change', value, extraValue)
 }
 
 const ValidatorSingalField =(field)=>{

+ 214 - 0
src/components/BsUi/TableSelector/index.vue

@@ -0,0 +1,214 @@
+<template>
+  <div class="table-selector flex">
+    <!-- 选择器显示内容 -->
+    <a-select
+      mode="tags"
+      style="width: 100%"
+      :placeholder="placeholder"
+      :open="false"
+      :options="options"
+      v-model:value="selectedKeys"
+      allowClear
+      @change="handleChange"
+      v-bind="extraProps"
+    >
+      <template #tagRender="{ value: val, label, closable, onClose, option }">
+        <a-tag v-if="multiple === SELECT_MULTIPLE.MORE" :closable="closable" style="margin-right: 3px" @close="handleDelete(val, onClose)"
+          >{{ label }}
+        </a-tag>
+        <span v-else>{{ label }}</span>
+      </template>
+    </a-select>
+    <a-form-item-rest>
+      <!-- 选择器输入框 -->
+      <bs-modal-table-selector
+        :bs-modal="bsModalBean"
+        :bs-table="bsTableBean"
+        @ok="handleConfirm"
+        :selected-keys="[]"
+        :multiple="multiple"
+        class="bs-table-selector"
+      ></bs-modal-table-selector>
+    </a-form-item-rest>
+    <a-button type="primary" @click="showModal">
+      <template #icon>
+        <SearchOutlined />
+      </template>
+    </a-button>
+  </div>
+</template>
+
+<script setup lang="jsx">
+  import { computed, ref, watch } from 'vue';
+  import { useBsTable, useBsModal, BsModalTableSelector } from '/@/components/BsUi';
+  import { cloneDeep, isArray, isEmpty } from 'lodash';
+  import { SELECT_MULTIPLE } from '/@/components/BsUi/constant.js';
+
+  const props = defineProps({
+    value: {
+      type: Array || Object,
+    },
+    tableOptions: {
+      type: Object,
+      default: {},
+    },
+    modalOptions: {
+      type: Object,
+      default: {},
+    },
+    placeholder: {
+      type: String,
+      default: '请选择',
+    },
+    labelField: {
+      type: String,
+      default: 'label',
+    },
+    valueField: {
+      type: String,
+      default: 'value',
+    },
+    multiple: {
+      type: Boolean,
+      default: SELECT_MULTIPLE.ONE,
+    },
+    extraProps: {
+      type: Object,
+      default: {}
+    }
+  });
+
+  const emits = defineEmits(['update:value', 'change']);
+
+  // 用于回显勾中的行
+  const selectedKeys = ref([]);
+
+  const options = computed(() => {
+    if (isEmpty(props.value)) {
+      return [];
+    } else {
+      return isArray(props.value)
+        ? props.value.map((v) => ({
+            value: v[props.valueField],
+            label: v[props.labelField],
+          }))
+        : [
+            {
+              value: props.value[props.valueField],
+              label: props.value[props.labelField],
+            },
+          ];
+    }
+  });
+
+  watch(
+    () => props.value,
+    (val) => {
+      if (!isEmpty(val)) {
+        selectedKeys.value = isArray(props.value) ? props.value.map((v) => v[props.valueField]) : [props.value[props.valueField]];
+      } else {
+        selectedKeys.value = [];
+      }
+    },
+    {
+      immediate: true,
+    }
+  );
+
+  const bsTableBean = useBsTable({
+    tableOptions: {
+      isLoadRequest: false,
+      toolbarConfig: {
+        enable: false,
+      },
+      // 表格初始化完成,只加载一次
+      mounted(gridRef) {},
+      ...props.tableOptions,
+    },
+  });
+  const bsModalBean = useBsModal({
+    modalOptions: {
+      width: '700px',
+      visible: false,
+      title: '表格选择器开窗',
+      modalExtraProps: {
+        destroyOnClose: true,
+      },
+      ...props.modalOptions,
+    },
+  });
+
+  const { setModalPropsValue: setMVal } = bsModalBean;
+
+  const updateValue = (value, mode, multiple) => {
+    if (isEmpty(value)) {
+      emits('update:value', undefined);
+      emits('change', undefined, { raw: undefined, mode });
+      return;
+    }
+    const val = multiple
+      ? value.map((v) => ({
+          [props.valueField]: v[props.valueField],
+          [props.labelField]: v[props.labelField],
+        }))
+      : {
+          [props.valueField]: value[0][props.valueField],
+          [props.labelField]: value[0][props.labelField],
+        };
+    emits('update:value', val);
+    emits('change', val, { raw: value, mode });
+  };
+
+  const handleChange = (val) => {
+    if (isEmpty(val)) {
+      updateValue([], 'delete', props.multiple === SELECT_MULTIPLE.MORE);
+    }
+  };
+
+  const handleConfirm = ({ value, setLoading, close }) => {
+    updateValue(value, 'add', props.multiple === SELECT_MULTIPLE.MORE);
+    close();
+    setLoading(false);
+  };
+
+  const showModal = () => {
+    setMVal('visible', true);
+  };
+
+  const handleDelete = (value, onClose) => {
+    if (props.multiple === SELECT_MULTIPLE.MORE) {
+      const newVal = cloneDeep(props.value);
+      const delIndex = newVal.findIndex((v) => v[props.valueField] === value);
+      newVal.splice(delIndex, 1);
+      updateValue(newVal, 'delete', true);
+    } else {
+      updateValue([], 'delete', false);
+    }
+    onClose();
+  };
+
+  defineExpose({
+    showModal,
+  });
+</script>
+
+<style scoped>
+  .table-selector {
+    width: 100%;
+
+    .bs-table-selector {
+      :deep(.ant-input-status-error) {
+        border: none !important;
+        box-shadow: none !important;
+      }
+      :deep(.ant-input-affix-wrapper) {
+        border: 1px solid #d9d9d9 !important;
+        box-shadow: none !important;
+      }
+      :deep(.ant-select-selector) {
+        border: 1px solid #d9d9d9 !important;
+        box-shadow: none !important;
+      }
+    }
+  }
+</style>

+ 7 - 1
src/components/BsUi/index.js

@@ -16,6 +16,8 @@ import BsLink from "./Link/index.vue"
 import BsCatalog from "./Catalog/index.vue"
 import BsSvgIcon from "./SvgIcon/index.vue"
 import BsTabBar from "/@/components/BsUi/TabBar/index.vue"
+import BsPageWrapper from "./PageWrapper/index.vue"
+import BsTableSelector from './TableSelector/index.vue'
 
 const BsUi = {
   install(app) {
@@ -35,6 +37,8 @@ const BsUi = {
     app.component('BsCatalog', BsCatalog);
     app.component('BsSvgIcon', BsSvgIcon);
     app.component('BsTabBar', BsTabBar);
+    app.component('BsPageWrapper', BsPageWrapper);
+    app.component('BsTableSelector', BsTableSelector);
   },
 };
 
@@ -62,5 +66,7 @@ export {
   BsLink,
   BsCatalog,
   BsSvgIcon,
-  BsTabBar
+  BsTabBar,
+  BsPageWrapper,
+  BsTableSelector
 };