|
@@ -1,13 +1,42 @@
|
|
|
<script setup lang="ts">
|
|
|
-import { tableSelectProps, tableSelectEmits } from './props'
|
|
|
+import type { TableSelectProps } from './props'
|
|
|
+import { tableSelectEmits } from './props'
|
|
|
import { ElPopover } from 'element-plus'
|
|
|
import type { VxeTableInstance } from 'vxe-table'
|
|
|
-// ToDo: emit => emits
|
|
|
-// ToDo: modelvalue => {key, value}
|
|
|
-// 提供一个转换数据的方法 transformData 默认json => string
|
|
|
-// 提交数据转换 submitData => json
|
|
|
-const emit = defineEmits(tableSelectEmits)
|
|
|
-const props = defineProps(tableSelectProps)
|
|
|
+
|
|
|
+const emits = defineEmits(tableSelectEmits)
|
|
|
+const props = withDefaults(defineProps<TableSelectProps>(), {
|
|
|
+ modelValue: '',
|
|
|
+ size: 'default',
|
|
|
+ clearable: true,
|
|
|
+ valueKey: 'id',
|
|
|
+ labelKey: 'name',
|
|
|
+ placement: 'bottom-start',
|
|
|
+ placeholder: '请选择',
|
|
|
+ popperWidth: 560,
|
|
|
+ tagType: 'info',
|
|
|
+ maxTagCount: 5
|
|
|
+})
|
|
|
+
|
|
|
+/* 格式化提交数据 */
|
|
|
+const transformData = (value: any) => {
|
|
|
+ let result = ''
|
|
|
+ if (value) {
|
|
|
+ if (Array.isArray(value)) {
|
|
|
+ result = value
|
|
|
+ .map(item => {
|
|
|
+ return JSON.stringify({
|
|
|
+ [props.valueKey]: item[props.valueKey],
|
|
|
+ [props.labelKey]: item[props.labelKey]
|
|
|
+ })
|
|
|
+ })
|
|
|
+ .join(',')
|
|
|
+ } else {
|
|
|
+ result = JSON.stringify({ [props.valueKey]: value[props.valueKey], [props.labelKey]: value[props.labelKey] })
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return result
|
|
|
+}
|
|
|
|
|
|
// popover 实例
|
|
|
const popoverRef = ref<InstanceType<typeof ElPopover>>()
|
|
@@ -23,13 +52,12 @@ const loading = ref(false)
|
|
|
const tableData = ref<any[]>([])
|
|
|
// 页码
|
|
|
const pageIndex = ref<number>(1)
|
|
|
+// 总数
|
|
|
+const tableTotal = ref<number>(0)
|
|
|
|
|
|
// 是否未选中
|
|
|
const isEmpty = computed<boolean>(() => {
|
|
|
- if (!props.multiple) {
|
|
|
- return !!props.modelValue
|
|
|
- }
|
|
|
- return !Array.isArray(props.modelValue) || !props.modelValue.length
|
|
|
+ return props.modelValue == null || props.modelValue === ''
|
|
|
})
|
|
|
|
|
|
// 是否需要清空图标
|
|
@@ -52,28 +80,23 @@ const omittedValues = computed(() => {
|
|
|
return selectLabel.value.slice(props.maxTagCount)
|
|
|
})
|
|
|
|
|
|
-onMounted(() => {
|
|
|
- initValueChange(props.initValue)
|
|
|
-})
|
|
|
-
|
|
|
/* 打开弹窗 */
|
|
|
const onFocus = (e: FocusEvent) => {
|
|
|
- visible.value = true
|
|
|
- emit('focus', e)
|
|
|
+ emits('focus', e)
|
|
|
}
|
|
|
|
|
|
/* 关闭弹窗 */
|
|
|
const onBlur = (e: FocusEvent) => {
|
|
|
- emit('blur', e)
|
|
|
+ emits('blur', e)
|
|
|
}
|
|
|
|
|
|
/* 清除事件 */
|
|
|
const onClear = () => {
|
|
|
- updateModelValue(props.multiple ? [] : null)
|
|
|
+ updateModelValue('')
|
|
|
selectLabel.value = ''
|
|
|
// 取消表格全部选中
|
|
|
tableRef.value?.clearCheckboxRow()
|
|
|
- emit('clear')
|
|
|
+ emits('clear')
|
|
|
}
|
|
|
|
|
|
/* 单个清除事件 */
|
|
@@ -85,8 +108,8 @@ const onItemClear = (item: any) => {
|
|
|
|
|
|
// 取消表格选中数据
|
|
|
tableRef.value?.toggleCheckboxRow(item)
|
|
|
- updateModelValue(list.map(x => x[props.valueKey]))
|
|
|
- emit('item-clear', { item, list })
|
|
|
+ updateModelValue(list)
|
|
|
+ emits('item-clear', { item, list })
|
|
|
}
|
|
|
|
|
|
/* 表格单选事件 */
|
|
@@ -94,41 +117,43 @@ const tableRadioChange = (data: any) => {
|
|
|
selectLabel.value = data.row[props.labelKey]
|
|
|
visible.value = false
|
|
|
// 发出选择事件
|
|
|
- updateModelValue(data.row[props.valueKey])
|
|
|
- emit('change', data.row)
|
|
|
+ updateModelValue(data.row)
|
|
|
+ emits('change', data.row)
|
|
|
}
|
|
|
|
|
|
/* 表格多选择事件 */
|
|
|
const tableCheckboxChange = (data: any) => {
|
|
|
- let result = []
|
|
|
+ let result: Array<any> = []
|
|
|
if (data.checked) {
|
|
|
// 使用 Set 去重
|
|
|
const uniqueArray = Array.from(
|
|
|
new Set([...selectLabel.value, ...data.records].map((x: any) => JSON.stringify(x)))
|
|
|
).map((str: any) => JSON.parse(str))
|
|
|
selectLabel.value = uniqueArray
|
|
|
- result = selectLabel.value.map(x => x[props.valueKey])
|
|
|
+ result = uniqueArray
|
|
|
} else {
|
|
|
const selects = selectLabel.value as Array<any>
|
|
|
const index = selects.findIndex(x => x[props.valueKey] === data.row[props.valueKey])
|
|
|
selects?.splice(index, 1)
|
|
|
- result = selects.map(x => x[props.valueKey])
|
|
|
+ result = selects
|
|
|
}
|
|
|
// 发出选择事件
|
|
|
updateModelValue(result)
|
|
|
- emit('change', selectLabel.value)
|
|
|
+ emits('change', selectLabel.value)
|
|
|
}
|
|
|
|
|
|
/* initValue 改变 */
|
|
|
const initValueChange = (value: any) => {
|
|
|
+ // 如果是字符串,则解析成对象
|
|
|
+ value = typeof value === 'string' ? JSON.parse(value) : value
|
|
|
if (props.initValue) {
|
|
|
// 处理回显数据
|
|
|
if (props.multiple) {
|
|
|
- selectLabel.value = value as Array<any>
|
|
|
+ selectLabel.value = value
|
|
|
} else {
|
|
|
- selectLabel.value = value[props.labelKey] as any
|
|
|
+ selectLabel.value = value[props.labelKey] as string
|
|
|
}
|
|
|
- updateModelValue(props.multiple ? value.map((x: any) => x[props.valueKey]) : value[props.valueKey])
|
|
|
+ updateModelValue(value)
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -138,11 +163,6 @@ const paginationChange = (data: number) => {
|
|
|
request()
|
|
|
}
|
|
|
|
|
|
-/* 重新加载表格 ToDo:直接使用request */
|
|
|
-const reload = (where: any) => {
|
|
|
- request(where)
|
|
|
-}
|
|
|
-
|
|
|
/* 表格请求完成 */
|
|
|
const tableDone = () => {
|
|
|
nextTick(() => {
|
|
@@ -153,7 +173,7 @@ const tableDone = () => {
|
|
|
Array.isArray(selectLabel.value) && selectLabel.value.find(x => x[props.valueKey] === item[props.valueKey])
|
|
|
temp && tableRef.value?.setCheckboxRow(item, true)
|
|
|
} else {
|
|
|
- const temp = item[props.valueKey] === props.modelValue
|
|
|
+ const temp = item[props.valueKey] === (props.modelValue && JSON.parse(props.modelValue)[props.valueKey])
|
|
|
temp && tableRef.value?.setRadioRow(item)
|
|
|
}
|
|
|
})
|
|
@@ -175,6 +195,7 @@ const request = (where?: any) => {
|
|
|
...where
|
|
|
})
|
|
|
.then((res: any) => {
|
|
|
+ tableTotal.value = res.total || res.totalCount
|
|
|
tableData.value = res.infos || res.list || res.records || res.data || res.info
|
|
|
tableDone()
|
|
|
})
|
|
@@ -192,7 +213,7 @@ request()
|
|
|
|
|
|
/* 更新选中值 */
|
|
|
const updateModelValue = (value: any) => {
|
|
|
- emit('update:modelValue', value)
|
|
|
+ emits('update:modelValue', props.transformData ? props.transformData(value) : transformData(value))
|
|
|
}
|
|
|
|
|
|
/* 更新气泡位置 */
|
|
@@ -210,12 +231,13 @@ watch(currentValues, () => {
|
|
|
watch(
|
|
|
() => props.initValue,
|
|
|
() => {
|
|
|
- initValueChange(props.initValue as object | Array<any>)
|
|
|
- }
|
|
|
+ initValueChange(props.initValue)
|
|
|
+ },
|
|
|
+ { immediate: true }
|
|
|
)
|
|
|
|
|
|
defineExpose({
|
|
|
- reload
|
|
|
+ request
|
|
|
})
|
|
|
</script>
|
|
|
|
|
@@ -240,7 +262,6 @@ defineExpose({
|
|
|
:placeholder="multiple && !isEmpty ? '' : placeholder"
|
|
|
:readonly="true"
|
|
|
:validateEvent="false"
|
|
|
- :autocomplete="autocomplete"
|
|
|
:modelValue="multiple ? '' : selectLabel"
|
|
|
@focus="onFocus"
|
|
|
@blur="onBlur"
|
|
@@ -303,14 +324,14 @@ defineExpose({
|
|
|
</template>
|
|
|
</vxe-column>
|
|
|
</vxe-table>
|
|
|
- <div class="table-select-pagination" v-if="tableConfig.total">
|
|
|
+ <div class="table-select-pagination" v-if="tableTotal">
|
|
|
<el-pagination
|
|
|
background
|
|
|
layout="total, prev, pager, next, jumper"
|
|
|
size="small"
|
|
|
:pager-count="5"
|
|
|
- :page-size="tableConfig.pageSize"
|
|
|
- :total="tableConfig.total"
|
|
|
+ :page-size="tableConfig && tableConfig.pageSize"
|
|
|
+ :total="tableTotal"
|
|
|
v-model:current-page="pageIndex"
|
|
|
@current-change="paginationChange"
|
|
|
/>
|