问题

最近在使用SSR(服务器端渲染)方式引入vue+element-ui开发一个商城项目的时候遇到一个问题:因为商城的订单是可能包含多个商品,所以订单的评价涉及到同一个页面多组表单的异步提交(每一组表单包含评价内容和上传的多张图片)
由于element-uiupload组件默认没有提供多个组件在同一页面绑定不同模型的接口,因此在网上搜了一下,搜到了这篇文章,文章中最后的建议是自己封装一个组件来调用upload组件,使用的时候直接调用自己封装的这个组件,但是项目时间紧迫,我这边希望更快的搞定这个问题,于是想到了以下办法

解决方法

upload组件的接口中,有一个data接口,可以绑定需要上传的除文件之外的其他数据对象,由于订单评价页的一个特点:每个商品不论数量大小都只会被评价一次,因此此处直接将当前数组中商品的uuid绑定到data并传递至上传接口,此操作后表单提交的payload就会包含类似如下数据:

Content-Disposition: form-data; name="uuid"

E7D947BA-79F1-11E8-B786-00163E063020

而后台文件上传位置可以做一个判断:如果接收的上传请求包含额外参数,则全部原路返回,因此在上传成功后又会在on-success这个钩子接收到这个唯一的uuid,此处对当前页面商品数组进行遍历并进行比对,在包含返回的uuid对应数组的对应保存组图路径的数组push当前上传成功的图片路径

this.data.goods_list.forEach((e,k)=>{
    if(e.uuid === response.uuid){
        e.evaluate.thumbs.push(response.url)
    }
})

以下是完整代码(html):

<div class="userEva-cont" v-for="(item,key) in data.goods_list">
    <table class="userEva-table">
        <thead>
        <tr>
            <th width="420">商品</th>
            <th width="280">型号</th>
            <th width="280">数量</th>
        </tr>
        </thead>
        <tbody>
        <tr>
            <td>
                <div class="evaluate-pic"><a :href="'/product/'+item.goods_id+'.html'"><img :src="'__PHOTO__'+item.thumb"></a></div>
                <div class="evaluate-text">
                    <h3><a></a></h3>
                    <p>编号:</p>
                </div>
            </td>
            <td>型号:</td>
            <td></td>
        </tr>
        </tbody>
    </table>
    <div class="evaluate-wrap">
        <form>
            <dl>
                <dt>评论:</dt>
                <dd>
                    <textarea v-model="item.evaluate.content" placeholder="评论内容"></textarea>
                </dd>
            </dl>
            <dl>
                <dt>晒单:</dt>
                <dd>
                    <el-upload
                            class="upload-demo"
                            :action="basePath"
                            :on-preview="handlePreview"
                            :on-remove="handleRemove"
                            drag
                            multiple
                            :data="item"
                            :limit="5"
                            :on-success="setFileList"
                            list-type="picture">
                        <i class="el-icon-upload"></i>
                        <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
                        <div class="el-upload__tip" slot="tip">只能上传jpg/png文件,且不超过500kb</div>
                    </el-upload>
                </dd>
            </dl>
            <div class="evaluate-btns">
                <button type="button" class="evaluate-sub" @click="submit(item.evaluate,item)">提交评价</button>
                <label><input type="checkbox" class="evaluate-show" v-model="item.evaluate.is_anonymous">匿名评价</label>
            </div>
        </form>
    </div>
</div>

js

/*
    * todo:初始化vue
    * */
var app = new Vue({
    el: '#container',
    data: {
        data: __PAGE_DATA__,
        evaluateUrl: '/evaluate.html',
        imgDialogVisible: false,
        tempPath: '',
        basePath: ''
    },
    mounted() {
        this.basePath = Vue.prototype.fileUploadBasePath
    },
    methods: {
        handleRemove(file, fileList) {
            this.data.goods_list.forEach((e,k)=>{
                if(e.uuid === file.response.uuid){
                    //找到当前url下标
                    const index = e.evaluate.thumbs.indexOf(file.response.url)
                    if(index !== -1){
                        //删除
                        e.evaluate.thumbs.splice(index,1)
                    }
                }
            })
        },
        handlePreview(file) {
            this.tempPath = file.response.url
            this.imgDialogVisible = true
        },
        setFileList(response, file, fileList){
            this.data.goods_list.forEach((e,k)=>{
                if(e.uuid === response.uuid){
                    e.evaluate.thumbs.push(response.url)
                }
            })
        },
        submit(evaluate,item){
            evaluate.id = item.goods_id
            evaluate.goods_name = item.goods_name
            evaluate.goods_specification_name = item.goods_specification_name
            evaluate.order_id = this.data.goods.o_id
            evaluate = Object.assign({}, evaluate)

            this.$http.post(this.evaluateUrl,{no:this.data.goods.o_orderno,evaluate:evaluate}).then(response => {
                if(response.data.status === 200){
                    //重新拉取数据
                    this.$http.get(location.href).then(function(response){
                        if(response.data.status === 200){
                            this.$message({
                                message:'评价成功!',
                                type:'success'
                            })
                            //重新拉取数据
                            this.data = response.data.data
                        }
                    }).catch(e => {})
                }else{
                    this.$message({
                        message:response.data.message,
                        type:'error'
                    })
                }
            }).catch(e => {})
        }
    }
})

至此,经过测试,解决了同一页面多个upload组件上传预览并分别异步提交对应表单到后台的问题