方案 vue+vuedraggable+Sortable+自定义css+elementui
业务繁琐后海量配置或者其他场景需要,仿照板栗看板写一个简单的网页版,这里贴出大概贴出部分代码
1.列表拖动插入,主要样式代码
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head th:include="include/header_element::header('')"></head>
<style>
body, html {
}
.el-form-item {
margin-bottom: 10px;
}
.el-card {
border-radius: 10px;
margin: 10px;
}
.el-avatar {
background: #235374;
}
.drag {
-o-transform: rotate(5deg); /* Opera浏览器 */
-webkit-transform: rotate(5deg); /* Webkit内核浏览器 */
-moz-transform: rotate(5deg); /* Firefox浏览器 */
}
.chosen {
margin-top: -10px !important;
-o-transform: rotate(5deg); /* Opera浏览器 */
-webkit-transform: rotate(5deg); /* Webkit内核浏览器 */
-moz-transform: rotate(5deg); /* Firefox浏览器 */
}
.ghost {
-o-transform: rotate(5deg) !important; /* Opera浏览器 */
-webkit-transform: rotate(5deg) !important; /* Webkit内核浏览器 */
-moz-transform: rotate(5deg) !important; /* Firefox浏览器 */
}
.ghost .el-card, .ghost
.el-textarea__inner,
.ghost .title,
.ghost .el-button--text,
.ghost .el-button--primary,
.ghost .el-button--info,
.ghost .el-button--danger {
color: #fff;
background: rgba(255, 255, 255, 0) !important;
}
.configls .el-textarea__inner {
border: 0px !important;
}
.configls:hover {
background-color: #eaf2f8;
}
.configls .el-card:hover {
/*background-color: #eaf2f8;*/
/*width: 600px;*/
color: #ac0a2c;
font-size: 20px;
}
</style>
<body>
<div id="zsvm" v-cloak>
<auto-config-user v-if="!toMore"></auto-config-user>
<el-row v-if="toMore">
<el-row class="searchRow"
:style="'width:'+ 420*arrs.length+'px;padding:13px; font-weight:300;min-width:100%;font-size:15px;'">
<el-button @click="toMore=false" icon="el-icon-s-home" size="mini" type="danger">
返回
</el-button>
<el-divider direction="vertical"></el-divider>
{{user.userName}},关于 【{{user.remark}}】的配置
<el-divider direction="vertical"></el-divider>
<el-button @click="toAdd" size="mini" type="primary">
新建一列
</el-button>
<el-button @click="smo=!smo" size="mini" type="primary">
切换模式
</el-button>
</el-row>
<el-dialog title="新建一个类型" :visible.sync="addShow" width="30%" destroy-on-close @open="common.toSmall()"
@closed="common.toBig()">
<el-row style="padding: 10px;">
<el-form size="mini" status-icon label-width="100px">
<el-form-item label="列名">
<el-input v-model.trim="addTypeName"></el-input>
</el-form-item>
<el-form-item label="">
<el-button type="danger" @click="addType" style="width: 100%">保存</el-button>
</el-form-item>
</el-form>
</el-row>
</el-dialog>
<el-dialog title="修改配置" :visible.sync="showEditConfig" width="38%" destroy-on-close @open="common.toSmall()"
@closed="common.toBig()">
<edit-config v-if="showEditConfig"></edit-config>
</el-dialog>
<el-dialog title="新加配置" :visible.sync="showCopyConfig" width="38%" destroy-on-close @open="common.toSmall()"
@closed="common.toBig()">
<add-config v-if="showCopyConfig"></add-config>
</el-dialog>
<el-drawer :with-header="false" size="90%" direction="rtl"
:visible.sync="drawer_apiConfig">
<api-config v-if="drawer_apiConfig" ref="drawerApiConfig"></api-config>
</el-drawer>
<el-row :style="'width:'+ 420*arrs.length+'px;'">
<draggable v-model="arrs"
chosen-class="chosen"
drag-class="drag"
ghost-class="ghost"
force-fallback="true"
animation="100"
group="ss"
handle=".mover"
@end="onEnd">
<el-col v-for="eaa,i in arrs" class="configls"
style="width: 400px;;margin:0 10px;border-radius: 10px;padding:1px;">
<el-row class="title"
style="background: #fff;padding:5px;font-weight:700;font-size:15px;border-radius: 10px 10px 0 0; ">
<el-row v-show="smo">
<!-- {{eaa.configIdArr}}-->
<el-divider direction="vertical"></el-divider>
<!-- <el-button @click="deleteCol(eaa.id)" type="text">-->
<!-- 删除本列-->
<!-- </el-button>-->
<el-button type="danger" icon="el-icon-delete" size="mini" @click="deleteCol(eaa.id)"
circle></el-button>
<el-divider direction="vertical"></el-divider>
<el-button type="primary" icon="el-icon-plus" size="mini" @click="addConfig(eaa)"
circle></el-button>
<!-- <el-button type="text">-->
<!-- 增加配置-->
<!-- </el-button>-->
<el-divider direction="vertical"></el-divider>
<el-button type="info" icon="el-icon-thumb" class="mover" size="mini" circle></el-button>
<!-- <i class="el-icon-more" style="float: right;margin-right: 10px;"></i>-->
</el-row>
<el-row style="margin-top: 10px;">
<el-divider direction="vertical"></el-divider>
{{eaa.typeName}}({{eaa.configIdArr.length}})
</el-row>
</el-row>
<el-row :style="'height:'+window.screen.height*0.7+'px;overflow-y:auto;'">
<draggable v-model="eaa.configIdArr"
chosen-class="chosen"
drag-class="drag"
ghost-class="ghost"
force-fallback="true"
animation="100"
group="test"
handle=".mover1"
style="width: 100%; min-height: 330px"
@end="onEnd1">
<el-row v-for="e,j in eaa.configIdArr" class="item" :key="j">
<el-card shadow="hover" style="margin: 4px 0 0 0;">
<el-row style="font-size: 15px;font-weight: 300; white-space: normal;">
<el-row v-show="smo">
<el-dropdown v-if="types[e]!=null">
<span class="el-dropdown-link">
{{types[e].type}}
<i class="el-icon-arrow-down el-icon--right"></i>
</span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item
@click.native="changeTypeidType(types[e],'string')">
string
</el-dropdown-item>
<el-dropdown-item
@click.native="changeTypeidType(types[e],'json')">json
</el-dropdown-item>
<el-dropdown-item
@click.native="changeTypeidType(types[e],'array')">array
</el-dropdown-item>
<el-dropdown-item
@click.native="changeTypeidType(types[e],'boolean')">
boolean
</el-dropdown-item>
<el-dropdown-item
@click.native="changeTypeidType(types[e],'number')">
number
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<!-- <el-select v-if="types[e]!=null" v-model="types[e].type"-->
<!-- style="width: 50px;" size="mini">-->
<!-- <el-option value="string" label="string"></el-option>-->
<!-- <el-option value="json" label="json"></el-option>-->
<!-- <el-option value="array" label="array"></el-option>-->
<!-- <el-option value="boolean" label="boolean"></el-option>-->
<!-- </el-select>-->
<el-divider direction="vertical"></el-divider>
<el-button @click="deleteConfig(eaa,e)" size="mini" type="text">
删除
</el-button>
<el-divider direction="vertical"></el-divider>
<el-button @click="copyConfig(configs[e],eaa)" size="mini" type="text">
复制
</el-button>
<el-divider direction="vertical"></el-divider>
<i class="el-icon-thumb mover1"></i>
</el-row>
<el-row style="margin-bottom: 12px; font-size: 12px; font-weight:300;white-space: normal;">
{{j+1}}
<el-divider direction="vertical"></el-divider>
{{e}}
<!-- <i class="el-icon-star-off" style="font-size: 12px;font-weight: 700; white-space: normal;"> </i>-->
</el-row>
<el-row v-if="configs[e]!=null">
<el-row>
<el-button @click="editConfig(configs[e],types[e])" size="mini"
type="text">
修改
</el-button>
<el-divider direction="vertical"></el-divider>
<el-button @click="common.toConfigs(configs[e])" size="mini"
type="text">
所有产品
</el-button>
<el-divider direction="vertical"></el-divider>
<i class="el-icon-document"
style="font-size: 15px;font-weight: 700; white-space: normal;">
{{configs[e].remark}}</i>
</el-row>
<el-row style="margin-top: 10px;">
<el-input size="mini" readonly
type="textarea"
:autosize="{ minRows: 1, maxRows: 2}"
v-model.trim="configs[e].valueStr"></el-input>
<!-- <i class="el-icon-arrow-right"-->
<!-- style="font-size: 13px;font-weight: 700;margin-top: 10px; white-space: normal;">-->
<!-- </i>-->
</el-row>
</el-row>
<el-row v-if="configs[e]==null">
<i class="el-icon-document-delete"
style="font-size: 10px;font-weight: 700; white-space: normal;color:#F56C6C">没有对应配置</i>
</el-row>
</el-row>
<!-- <i class="el-icon-s-operation"></i>-->
</el-card>
</el-row>
<!-- </transition-group>-->
</draggable>
</el-row>
</el-col>
</draggable>
</el-row>
</el-row>
</div>
<div th:include="include/footer_element::footer"></div>
<script th:src="@{../../libs/sort/Sortable.min.js}"></script>
<script th:src="@{../../libs/dr/vuedraggable.umd.min.js}"></script>
<div th:include="autoConfigUser/list"></div>
<div th:include="autoConfig/apiConfig"></div>
<div th:include="autoConfig/editConfig"></div>
<div th:include="autoConfig/add"></div>
<script>
toBig(0.3)
Vue.component('vuedraggable', window.vuedraggable)
var vm = new Vue({
el: '#zsvm',
components: {
vuedraggable: window.vuedraggable,//当前页面注册组件
},
data: {
toMore: false,
drawer_apiConfig: false,
user: {},
addTypeName: null,
addShow: false,
arrs: [],
selectCol: {},//选中的列
configs: {},
types: {},//类型
smo: false,
editConfigMsg: {},
editType: 'string',
showEditConfig: false,
showCopyConfig: false,
copyConfigParams: {}
},
methods: {
loadType: function () {//查询列表
var keys = [];
var th = this;
zs_post({
url: '../../autoConfig/type/list?_' + $.now(),
param: {
userAsId: th.user.id,
},
success: function (r) {
var typeIds = JSON.parse(th.user.typeIds);
th.arrs = [];
for (i in typeIds) {
for (j in r) {
if (r[j].id == typeIds[i]) {
th.arrs.push(r[j])
break;
}
}
}
th.loadConfig();
}
})
},
loadConfig: function () {//查询列表用到的配置
var keys = [];
var th = this;
for (i in th.arrs) {
var configIdArr = JSON.parse(th.arrs[i].configIds);
th.$set(th.arrs[i], 'configIdArr', configIdArr)
// th.arr[i].configIdArr.push("rootSave");
// th.arrs[i].configIdArr = JSON.parse(th.arrs[i].configIds);
for (j in th.arrs[i].configIdArr) {
keys.push(th.arrs[i].configIdArr[j])
}
}
if (keys.length == 0)
return;
th.configs = {};
th.types = {};
zs_postFapi({
url: '../../api/config/findByKeys?_' + $.now(),
param: {
keyTypes: keys
},
success: function (r) {
for (i in r) {
var key = r[i].type + ":" + r[i].keyStr;
th.$set(th.configs, key, r[i]);
}
}
})
zs_post({
url: '../../auto/config/list?_' + $.now(),
param: {
typeKeys: keys
},
success: function (r) {
// th.types = r.rows;
for (i in r.rows) {
th.$set(th.types, r.rows[i].typeKey, r.rows[i])
}
console.log(th.types)
}
})
},
copyConfig: function (c,col) {
this.selectCol = col;
this.copyConfigParams = {};
var p= this.copyConfigParams;
for (key in c) {
if (key == 'keyStr'||key=='id')
continue;
this.$set(p,key,c[key])
}
this.showCopyConfig = true
},
changeTypeidType: function (row, type) {
row.type = type
zs_post({
url: '../../auto/config/update?_' + $.now(),
param: row,
success: function (r) {
}
})
},
deleteCol: function (id) {//删除配置一个
var th = this;
this.$confirm('确定删除?')
.then(function () {
var typeIds = [];
for (i in th.arrs) {
console.log(th.arrs[i].id, id)
if (th.arrs[i].id != id)
typeIds.push(th.arrs[i].id);
}
th.user.typeIds = JSON.stringify(typeIds);
th.user.typeIdArr = typeIds;
zs_post({
url: '../../autoConfig/user/update?_' + $.now(),
param: th.user,
success: function (r) {
th.loadType();
}
})
zs_post({
url: '../../autoConfig/type/remove?_' + $.now(),
param: [id],
success: function (r) {
}
})
}).catch(function () {
})
},
toAdd: function () {//增加一列
this.addTypeName = null;
this.addShow = true;
},
addType: function () {//增加一列
var th = this;
zs_post({
url: '../../autoConfig/type/save?_' + $.now(),
param: {
typeName: th.addTypeName,
userAsId: th.user.id
},
success: function (r) {
th.user = r.msg;
th.loadType();
th.addShow = false;
}
})
},
onEnd(e) {//更改列顺序
this.drag = false;
var th = this;
var typeIds = [];
for (i in th.arrs) {
typeIds.push(th.arrs[i].id);
}
th.user.typeIds = JSON.stringify(typeIds);
zs_post({
url: '../../autoConfig/user/update?_' + $.now(),
param: th.user,
success: function (r) {
}
})
},
addConfig: function (col) {//添加一个配置
this.selectCol = col;
this.drawer_apiConfig = true
},
deleteConfig: function (row, key) {//删除配置一个
var th = this;
this.$confirm('确定删除?')
.then(function () {
var newArr = [];
for (i in row.configIdArr) {
if (key != row.configIdArr[i])
newArr.push(row.configIdArr[i])
}
row.configIds = JSON.stringify(newArr);
zs_postA(th, {
url: '../../autoConfig/type/update?_' + $.now(),
param: row,
success: function (r) {
th.loadType();
}
})
}).catch(function () {
})
},
onEnd1(e) {//更改配置顺序
this.drag = false;
for (i in this.arrs) {
this.arrs[i].configIds = JSON.stringify(this.arrs[i].configIdArr);
// this.editType(this.arrs[i])
var th = this;
zs_post({
url: '../../autoConfig/type/update?_' + $.now(),
param: th.arrs[i],
success: function (r) {
}
})
}
},
editConfig: function (config, typeMsg) {
this.editConfigMsg = config;
this.editType = typeMsg == null ? 'string' : typeMsg.type;
this.showEditConfig = true;
},
},
mounted: function () {
//this.load();
}
})
</script>
</body>
</html>
组件1
<template id="edit-config">
<div>
<el-row style="padding: 10px;">
<el-form size="mini" status-icon label-width="0px">
<el-form-item label="">
<el-input v-model.trim="$root.editConfigMsg.type" disabled></el-input>
</el-form-item>
<el-form-item label="">
<el-input v-model.trim="$root.editConfigMsg.keyStr" disabled></el-input>
</el-form-item>
<el-form-item label="">
<el-input v-model.trim="$root.editConfigMsg.remark"></el-input>
</el-form-item>
<el-form-item label="">
<el-input v-if="$root.editType=='string'||$root.editType=='json'"
type="textarea"
:autosize="{ minRows: 2, maxRows: 10}"
v-model.trim="$root.editConfigMsg.valueStr"></el-input>
<el-input-number v-if="$root.editType=='number'||$root.editType=='number'"
style="width: 100%"
v-model.trim="$root.editConfigMsg.valueStr"></el-input-number>
<el-row v-if="$root.editType=='json'">
{{theType ($root.editConfigMsg.valueStr) }}
</el-row>
<el-switch v-if="$root.editType=='boolean'"
style="display: block"
v-model="$root.editConfigMsg.valueStr"
active-color="#13ce66"
inactive-color="#ff4949"
active-value="true"
inactive-value="false"
active-text="开启"
inactive-text="关闭">
</el-switch>
<el-row v-if="$root.editType=='array'">
<draggable v-model="arr"
chosen-class="chosen"
drag-class="drag"
ghost-class="ghost"
force-fallback="true"
animation="100"
group="mm">
<el-tag style="margin: 5px 5px;"
:key="tag"
v-for="tag in arr"
closable
effect="plain"
:disable-transitions="false"
@close="handleClose(tag)">
{{tag}}
</el-tag>
</draggable>
<el-input
class="input-new-tag"
v-if="inputVisible"
v-model="inputValue"
ref="saveTagInput"
size="small"
@keyup.enter.native="handleInputConfirm"
@blur="handleInputConfirm">
</el-input>
<el-button v-else class="button-new-tag" size="small" @click="showInput">+ New Tag</el-button>
<!-- <el-tag v-for="ai in arr">{{ai}}</el-tag>-->
</el-row>
</el-form-item>
<el-form-item label="">
<el-button type="danger"
@click="saveEditConfig" style="width: 100%">保存
</el-button>
</el-form-item>
</el-form>
</el-row>
</div>
</template>
<script>
Vue.component('edit-config', {
template: "#edit-config",
data: function () {
return {
arr: [],
obj: {},
inputVisible: false,
inputValue: ''
}
},
methods: {
saveEditConfig: function (config, fun) {
var root = this.$root;
if (root.editType == 'array') {
if (this.$root.editConfigMsg.valueStr.indexOf("[") != -1) {
root.editConfigMsg.valueStr = JSON.stringify(this.arr);
} else {
var str = "";
for (i in this.arr) {
if (i == 0) {
str += this.arr[i]
} else {
str += ("," + this.arr[i]);
}
}
root.editConfigMsg.valueStr = str;
}
}
if (root.editType == 'json') {
var ttype = theType(root.editConfigMsg.valueStr);
if (ttype != 'object' && ttype != 'array') {
zs_error(this, "非json格式或者array格式无法保存")
return;
}
}
zs_postFapi({
url: '../../api/config/update?_' + $.now(),
param: root.editConfigMsg,
success: function (data) {
zs_info(root, data)
root.showEditConfig = false;
root.loadConfig()
}
});
},
handleClose(tag) {
this.arr.splice(this.arr.indexOf(tag), 1);
},
showInput() {
this.inputVisible = true;
this.$nextTick(_ => {
this.$refs.saveTagInput.$refs.input.focus();
});
},
handleInputConfirm() {
let inputValue = this.inputValue;
if (inputValue) {
this.arr.push(inputValue);
}
this.inputVisible = false;
this.inputValue = '';
}
},
mounted: function () {
if (this.$root.editType == 'array') {
if (this.$root.editConfigMsg.valueStr.indexOf("[") != -1) {
this.arr = JSON.parse(this.$root.editConfigMsg.valueStr);
} else {
this.arr = this.$root.editConfigMsg.valueStr.split(",")
}
}
if (this.$root.editType == 'json') {
this.obj = JSON.parse(this.$root.editConfigMsg.valueStr);
}
}
})
</script>
</body>
</html>
组件2
<template id="api-config">
<div>
<el-select size="small" v-model="type" filterable clearable
style="width: 300px;margin: 30px ;" @change="showA">
<el-option :label="t"
v-for="t in types"
:value="t"></el-option>
</el-select>
<el-table stripe :data="table.data" border style="width: 100%"
highlight-current-row size="mini" @selection-change="selectCases">
<!-- <el-table-column type="index" width="40"></el-table-column>-->
<el-table-column label="添加" width="100px">
<template slot-scope="scope">
<el-button type="text" @click="addTo(scope.row.type +':'+scope.row.keyStr)"
v-if="$root.selectCol.configIdArr.indexOf(scope.row.type+':'+scope.row.keyStr)==-1">添加
</el-button>
</template>
</el-table-column>
<el-table-column :label="col.title" :width="col.width" :prop="col.field"
v-for="col in table.col">
</el-table-column>
</el-table>
</div>
</template>
<script>
Vue.component('api-config', {
template: "#api-config",
data: function () {
return {
param: {//搜索参数
type: null
},
types: [],
type: null,
table: {//表格数据
"col": [
{field: "type", title: "分类", width: "200px"},
{field: "keyStr", title: "key", width: "250px"},
{field: "valueStr", title: "value", width: ""},
{field: "remark", title: "备注", width: "300px"},
],
"pagesizes": [1, 10, 20, 30, 100],//size选择器
"pagesize ": 10,
"sync": 1,//当前页数
"total": 0,
"data": [],//不分类型部分数据
},
selectMsg: {},//所有key的选项项
}
},
methods: {
selectCases: function (selects) {
this.table.selects = selects;
},
showA: function () {
var ss = [];
for (i in this.allRow) {
if (this.allRow[i].type == this.type || this.type == null || this.type == '')
ss.push(this.allRow[i]);
}
this.table.data = ss;
},
addTo: function (key) {
var col = this.$root.selectCol;
console.log(col)
var th = this;
if (col.configIdArr.indexOf(key) == -1)
col.configIdArr.push(key);
col.configIds = JSON.stringify(col.configIdArr);
zs_post({
url: '../../auto/config/save?_' + $.now(),
param: {
typeKey: key
},
success: function (r) {
}
})
zs_postA(th, {
url: '../../autoConfig/type/update?_' + $.now(),
param: col,
success: function (r) {
th.$root.loadType();
}
})
},
load: function () {//查询
var th = this;
th.types = [];
zs_postFapi({
url: '../../api/config/findByKeys?_' + $.now(),
param: th.param,
success: function (r) {
// console.log(r)
if (r.code != null && r.code != 0) {
zs_error(th, "查询异常");
return;
}
var rows = r;
if (rows.length == 0) {
return;
}
th.allRow = rows;
for (i in th.allRow) {
th.table.data.push(th.allRow[i]);
}
for (i in rows) {
if (th.types.indexOf(rows[i].type) == -1)
th.types.push(rows[i].type)
}
}
})
},
},
mounted: function () {
this.load();//加载所有参数列表
}
})
</script>
</body>
</html>