Vue3中a-tree插槽自定义树形新增组件、扩展a-input实现a-input-number功能

组件代码
<template>
<a-spin :spinning="loading">
<div style="min-height: 220px;">
<a-tree
v-model:checkedKeys="checkedKeys"
v-model:expandedKeys="expandedKeys"
v-model:selectedKeys="selectedKeys"
:fieldNames="{
children:'children', title:'name', key:'code'
}"
:tree-data="dataSource"
checkable
>
<template #title="{parentCode,collectionDate, name,pictureUrl,quantity, unit, code, time}">
<div v-if="parentCode === '0'">
{{ name }}
</div>
<div v-else style="display: flex; align-items: center; gap: 12px;">
<img :src="pictureUrl" alt="" style="height: 80px; width: 80px" />
<span style="width: 260px;">{{ name }}</span>
<a-input :min="0" :value="quantity" size="small" style="height: 25px; width: 66px;"
@change="(e) => handleQuantityChange(e?.target?.value, code)" />
<div
class="arrow-container"
>
<CaretUpOutlined class="up" @click="handleQuantityChange(quantity + 1, code)"/>
<CaretDownOutlined class="down" @click="handleQuantityChange(quantity - 1, code)"/>
</div>
<span>{{ unit }}</span>
<a-date-picker
:getPopupContainer="(triggerNode) => triggerNode.parentNode"
:show-time="false"
format="YYYY-MM-DD"
placeholder="请选择领取日期"
style="width: 160px"
@change="(date, dateString) => handleCollectionDate(date, dateString, code)"
/>
</div>
</template>
</a-tree>
</div>
</a-spin>
</template>
<script setup>
import { onMounted, onUnmounted, ref, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { RESPONSE_STATUS } from '@/utils/constants'
import mitt from '@/utils/mitt'
import { useStore } from 'vuex'
import { isEmpty } from 'lodash'
import { doDownload } from '@/utils/common'
import { typeList } from '@/api/biz/common'
import { CaretDownOutlined, CaretUpOutlined } from '@ant-design/icons-vue'
const store = useStore()
const route = useRoute()
const router = useRouter()
const emits = defineEmits('updateCheckedSource')
const expandedKeys = ref([])
const selectedKeys = ref([])
const checkedKeys = ref([])
const props = defineProps({
tableCols: {
type: Array
},
formState: {
type: Object
},
modelInputVal: {
type: String,
default: ''
}
})
const handleCollectionDate = (date, dateString, code) => {
handleDateChange(dateString, code)
}
const handleDateChange = (newVal, nodeCode) => {
const updateNode = (nodes) => {
return nodes.map(node => {
if (node.code === nodeCode) {
return { ...node, collectionDate: newVal }
}
if (node.children) {
return { ...node, children: updateNode(node.children) }
}
return node
})
}
dataSource.value = updateNode(dataSource.value)
}
const handleQuantityChange = (newVal, nodeCode) => {
console.log('output-> {newVal, nodeCode}::: 💡💡', { newVal, nodeCode })
const updateNode = (nodes) => {
return nodes.map(node => {
if (node.code === nodeCode) {
checkedKeys.value = [...checkedKeys.value, nodeCode]
return { ...node, quantity: parseInt(newVal) }
}
if (node.children) {
return { ...node, children: updateNode(node.children) }
}
return node
})
}
dataSource.value = updateNode(dataSource.value)
}
const onSelectChange = (selectedRowKeys, selectedRows) => {
// console.log('output-> selectedRows::: ', selectedRows)
// if (isEmpty(selectedRowKeys)) {
// store.dispatch('setIsMainSelected', false)
// } else {
// store.dispatch('setIsMainSelected', true)
// }
// let curPageIds = state.dataSource.map(item => item.id)
// let unSelectedIds = curPageIds.filter(id => !selectedRowKeys.includes(id))
// state.selectedRowKeys = selectedRowKeys
// state.allSelectedRowKeys = Array.from(new Set([...state.allSelectedRowKeys, ...selectedRowKeys]))
// state.allSelectedRowKeys = state.allSelectedRowKeys.filter(key => !unSelectedIds.includes(key))
// mitt.emit('activeBtn', { len: state.selectedRowKeys.length })
// mitt.emit('emitImportData', state.importDataPayload)
}
const loading = ref(false)
const dataSource = ref([])
function filterNodesByCheckedKeysDeep(dataSource, checkedKeys) {
const result = []
function traverse(nodes) {
for (const node of nodes) {
if (checkedKeys.includes(node.code)) {
result.push(node)
}
if (node.children && node.children.length > 0) {
traverse(node.children)
}
}
}
traverse(dataSource)
return result
}
watch([() => checkedKeys.value, () => dataSource.value], (newValue, oldValue) => {
const filteredNodes = filterNodesByCheckedKeysDeep(dataSource.value, checkedKeys.value)
console.log('output-> filteredNodes', filteredNodes)
emits('updateCheckedSource', filteredNodes)
}, { deep: true })
const selectedRowKeys = ref([])
const loadTableData = async (field, orderBy, isCache = false) => {
loading.value = true
console.log('output-> props.modelInputVal.value::: ', props.modelInputVal)
console.log('output-> route.query?.sfzh::: ', route.query?.sfzh)
const res = await typeList({ keyword: props.modelInputVal, sfzh: route.query?.sfzh })
if (RESPONSE_STATUS.SUCCESS === res.status) {
loading.value = false
dataSource.value = res.data?.data || []
checkedKeys.value = getCheckedCodes(dataSource.value)
console.log('output-> dataSource.value::: ', dataSource.value)
console.log('output-> checkedKeys.value::: ', checkedKeys.value)
}
}
const getCheckedCodes = (nodes) => {
let result = []
const traverse = (nodeList) => {
for (const node of nodeList) {
if (node.checked === 1) {
result.push(node.code)
}
if (node.children && node.children.length > 0) {
traverse(node.children)
}
}
}
traverse(nodes)
return result
}
const onQuery = () => {
console.log('output-> 查询 emitQueryForm')
}
const refreshModal = () => {
loadTableData('', '', true)
}
onMounted(() => {
loadTableData('', '', false)
mitt.on('emitQueryForm', onQuery)
mitt.on('emitResetForm', () => {
console.log('output-> 重置')
})
mitt.on('refresh-add-modal', refreshModal)
})
onUnmounted(() => {
mitt.off('emitQueryForm', onQuery)
mitt.off('emitResetForm')
mitt.off('emitDeliveryCheck')
mitt.off('refresh-add-modal', refreshModal)
})
const onVisibleChange = () => {
}
const onDownLoad = ({ attachmentUrl, attachmentName, extName }) => {
if (isEmpty(attachmentUrl)) {
return
}
let param = {
name: attachmentName.split('.')[0],
extName: extName,
address: attachmentUrl
}
doDownload(param)
}
</script>
<style lang="scss" scoped>
:deep(.ant-table-thead) {
display: none;
}
.score-info {
overflow-x: scroll;
}
.scheme-sign-box {
width: 100%;
display: flex;
justify-content: flex-start;
}
.month-info {
padding: 16px 52px;
}
.tb-pagination {
margin-top: 10px;
text-align: right;
}
.table-switch {
display: flex;
align-items: center;
justify-content: flex-start;
span {
margin-left: 8px;
}
}
:deep(.ant-pagination-total-text) {
float: left;
}
.single-text {
overflow: hidden; //超出的文本隐藏
text-overflow: ellipsis; //用省略号显示
white-space: nowrap; //不换行(文字不允许换行,单行文本)
text-decoration: underline; // 添加下划线
text-decoration-color: dodgerblue; // 设置下划线颜色为蓝色
text-decoration-thickness: 2px; // 设置下划线宽度为2px
}
.arrow-container {
cursor: pointer;
display: flex;
flex-direction: column;
align-items: center;
gap: 1px;
}
.up, .down {
font-size: 12px;
}
.up:hover :deep(svg) {
color: dodgerblue;
}
.down:hover :deep(svg) {
color: dodgerblue;
}
</style>
学而不思则罔,思而不学则殆!

浙公网安备 33010602011771号