在做多图片上传时,需求为一个字段以“,”隔开的路径,并且存储的是服务器内的图片名称,一开始选择了照片墙上传,后来发现需要进行额外操作。
html 新增
<el-form-item label="商品图片" prop="headerimg">
<!-- AddForm.headerimg 是图片上传的数组列表 -->
<!-- handlePictureCardPreview 是点击图片的预览事件 -->
<!-- UPImgurl 是上传图片的基地址 也就是上传图片接口 -->
<el-upload v-model:file-list="AddForm.headerimg" :on-preview="handlePictureCardPreview" :action="UPImgurl" list-type="picture-card">
<el-icon>
<Plus />
</el-icon>
</el-upload>
</el-form-item>
js 新增提交
// 新增提交
const SubmitForm = () => {
formRef.value.validate((valid) => {
if (valid) {
// 声明一个临时变量
let str = ''
// 循环图片列表数组
AddForm.headerimg.map(item => {
str = str + item.response.data[0] + ','
// 把图片地址赋值给临时变量 以,拼接
})
// 赋值给需要的字段 拼接会多一个, 在赋值时删除
AddForm.headerimg = str.slice(0, -1)
SUMBITPRODUCT(AddForm).then(res => {
AddDialog.value = false
if (res.code == 0) { ElMessage({ type: 'success', message: `${res.message}`, }) }
else { ElMessage({ type: 'info', message: `${res.message}`, }) }
GET()
})
} else {
console.log('验证失败');
return false;
}
});
};
这样新增时的数据就是 24313020231204170409.jpg,24313020231204170409.jpg
但是问题也来了,回显时需要数组结构并且图片路径在对象的url上面,同时回显完成后如果再次上传图片结构又变回之前的,所以我在点击编辑的时候这样操作:
编辑回显html代码:
<el-form-item label="商品图片" prop="headerimg">
<el-upload v-model:file-list="EditForm.str1img" :on-preview="handlePictureCardPreview" :action="UPImgurl" list-type="picture-card">
<el-icon>
<Plus />
</el-icon>
</el-upload>
</el-form-item>
点击编辑js代码:
// 点击编辑
const OnhandleEdit = (row) => {
EditForm = row
// 声明一个临时变量
EditForm.str1img = EditForm.headerimg.split(',').map(item => {
// 字符串以,转数组 循环数组 把字符串转对象 拼接图片预览路径 返回给数组
// IMGAPI 预览图片的基地址
return { url: IMGAPI + item }
})
EditDialog.value = true
if (formRef.value) {
formRef.value.resetFields();
}
}
把数据里面的字符串循环操作为数组对象的形式然后赋值给一个临时变量,这样就可以正常回显,回显之后的上传在表单提交事件里面操作
编辑提交js代码:
// 编辑提交
const OnEditForm = () => {
formRef.value.validate((valid) => {
if (valid) {
// 声明一个临时变量
let str = ''
EditForm.str1img.map(item => {
// 循环图片的数组 如果有 name 就是新上传的 用图片预览地址拼接
if (item.name) {
item.url = IMGAPI + item.response.data[0]
}
// 把 图片的预览地址截取掉并以,拼接
str = str + item.url.slice(35) + ','
})
// 删除,并赋值给需要上传的字段
EditForm.headerimg = str.slice(0, -1)
delete EditForm.str1img
UPDATECARINFO(EditForm).then(res => {
EditDialog.value = false
if (res.code == 0) { ElMessage({ type: 'success', message: `${res.message}`, }) }
else { ElMessage({ type: 'info', message: `${res.message}`, }) }
GET()
})
} else {
console.log('验证失败');
return false;
}
});
};
完整代码:
<!-- 用户 -->
<template>
<div style="height: 100%;width: 100%;margin: 0 30px;">
<!-- 功能按钮区域 -->
<div style="margin: 10px 0 0 0;">
<el-button @click="OnhandleSubmit" :size="counter.ISSize" :color="counter.ISQdbutton" :dark="true" :icon="Plus">
新增
</el-button>
</div>
<!-- 内容 -->
<div style="padding:10px 0;">
<el-table border :data="tableData" max-height="76vh">
<!-- <el-table-column prop="createtime" label="创建时间" width="200" /> -->
<el-table-column prop="proname" label="商品名称" width="200" />
<el-table-column prop="description" label="描述" width="200" />
<el-table-column prop="leaseunit" label="租赁方式" width="200" />
<el-table-column prop="price" label="价格" />
<el-table-column prop="onlease" label="起租周期" width="200" />
<el-table-column prop="param" label="参数" />
<el-table-column prop="leasedes" label="租赁说明" width="120" />
<el-table-column prop="recommend" label="是否为推荐商品" width="150" />
<el-table-column prop="headerimg" label="商品图片" width="500">
<template #default="scope">
<div style="display: flex;">
<div v-for="item in scope.row.headerimg.split(',')" :key="item.id">
<img style="width: 30px;height: 30px;margin: 0 5px;" :src="IMGAPI+''+ item" alt=" ">
</div>
</div>
</template>
</el-table-column>
<el-table-column prop="newdegree" label="成新度" />
<el-table-column prop="attachment" label="配件" />
<el-table-column label="操作" width="150" fixed="right">
<template #default="scope">
<el-button link type="primary" @click="OnhandleEdit(scope.row)" :size="counter.ISSize">编辑</el-button>
<el-button link type="danger" @click="OnhandleDelete(scope.row)" :size="counter.ISSize">删除</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<div style="display: flex;justify-content: center;">
<el-pagination v-model:current-page="size.current" v-model:page-size="size.size" :page-sizes="[ 10, 30, 50, 100]" :small="true"
layout="total, sizes, prev, pager, next, jumper" :total="total" @size-change="handleSizeChange" @current-change="handleCurrentChange" />
</div>
</div>
<!-- 新增 对话框 -->
<el-dialog v-model="AddDialog" :show-close="false" :close-on-click-modal="false" title="新增商品" center draggable width="600px">
<el-form :model="AddForm" :rules="rules" ref="formRef" label-width="80px" :size="counter.ISSize">
<div style="display: flex;justify-content: space-between;">
<el-form-item label="商品名称" prop="proname"><el-input clearable v-model="AddForm.proname"></el-input></el-form-item>
<el-form-item label="租赁方式" prop="leaseunit"><el-input clearable v-model="AddForm.leaseunit"></el-input></el-form-item>
</div>
<div style="display: flex;justify-content: space-between;">
<el-form-item label="价格" prop="price"><el-input clearable v-model="AddForm.price"></el-input></el-form-item>
<el-form-item label="起租周期" prop="onlease"><el-input clearable v-model="AddForm.onlease"></el-input></el-form-item>
</div>
<div style="display: flex;justify-content: space-between;">
<el-form-item label="成新度" prop="newdegree"><el-input clearable v-model="AddForm.newdegree"></el-input></el-form-item>
<el-form-item label="配件" prop="attachment"><el-input clearable v-model="AddForm.attachment"></el-input></el-form-item>
</div>
<div style="display: flex;">
<el-form-item label="租赁次数" prop="numleases"><el-input clearable v-model="AddForm.numleases"></el-input></el-form-item>
<el-form-item label="推荐商品" prop="numleases" style="margin-left: 55px;">
<el-switch v-model="AddForm.recommended" :size="counter.ISSize" active-text="是" inactive-text="否" :active-value="1" :inactive-value="2" />
</el-form-item>
</div>
<el-form-item label="商品描述" prop="description">
<el-input v-model="AddForm.description" type="textarea" maxlength="200" show-word-limit placeholder="请输入商品描述,要求长度为200字之内"
:autosize="{ minRows: 2, maxRows: 4}"></el-input>
</el-form-item>
<el-form-item label="商品参数" prop="param">
<el-input v-model="AddForm.param" type="textarea" maxlength="200" show-word-limit placeholder="请输入商品参数,要求长度为200字之内"
:autosize="{ minRows: 2, maxRows: 4}"></el-input>
</el-form-item>
<el-form-item label="租赁说明" prop="leasedes">
<el-input v-model="AddForm.leasedes" type="textarea" maxlength="200" show-word-limit placeholder="请输入租赁说明,要求长度为200字之内"
:autosize="{ minRows: 2, maxRows: 4}"></el-input>
</el-form-item>
<el-form-item label="商品图片" prop="headerimg">
<el-upload v-model:file-list="AddForm.headerimg" :on-preview="handlePictureCardPreview" :action="UPImgurl" list-type="picture-card">
<el-icon>
<Plus />
</el-icon>
</el-upload>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="AddDialog=false" :size="counter.ISSize">关闭</el-button>
<el-button type="primary" @click="SubmitForm" :size="counter.ISSize">确定</el-button>
</span>
</template>
</el-dialog>
<!-- 编辑 对话框 -->
<el-dialog v-model="EditDialog" :show-close="false" :close-on-click-modal="false" title="编辑分类" center draggable width="600px">
<el-form :model="EditForm" ref="formRef" :rules="rules" label-width="80px" :size="counter.ISSize">
<div style="display: flex;justify-content: space-between;">
<el-form-item label="商品名称" prop="proname"><el-input clearable v-model="EditForm.proname"></el-input></el-form-item>
<el-form-item label="租赁方式" prop="leaseunit"><el-input clearable v-model="EditForm.leaseunit"></el-input></el-form-item>
</div>
<div style="display: flex;justify-content: space-between;">
<el-form-item label="价格" prop="price"><el-input clearable v-model="EditForm.price"></el-input></el-form-item>
<el-form-item label="起租周期" prop="onlease"><el-input clearable v-model="EditForm.onlease"></el-input></el-form-item>
</div>
<div style="display: flex;justify-content: space-between;">
<el-form-item label="成新度" prop="newdegree"><el-input clearable v-model="EditForm.newdegree"></el-input></el-form-item>
<el-form-item label="配件" prop="attachment"><el-input clearable v-model="EditForm.attachment"></el-input></el-form-item>
</div>
<div style="display: flex;">
<el-form-item label="租赁次数" prop="numleases"><el-input clearable v-model="EditForm.numleases"></el-input></el-form-item>
<el-form-item label="推荐商品" prop="recommended" style="margin-left: 55px;">
<el-switch v-model="EditForm.recommended" :size="counter.ISSize" active-text="是" inactive-text="否" :active-value="1"
:inactive-value="2" />
</el-form-item>
</div>
<el-form-item label="商品描述" prop="description">
<el-input v-model="EditForm.description" type="textarea" maxlength="200" show-word-limit placeholder="请输入商品描述,要求长度为200字之内"
:autosize="{ minRows: 2, maxRows: 4}"></el-input>
</el-form-item>
<el-form-item label="商品参数" prop="param">
<el-input v-model="EditForm.param" type="textarea" maxlength="200" show-word-limit placeholder="请输入商品参数,要求长度为200字之内"
:autosize="{ minRows: 2, maxRows: 4}"></el-input>
</el-form-item>
<el-form-item label="租赁说明" prop="leasedes">
<el-input v-model="EditForm.leasedes" type="textarea" maxlength="200" show-word-limit placeholder="请输入租赁说明,要求长度为200字之内"
:autosize="{ minRows: 2, maxRows: 4}"></el-input>
</el-form-item>
<el-form-item label="商品图片" prop="headerimg">
<el-upload v-model:file-list="EditForm.str1img" :on-preview="handlePictureCardPreview" :action="UPImgurl" list-type="picture-card">
<el-icon>
<Plus />
</el-icon>
</el-upload>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="EditDialog=false" :size="counter.ISSize">关闭</el-button>
<el-button type="primary" @click="OnEditForm" :size="counter.ISSize">确定</el-button>
</span>
</template>
</el-dialog>
<el-dialog v-model="Imgshow" title="预览" center draggable width="70%">
<img style="width: 100%;height: 100%;" :src="Imgurl" alt="">
</el-dialog>
</div>
</template>
<script setup>
import { GETCARINFO, SUMBITCARINFO, DELETECARINFO, UPDATECARINFO } from '../../API/carinfo'
import { onMounted, ref, reactive } from 'vue';
import { Delete, Edit, Search, Share, Upload, Plus, Minus, Monitor, FolderOpened } from '@element-plus/icons-vue'
// 导入pinia
import { GlobalStatu } from '@/stores/counter'
// 使用pinia
let counter = GlobalStatu()
onMounted(() => {
GET()
})
// 表格数据
let tableData = ref([])
// 表格数据总条数
let total = ref(0)
// 分页数据
let size = ref({
current: 1,
size: 10
})
const IMGAPI = import.meta.env.VITE_BASE_CHECKURL
const UPImgurl = import.meta.env.VITE_BASE_UPIMGURL
let Imgshow = ref(false)
let Imgurl = ref()
let AddDialog = ref(false) // 新增显示隐藏
let AddForm = reactive({}); // 新增表单数据
let formRef = ref(null); // ref属性
// 规则
let rules = {
proname: [{ required: true, message: '请输入商品名称', trigger: 'blur' }],
description: [{ required: true, message: '请输入商品描述', trigger: 'blur' }],
leaseunit: [{ required: true, message: '请输入租赁方式', trigger: 'blur' }],
price: [{ required: true, message: '请输入价格', trigger: 'blur' }],
onlease: [{ required: true, message: '请输入起租周期', trigger: 'blur' }],
param: [{ required: true, message: '请输入参数', trigger: 'blur' }],
leasedes: [{ required: true, message: '请输入租赁说明', trigger: 'blur' }],
numleases: [{ required: true, message: '请输入租赁次数', trigger: 'blur' }],
newdegree: [{ required: true, message: '请输成新度', trigger: 'blur' }],
attachment: [{ required: true, message: '请输入配件', trigger: 'blur' }],
headerimg: [{ required: true, message: '请上传商品图片', trigger: 'change' }],
recommended: [{ required: true, message: '请选择是否热卖', trigger: 'change' }],
};
// 点击新增
let OnhandleSubmit = () => {
AddDialog.value = true
if (!formRef.value) return
formRef.value.resetFields();
}
// 新增提交
const SubmitForm = () => {
formRef.value.validate((valid) => {
if (valid) {
// 声明一个临时变量
let str = ''
AddForm.headerimg.map(item => {
str = str + item.response.data[0] + ','
// 变量用图片地址和,拼接
})
// 赋值给需要的字段 拼接会多一个, 在赋值时删除
AddForm.headerimg = str.slice(0, -1)
SUMBITCARINFO(AddForm).then(res => {
AddDialog.value = false
if (res.code == 0) { ElMessage({ type: 'success', message: `${res.message}`, }) }
else { ElMessage({ type: 'info', message: `${res.message}`, }) }
GET()
})
} else {
console.log('验证失败');
return false;
}
});
};
let EditDialog = ref(false) // 编辑显示隐藏
let EditForm = reactive({}); // 编辑表单数据
// 点击编辑
const OnhandleEdit = (row) => {
EditForm = row
// 声明一个临时变量
EditForm.str1img = EditForm.detailimg.split(',').map(item => {
// 字符串以,转数组 循环数组 把字符串转对象 拼接图片预览路径 返回给数组
return { url: IMGAPI + item }
})
EditDialog.value = true
if (formRef.value) {
formRef.value.resetFields();
}
}
// 编辑提交
const OnEditForm = () => {
formRef.value.validate((valid) => {
if (valid) {
// 声明一个临时变量
let str = ''
EditForm.str1img.map(item => {
// 循环图片的数组 如果有 name 就是新上传的 用图片预览地址拼接
if (item.name) {
item.url = IMGAPI + item.response.data[0]
}
// 把 图片的预览地址截取掉
str = str + item.url.slice(35) + ','
})
// 删除,并赋值给需要上传的字段
EditForm.headerimg = str.slice(0, -1)
delete EditForm.str1img
UPDATECARINFO(EditForm).then(res => {
EditDialog.value = false
if (res.code == 0) { ElMessage({ type: 'success', message: `${res.message}`, }) }
else { ElMessage({ type: 'info', message: `${res.message}`, }) }
GET()
})
} else {
console.log('验证失败');
return false;
}
});
};
// 获取商品
let GET = () => {
GETCARINFO().then(res => {
tableData.value = res.data.records
total = res.data.total
})
AddForm = {}
EditForm = {}
}
// 点击删除
const OnhandleDelete = (row) => {
ElMessageBox.confirm(
'是否确认删除该商品?',
'提示',
{ confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning', }
).then(() => {
DELETECARINFO(row.id).then(res => {
if (res.code == 0) {
ElMessage({ type: 'success', message: `${res.message}`, })
GET()
}
else {
ElMessage({ type: 'info', message: `${res.message}`, })
}
})
}).catch(() => {
ElMessage({ type: 'info', message: '已取消删除', })
})
}
// 一页多少
let handleSizeChange = (e) => {
size.value.size = e
GET()
}
// 当前第几页
let handleCurrentChange = (e) => {
size.value.current = e
GET()
}
// 预览
const handlePictureCardPreview = (uploadFile) => {
Imgurl.value = uploadFile.url
Imgshow.value = true
}
</script>
<style scoped lang="less">
// 图片上传样式
:deep(.el-upload--picture-card) {
width: 120px !important;
height: 120px !important;
}
:deep(.el-upload-list__item.is-success) {
width: 120px !important;
height: 120px !important;
}
:deep(.el-upload-list__item.is-uploading) {
width: 120px !important;
height: 120px !important;
}
</style>