AntDesign Form表单相关组件

可增减输入框

  • 组件代码
<template>
	<div class="custom-report-row" v-for="(row, index) in reportTimeList" :key="index">
		<a-date-picker
			v-model:value="row.reportTime"
			allowClear
			style="width: 100%; margin-bottom: 12px;"
			:getPopupContainer="(triggerNode) => triggerNode.parentNode"
			format="YYYY-MM-DD"
			value-format="YYYY-MM-DD"
			:show-time="false"
			:disabled="props.isEditModal ? (UserRole === 'normalAdmin' || UserRole === 'normalUser') : false"
			:disabled-date="isAdmin ? null : disabledDate"
		/>
		<a-radio-group
			:disabled="props.isEditModal ? (UserRole === 'normalAdmin' || UserRole === 'normalUser') : false"
			v-model:value="row.reportType" @change="onRadioChange">
			<a-radio value="早餐">早餐</a-radio>
			<a-radio value="中餐">中餐</a-radio>
			<a-radio value="晚餐">晚餐</a-radio>
			<a-radio value="夜宵">夜宵</a-radio>
		</a-radio-group>
		<span class="operate-btn-report" v-if="!isEditModal">
			<PlusCircleOutlined class="custom-icon" @Click="onAdd" title="新增"/>
			<MinusCircleOutlined v-show="!!index" class="custom-icon" @Click="onReduce(index)" title="删除"/>
		</span>
	</div>
</template>
<script setup>
import { computed, ref, watch } from 'vue'
import dayjs from 'dayjs'
import { useStore } from 'vuex'
import { PlusCircleOutlined, MinusCircleOutlined } from '@ant-design/icons-vue'
const store = useStore()
const props = defineProps({
	isEditModal: {
		type: Boolean,
		default: false
	},
	drinkTypeList: {
		type: Array,
		default: []
	}
})
const {isEditModal, drinkTypeList} = props
const onRadioChange = () => {
	console.log('output-> reportTimeList::: ', reportTimeList.value)
}
const emptyItem = {
	reportTime: '',
	reportType: undefined
}
const reportTimeList = ref([
	{
		...emptyItem
	}
])
defineExpose({
	reportTimeList,
})
watch(() => props.drinkTypeList,(newVal, oldVal) => {
	if(props.isEditModal) {
		reportTimeList.value = newVal
	}
}, {deep: true, immediate: true})
const onAdd = () => {
	reportTimeList.value = [
		...reportTimeList.value,
		{
			...emptyItem
		}
	]
}
const onReduce = (index) => {
	reportTimeList.value.splice(index, 1)
}
const UserRole = computed(() => store.state.user.userRole)
let isAdmin = computed(() => store.state.user.userInfo?.isManager === 1)
const disabledDate = (current) => {
	return current && current <= dayjs().subtract(1, 'day')
}
</script>
<style lang="scss" scoped>
.custom-report-row {
	margin-bottom: 12px;
	position: relative;
	.operate-btn-report {
		width: 60px;
		position: absolute;
		top: 20px;
		right: -86px;
		.custom-icon {
			color: #8f9090;
			font-size: 22px;
			cursor: pointer;
		}
		span:first-child {
			margin-right: 8px;
		}
	}
}
</style>

// ---------------- 使用组件 ----------------------
<ReportTimeSelector :drinkTypeList="echoDrinkTypeList" :isEditModal="isEditModal" ref="reportSelectorRef" />

附件上传

  • 组件代码
* UploadCom.vue
<template>
	<a-upload
		action="report/attachment/upload"
		:multiple="true"
		:file-list="fileList"
		@change="handleChange"
	>
		<a-button>
			<upload-outlined></upload-outlined>
			上传
		</a-button>
		<span class="ant-upload-text">* 选择本地文件上传</span>
	</a-upload>
</template>
<script lang="ts" setup>
import { UploadOutlined } from '@ant-design/icons-vue'
import { computed, ref, watch } from 'vue'
import type { UploadChangeParam, UploadProps } from 'ant-design-vue'
import { nanoid } from 'nanoid'
import { isEmpty } from 'lodash'

const fileList = ref<UploadProps['fileList']>([])
const resFileData = computed(() => {
	if(fileList.value.length && fileList.value[0]?.response) {
		return fileList.value.map(item => {
			let name = `${item.response.data.name}.${item.response.data.extName}`
			let url = item.response.data.address
			return {
				attachmentName: name,
				attachmentUrl: url
			}
		})
	}
	return []
})

const props = defineProps({
	echoAttachments: {
		type: Array,
		default: []
	}
})

const {echoAttachments} = props
watch(() => echoAttachments, (newVal, oldVal) => {
	if(newVal.length) {
		fileList.value = newVal.map(img => {
			return {
				uid: `vc-upload-${nanoid()}`,
				name: img.attachmentName,
				type: 'image/jpeg',
				status: 'done',
				response: {
					status: 0,
					message: 'success',
					traceId: null,
					data: {
						address: img.attachmentUrl,
						name: img.attachmentName.split('.')[0],
						id: img?.id,
						extName: img.attachmentName.split('.')[1],
						url: img.attachmentUrl,
					}
				}
			}
		}) || []

	}
}, {deep: true, immediate: true})
defineExpose({
	fileList: resFileData
})
const handleChange = (info: UploadChangeParam) => {
	let resFileList = [...info.fileList]

	// 1. Limit the number of uploaded files
	//    Only to show two recent uploaded files, and old ones will be replaced by the new
	// resFileList = resFileList.slice(-2)

	// 2. read from response and show file link
	resFileList = resFileList.map(file => {
		if (file.response) {
			// Component will show file.url as link
			file.url = file.response.url
		}
		return file
	})

	fileList.value = resFileList
}
</script>

<style lang="scss" scoped>
.ant-upload-text {
	font-family: 'PingFang SC';
	font-style: normal;
	font-weight: 400;
	font-size: 12px;
	line-height: 20px;
	margin-left: 12px;
	color: rgba(21, 22, 24, 0.48);

}

;
.uplaod-imgs {
	max-width: 218px;
}

.avatar-uploader {
	.custom-btn {
		background-color: rgba(43, 121, 255, 0.1);
		color: #1F71FF;
	}
}
</style>
// ------------ 组件使用 ---------------
<UploadCom :echoAttachments="echoAttachments" :isEditModal="isEditModal" ref="uploadCommonRef" />
const echoAttachments = ref([])

posted @ 2025-05-13 10:02  Felix_Openmind  阅读(27)  评论(0)    收藏  举报
*{cursor: url(https://files-cdn.cnblogs.com/files/morango/fish-cursor.ico),auto;}