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([])
学而不思则罔,思而不学则殆!

浙公网安备 33010602011771号