jsonarray 的put功能失效_sortblejs 將 excel 表格透視部分功能搬運到 web 上面(最初版本)...
技術標籤:jsonarray 的put功能失效
這個功能其實嘗試了很多周了,磕磕絆絆的,知道昨天 12-27 週五才完成,為什麼呢,因為之前的需求,設計稿都不是很明確,之前寫的例子好像報廢了,為什麼呢?接下來我們看看碰到什麼樣的問題,如果還對 sortablejs 不是很瞭解的話,可以看我之前的文章
子由風:sortable.js 的研究zhuanlan.zhihu.com- sortablejs 的拖拽 new Sortble(el, {}),只能是在原本的區域中,超出這個區域貌似 onMove 事件會失效,沒法獲取到 evt.originalEvent.clientX, evt.originalEvent.clientY
2. sortblejs 如果某個區域一旦設定了 pull="clone", 這個表示可以 clone 你當前拖拽會導致事件失效,按照圖上所示的話,如果將紅色方框的內容統一佈局在 一個 li 標籤的話,一旦拖動 clone 某一項,會導致 checkbox 的change 事件失效,也不知道什麼原因,找不到解決方法,只能重新改掉佈局方式,讓 checkbox 單獨成為一列,使用 flex 佈局方式,讓左右成為一行,這樣就能解決拖動 clone問題
<div class="create-dialysis-table-columns-content"> <ul class="create-dialysis-table-columns-ul" data-id="columns"> <li :data-alias="item.name" :data-field="item.field" :data-id="item.id" :data-type="item.type" :data-index="index" :key="index" v-for="(item, index) in columns" > <div class="left"> <i class="drag-icon"></i> <span class="column">{{ item.name }}</span> </div> </li> </ul> <ul class="create-dialysis-table-columns-checkbox" data-id="checkbox"> <li :data-alias="item.name" :data-field="item.field" :data-id="item.id" :data-type="item.type" :data-index="index" :class="`columns-${item.id}`" :key="index" v-for="(item, index) in columns" > <el-checkbox :key="index" @change.native="columnsUlChange($event, item, index)"></el-checkbox> </li> </ul> </div>
4. 之前 demo 的是採用直接拖拽放置的方式,是直接把 DOM 放進某個區域的,現在由於設計稿變化,我們無法採用之前 demo 中的例子,只能重新思考採用別的方式,經過我們的討論,以及我在實施的時候,發現我們必須把資料都定義在 data- 屬性裡面,採用假的拖動方式,然後獲取到 data- 屬性資料,存進陣列,再進行渲染
<li :data-alias="item.name" :data-field="item.field" :data-id="item.id" :data-type="item.type" :key="index" v-for="(item, index) in rows" > <div class="left"> <i class="drag-icon"></i> <span class="column">{{ item.name }}</span> </div> </li>
5. 之前的 demo 中在拖拽項溢位某個區域的時候,是啟動了 removeSpill 屬性,發現也是有很多問題,這個屬性還必須結合 onSpill 方法,但是實在是太不靈活了,一旦 removeSpill 被禁用這個 onSpill 方法就沒法使用了,所以經過我的思考,我只能使用脫離原本的區域,left,top,right,bottom,
dragColumnsUl() {
// 這裡的 this 指向 vue 例項
const _this = this
const oColumnsUl = document.querySelector(
'ul.create-dialysis-table-columns-ul',
) // 好像這一步也是非同步的
const oRowsContent = document.querySelector(
'.create-dialysis-table-row-content',
)
const oValuesContent = document.querySelector(
'.create-dialysis-table-value-content',
)
const sortable = new Sortable(oColumnsUl, {
animation: 150,
group: {
name: 'shared',
pull: 'clone',
put: false,
},
sort: false,
onStart: function(evt) {
// 這裡的 this 指向 sortable 例項
this.start = {
columnsObj: {
top: evt.item.offsetTop,
right:
evt.item.offsetLeft +
evt.item.parentNode.parentNode.offsetWidth,
bottom:
evt.item.offsetTop +
evt.item.parentNode.parentNode.offsetHeight,
left: evt.item.offsetLeft,
},
rowsObj: {
top: oRowsContent.offsetTop,
left: oRowsContent.offsetLeft,
right: oRowsContent.offsetWidth + oRowsContent.offsetLeft,
bottom: oRowsContent.offsetHeight + oRowsContent.offsetTop,
},
valuesObj: {
top: oValuesContent.offsetTop,
left: oValuesContent.offsetLeft,
right: oValuesContent.offsetWidth + oValuesContent.offsetLeft,
bottom: oValuesContent.offsetHeight + oValuesContent.offsetTop,
},
}
console.log('this.start===>', this.start)
},
onMove: function(evt) {
console.log(
'evt.item',
evt.originalEvent.clientX,
evt.originalEvent.clientY,
)
},
onEnd: function(evt) {
// 這裡的 this 物件指向 sortable 物件
const from = evt.from
const to = evt.to
const item = evt.item
const oldIndex = evt.oldIndex
this.end = {
top: item.offsetTop,
left: item.offsetLeft,
right: item.offsetWidth + item.offsetLeft,
bottom: item.offsetHeight + item.offsetTop,
}
// 處理拖拽進入 row 行分類
if (
this.end.top > this.start.rowsObj.top &&
this.end.top < this.start.rowsObj.bottom &&
this.end.top < this.start.valuesObj.top
) {
to.removeChild(item)
_this.rows.map((item, index) => {
if (item.id === evt.item.dataset.id) {
_this.rows.splice(index, 1)
}
})
_this.rows.push({
name: item.dataset.alias,
field: item.dataset.field,
type: item.dataset.type,
id: item.dataset.id,
})
// 設定 checkbox 選中
_this.setDomChecked(evt.item.dataset.id, true)
console.log('evt.item.dataset====>', evt.item.dataset, _this.rows)
console.log('進入行分組')
} else {
console.log('沒有進入行分組')
}
// 處理拖拽進入 value 值分類
if (
this.end.top > this.start.valuesObj.top &&
this.end.top < this.start.valuesObj.bottom
) {
to.removeChild(item)
_this.values.map((item, index) => {
if (item.id === evt.item.dataset.id) {
_this.values.splice(index, 1)
}
})
_this.values.push({
name: item.dataset.alias,
field: item.dataset.field,
type: item.dataset.type,
id: item.dataset.id,
})
_this.setDomChecked(evt.item.dataset.id, true)
console.log('進入值分組')
} else {
console.log('沒有進入值分組')
}
console.log('this.end===>', this.end)
},
})
console.log('oColumnsUl==>', oColumnsUl, sortable)
},
6. 想要讓 element-ui 中 el-checkbox 元件觸發原生事件,獲取 event 事件物件,需要給 change事件加上 .native,否則無法獲取到 原生的 event 事件物件
<el-checkbox :key="index" @change.native="columnsUlChange($event, item, index)"></el-checkbox>
7. 拖拽超出區域的處理步驟,第一步是超出原有的區域,沒進入別的可拖拽區域,第二是進入了其他可拖拽區域,
dragRowsUl() {
// 這裡的 this 指向 vue 例項
const _this = this
const oRowsUl = document.querySelector('ul.create-dialysis-table-row-ul') // 好像這一步也是非同步的
const oRowsContent = document.querySelector('.create-dialysis-table-row-content')
const sortable = new Sortable(oRowsUl, {
animation: 150,
group: {
name: 'shared',
put: true,
},
sort: true,
onStart: function(evt) {
// 這裡的 this 指向 sortable 例項
this.start = {
rowsObj: {
top: oRowsContent.offsetTop,
left: oRowsContent.offsetLeft,
right: oRowsContent.offsetWidth + oRowsContent.offsetLeft,
bottom: oRowsContent.offsetHeight + oRowsContent.offsetTop,
},
}
console.log("this.start===>", this.start)
},
onEnd: function(evt) {
// 這裡的 this 物件指向 sortable 物件
console.log("evt.from, evt.to", evt.from, evt.to)
this.end = {
x: evt.originalEvent.clientX,
y: evt.originalEvent.clientY,
}
if (
evt.to.dataset.id === evt.from.dataset.id &&
(this.end.x < this.start.rowsObj.left ||
this.end.x > this.start.rowsObj.right ||
(this.end.y < this.start.rowsObj.top || this.end.y > this.start.rowsObj.bottom))
) {
evt.to.removeChild(evt.item)
_this.rows.map((item, index) => {
if(item.id === evt.item.dataset.id) {
_this.rows.splice(index, 1)
}
})
// 設定 checkbox
_this.setDomChecked(evt.item.dataset.id, false)
console.log("true")
}
// 處理 rows 行分類 to values 值分類
if(evt.to.dataset.id === 'values' && evt.from.dataset.id === 'rows') {
// 先移除當前拖動項
evt.to.removeChild(evt.item)
// 遍歷刪除重複項
_this.values.map((item, index)=>{
if(item.id === evt.item.dataset.id) {
_this.values.splice(index, 1)
}
})
// 遍歷刪除重複項
_this.rows.map((item, index)=>{
if(item.id === evt.item.dataset.id) {
_this.rows.splice(index, 1)
}
})
// 再添加當前項
_this.values.push({
name: evt.item.dataset.alias,
field: evt.item.dataset.field,
type: evt.item.dataset.type,
id: evt.item.dataset.id,
})
// 設定 checkbox
_this.setDomChecked(evt.item.dataset.id, true)
}
// 處理 values 值分類 to rows 行分類
if(evt.to.dataset.id === 'rows' && evt.from.dataset.id === 'values') {
evt.to.removeChild(evt.item)
_this.rows.map((item, index)=>{
if(item.id === evt.item.dataset.id) {
_this.rows.splice(index, 1)
}
})
_this.values.map((item, index)=>{
if(item.id === evt.item.dataset.id) {
_this.values.splice(index, 1)
}
})
_this.rows.push({
name: evt.item.dataset.alias,
field: evt.item.dataset.field,
type: evt.item.dataset.type,
id: evt.item.dataset.id,
})
_this.setDomChecked(evt.item.dataset.id, true)
}
console.log('this.end===>', this.end)
},
})
},
最終附上原本的程式碼,程式碼實在是太長了,應該還有狠毒地方可以優化,由於是昨天一天衝忙之中完成的,所以好多重複的程式碼塊,下週準備提取一下,然後再做其他功能模組,可以拿過去執行一下,如果沒有圖片檔案,就把相應的樣式給註釋掉就好了
<template>
<div class="opt-apartment-in-come-wrap">
<div class="tree-wrap">
<div class="tree-parent-wrap">
<div
:key="index"
@click="treeParentClick(item, index)"
class="tree-parent-content"
v-for="(item, index) in dataList"
>
<div class="tree-parent">
<div class="tree-parent-left">
<i
:class="index===dropDownIndex ? 'drop-down-icon-active drop-down-icon' : 'drop-down-icon'"
@click.stop="dropDown(index)"
v-show="item.show"
></i>
<i class="file-icon"></i>
<span class="tree-parent-text">{{item.title}}</span>
</div>
<div class="tree-parent-right">
<span class="date">{{item.date}}</span>
<span class="name">{{item.name}}</span>
</div>
</div>
<el-collapse-transition>
<div class="tree-child-wrap" v-if="index===dropDownIndex">
<div
@click.stop="treeChildClick(c,i)"
class="tree-child-content"
v-for="(c, i) in item.child"
>
<div class="tree-child">
<div class="tree-parent-left">
<i class="file-icon"></i>
<span class="tree-parent-text">{{c.title}}</span>
</div>
<div class="tree-parent-right">
<span class="date">{{c.date}}</span>
<span class="name">{{c.name}}</span>
</div>
</div>
</div>
</div>
</el-collapse-transition>
</div>
</div>
</div>
<div class="dialysis-table-wrap">
<div class="chart-table">
<div class="chart-table-tab">
<span
:class="index===curIndex ? 'active' : ''"
:key="index"
@click="tabClick(index)"
class="chart-table-text"
v-for="(item, index) in tabs"
>{{ item }}</span>
</div>
<div class="chart-table-content" v-if="!showTabContent">chart</div>
<div class="chart-table-content" v-if="showTabContent">table</div>
</div>
<div class="create-dialysis-table">
<div class="create-dialysis-table-title">建立資料透析表</div>
<div class="create-dialysis-table-content">
<div class="create-dialysis-table-tab">
<span
:class="index === columnFilterIndex ? 'columns' : ''"
:key="index"
@click="columnFilterClick(index)"
v-for="(item, index) in columnFilter"
>{{ item }}</span>
</div>
<!-- 列分類 -->
<div class="create-dialysis-table-columns">
<div class="create-dialysis-table-columns-select">
銷售
<!-- 有可能放置一個下拉框 -->
</div>
<div class="create-dialysis-table-columns-content">
<ul class="create-dialysis-table-columns-ul" data-id="columns">
<li
:data-alias="item.name"
:data-field="item.field"
:data-id="item.id"
:data-type="item.type"
:data-index="index"
:key="index"
v-for="(item, index) in columns"
>
<div class="left">
<i class="drag-icon"></i>
<span class="column">{{ item.name }}</span>
</div>
</li>
</ul>
<ul class="create-dialysis-table-columns-checkbox" data-id="checkbox">
<li
:data-alias="item.name"
:data-field="item.field"
:data-id="item.id"
:data-type="item.type"
:data-index="index"
:class="`columns-${item.id}`"
:key="index"
v-for="(item, index) in columns"
>
<el-checkbox :key="index" @change.native="columnsUlChange($event, item, index)"></el-checkbox>
</li>
</ul>
</div>
</div>
<!-- 行分類 -->
<div class="create-dialysis-table-row">
<div class="create-dialysis-table-row-title">行分組</div>
<div class="create-dialysis-table-row-content">
<ul class="create-dialysis-table-row-ul" data-id="rows">
<li
:data-alias="item.name"
:data-field="item.field"
:data-id="item.id"
:data-type="item.type"
:key="index"
v-for="(item, index) in rows"
>
<div class="left">
<i class="drag-icon"></i>
<span class="column">{{ item.name }}</span>
</div>
</li>
</ul>
</div>
</div>
<!-- 值分類 -->
<div class="create-dialysis-table-value">
<div class="create-dialysis-table-value-title">值</div>
<div class="create-dialysis-table-value-content">
<ul class="create-dialysis-table-value-ul" data-id="values">
<li
:data-alias="item.name"
:data-field="item.field"
:data-id="item.id"
:data-type="item.type"
:key="index"
v-for="(item, index) in values"
>
<div class="left">
<i class="drag-icon"></i>
<!-- 給下劃線可以給加個 div -->
<div class="select">
<fy-select
:options="defaultArr"
:selectunderline="true"
:width="'100px'"
label-key="keyName"
value-key="keyValue"
></fy-select>
</div>
<span class="column">{{ item.name }}</span>
</div>
</li>
</ul>
</div>
</div>
<!-- 報表名字 -->
<div class="create-dialysis-table-name">
<div class="create-dialysis-table-name-title">報表名稱</div>
<div class="create-dialysis-table-name-input">
<fy-input v-model="tableName"></fy-input>
</div>
</div>
<!-- 按鈕組 -->
<div class="create-dialysis-table-button">
<fy-ripple-large-button value="取消"></fy-ripple-large-button>
<fy-ripple-button value="儲存"></fy-ripple-button>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import Sortable from 'sortablejs'
export default {
name: 'optApartmentInCome',
data() {
return {
tabs: ['圖表', '列表'],
columnFilter: ['列', '篩選'],
curIndex: 1, // 預設選中列表
showTabContent: true, // 預設列表顯示
dropDownIndex: -1,
showDropDown: false,
columnFilterIndex: 0, // 預設選中列 columns
showColumnFilter: true, // 預設列顯示
dataList: [
{
title: '操作部門收入成本一覽表',
date: '2019-12-12 12:12',
name: 'Administrators',
show: true,
child: [
{
title: '操作部門收入成本一覽表1',
date: '2019-12-12 12:12',
name: 'Administrators1',
},
{
title: '操作部門收入成本一覽表2',
date: '2019-12-13 12:12',
name: 'Administrators2',
},
{
title: '操作部門收入成本一覽表3',
date: '2019-12-14 12:12',
name: 'Administrators2',
},
{
title: '操作部門收入成本一覽表4',
date: '2019-12-15 12:12',
name: 'Administrators2',
},
],
},
{
title: '操作部門收入成本一覽表',
date: '2019-12-12 12:12',
name: 'Administrators',
show: true,
child: [
{
title: '操作部門收入成本一覽表1',
date: '2019-12-12 12:12',
name: 'Administrators1',
},
{
title: '操作部門收入成本一覽表2',
date: '2019-12-13 12:12',
name: 'Administrators2',
},
{
title: '操作部門收入成本一覽表3',
date: '2019-12-14 12:12',
name: 'Administrators2',
},
{
title: '操作部門收入成本一覽表4',
date: '2019-12-15 12:12',
name: 'Administrators2',
},
],
},
{
title: '操作部門收入成本一覽表',
date: '2019-12-12 12:12',
name: 'Administrators',
show: false,
child: [],
},
],
defaultArr: [
{
keyName: '計數項',
keyValue: 'count',
},
{
keyName: '求和項',
keyValue: 'sum',
},
{
keyName: '乘積項',
keyValue: 'product',
},
{
keyName: '最大項',
keyValue: 'max',
},
{
keyName: '最小項',
keyValue: 'min',
},
],
columns: [
{
name: '訂購時間',
field: 'orderTime',
type: 'date',
id: 1,
},
{
name: '訂單號',
field: 'orderNum',
type: 'string',
id: 2,
},
{
name: '訂單人數',
field: 'orderPNum',
type: 'number',
id: 3,
},
{
name: '訂單應收',
field: 'ordePricd',
type: 'number',
id: 4,
},
{
name: '銷售部門',
field: 'salesPart',
type: 'string',
id: 5,
},
{
name: '訂單列表',
field: 'orderList',
type: 'string',
id: 6,
},
],
rows: [],
values: [],
tableName: '操作部門收入成本一覽表',
elCheckboxIndex: -1,
value: '',
}
},
methods: {
tabClick(index) {
this.curIndex = index
if (index === 1) {
this.showTabContent = true
} else {
this.showTabContent = false
}
},
dropDown(index) {
if (this.dropDownIndex === index) {
this.dropDownIndex = -1
} else {
this.dropDownIndex = index
}
this.showDropDown = !this.showDropDown
},
treeChildClick(c, i) {
console.log('c==>', c, 'i===>', i)
},
treeParentClick(item, index) {
console.log('item===>', item, 'index===>', index)
},
columnFilterClick(index) {
this.columnFilterIndex = index
console.log('index===>', index)
},
dragColumnsUl() {
// 這裡的 this 指向 vue 例項
const _this = this
const oColumnsUl = document.querySelector(
'ul.create-dialysis-table-columns-ul',
) // 好像這一步也是非同步的
const oRowsContent = document.querySelector(
'.create-dialysis-table-row-content',
)
const oValuesContent = document.querySelector(
'.create-dialysis-table-value-content',
)
const sortable = new Sortable(oColumnsUl, {
animation: 150,
group: {
name: 'shared',
pull: 'clone',
put: false,
},
sort: false,
onStart: function(evt) {
// 這裡的 this 指向 sortable 例項
this.start = {
columnsObj: {
top: evt.item.offsetTop,
right:
evt.item.offsetLeft +
evt.item.parentNode.parentNode.offsetWidth,
bottom:
evt.item.offsetTop +
evt.item.parentNode.parentNode.offsetHeight,
left: evt.item.offsetLeft,
},
rowsObj: {
top: oRowsContent.offsetTop,
left: oRowsContent.offsetLeft,
right: oRowsContent.offsetWidth + oRowsContent.offsetLeft,
bottom: oRowsContent.offsetHeight + oRowsContent.offsetTop,
},
valuesObj: {
top: oValuesContent.offsetTop,
left: oValuesContent.offsetLeft,
right: oValuesContent.offsetWidth + oValuesContent.offsetLeft,
bottom: oValuesContent.offsetHeight + oValuesContent.offsetTop,
},
}
console.log('this.start===>', this.start)
},
onMove: function(evt) {
console.log(
'evt.item',
evt.originalEvent.clientX,
evt.originalEvent.clientY,
)
},
onEnd: function(evt) {
// 這裡的 this 物件指向 sortable 物件
const from = evt.from
const to = evt.to
const item = evt.item
const oldIndex = evt.oldIndex
this.end = {
top: item.offsetTop,
left: item.offsetLeft,
right: item.offsetWidth + item.offsetLeft,
bottom: item.offsetHeight + item.offsetTop,
}
// 處理拖拽進入 row 行分類
if (
this.end.top > this.start.rowsObj.top &&
this.end.top < this.start.rowsObj.bottom &&
this.end.top < this.start.valuesObj.top
) {
to.removeChild(item)
_this.rows.map((item, index) => {
if (item.id === evt.item.dataset.id) {
_this.rows.splice(index, 1)
}
})
_this.rows.push({
name: item.dataset.alias,
field: item.dataset.field,
type: item.dataset.type,
id: item.dataset.id,
})
// 設定 checkbox 選中
_this.setDomChecked(evt.item.dataset.id, true)
console.log('evt.item.dataset====>', evt.item.dataset, _this.rows)
console.log('進入行分組')
} else {
console.log('沒有進入行分組')
}
// 處理拖拽進入 value 值分類
if (
this.end.top > this.start.valuesObj.top &&
this.end.top < this.start.valuesObj.bottom
) {
to.removeChild(item)
_this.values.map((item, index) => {
if (item.id === evt.item.dataset.id) {
_this.values.splice(index, 1)
}
})
_this.values.push({
name: item.dataset.alias,
field: item.dataset.field,
type: item.dataset.type,
id: item.dataset.id,
})
_this.setDomChecked(evt.item.dataset.id, true)
console.log('進入值分組')
} else {
console.log('沒有進入值分組')
}
console.log('this.end===>', this.end)
},
})
console.log('oColumnsUl==>', oColumnsUl, sortable)
},
dragRowsUl() {
// 這裡的 this 指向 vue 例項
const _this = this
const oRowsUl = document.querySelector('ul.create-dialysis-table-row-ul') // 好像這一步也是非同步的
const oRowsContent = document.querySelector('.create-dialysis-table-row-content')
const sortable = new Sortable(oRowsUl, {
animation: 150,
group: {
name: 'shared',
put: true,
},
sort: true,
onStart: function(evt) {
// 這裡的 this 指向 sortable 例項
this.start = {
rowsObj: {
top: oRowsContent.offsetTop,
left: oRowsContent.offsetLeft,
right: oRowsContent.offsetWidth + oRowsContent.offsetLeft,
bottom: oRowsContent.offsetHeight + oRowsContent.offsetTop,
},
}
console.log("this.start===>", this.start)
},
onEnd: function(evt) {
// 這裡的 this 物件指向 sortable 物件
console.log("evt.from, evt.to", evt.from, evt.to)
this.end = {
x: evt.originalEvent.clientX,
y: evt.originalEvent.clientY,
}
if (
evt.to.dataset.id === evt.from.dataset.id &&
(this.end.x < this.start.rowsObj.left ||
this.end.x > this.start.rowsObj.right ||
(this.end.y < this.start.rowsObj.top || this.end.y > this.start.rowsObj.bottom))
) {
evt.to.removeChild(evt.item)
_this.rows.map((item, index) => {
if(item.id === evt.item.dataset.id) {
_this.rows.splice(index, 1)
}
})
// 設定 checkbox
_this.setDomChecked(evt.item.dataset.id, false)
console.log("true")
}
// 處理 rows 行分類 to values 值分類
if(evt.to.dataset.id === 'values' && evt.from.dataset.id === 'rows') {
// 先移除當前拖動項
evt.to.removeChild(evt.item)
// 遍歷刪除重複項
_this.values.map((item, index)=>{
if(item.id === evt.item.dataset.id) {
_this.values.splice(index, 1)
}
})
// 遍歷刪除重複項
_this.rows.map((item, index)=>{
if(item.id === evt.item.dataset.id) {
_this.rows.splice(index, 1)
}
})
// 再添加當前項
_this.values.push({
name: evt.item.dataset.alias,
field: evt.item.dataset.field,
type: evt.item.dataset.type,
id: evt.item.dataset.id,
})
// 設定 checkbox
_this.setDomChecked(evt.item.dataset.id, true)
}
// 處理 values 值分類 to rows 行分類
if(evt.to.dataset.id === 'rows' && evt.from.dataset.id === 'values') {
evt.to.removeChild(evt.item)
_this.rows.map((item, index)=>{
if(item.id === evt.item.dataset.id) {
_this.rows.splice(index, 1)
}
})
_this.values.map((item, index)=>{
if(item.id === evt.item.dataset.id) {
_this.values.splice(index, 1)
}
})
_this.rows.push({
name: evt.item.dataset.alias,
field: evt.item.dataset.field,
type: evt.item.dataset.type,
id: evt.item.dataset.id,
})
_this.setDomChecked(evt.item.dataset.id, true)
}
console.log('this.end===>', this.end)
},
})
},
dragValuesUl() {
// 這裡的 this 指向 vue 例項
const _this = this
const oValuesUl = document.querySelector(
'ul.create-dialysis-table-value-ul',
) // 好像這一步也是非同步的
const oValuesContent = document.querySelector('.create-dialysis-table-value-content')
const sortable = new Sortable(oValuesUl, {
animation: 150,
group: {
name: 'shared',
put: true,
},
sort: true,
onStart: function(evt) {
// 這裡的 this 指向 sortable 例項
// 儲存邊界值 top, left, right, bottom
this.start = {
valuesObj: {
top: oValuesContent.offsetTop,
left: oValuesContent.offsetLeft,
right: oValuesContent.offsetWidth + oValuesContent.offsetLeft,
bottom: oValuesContent.offsetHeight + oValuesContent.offsetTop,
},
}
console.log("this.start===>", this.start)
},
onEnd: function(evt) {
// 這裡的 this 物件指向 sortable 物件
console.log("evt.from, evt.to", evt.from, evt.to)
this.end = {
x: evt.originalEvent.clientX,
y: evt.originalEvent.clientY,
}
// 溢位邊界的時候,刪除資料,同時設定 checkbox
if (
evt.to.dataset.id === evt.from.dataset.id &&
(this.end.x < this.start.valuesObj.left ||
this.end.x > this.start.valuesObj.right ||
(this.end.y < this.start.valuesObj.top || this.end.y > this.start.valuesObj.bottom))
) {
evt.to.removeChild(evt.item)
_this.values.map((item, index) => {
if(item.id === evt.item.dataset.id) {
_this.values.splice(index, 1)
}
})
// 設定 checkbox
_this.setDomChecked(evt.item.dataset.id, false)
console.log("true")
}
// 處理 rows 行分類 to values 值分類
if(evt.to.dataset.id === 'values' && evt.from.dataset.id === 'rows') {
// 先移除 evt.item
evt.to.removeChild(evt.item)
// 刪除當前移動項對應的陣列元素(主要是去除重複項)
_this.values.map((item, index)=>{
if(item.id === evt.item.dataset.id) {
_this.values.splice(index, 1)
}
})
// 刪除當前移動項對應的陣列元素(主要是去除重複項)
_this.rows.map((item, index)=>{
if(item.id === evt.item.dataset.id) {
_this.rows.splice(index, 1)
}
})
// 再新增資料
_this.values.push({
name: evt.item.dataset.alias,
field: evt.item.dataset.field,
type: evt.item.dataset.type,
id: evt.item.dataset.id,
})
// 設定 checkbox
_this.setDomChecked(evt.item.dataset.id, true)
}
// 處理 values 值分類 to rows 行分類
if(evt.to.dataset.id === 'rows' && evt.from.dataset.id === 'values') {
evt.to.removeChild(evt.item)
_this.rows.map((item, index)=>{
if(item.id === evt.item.dataset.id) {
_this.rows.splice(index, 1)
}
})
_this.values.map((item, index)=>{
if(item.id === evt.item.dataset.id) {
_this.values.splice(index, 1)
}
})
_this.rows.push({
name: evt.item.dataset.alias,
field: evt.item.dataset.field,
type: evt.item.dataset.type,
id: evt.item.dataset.id,
})
_this.setDomChecked(evt.item.dataset.id, true)
}
console.log('this.end===>', this.end)
},
})
},
columnsUlChange(e, item, index) {
// 1. 根據型別判斷放置再哪個區域
if(e.currentTarget.classList.contains("is-checked")) {
switch(item.type) {
case 'date':
this.values.map((v, i)=>{
if(v.id === item.id) {
this.values.splice(i, 1)
}
})
this.$set(this.values, this.values.length, item)
// this.values.push(item)
break;
case 'string':
this.rows.map((v, i)=>{
if(v.id === item.id) {
this.rows.splice(i, 1)
}
})
this.$set(this.rows, this.rows.length, item)
// this.rows.push(item)
break;
case 'number':
this.values.map((v, i)=>{
if(v.id === item.id) {
this.values.splice(i, 1)
}
})
this.$set(this.values, this.values.length, item)
// this.values.push(item)
default:
break;
}
} else {
switch(item.type) {
case 'date':
this.values.map((v, i)=>{
if(v.id === item.id) {
this.values.splice(i, 1)
}
})
break;
case 'string':
this.rows.map((v, i)=>{
if(v.id === item.id) {
this.rows.splice(i, 1)
}
})
break;
case 'number':
this.values.map((v, i)=>{
if(v.id === item.id) {
this.values.splice(i, 1)
}
})
default:
break;
}
}
// 2. 如果已選中,則刪除
if(e.currentTarget.classList.contains("is-checked"))
//
console.log('e===>', e.currentTarget.children[0])
console.log('item===>', item)
// if(e.currentTarget.classList.contains("is-checked")) {
// e.currentTarget.classList.remove('is-checked')
// e.currentTarget.children[0].classList.remove('is-checked')
// console.log("true")
// } else {
// e.currentTarget.classList.add('is-checked')
// e.currentTarget.children[0].classList.add('is-checked')
// }
},
setChecked(from, oldIndex, bool) {
// 設定 checkbox 選中
if(bool) {
from.children[oldIndex].children[1].classList.add('is-checked')
from.children[oldIndex].children[1].children[0].classList.add(
'is-checked',
)
} else {
from.children[oldIndex].children[1].classList.remove('is-checked')
from.children[oldIndex].children[1].children[0].classList.remove(
'is-checked',
)
}
},
setDomChecked(id, bool) {
const oLi = document.querySelector(`.create-dialysis-table-columns-checkbox li.columns-${id}`)
console.log("oLi===>", oLi)
if(bool) {
oLi.children[0].classList.add('is-checked')
oLi.children[0].children[0].classList.add(
'is-checked',
)
} else {
oLi.children[0].classList.remove('is-checked')
oLi.children[0].children[0].classList.remove(
'is-checked',
)
}
}
},
mounted() {
this.dragColumnsUl()
this.dragRowsUl()
this.dragValuesUl()
},
}
</script>
<style lang="scss" scoped>
.opt-apartment-in-come-wrap {
position: relative;
display: flex;
box-sizing: border-box;
width: 100%;
height: 100vh;
overflow-x: scroll;
.tree-wrap {
box-sizing: border-box;
width: 654px;
height: 100vh;
margin-right: 20px;
border-radius: 8px;
background-color: $color-fff;
box-shadow: 0px 2px 10px 0px rgba(0, 0, 0, 0.08);
.tree-parent-wrap {
border-bottom: 1px solid rgba(230, 230, 230, 1);
.tree-parent-content {
border-bottom: 1px solid rgba(230, 230, 230, 1);
&:last-child {
border-bottom: none;
}
.tree-parent {
display: flex;
justify-content: space-between;
box-sizing: border-box;
width: 100%;
padding: 10px 40px 10px 20px;
cursor: pointer;
.tree-parent-left {
display: flex;
align-items: center;
min-height: 44px;
.drop-down-icon {
display: block;
width: 0;
height: 0;
margin-right: 8px;
border-bottom: 10px solid transparent;
border-top: 10px solid transparent;
border-left: 10px solid #666666;
border-radius: 10px;
}
.drop-down-icon-active {
transform: rotate(90deg);
-webkit-transform: rotate(90deg);
-moz-transform: rotate(90deg);
-ms-transform: rotate(90deg);
-o-transform: rotate(90deg);
}
.file-icon {
display: block;
width: 24px;
height: 24px;
margin-right: 8px;
background-image: url('[email protected]/dropDown/set.png');
background-repeat: no-repeat;
background-size: 100%;
}
.tree-parent-text {
font-size: 16px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: rgba(51, 51, 51, 1);
}
}
.tree-parent-right {
display: flex;
justify-content: space-between;
align-items: center;
min-width: 273px;
.date {
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: rgba(51, 51, 51, 1);
}
.name {
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: rgba(51, 51, 51, 1);
}
}
}
.tree-child-content {
width: 100%;
}
}
}
}
.dialysis-table-wrap {
display: flex;
width: calc(100% - 654px - 20px);
height: 100vh;
border-radius: 8px;
background-color: $color-fff;
box-shadow: 0px 2px 10px 0px rgba(0, 0, 0, 0.08);
.chart-table {
box-sizing: border-box;
width: calc(100% - 307px);
min-width: 852px;
height: 100%;
border-right: 1px solid rgba(230, 230, 230, 1);
border-top-left-radius: 8px;
border-bottom-left-radius: 8px;
background-color: bisque;
.chart-table-tab {
box-sizing: border-box;
width: 100%;
padding: 11px 0 11px 19px;
border-bottom: 1px solid rgba(230, 230, 230, 1);
font-size: 16px;
font-family: PingFangSC-Semibold, PingFang SC;
font-weight: 600;
color: rgba(102, 102, 102, 1);
.chart-table-text {
margin-right: 40px;
cursor: pointer;
&:last-child {
margin-right: 0;
}
&.active {
color: rgba(51, 51, 51, 1);
}
}
}
.chart-table-content {
width: 100%;
background-color: blueviolet;
}
}
.create-dialysis-table {
box-sizing: border-box;
width: 307px;
height: 100%;
border-top-right-radius: 8px;
border-bottom-right-radius: 8px;
.create-dialysis-table-title {
box-sizing: border-box;
padding: 11px 0 11px 20px;
border-bottom: 1px solid rgba(230, 230, 230, 1);
font-size: 16px;
font-family: PingFangSC-Semibold, PingFang SC;
font-weight: 600;
color: rgba(51, 51, 51, 1);
}
.create-dialysis-table-content {
box-sizing: border-box;
padding: 20px 32px;
.create-dialysis-table-tab {
span {
margin-right: 20px;
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: rgba(102, 102, 102, 1);
cursor: pointer;
&.columns {
font-weight: 600;
color: rgba(51, 51, 51, 1);
}
}
}
// 列分組
.create-dialysis-table-columns {
box-sizing: border-box;
height: 268px;
margin-top: 8px;
padding: 12px 12px 0 12px;
border-radius: 2px;
border: 1px dashed rgba(204, 204, 204, 1);
overflow-y: scroll;
.create-dialysis-table-columns-select {
width: 100%;
height: 32px;
line-height: 32px;
border-bottom: 1px solid rgba(220, 220, 220, 1);
}
.create-dialysis-table-columns-content {
display: flex;
flex-flow: row nowrap;
align-items: center;
justify-content: space-between;
margin-top: 12px;
ul {
li {
height: 40px;
display: flex;
flex-flow: row nowrap;
align-items: center;
justify-content: space-between;
.left {
display: flex;
align-items: center;
.drag-icon {
width: 24px;
height: 24px;
background-image: url('[email protected]/dropDown/ic_drop-down.png');
background-size: 100%;
background-repeat: no-repeat;
}
}
}
}
}
}
// 行分組
.create-dialysis-table-row {
margin-top: 20px;
.create-dialysis-table-row-title {
font-size: 14px;
font-family: PingFangSC-Semibold, PingFang SC;
font-weight: 600;
color: rgba(51, 51, 51, 1);
}
.create-dialysis-table-row-content {
height: 100px;
padding: 12px;
margin-top: 8px;
border: 1px dashed rgba(204, 204, 204, 1);
overflow-y: scroll;
}
}
// 值分組
.create-dialysis-table-value {
margin-top: 20px;
.create-dialysis-table-value-title {
font-size: 14px;
font-family: PingFangSC-Semibold, PingFang SC;
font-weight: 600;
color: rgba(51, 51, 51, 1);
}
.create-dialysis-table-value-content {
height: 100px;
padding: 12px;
margin-top: 8px;
border: 1px dashed rgba(204, 204, 204, 1);
overflow-y: scroll;
.create-dialysis-table-value-ul {
li {
div.left {
.select {
border-bottom: 1px solid rgba(204, 204, 204, 1);
}
::v-deep.el-input__suffix-inner .el-input__icon::before {
position: absolute;
top: 19px;
}
}
}
}
}
}
// 報表名字
.create-dialysis-table-name {
margin-top: 20px;
.create-dialysis-table-name-title {
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: rgba(102, 102, 102, 1);
}
.create-dialysis-table-name-input {
border-bottom: 1px solid rgba(230, 230, 230, 1);
}
}
// 按鈕組
.create-dialysis-table-button {
position: absolute;
right: 0;
bottom: 0px;
}
}
}
}
}
.tree-child {
display: flex;
justify-content: space-between;
box-sizing: border-box;
width: 100%;
padding: 10px 40px 10px 20px;
border-top: 1px solid rgba(230, 230, 230, 1);
cursor: pointer;
.tree-parent-left {
box-sizing: border-box;
display: flex;
align-items: center;
min-height: 44px;
padding-left: 78px;
.file-icon {
display: block;
width: 24px;
height: 24px;
margin-right: 8px;
background-image: url('[email protected]/dropDown/box.png');
background-repeat: no-repeat;
background-size: 100%;
}
.tree-parent-text {
font-size: 16px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: rgba(51, 51, 51, 1);
}
}
.tree-parent-right {
display: flex;
justify-content: space-between;
align-items: center;
min-width: 273px;
.date {
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: rgba(51, 51, 51, 1);
}
.name {
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: rgba(51, 51, 51, 1);
}
}
}
ul {
li {
height: 40px;
display: flex;
flex-flow: row nowrap;
justify-items: center;
justify-content: space-between;
.left {
display: flex;
align-items: center;
.drag-icon {
width: 24px;
height: 24px;
background-image: url('[email protected]/dropDown/ic_drop-down.png');
background-size: 100%;
background-repeat: no-repeat;
}
}
}
}
</style>
最終效果