|
|
@@ -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>
|