美文网首页
antd 表单图片上传、表格拖拽排序

antd 表单图片上传、表格拖拽排序

作者: 领带衬有黄金 | 来源:发表于2019-10-25 10:31 被阅读0次

    1. 需求

    需求1:antd 表单中图片收集
    需求2:表格拖拽排序

    2.说明

    表单提交图片时,使用a-uupload 或者 el-upload 都需要阻止图片自动提交。
    表格拖拽需要使用到vuedraggable,拖拽后,保存顺序,返回到后台。

    3. 核心代码

    DatabaseList.vue (父)
    <template>
      <div class="content-wrap database-list">
        <!-- 按钮 -->
        <div class="database-list-btn">
          <div class="add_modal">
            <a-button type="dashed" icon="plus" @click="showModal">添加数据库</a-button>
            <a-modal
              title="添加数据库"
              v-model="visible"
              :footer="null"
              width="60%"
              style="margin:0 25%"
              okText="确认"
              cancelText="取消"
              @ok=""
            >
              <a-form :form="form" @submit="handleSubmit">
                <a-form-item label="分类英文" :label-col="{ span: 2 }" :wrapper-col="{ span: 6 }">
                  <a-input placeholder="分类英文"
                           v-decorator="['name_en', { rules: [{ required: true, message: '输入不能为空!' }] }]"
                  />
                </a-form-item>
                <a-form-item label="分类中文" :label-col="{ span: 2 }" :wrapper-col="{ span: 6 }">
                  <a-input placeholder="分类中文"
                           v-decorator="['name_cn', { rules: [{ required: true, message: '输入不能为空!' }] }]"
                  />
                </a-form-item>
                <a-form-item label="分类编码" :label-col="{ span: 2 }" :wrapper-col="{ span: 6 }">
                  <a-input placeholder="分类编码"
                           v-decorator="['code', { rules: [{ required: true, message: '输入不能为空!' }] }]"
                  />
                </a-form-item>
                <a-form-item label="封面设置" :label-col="{ span: 2 }" :wrapper-col="{ span: 12 }">
                  <template>
                    <div class="clearfix">
                      <a-upload
                        listType="picture-card"
                        :beforeUpload="beforeUpload"
                        class="avatar-uploader"
                        :showUploadList="false"
                        @change="handleChange"
                        v-decorator="['cover', { rules: [{ required: true, message: '封面必须上传!' }] }]"
                      >
                        <!--直接上传base64数据,进行后台保存-->
                        <img v-if="imageUrl" :src="imageUrl" alt="cover" height="100px"/>
                        <div v-else>
                          <a-icon :type="loading ? 'loading' : 'plus'"/>
                          <div class="ant-upload-text">上传</div>
                        </div>
                      </a-upload>
                    </div>
                  </template>
                </a-form-item>
                <a-form-item label="备注" :label-col="{ span: 2 }" :wrapper-col="{ span: 6 }">
                  <a-textarea placeholder="备注信息" :rows="4"
                              v-decorator="['des', { rules: [{ required: true, message: '输入不能为空!' }] }]"/>
                </a-form-item>
                <a-form-item :wrapper-col="{ span: 12, offset: 5 }">
                  <a-button type="primary" html-type="submit">提交</a-button>
                  <a-button :style="{ marginLeft: '8px' }" @click="handleReset">
                    重置
                  </a-button>
                </a-form-item>
              </a-form>
            </a-modal>
          </div>
          <a-button type="dashed" icon="reload" @click="reload()">刷新</a-button>
          <a-button :type="type?'danger':'dashed'" :icon="type?'check-circle':'edit'" @click="onedit()">
            {{type?'完成':'拖拽表格'}}
          </a-button>
        </div>
        <DataTable :type="type"/>
      </div>
    </template>
    
    <script>
        import {mapGetters} from 'vuex'
        import DataTable from "@/components/Database/DataTable"
        import {update_structure, add_type} from '@/api/db'
    
        function getBase64(img, callback) {
            const reader = new FileReader();
            reader.addEventListener('load', () => callback(reader.result));
            reader.readAsDataURL(img);
        }
    
        export default {
            name: "databaselist",
            data() {
                return {
                    type: false,
                    visible: false,
                    form: this.$form.createForm(this, {name: "add_database"}),
                    imageUrl: '',
                    loading: false,
                }
            },
            components: {
                DataTable
            },
            methods: {
                showModal() {
                    this.visible = true;
                },
                handleReset() {
                    this.imageUrl = ''
                    // 发送请求删除图片
                    this.form.resetFields();
                },
                handleSubmit(e) {
                    e.preventDefault();
                    this.form.validateFields((err, values) => {
                        if (!err) {
                            console.log("Received values of form: ", values);
                            values.cover = this.file
                            add_type(values).then(res => {
                                console.log(res)
                            }).catch(err => {
                                console.log(err)
                            })
                        }
                    })
                },
                handleChange(info) {
                    if (info.file.status === 'uploading') {
                        this.loading = true;
                        return;
                    }
                    if (info.file.status === 'done') {
                        // Get this url from response in real world.
                        getBase64(info.file.originFileObj, imageUrl => {
                            this.imageUrl = imageUrl;
                            this.loading = false;
                        });
                    }
                },
                beforeUpload(file) {
                    const isJPG = file.type === 'image/jpeg';
                    if (!isJPG) {
                        this.$message.error('You can only upload JPG file!');
                    }
                    const isLt2M = file.size / 1024 / 1024 < 20;
                    if (!isLt2M) {
                        this.$message.error('Image must smaller than 20MB!');
                    }
                    //创建临时的路径来展示图片
                    const windowURL = window.URL || window.webkitURL;
                    this.imageUrl = windowURL.createObjectURL(file);
                    this.file = file
                    //阻止默认提交
                    // return isJPG && isLt2M;
                    return false
                },
                // 点击刷新
                reload() {
                    console.log('1111');
    
                },
                // 点击编辑表格,拖拽
                onedit() {
                    this.type = !this.type
                    if (!this.type) {
                        // 完成编辑模式时,发送请求,修改数据
                        const data = this.db_types.map((item) => {
                            return item.id
                        });
                        update_structure(data).then(res => {
                            this.$message({
                                message: '更新成功',
                                type: 'success'
                            })
                        }).catch(err => {
                            console.log(err)
                        })
                    }
                }
            },
            computed: {
                ...mapGetters([
                    'db_types'
                ]),
            }
        }
    </script>
    
    <style lang="scss" scoped>
      .database-list {
        &-btn {
          display: flex;
          padding: 0 0 20px 0;
    
          .ant-btn,
          .ant-btn:active,
          .ant-btn:focus {
            margin: 0 15px 0 0;
          }
        }
      }
    </style>
    <style scoped>
      .avatar-uploader > .ant-upload {
        width: 300px;
        height: 300px;
      }
    
      .ant-upload-select-picture-card i {
        font-size: 32px;
        color: #999;
      }
    
      .ant-upload-select-picture-card .ant-upload-text {
        margin-top: 8px;
        color: #666;
      }
    </style>
    
    
    DataTable(子)
    <template>
      <div class="table_wrap">
        <!-- <el-table :data="tableData" border style="width: 96%; margin: 10px auto">
        <el-table-column type="index" width="100" label="序号"></el-table-column>
        <el-table-column prop="name_en" label="分类英文" width="180"></el-table-column>
        <el-table-column prop="name_zh" label="分类中文" width="180"></el-table-column>
        <el-table-column prop="t_code" label="分类编码"></el-table-column>
        <el-table-column prop="t_des" label="备注"></el-table-column>
        <el-table-column prop="add_time" label="创建时间"></el-table-column>
        <el-table-column prop="active" label="状态">
          <el-button type="success" plain size="mini">启用中</el-button>
        </el-table-column>
        <el-table-column label="操作">
          <template slot-scope="scope">
            <el-button size="mini" @click="handleEdit(scope.$index, scope.row)">编辑</el-button>
            <el-button size="mini" type="danger" @click="handleDelete(scope.$index, scope.row)">删除</el-button>
          </template>
        </el-table-column>
        </el-table>-->
        <!-- antd -->
        <!--    <a-table :columns="columns" :dataSource="db_types" :pagination="false" bordered>-->
        <!--      <template-->
        <!--        v-for="col in ['name_en', 'name_cn', 'des','code']"-->
        <!--        :slot="col"-->
        <!--        slot-scope="text, record, index"-->
        <!--      >-->
        <!--        <div :key="col">-->
        <!--          <a-input-->
        <!--            v-if="record.editable"-->
        <!--            style="margin: -5px 0"-->
        <!--            :value="text"-->
        <!--            @change="e => handleChange(e.target.value, record.key, col)"-->
        <!--          />-->
        <!--          <template v-else>{{text}}</template>-->
        <!--        </div>-->
        <!--      </template>-->
        <!--      <template slot="active" slot-scope="active">-->
        <!--        <span>-->
        <!--          &lt;!&ndash; <a-tag v-for="item in active" color="blue" :key="item">{{item}}</a-tag> &ndash;&gt;-->
        <!--          <a-switch :defaultChecked="active?true:false" @change="onChange">-->
        <!--            <a-icon type="check" slot="checkedChildren"/>-->
        <!--            <a-icon type="close" slot="unCheckedChildren"/>-->
        <!--          </a-switch>-->
        <!--        </span>-->
        <!--      </template>-->
        <!--      <template slot="operation" slot-scope="text, record, index">-->
        <!--        <div class="editable-row-operations">-->
        <!--          <span v-if="record.editable">-->
        <!--            <a @click="() => save(record.key)">确认</a>-->
        <!--            <a-popconfirm title="确定取消本次编辑吗?" @confirm="() => cancel(record.key)" okText="确定" cancelText="取消">-->
        <!--              <a>取消</a>-->
        <!--            </a-popconfirm>-->
        <!--          </span>-->
        <!--          <span v-else>-->
        <!--            <a @click="() => edit(record.key)">编辑</a>-->
        <!--          </span>-->
        <!--        </div>-->
        <!--      </template>-->
        <!--    </a-table>-->
        <!--原生table-->
        <table class="table">
          <thead>
          <th>序号</th>
          <th>中文</th>
          <th>英文</th>
          <th>编码</th>
          <th>备注</th>
          <th>创建时间</th>
          <th>封面</th>
          <th>状态</th>
          <th>操作</th>
          </thead>
          <draggable v-model="db_types" ghost-class="ghost" :disabled="!type" element="tbody">
            <tr v-for="(item,index) in db_types" :key="index" :class="{'tr_cursor':type}">
              <td width="5%">
                {{item.key}}
              </td>
              <td width="14%">
                <a-input
                  v-if="item.editable"
                  style="margin: -5px 0"
                  :value="item.name_cn"
                  @change="e => handleChange(e.target.value, item.key,'name_cn')"/>
                <span v-else>{{item.name_cn}}</span>
              </td>
              <td width="14%">
                <a-input
                  v-if="item.editable"
                  style="margin: -5px 0"
                  :value="item.name_en"
                  @change="e => handleChange(e.target.value, item.key,'name_en')"/>
                <span v-else>{{item.name_en}}</span>
              </td>
              <td width="8%">
                <a-input
                  v-if="item.editable"
                  style="margin: -5px 0"
                  :value="item.code"
                  @change="e => handleChange(e.target.value, item.key,'name_code')"/>
                <span v-else>{{item.code}}</span>
              </td>
              <td width="12%">
                <a-input
                  v-if="item.editable"
                  style="margin: -5px 0"
                  :value="item.des"
                  @change="e => handleChange(e.target.value, item.key,'des')"/>
                <span v-else>{{item.des}}</span>
              </td>
              <td width="12%">
                {{item.add_time}}
              </td>
              <td width="12%">
                {{item.cover}}
              </td>
              <td width="8%">
                <a-switch :defaultChecked="item.active?true:false"
                          @change="onChange(item.key,!item.active,'active')">
                  <a-icon type="check" slot="checkedChildren"/>
                  <a-icon type="close" slot="unCheckedChildren"/>
                </a-switch>
              </td>
              <td width="15%">
                <span v-if="item.editable">
                  <a @click="() => save(item.key)" class="btn ok_btn">确认</a>
                  <a-popconfirm title="确定取消本次编辑吗?" @confirm="() => cancel(item.key)" okText="确定" cancelText="取消">
                  <a class="btn no_btn">取消</a>
                  </a-popconfirm>
                </span>
                <span v-else class="span">
                  <span type="primary" @click="edit(item.key)" class="btn tr_cursor">编辑</span>
                  <span type="primary" @click="del(item.key)" class="btn tr_cursor">删除</span>
                </span>
              </td>
            </tr>
          </draggable>
        </table>
      </div>
    </template>
    
    <script>
        import draggable from "vuedraggable";
        import {update_data, update_status} from '@/api/db'
    
        export default {
            name: "data_table",
            data() {
                return {}
            },
            props: {type: Boolean},
            components: {
                draggable
            },
            methods: {
                // 发生修改单行语句时,回调函数
                handleChange(value, key, column) {
                    const newData = [...this.db_types];
                    const target = newData.filter(item => key === item.key)[0];
                    if (target) {
                        target[column] = value;
                        this.db_types = newData;
                    }
                },
                // 编辑单行
                edit(key) {
                    const newData = [...this.db_types];
                    const target = newData.filter(item => key === item.key)[0];
                    if (target) {
                        target.editable = true;
                        this.db_types = newData;
                    }
                },
                del() {
                    console.log('删除')
                },
                // 保存单行数据
                save(key) {
                    const newData = [...this.db_types];
                    const target = newData.filter(item => key === item.key)[0];
                    if (target) {
                        delete target.editable;
                        this.db_types = newData;
                        // 保存单条修改语句--持久化
                        const id = target.id;
                        const {name_cn, name_en, code, des} = target;
                        const data = {
                            id, name_cn, name_en, code, des
                        };
                        update_data(data).then(res => {
                            this.$message({
                                message: '修改成功',
                                type: 'success'
                            })
                        }).catch(err => {
                            console.log(err)
                        })
                    }
                },
                cancel(key) {
                    const newData = [...this.db_types];
                    const target = newData.filter(item => key === item.key)[0];
                    if (target) {
                        Object.assign(
                            target,
                        );
                        delete target.editable;
                        this.db_types = newData;
                    }
                },
                onChange(key, bol, col) {
                    const newData = [...this.db_types];
                    const target = newData.filter(item => key === item.key)[0];
                    if (target) {
                        target[col] = bol;
                        this.db_types = newData;
                        // 向后台发送状态修改请求
                        update_status({id: target.id, bol, type: 'db_type'}).then(res => {
                            this.$message({
                                message: res.msg,
                                type: 'success'
                            })
                        }).catch(err => {
                            console.log(err)
                        })
                    }
                }
            },
            computed: {
                db_types: {
                    get() {
                        return this.$store.getters.db_types.map((item, index) => {
                            item['key'] = index + 1;
                            return item
                        })
                    },
                    set(val) {
                        // 修改state中的值
                        this.$store.commit('db/SET_TYPES', val)
                    }
                }
            }
        };
    </script>
    
    <style lang="scss" scoped>
      .btn {
        margin-right: 15px;
        display: inline-block;
        color: white;
        padding: 4px 15px;
        border-radius: 4px;
      }
    
      .ok_btn {
        color: #28B78D;
        border: 1px solid #28B78D;
      }
    
      .ghost {
        opacity: 0.5;
        background: #c8ebfb;
      }
    
      .no_btn {
        color: #ccc;
        border: 1px solid #ccc;
      }
    
      .table {
        font-size: 14px;
        line-height: 24px;
        width: 100%;
        border-collapse: collapse;
      }
    
      .tr_cursor {
        cursor: pointer;
      }
    
      table, th, td {
        border: 1px solid #eaeaea;
      }
    
      th {
        padding: 6px 0;
        font-weight: normal;
        color: #333;
        height: 55px;
        background-color: #fcfcfc;
      }
    
      tr:hover {
        background-color: #e9f7f0;
      }
    
      td, th {
        text-align: left;
        padding: 10px 15px;
      }
    
      td {
        color: #777;
    
        .span {
          span {
            /*margin-right: 15px;*/
            /*display: inline-block;*/
            /*color: white;*/
            /*padding: 5px 15px;*/
            /*border-radius: 4px;*/
            &:nth-child(1) {
              background-color: rgb(64, 158, 255);
    
              &:hover {
                background-color: rgba(64, 158, 255, .7);
              }
            }
    
            &:nth-child(2) {
              background-color: #f5222d;
    
              &:hover {
                background-color: rgba(245, 35, 45, .7);
              }
            }
          }
        }
      }
    
    
    </style>
    
    

    相关文章

      网友评论

          本文标题:antd 表单图片上传、表格拖拽排序

          本文链接:https://www.haomeiwen.com/subject/fzdrmctx.html