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>-->
<!-- <!– <a-tag v-for="item in active" color="blue" :key="item">{{item}}</a-tag> –>-->
<!-- <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>
网友评论