Vue中使用formData对象实现表单和文件一起上传,以及图片的CRUD
vue:只要看el-upload 和submitForm 、handleAddChange方法(上传)部分。handleEdit、handleRemove也很重要。一个是回显附件一个是删除附件。提交表单前将表单信息和附件信息遍历,将表单信息和附件通过formData实例的append方法挂载在实例上,然后提交这个实例。实现原理 new formData() 对象。接收一个[key,value]的集
·
效果图:
实现原理 new formData() 对象。接收一个[key,value]的集合。
提交表单前将表单信息和附件信息遍历,将表单信息和附件通过formData实例的append方法挂载在实例上,然后提交这个实例。
上代码。
vue:只要看el-upload 和submitForm 、handleAddChange方法(上传)部分。handleEdit、handleRemove也很重要。一个是回显附件一个是删除附件。
<template>
<div>
<el-form>
<el-row>
<el-col :span="4">
<el-form-item label="城市">
<el-select
style="width: 50%"
clearable
size="small"
v-model="queryparam.AreaCode"
placeholder="请选择"
@change="changeCitys"
>
<el-option
v-for="(item, index) in selectCitys"
:key="index"
:label="item.Text"
:value="item.Value"
></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item label="断面名称">
<el-input
style="width: 50%"
size="small"
v-model="queryparam.SourceName"
autocomplete="off"
placehoilder="请输入内容"
></el-input>
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item label="年">
<el-date-picker
style="width: 50%"
v-model="queryparam.Year"
type="year"
value-format="yyyy"
placeholder="选择年"
></el-date-picker>
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item label="河流类型">
<el-radio v-model="queryparam.SourceType" label="false">
河流
</el-radio>
<el-radio v-model="queryparam.SourceType" label="true">
湖库
</el-radio>
</el-form-item>
</el-col>
<el-col :span="8">
<el-button type="success" @click="getList">查询</el-button>
<el-button type="success" @click="choice" v-show="!isShowBtn">
选择
</el-button>
<el-button type="success" @click="configSave" v-show="!isShowBtn">
保存
</el-button>
<el-link
type="primary"
@click.native="downTemplate"
v-show="isShowBtn"
>
模板下载
</el-link>
<el-upload
style="display: inline-block"
class="upload-demo"
:limit="1"
:action="action"
:headers="headers"
:before-upload="beforeUpload"
:on-success="uploadSuccess"
>
<el-button
v-show="isShowBtn"
size="small"
v-has="'StnMgr_handleImport'"
icon="el-icon-upload2"
type="primary"
>
模板导入
</el-button>
</el-upload>
</el-col>
</el-row>
</el-form>
<el-button type="success" @click="handleAdd" v-show="isShowBtn">
新增
</el-button>
<rate-table
:list="list"
@handleSelectionChange="handleSelectionChange"
@sizeChange="getSizeChange"
@currentPage="getCurrentPage"
:options="options"
:columns="columns"
:operates="operates"
:pageShow="page.pageShow"
:total="page.total"
></rate-table>
<el-dialog :title="title" :visible.sync="dialogVisible" width="30%">
<el-form
:model="ruleForm"
status-icon
:rules="rules"
ref="ruleForm"
label-width="100px"
class="demo-ruleForm"
size="mini"
>
<el-row>
<el-col :span="24">
<el-form-item label="城市" prop="AreaCode">
<el-select
style="width: 100%"
clearable
size="small"
v-model="ruleForm.AreaCode"
placeholder="请选择"
@change="changeCitys"
>
<el-option
v-for="(item, index) in selectCitys"
:key="index"
:label="item.Text"
:value="item.Value"
></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="区县" prop="RegionCode">
<el-select
style="width: 100%"
clearable
size="small"
v-model="ruleForm.RegionCode"
placeholder="请选择"
@change="changeRegion"
>
<el-option
v-for="(item, index) in selectRegions"
:key="index"
:label="item.nodeName"
:value="item.code"
></el-option>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-form-item label="经度(E)" prop="GLongitude">
<el-input-number
style="width: 100%"
v-model="ruleForm.GLongitude"
:precision="15"
:step="0.1"
:min="0.0"
></el-input-number>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="纬度(N)" prop="GLatitude">
<el-input-number
style="width: 100%"
v-model="ruleForm.GLatitude"
:precision="15"
:step="0.1"
:min="0.0"
></el-input-number>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-form-item label="乡镇/街道" prop="TownName">
<el-input
size="small"
v-model="ruleForm.TownName"
autocomplete="off"
></el-input>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="村庄名称" prop="Village">
<el-input
size="small"
v-model="ruleForm.Village"
autocomplete="off"
></el-input>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="断面名称" prop="SourceName">
<el-input
size="small"
v-model="ruleForm.SourceName"
autocomplete="off"
></el-input>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="站点编码" prop="SStationId">
<el-input
size="small"
v-model="ruleForm.SStationId"
autocomplete="off"
></el-input>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="水源地类型" prop="SourceType">
<el-radio v-model="ruleForm.SourceType" label="false">
河流
</el-radio>
<el-radio v-model="ruleForm.SourceType" label="true">
湖库
</el-radio>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="服务人口数量" prop="Population">
<el-input
size="small"
v-model="ruleForm.Population"
autocomplete="off"
></el-input>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="日供水规模" prop="WScale">
<el-input
size="small"
v-model="ruleForm.WScale"
autocomplete="off"
></el-input>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="年份" prop="Year">
<el-date-picker
v-model="ruleForm.Year"
type="year"
value-format="yyyy"
placeholder="选择年"
></el-date-picker>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-form-item label="所属河流" prop="BasinRiver">
<el-input
size="small"
v-model="ruleForm.BasinRiver"
autocomplete="off"
></el-input>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="备注" prop="Remark">
<el-input
type="textarea"
size="small"
v-model="ruleForm.Remark"
autocomplete="off"
></el-input>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="附件">
<el-upload
action=""
list-type="picture-card"
multiple
:limit="10000"
:file-list="fileListAdd"
:on-change="handleAddChange"
:auto-upload="false"
:class="{uoloadSty:showBtnImg,disUoloadSty:noneBtnImg,deletehide:hide}"
>
<i class="el-icon-plus"></i>
<div class="el-upload__tip" slot="tip">(每个附件不超过20M)</div>
</el-upload>
<template v-for='(item,index) in ruleForm.Imgs'>
<el-image style="margin:2px;width: 90px; height: 100px;border:1px solid #ccc;" :src="item" :preview-src-list="ruleForm.Imgs"></el-image>
<i style="position: relative;right: 20px;bottom: 87px;border-radius: 2px;background: red;color: yellow;cursor: pointer;" class="el-icon-delete" @click="handleRemove(item)"></i>
<!-- <img height=80px; width=100px; :src='item'/> -->
</template>
</el-form-item>
</el-col>
</el-row>
<el-row style="text-align: right">
<el-col :span="24">
<div>
<el-form-item>
<el-button size="small" @click="close">取消</el-button>
<el-button
size="small"
type="primary"
@click="submitForm('ruleForm')"
>
确定
</el-button>
</el-form-item>
</div>
</el-col>
</el-row>
</el-form>
</el-dialog>
</div>
</template>
<script>
import base from '@/api/base'
import store from '@/store'
import rateTable from '@/components/table/rateTable' //引入table组件
import rateUpload from '@/components/SelectTree/rateUpload' //引入rateUpload组件
import {
commonGetDownLoadPath,
getDBSList,
DBSAddOrEdit,
DBSGetInfoById,
DBSDelete,
getSelect,
SelectTreeListByType,
SelectListByTypeToFirstFloor,
DeleteByFileUrl
} from '@/api/sysconfig/allstnmgr'
export default {
props: {
isShowBtn: {
//是否显示跳转页
type: Boolean,
default: true,
},
},
components: {
rateTable,
rateUpload,
},
data() {
return {
obj:{},
hide:true,
param: new FormData(), //图片上传相关
fileListAdd:[],
action: base.env + '/api/CommonS/ExportTemp',
headers: { token: sessionStorage.getItem('Authorization') },
title: '新增',
dialogVisible: false,
selectCitys: [], //城市下拉集合
selectRegions: [], //县级市、区下拉集合
queryparam: {
AreaCode: '',
SourceName: '',
SourceType: 'false',
Year: '',
},
page: {
//关于页码的相关参数
pageShow: true, //是否显示
total: 0, //总条数
pageSize: 10, //每页条数
pageNo: 1, //第几页
},
handleSelection: [], //checkbox选中行
list: [], // table数据
options: {
// table样式参数
stripe: true, // 是否为斑马纹 table
loading: true, // 是否添加表格loading加载动画
highlightCurrentRow: true, // 是否支持当前行高亮显示
mutiSelect: true, // 是否支持列表项选中功能
}, // table 的参数结束
columns: [
{ prop: 'Id', label: 'Id', align: 'center', isShow: false },
{ prop: 'City', label: '城市', align: 'center', isShow: true },
{ prop: 'RegionName', label: '区县', align: 'center', isShow: true },
{ prop: 'TownName', label: '乡镇', align: 'center', isShow: true },
{ prop: 'Village', label: '村庄名称', align: 'center', isShow: true },
{
prop: 'SourceName',
label: '断面名称',
align: 'center',
isShow: true,
},
{
prop: 'SourceType',
label: '河流类型',
align: 'center',
isShow: true,
formatter: (row, column, cellValue) => {
if (row.SourceType) {
return '湖库'
} else {
return '河流'
}
},
},
// { prop: 'c', label: '断面类型', align: 'center', isShow: false },
{
prop: 'GLongitude',
label: '经度(E)',
align: 'center',
isShow: true,
},
{
prop: 'GLatitude',
label: '纬度(N)',
align: 'center',
isShow: true,
},
{
prop: 'Population',
label: '服务人口数量(人)',
width: 150,
align: 'center',
isShow: true,
},
{
prop: 'WScale',
label: '日供水规模(吨)',
width: 150,
align: 'center',
isShow: true,
},
], // 需要展示的列
operates: {
//操作栏
width: 300,
fixed: 'right',
list: [
{
id: '2',
label: '编辑',
bgColortype: 'success',
show: true, //是否显示按钮
hasbutton: 'StnMgr_handleEdit',
className: 'success', //样式类名
iconss: 'el-icon-edit',
disabled: false, //是否禁用按钮 默认是danger的禁用样式
method: (index, row) => {
this.handleEdit(index, row)
},
},
{
id: '3',
label: '删除',
show: true,
hasbutton: 'StnMgr_handleMultiplDel',
bgColortype: 'danger',
disabled: false,
iconss: 'el-icon-delete',
method: (index, row) => {
this.handleMultiplDel(index, row)
},
},
],
}, // 列操作按钮
ruleForm: {
Id: '',
SStationId: '',
City: '',
RegionName: '',
TownName: '',
AreaCode: '',
GLatitude: '',
GLongitude: '',
Remark: '',
RegionCode: '',
SourceName: '',
BasinRiver: '',
SourceType: 'false',
SStationType: '',
Year: '',
Population: '',
WScale: '',
Village: '',
Status: '',
FileBusinessId:"1"
},
rules: {
AreaCode: [{ required: true, message: '必填项', trigger: 'blur' }],
RegionCode: [{ required: true, message: '必填项', trigger: 'blur' }],
TownName: [{ required: true, message: '必填项', trigger: 'blur' }],
Village: [{ required: true, message: '必填项', trigger: 'blur' }],
SourceName: [{ required: true, message: '必填项', trigger: 'blur' }],
SStationId: [{ required: true, message: '必填项', trigger: 'blur' }],
SourceType: [{ required: true, message: '必填项', trigger: 'blur' }],
Year: [{ required: true, message: '必填项', trigger: 'blur' }],
GLongitude: [{ required: true, message: '必填项', trigger: 'blur' }],
GLatitude: [{ required: true, message: '必填项', trigger: 'blur' }],
BasinRiver: [{ required: false, message: '必填项', trigger: 'blur' }],
},
}
},
mounted() {
this.getList()
this.getSelectCitys()
},
watch: {
'ruleForm.AreaCode': {
handler(newName, oldName) {
this.changeCitys(this.ruleForm.AreaCode)
},
immediate: true,
// deep: true
},
},
methods: {
async getSelectCitys() {
var res = await SelectListByTypeToFirstFloor({
type: 'city',
condition: '',
})
this.selectCitys = res.data
},
async changeCitys(val) {
if (val != '') {
var Enumerable = require('linq')
var res = await SelectTreeListByType({ type: 'city' })
var a = Enumerable.from(res[0].children)
.where((p) => p.code == val)
.orderBy('p=>p.order')
.toArray()
this.selectRegions = a[0].children
this.ruleForm.City = a[0].nodeName
} else {
this.selectRegions = []
}
},
async changeRegion(val) {
var self = this
if (val != '') {
for (var i = 0; i < self.selectRegions.length; i++) {
if (self.selectRegions[i].code == val) {
this.ruleForm.RegionName = self.selectRegions[i].nodeName
this.ruleForm.RegionCode = val
}
}
// this.selectRegions.foreach((item,index)=>{});
} else {
}
},
async getList() {
var res = await getDBSList({
AreaCode: this.queryparam.AreaCode,
SourceName: this.queryparam.SourceName,
SourceType: this.queryparam.SourceType,
Year: this.queryparam.Year,
pageSize: this.page.pageSize,
pageNo: this.page.pageNo,
})
this.list = res.data
this.page.total = res.total
this.options.loading = false
},
downTemplate() {
this.commonDownLoad(
'地表水站点导入模板.xls',
'/Upload/ExportMb/地表水站点导入模板.xls'
)
},
async commonDownLoad(fileName, path) {
var self = this
var res = await commonGetDownLoadPath({
partialPath: path,
})
if (res.code == 200) {
location.href =
base.env +
'/api/CommonS/commonDownLoad?fileName=' +
fileName +
'&path=' +
res.data
// location.href = 'http://localhost:52506/api/CommonS/commonDownLoad?fileName='+fileName+'&path='+res.data;
}
},
beforeUpload(file) {
var self = this
var ext = file.name
.substring(file.name.lastIndexOf('.') + 1, file.name.length)
.toLowerCase()
const isLt4M = file.size / 1024 / 1024 <= 20 //图片大小不超过2MB
if (ext != 'xls' && ext != 'xlsx') {
this.$message.error('上传文件格式不对,请下载模板再导入!')
return false
}
},
uploadSuccess() {
this.$message({
message: '导入成功!',
type: 'success', //success,warning,info,error
})
this.getList() //调用获取列表页的方法
},
choice() {
this.$emit('choice', this.handleSelection)
},
clearSelection() {
this.handleSelection = []
},
configSave() {
this.$emit('configSave', {})
},
handleSelectionChange(val) {
//checkbox选中的数据val 是选中行的所有数组
this.handleSelection = val
},
getSizeChange(val) {
//table组件发射的方法 用于改变每页数据量
this.page.pageSize = val
//这下面需要重新调用 获取列表页的函数
this.getList()
},
getCurrentPage(val) {
//table组件发射的方法 用于改变当前所在页码
this.page.pageNo = val
//这下面需要重新调用 获取列表页的函数
this.getList()
},
close() {
this.dialogVisible = false
},
handleAdd() {
this.dialogVisible = true
this.ruleForm = {
Id: '',
SStationId: '',
City: '',
RegionName: '',
TownName: '',
AreaCode: '',
GLatitude: '',
GLongitude: '',
Remark: '',
RegionCode: '',
SourceName: '',
BasinRiver: '',
SourceType: 'false',
SStationType: '',
Year: '',
Population: '',
WScale: '',
Village: '',
Status: '',
FileBusinessId:"1",
}
this.fileListAdd=[];
},
async handleEdit(index, row) {
this.title = '编辑'
this.dialogVisible = true
this.fileListAdd=[];
const res = await DBSGetInfoById({ Id: row.Id })
res.data.SourceType = res.data.SourceType.toString()
res.data.Year = res.data.Year.toString()
this.ruleForm = res.data
var arr=[];
for(var item of res.data.Imgs){
arr.push(`${base.env}${item.FileUrl}`);
}
this.ruleForm.Imgs=arr;
},
handleMultiplDel(index, row) {
var self = this
this.$confirm('确认删除?')
.then(async () => {
const res = await DBSDelete({ id: row.Id })
this.getList()
if (res.res) {
this.$baseMessage('操作成功!', 'success')
} else {
this.$baseMessage('操作失败!', 'error')
}
})
.catch(function () {})
},
submitForm(formName) {
var self=this;
var qs = require('qs')
//提交表单
this.$refs[formName].validate(async (valid) => {
if (valid) {
debugger
//表单属性加到FormData中
for(let x in self.ruleForm){
self.param.append(x,self.ruleForm[x]);
}
//图片流加入到FormData中
let existPic='';
//清除已经有的
if(self.param.has('files')){
self.param.delete('files');
}
for (var int = 0; int < self.fileListAdd.length; int++) {
var list = self.fileListAdd[int];
var file = list.raw;
if(file==undefined){
existPic += list.url+';'
}
else{
self.param.append('files', file); // 文件对象
}
}
//已经上传的图片
self.param.append('url',existPic);
var info = store.getters['user/info']
this.$http({
headers: {
'deviceCode': 'A95ZEF1-47B5-AC90BF3',
'Content-Type': 'multipart/form-data'
},
token: `Bearer ${info.Token}`,
method: 'post',
url: base.env+'/api/AllStnMgr/AddOrEdit',
data:this.param
}).then(res => {
if(res.data.code==200){
self.$message({
message: '操作成功!',
type: 'success' //warning,success,info,error
});
//图片显示成功
self.fileListAdd =[];
self.hide =true;
}
}).catch(error => {
console.log(error);
});
// const res = await DBSAddOrEdit(this.param)
this.dialogVisible = false
if (res) {
this.$baseMessage('操作成功!', 'success')
} else {
this.$baseMessage('操作失败!', 'error')
}
this.getList()
} else {
return false
}
})
},
//上传change事件
handleAddChange(file, fileList) {
//清空列表
const isLt20M = file.size / 1024 / 1024 < 20;
if (!isLt20M) {
this.$message({
message: "请上传小于20M的图片",
type: "warning" //success,warning,info,error
});
return;
fileList.splice(-1, 1);
} else {
this.fileListAdd.push(file);
}
this.noneBtnImg = fileList.length >= this.limitCountImg;
},
// 移除文件
handleRemove(FileUrl) {
var self=this;
this.$confirm('确认删除吗?').then(async () =>{
let res=await DeleteByFileUrl({FileUrl:FileUrl.replace(base.env,"")});
self.$message({ message: res.message,type: res.type,});
self.ruleForm.Imgs=self.ruleForm.Imgs.filter((item,index,arr)=>{
return item!=FileUrl;
});
})
},
},
}
</script>
<style>
.uoloadSty .el-upload--picture-card{
width:145px;
height:145px;
line-height:145px;
}
.disUoloadSty .el-upload--picture-card{
display:none; /* 上传按钮隐藏 */
}
.deletehide .el-upload-list--picture-card .el-upload-list__item-actions .el-upload-list__item-delete {
display: block;
opacity: 1;
}
</style>
接口代码:基于.net core 3.1
private readonly IHostingEnvironment _hostingEnvironment;
private string _webRootPath = string.Empty;
private string _contentRootPath = string.Empty;
/// <summary>
/// 构造函数相关
/// </summary>
/// <param name="hostingEnvironment">参数</param>
public AllStnMgrController(IHostingEnvironment hostingEnvironment)
{
_hostingEnvironment = hostingEnvironment;
_webRootPath = _hostingEnvironment.WebRootPath;
_contentRootPath = _hostingEnvironment.ContentRootPath;
}
public bool AddOrEdit(DbsSstation model, string path)
{
bool res = false;
string partialPath = "/Upload/StnImg/" + DateTime.Now.ToString("yyyyMMddHHmmssfff");
string serverPath = path + partialPath;
if (!File.Exists(serverPath))
{
Directory.CreateDirectory(serverPath);
}
if (model.Id > 0)
{
res = model.Update() > 0 ? true : false;//编辑
}
else
{//新增
//if (!string.IsNullOrEmpty(model.RegionCode))
//{
// model.SStationId = GenSStationId(model.RegionCode);
//
//}
//断面编码自动生成,生成规则 regionCode 加 下划线 加00 加序号 依次往下增加
res = model.Insert() > 0 ? true : false;
}
//上传图片
List<sstationFile> fileInfoList = new List<sstationFile>();
if (model.files != null)
{
foreach (var file in model.files)
{
sstationFile fileInfo = new sstationFile();
fileInfo.BusinessId = "1";//地表水图片类型:1
fileInfo.FileName = file.FileName;
fileInfo.FileUrl = partialPath + "/" + file.FileName; ;
fileInfoList.Add(fileInfo);
}
}
fileInfoList.Insert();
StringBuilder returnPathSb = new StringBuilder();
if (fileInfoList.Count != 0)
{
foreach (var file in model.files)
{
var filePath = Path.Combine(serverPath, file.FileName);
returnPathSb.Append(partialPath + "/" + file.FileName + ";");
using (var stream = new FileStream(filePath, FileMode.Create))
{
file.CopyTo(stream);
}
}
}
return res;
}
回显接口:
public DbsSstation GetInfoById(string Id)
{
DbsSstation data = XCode.Entity<DbsSstation>.Find("Id", Id);
if (data!=null && !string.IsNullOrEmpty(data.FileBusinessId)) {
data.Imgs = XCode.Entity<sstationFile>.FindAll("BusinessId", data.FileBusinessId).ToList<sstationFile>();
}
return data;
}
删除接口:
/// <summary>
/// 删除上传的图片
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
[HttpPost, HttpGet]
public IActionResult DeleteByFileUrl(sstationFile model)
{
bool result = false;
string message = "";
string type = "success";//success,warning,,info,error
sstationFile data = XCode.Entity<sstationFile>.Find("FileUrl", model.FileUrl);
if (data!=null && data.Id>0) {
result = XCode.Entity<sstationFile>.Find("Id", data.Id).Delete() > 0 ? true : false;
string filePicFullPath = _contentRootPath + model.FileUrl;
if (System.IO.File.Exists(filePicFullPath))
{
System.IO.File.Delete(filePicFullPath); //删除图片
}
}
type = result ? "success" : "error";
message = result ? "操作成功" : "操作失败";
//日志写入相关
UserModel user = JsonConvert.DeserializeObject<UserModel>(this.User.FindFirstValue(ClaimTypes.UserData));
SysActionlog worker = new SysActionlog();
if (result)
{
worker.UsrDesc = user.UserName + "删除了地表水附件。";
}
worker.UsrName = user.UserName;
worker.RealName = user.LoginName;
LogBLL tool = new LogBLL();
tool.AddLog(worker, 3);
return Ok(new { code = 200, result, type, message });
}
数据库设计:
更多推荐
已为社区贡献6条内容
所有评论(0)