vue 带上传功能组件封装,级联选择器封装,附件预览组件封装

父组件,可渲染数据

<!--

 组件:职称填报
 created by hexiaobo

 参数说明:

 方法:
  setProfessionValue:向父组件传id,
  setProfessionLabel:向父组件传label,
 -->

<template>
    <div>
        <el-row :gutter="40" style="margin-left: 0;">
            <template v-if="data && data.length > 0">
                <el-col  :xs="24" :sm="12" :md="12" :lg="8" v-for="(item,index) in data" :key="index" style="padding-left: 0;">
                    <div class="zige-item card">

                        <el-popconfirm
                                title="确定删除吗?"
                                v-if="editAble"
                                @onConfirm="professionDel(item.id,index)"
                        >
                            <a class="del" slot="reference">
                                <i class="el-icon-delete"></i>
                            </a>
                        </el-popconfirm>

                        <div style="font-size: 20px;height: 60px;color: #333;padding-right: 30px;">
                            <svg class="icon" aria-hidden="true">
                                <use xlink:href="#icon-shouye-jieyezhengshu"></use>
                            </svg>
                            {{item.professionName}}
                        </div>
                        <div style="font-size: 14px;line-height: 30px;">职称编号:{{item.professionNumber}}</div>
                        <div style="font-size: 14px;line-height: 30px;margin-bottom: 15px;">获取时间:{{$formats.YYYYMMDDByHoriLine(item.certificateGetDate)}}</div>
                        <a class="showFiles" @click="showFileImg(item.files)">查看附件</a>
                    </div>
                </el-col>
            </template>
            <template v-else><el-col>暂无职称记录</el-col></template>
        </el-row>

        <!-- 查看附件 -->
        <files-preview
                :filesPreviewArr="this.filesPreviewArr"
                :dialogVisible.sync="dialogVisible"
        />
        <!--/. 查看附件 -->


        <!-- 新增form -->
        <div class="" v-if="data.length < 6 && editAble" style="margin-top: 1rem;">
            <el-form ref="professionsHolderForm" :inline="true" :model="professionsHolderForm">

                <el-form-item
                        label=""
                        :rules="[{ required: true, message: '请选择职称', trigger: 'change' }]"
                        prop="professionId"
                >
                    <profession-picker
                            ref="professionPicker"
                            :data="professionsHolderForm.professionId"
                            @setProfessionValueFC="setProfessionValue"
                            @setProfessionLabelFC="setProfessionLabel" />

                </el-form-item>
                <el-form-item label=""
                              prop="professionNumber"
                              :rules="[{ required: true, message: '请输入证书号', trigger: 'blur' }]"
                >
                    <el-input
                            v-model="professionsHolderForm.professionNumber"
                            placeholder="证书号"
                    ></el-input>
                </el-form-item>
                <el-form-item label=""
                              prop="certificateGetDate"
                              :rules="[{ required: true, message: '请选择时间', trigger: 'blur' }]"
                >
                    <el-date-picker
                            v-model="professionsHolderForm.certificateGetDate"
                    />

                </el-form-item>
                <el-form-item>
                    <el-button type="success" @click="addTitles('professionsHolderForm')">新增</el-button>
                </el-form-item>

                <div style="padding: 20px 0 10px">
                    <el-form-item prop="files" :rules="[{ required: true, message: '请上传附件'}]">
                        <el-upload
                                class="upload-box"
                                :on-success="handleUploadSuccess"
                                :before-upload="beforeUpload"
                                :on-remove="handleFileRemove"
                                :headers = "headers"
                                ref="professionUploader"
                                :limit="4"
                                :on-exceed="handleExceed"
                                :action="$baseUrl.common + '/file'"
                                >
                            <el-button size="mini" type="primary">点击上传</el-button>
                            <div slot="tip" class="" style="display: inline-block;padding-left: 1rem;font-size: 12px;">
                                请上传jpg/png/pdf文件,不超过2M
                            </div>
                        </el-upload>
                    </el-form-item>

                </div>
            </el-form>
        </div>
        <!--/. 新增form -->
    </div>
</template>

<script>
    import Vue from "vue"
    import {DatePicker,Dialog,Message,Carousel,CarouselItem} from "element-ui"
    import ProfessionPicker from "./pickers/ProfessionPicker";
    import FilesPreview from "./FilesPreview";

    Vue.use(DatePicker);
    Vue.use(Dialog);
    Vue.use(Carousel);
    Vue.use(CarouselItem);
    export default {
        name: "ProfessionalTitles",
        components: {FilesPreview, ProfessionPicker},
        data() {
            return {
                headers:{},
                options: [],
                filesPreviewArr: [], //附件查看数组
                dialogVisible: false,

                //职称暂存
                professionsHolderForm: {
                    "professionId":"",
                    "professionName": "",
                    "files": [],
                    "professionNumber": "",
                    "certificateGetDate": "",
                },
            }
        },
        props: {
            data: "",
            editAble:{default:true},
            width: {
                default: "80%"
            }

        },
        mounted() {
            //this.getOptions();
            this.headers ={Authorization : 'Bearer '+(sessionStorage.getItem('token') || '')}
        },
        methods: {
            getOptions() {
                this.$HTTP.get(this.$baseUrl.global + '/titles-option', {
                    params: {}
                }).then(response => {
                    let data = response.data;
                    this.options = data.data;
                })
            },
            //查看附件图片
            showFileImg(files){
                this.dialogVisible = true;
                this.filesPreviewArr = files;
            },
            setProfessionValue(v){
                this.professionsHolderForm.professionId = v;
            },
            setProfessionLabel(v){
                //取最后一级
                this.professionsHolderForm.professionName = v;
            },
            //新增职称
            addTitles(formName) {
                this.$refs[formName].validate((valid) => {
                    if (valid) {
                        //Message.success('新增成功');
                        if(this.isRepeat()){
                            this.$emit('professionAdd',this.professionsHolderForm);
                            this.professionsHolderForm = {
                                "professionId": "",
                                "files": [],
                                "professionName": "",
                                "professionNumber": "",
                                "certificateGetDate": ""
                            }
                        }

                    } else {
                        console.log('error submit!!');
                        return false;
                    }
                });
            },
            //判断是否重复添加
            isRepeat(){
                let idArr = [],
                    data = this.data,
                    nowId =  this.professionsHolderForm.professionId;
                for(let i in data){
                    idArr.push(data[i].professionId);
                }
                if(idArr.includes(nowId)){
                    Message.warning('该职称已存在。');
                    return false;
                }else{
                    return true;
                }
            },
            //附件上传成功
            handleUploadSuccess(response, file ,fileList){
                console.log(file)
                let data = response;
                if(!data.code){
                    this.professionsHolderForm.files.push({
                        id:file.response.data,
                        name:file.name,
                        type:file.raw.type
                    });
                    this.$refs.professionsHolderForm.validateField('files')
                }else{
                    Message.error(data.msg);
                    this.clearUploadeList()
                }
            },
            //上传之前的检查
            beforeUpload(file) {
                const isJPG = file.type === 'image/jpeg' || file.type === 'image/png' || file.type === 'application/pdf';
                const isLt = file.size / 1024 < 2000;
                if (!isJPG) {
                    Message.error('请上传jpg/png/pdf文件');
                    return false;
                }
                if (!isLt) {
                    Message.error('图片大小不能超过 2M!');
                    return false;
                }
                return isJPG && isLt;
            },
            //删除数组中特定项
            deleteItem(item, list){
                for (var key in list) {
                    list[key].id === item ? list.splice(key, 1) : null;
                }
            },
            //删除附件
            handleFileRemove(file, fileList){
                let id=file.response.data;
                this.deleteItem(id,this.professionsHolderForm.files); //删除数组中特定id项
            },
            handleExceed(files, fileList) {
                Message.warning("附件数量已到上限。");
            },
            //清空上传列表
            clearUploadeList(){
                this.$refs.professionUploader.clearFiles()
            },
            //删除职称
            professionDel(id,index){
                this.$emit("professionDel",id,index)
            },
            clearPicker(){
                this.$refs.professionPicker.clearCascader();
            },
            clearForm(){
                this.clearUploadeList();
                this.clearPicker();
            }
        },
        computed: {

        },
        watch: {
            /*'professionsHolderForm.professionId':{
                handler:function(newV){
                    if(newV){
                        this.$refs.professionsHolderForm.validateField('professionId')
                    }
                }
            }*/
        }

    }
</script>

<style scoped lang="scss">

    .icon{
        width: 1.4em;
        height: 1.4em;
        vertical-align: middle;
    }
    .card{
        @extend %card;
        height: 200px;
        padding: 20px;
        color: #6d7592;
    }
    .zige-item{
        font-size: 14px;
        line-height: 26px;
        margin-bottom: .4rem;
        width: 100%;
        position: relative;

        a.showFiles{
            border-radius: 3px;
            padding: 4px 10px;
            background: $mainGraybg;
            color: #737373;
        }
        .del{
            position: absolute;
            top: 7px;
            height: 46px;
            padding: 0 15px;
            line-height: 46px;
            font-size: 16px;
            right: 7px;
            &:hover{
                background-color: $mainGraybg;
            }
        }
    }
</style>

级联选择器:

<!--

 组件:职称选择器
 created by hexiaobo

 参数说明:
 -->

<template>

    <el-cascader
            v-model="dataHolder"
            :options="options"
            :style="'width:'+ width"
            :props='{value:"id",label:"name",children:"list"}'
            :show-all-levels="false"
            placeholder="请选择职称"
            ref="cascader"
            @change="changeCascader"
    >
    </el-cascader>

</template>

<script>
    import Vue from "vue"
    import {Cascader} from "element-ui"

    Vue.use(Cascader);
    export default {
        name: "ProfessionPicker",
        data() {
            return {
                dataHolder: "",
                options: [],
                form: {}
            }
        },
        props: {
            data: {},
            width: {
                default: "100%"
            }

        },
        mounted() {
            if (sessionStorage.getItem("base_code")) {
                this.options = JSON.parse(sessionStorage.getItem("base_code")).tcprofession;
            } else {
                this.getOptions();
            }
        },
        methods: {
            getOptions() {
                this.$HTTP.get(this.$baseUrl.codeData + '/base_code.json')
                    .then(response => {
                        var obj = response.data;
                        sessionStorage.setItem("base_code", JSON.stringify(obj));
                        this.options = JSON.parse(sessionStorage.getItem("base_code")).tcprofession;
                    });
            },
            changeCascader(val) {
                let nodesObj = this.$refs['cascader'].getCheckedNodes();
                console.log(nodesObj);
                this.form.label = nodesObj[0].pathLabels.join("-");
                this.form.value = nodesObj[0].path;
                //向父级传值
                let lastId = this.form.value[this.form.value.length -1];
                let lastLabel = this.form.label.split("-")[this.form.label.split("-").length -1];


                this.$emit('setProfessionValueFC', lastId);
                this.$emit('setProfessionLabelFC', lastLabel);
            },
            //清空数据
            clearCascader(){
                this.dataHolder ="";
                this.form={
                    value:"",
                    label:""
                }
            },
            //拿到末级code,造出全级数组
            codeFormat(code){
                let arr=[],
                    lv1 = code.substring(0,2)+'0';
                arr.push(lv1,code);
                return arr;
            }
        },
        computed: {

        },
        watch: {
            data:{
                handler:function(nv,ov){
                    if(nv){
                        this.dataHolder = this.codeFormat(nv);
                    }
                },
                immediate:true
            }
        }

    }
</script>

<style scoped lang="scss">

</style>

附件预览组件:

<!--

 组件:附件预览
 created by hexiaobo

 参数说明:

 方法:

 -->

<template>
    <div>

        <el-dialog :visible.sync="dialogVisible" @close="close" width="100%" height="100%" style="height: 80%;top: 10%;width: 80%;left: 10%;">
            <el-carousel height="500px" :autoplay="false">
                <el-carousel-item v-for="file in filesPreviewArr" :key="file.id">
                    <template v-if="file.type === 'application/pdf'">
                        <a target="_blank" :href="$baseUrl.common + '/file/'+file.id" class="btn-main-theme btn-md">点击查看pdf文件</a>
                        <!--<iframe :src="$baseUrl.common + '/file/'+file.id" frameborder="0" style="width: 100%;height: 100%;"></iframe>-->
                    </template>
                    <template v-else>
                        <img style="max-height: 100%;width: auto;height: auto;max-width: 100%"
                             :src="$baseUrl.common + '/file/'+file.id" alt="file.name">
                    </template>

                </el-carousel-item>
            </el-carousel>
        </el-dialog>

    </div>
</template>

<script>
    import Vue from "vue"
    import {Carousel,CarouselItem} from "element-ui"
    Vue.use(Carousel);
    Vue.use(CarouselItem);

    export default {
        name: "FilesPreview",
        components: {},
        data() {
            return {
                //dialogVisible: false
            }
        },
        props: {
            filesPreviewArr: "",
            dialogVisible:{
                default:false
            }
        },
        mounted() {

        },
        methods: {
            close(){
                this.$emit("update:dialogVisible",false);
            }
        },
        computed: {

        },
        watch: {

        }

    }
</script>

<style scoped lang="scss">
    .el-carousel__item{
        @include display-flex();
        @include justify-content(center);
        @include align-items(center);
        overflow: auto;
    }

</style>
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。