<template>
<div class="editBox">
<div class="left_tab" id="thescroll_tab">
<div
v-for="tab in thetabmodule"
:key="tab.thename"
:class="{ active: activeName === tab.thename }"
class="tab-item"
@click="handleTabClick(tab)"
:data-tab="tab"
:id="tab.thename+'left'"
>
<div class="theheaderclass" :data-tab="tab">
<div class="left_text">{{ tab.label }}</div>
<div class="number_text">{{ "(" + tab.datelength + ")" }}</div>
</div>
</div>
</div>
<div ref="rightBox" class="edit-cards" id="thescroll_container" @scroll="bindScrollEvent">
<div
v-if="
currentArray[0].data.length ||
collectArray[0].data.length ||
thetabmodule.length
"
>
<div>
<div v-for="tab in currentArray" :key="tab.thename" id="currentuse">
<div
class="scroll_title"
:class="{ activescrollTitle: activeName === tab.thename }"
>
<div
class="smallbox"
:class="{ activebox: activeName === tab.thename }"
></div>
{{ tab.label }}
</div>
<div class="themodules_container">
<SmallModule
v-for="(item, index) in tab.data"
:key="index"
:moduleItem="item"
@searchContent="searchContent"
>
<!-- <SmallModule v-for="(item, index) in tab.data" :key="index" :moduleItem="item"> -->
<template v-slot:collect>
<div class="right_stare" v-if="item.iscollect == 1">
<i class="el-icon-star-on"></i>
</div>
</template>
<template v-slot:icon>
<img v-if="item.iconUrl" :src="item.iconUrl" alt="" />
<img v-else :src="theimage6" alt="" />
</template>
<template v-slot:theheader>
<!-- <div class="elliplice_1" v-if="item.type == 1">{{ item.name }}</div>
<div class="elliplice_1" v-else>{{ item.customName }}</div> -->
<div
class="elliplice_1"
v-if="item.type == 1"
v-html="item.name"
></div>
<div
class="elliplice_1"
v-else
v-html="item.customName"
></div>
</template>
</SmallModule>
</div>
</div>
</div>
<div>
<div v-for="tab in collectArray" :key="tab.thename" :id="tab.thename">
<div class="thelinkbutton">
<div
class="scroll_title"
:class="{ activescrollTitle: activeName === tab.thename }"
>
<div
class="smallbox"
:class="{ activebox: activeName === tab.thename }"
></div>
{{ tab.label }}
</div>
<div class="linkbutton" @click="addlink">
<i class="el-icon-plus"></i>
<div class="linktext">{{ $t("addLink.addLinkBtn") }}</div>
</div>
<div class="linkTip">
<!-- <div class="linkTip_content"> -->
{{ $t("addLink.collectTip") }}
<!-- </div> -->
</div>
</div>
<transition-group class="themodules_container">
<div
v-for="(item, index) in tab.data"
:key="index"
:draggable="true"
@dragstart="dragstart(item)"
@dragenter="dragenter(item, $event)"
@dragend="getDragend(tab.data, 'customer', $event)"
>
<SmallModule :moduleItem="item" @searchContent="searchContent">
<template v-slot:collect>
<div class="right_stare" v-if="item.iscollect == 1">
<i class="el-icon-star-on"></i>
</div>
</template>
<template v-slot:icon>
<img v-if="item.iconUrl" :src="item.iconUrl" alt="" />
<img v-else :src="theimage6" alt="" />
</template>
<template v-slot:theheader>
<!-- <div class="elliplice_1" v-if="item.type == 1">{{ item.name }}</div>
<div class="elliplice_1" v-else>{{ item.customName }}</div> -->
<div
class="elliplice_1"
v-if="item.type == 1"
v-html="item.name"
></div>
<div
class="elliplice_1"
v-else
v-html="item.customName"
></div>
</template>
</SmallModule>
</div>
</transition-group>
</div>
</div>
<div v-for="tab in thetabmodule" :key="tab.thename" :id="tab.thename">
<div
class="scroll_title"
:class="{ activescrollTitle: activeName === tab.thename }"
>
<div
class="smallbox"
:class="{ activebox: activeName === tab.thename }"
></div>
{{ tab.label }}
</div>
<div class="themodules_container">
<SmallModule
v-for="(item, index) in tab.data"
:key="index"
:moduleItem="item"
@searchContent="searchContent"
>
<template v-slot:collect>
<div class="right_stare" v-if="item.iscollect == 1">
<i class="el-icon-star-on"></i>
</div>
</template>
<template v-slot:icon>
<img :src="item.iconUrl" alt="" />
</template>
<template v-slot:theheader>
<div class="elliplice_1" v-html="item.name"></div>
</template>
</SmallModule>
</div>
</div>
<div
class="bottom_text"
v-if="
!searchvalue &&
currentArray[0]?.data.length == firstcurrentList[0]?.data.length &&
collectArray[0]?.data.length == firstcollectList[0]?.data.length
"
>
{{ $t("addLink.tishiyu") }}
</div>
</div>
<div class="theempty" v-show="showImg">
<img src="@/assets/images/none.png" alt="" />
<div class="img_text">未找到相关应用</div>
</div>
</div>
<addLinkdialog
:centerDialogVisible="centerDialogVisible"
@closedialog="closedialog"
/>
</div>
</template>
<script>
// import theimage6 from '@/assets/images/tubiao.jpg'
import SmallModule from "@/components/SmallModule.vue";
import addLinkdialog from "./addLinkdialog.vue";
import {
getEnabledAppListAPI,
recentlyAPI,
collectListAPI,
collectsortAPI,
} from "@/api/apply";
import theimage6 from "@/assets/images/default.png";
export default {
components: {
SmallModule,
addLinkdialog,
},
props: {
searchvalue: {
type: String,
},
},
data() {
return {
isempty: false,
centerDialogVisible: false,
theimage6: theimage6,
thetabmodule: [],
activeName:"", // 当前激活的标签名
theStareList: [],
//最近使用
currentArray: [{ data: [] }],
oldData: [],
newData: [],
dragStartId: "",
dragEndId: "",
//收藏
collectArray: [{ data: [] }],
firstcollectList: [],
firstcurrentList: [],
totalList: [],
showImg: false,//展示未找到应用标志
};
},
async activated() {
if (this.searchvalue) {
this.searchContent(this.searchvalue);
} else {
await this.getcollectList();
await this.getEnableApply("");
}
// this.bindScrollEvent();
},
mounted(){
window.addEventListener("beforeunload",()=>{
localStorage.removeItem('activeName')
});
},
methods: {
closedialog(value) {
if (value) {
this.searchContent(this.searchvalue);
}
this.centerDialogVisible = false;
// setTimeout(()=>{
// this.scrollToTop()
// },20)
},
addlink() {
this.centerDialogVisible = true;
},
dragstart(value) {
this.oldData = value;
this.dragStartId = value.collectId;
},
dragenter(value) {
this.newData = value;
this.dragEndId = value.collectId;
},
getDragend(listData) {
if (this.dragStartId !== this.dragEndId) {
let oldIndex = listData.indexOf(this.oldData);
let newIndex = listData.indexOf(this.newData);
let newItems = [...listData];
// 删除之前DOM节点
newItems.splice(oldIndex, 1);
// 在拖拽结束目标位置增加新的DOM节点
newItems.splice(newIndex, 0, this.oldData);
// 每次拖拽结束后,将拖拽处理完成的数据,赋值原数组,使DOM视图更新,页面显示拖拽动画
console.log("newItems", newItems);
const idList = newItems.map((item) => item.collectId);
this.collectArray = [
{
thename: this.$t("homeView.mycollect"),
label: this.$t("homeView.mycollect"),
data: newItems,
},
];
// {thename:'我的收藏',label:'我的收藏',data:collect.data.data?collect.data.data:[]}
// 每次拖拽结束后调用接口时时保存数据
collectsortAPI({ collectIds: idList }).then((res) => {
console.log(res);
});
}
},
async getcurrentList() {
const res = await recentlyAPI();
// this.currentArray.push({thename:'最近使用',label:'最近使用',data:res.data.data?res.data.data:[]})
let array2 = this.theStareList;
let index = 0;
const currently = [];
this.currentArray = [];
let length = "";
//4A在更多应用页面最多为8个最近使用
if (res.data.data.length < 8) {
length = res.data.data.length;
} else {
length = 8;
}
for (let i = 0; i < length; i++) {
// for (let i = 0; i < 8; i++) {
let isContained = false;
for (let j = 0; j < array2.length; j++) {
if (
res.data.data[i].name === array2[j].name &&
res.data.data[i].id === array2[j].id
) {
isContained = true;
break;
}
}
if (isContained) {
res.data.data[i].iscollect = 1;
} else {
res.data.data[i].iscollect = 2;
}
index = index++;
currently.push(res.data.data[i]);
}
this.currentArray.push({
thename: this.$t("homeView.lastuse"),
label: this.$t("homeView.lastuse"),
data: currently,
});
this.firstcurrentList = this.currentArray;
},
// 收藏的数据
async getcollectList() {
const res = await collectListAPI();
if (res) {
res.data.data.forEach((item) => {
item.iscollect = "1";
// if(value){
// item.name = this.highlightKeyword(item.name, value);
// item.customName = this.highlightKeyword(item.customName, value);
// }
});
this.theStareList = res.data.data;
this.collectArray = [];
this.collectArray.push({
thename: this.$t("homeView.mycollect"),
label: this.$t("homeView.mycollect"),
data: res.data.data ? res.data.data : [],
});
this.firstcollectList = this.collectArray;
}
},
highlightKeyword(text, keyword) {
const highlightedKeyword = `<span style="color: #2D57F2;">${keyword}</span>`;
const regex = new RegExp(keyword, "gi");
return text.replace(regex, highlightedKeyword);
},
async getEnabledAppList(value) {
const params = { appName: value };
const res = await getEnabledAppListAPI(params);
let array2 = this.theStareList || [];
let instanceArray = res.data.data;
let index = 0;
this.thetabmodule = [];
for (let key in instanceArray) {
let array1 = instanceArray[key] || [];
for (let i = 0; i < array1.length; i++) {
let isContained = false;
array1[i].name = this.highlightKeyword(array1[i].name, value);
for (let j = 0; j < array2.length; j++) {
if (array1[i].id === array2[j].id) {
isContained = true;
break;
}
}
if (isContained) {
array1[i].iscollect = 1;
} else {
array1[i].iscollect = 2;
}
}
this.thetabmodule.push({
thename: key || "",
label: key || "",
datelength: array1.length,
data: array1,
});
index = index++;
this.totalList = [];
for (let k = 0; k < this.thetabmodule.length; k++) {
this.totalList.push(this.thetabmodule[k].datelength);
}
const sum = this.totalList.reduce((accumulator, currentValue) => {
return accumulator + currentValue;
}, 0);
this.$emit("appSum", sum);
}
this.activeName = localStorage.getItem('activeName')||this.thetabmodule[0]?.thename;
if(this.collectArray[0].data.length == 0 && this.collectArray[0].data.length == 0 && this.thetabmodule.length == 0) {
this.showImg = true
} else {
this.showImg = false
}
},
async getEnableApply(value) {
await Promise.all([
this.getcurrentList(value),
this.getEnabledAppList(value),
]);
},
async searchContent(value) {
// console.log('firstcurrentList', this.firstcurrentList);
if (!value) {
await this.getcollectList();
this.getEnableApply("");
} else {
let searchObj = this.searchvalue;
let useArr = [...this.firstcurrentList];
let collectArr = [...this.firstcollectList];
let storeArr1 = [];
let storeArr2 = [];
this.currentArray = [];
this.collectArray = [];
//遍历最近使用,返回匹配item
for (let i = 0; i < useArr.length; i++) {
let data = useArr[i].data;
for (let j = 0; j < data.length; j++) {
if (data[j].customName) {
let name = data[j].customName;
if (name.indexOf(searchObj) != -1) {
name = this.highlightKeyword(
data[j].customName,
this.searchvalue
);
storeArr1.push({ ...data[j], customName: name });
}
} else {
let name = data[j].name;
if (name.indexOf(searchObj) != -1) {
name = this.highlightKeyword(data[j].name, this.searchvalue);
storeArr1.push({ ...data[j], name: name });
}
}
}
// console.log('storeArr1', storeArr1)
this.currentArray.push({
thename: this.$t("homeView.lastuse"),
label: this.$t("homeView.lastuse"),
data: storeArr1,
});
// if(this.currentArray[0].data)
}
console.log("111", this.firstcollectList);
this.collectArray = [];
//遍历我的收藏
for (let i = 0; i < collectArr.length; i++) {
let data = collectArr[i].data;
for (let j = 0; j < data.length; j++) {
if (data[j].customName) {
let name = data[j].customName;
if (name.indexOf(searchObj) != -1) {
name = this.highlightKeyword(
data[j].customName,
this.searchvalue
);
storeArr2.push({ ...data[j], customName: name });
}
} else {
let name = data[j].name;
if (name.indexOf(searchObj) != -1) {
let name = data[j].name;
if (name.indexOf(searchObj) != -1) {
name = this.highlightKeyword(data[j].name, this.searchvalue);
storeArr2.push({ ...data[j], name: name });
}
}
}
}
console.log("storeArr2", storeArr2);
this.collectArray.push({
thename: this.$t("homeView.mycollect"),
label: this.$t("homeView.mycollect"),
data: storeArr2,
});
}
//查询激活应用
this.getEnabledAppList(this.searchvalue);
}
},
// 根据右侧内容滚动,高亮侧边栏
bindScrollEvent() {
const editCards = document.querySelector(".edit-cards");
const tabHeights = this.thetabmodule.map((tab) => {
const card = document.getElementById(tab.thename);
return {
thename: tab.thename,
offsetTop: card.offsetTop-editCards.offsetTop-30,
};
});
editCards.addEventListener("scroll", () => {
const scrollPosition = editCards.scrollTop;
tabHeights.forEach((item, index) => {
if (editCards.scrollHeight - editCards.clientHeight === editCards.scrollTop||editCards.scrollHeight - editCards.clientHeight <= editCards.scrollTop) {
return false
}
if (
scrollPosition >= item.offsetTop && scrollPosition < tabHeights[index + 1].offsetTop
) {
this.activeName = item.thename;
localStorage.setItem('activeName',this.activeName)
this.tabToTop(this.activeName)
}
});
});
},
// 点击侧边栏,使得右侧内容滚动到对应为止
scrollToTabContent(tabName) {
const contentElement = document.getElementById(tabName);
const tabContainer = document.getElementById("thescroll_container");
if (contentElement && tabContainer) {
// 计算contentElement相对于tabContainer的位置
const offsetTop = contentElement.offsetTop - tabContainer.offsetTop;
tabContainer.scrollTop = offsetTop;
}
},
// 侧边栏滚动
tabToTop(tabName) {
const contentElement = document.getElementById(tabName+'left');
const leftTab = document.getElementById("thescroll_tab");
if (contentElement && leftTab) {
const offsetTop = contentElement.offsetTop-leftTab.offsetTop
// leftTab.scrollTop = offsetTop;
leftTab.scrollTo(0, offsetTop);
}
},
// 置顶
scrollToTop() {
const contentElement = document.getElementById("currentuse");
const tabContainer = document.getElementById("thescroll_container");
if (contentElement && tabContainer) {
this.activeName=this.thetabmodule[0].thename
localStorage.setItem('activeName',this.activeName)
this.tabToTop(this.thetabmodule[0].thename)
const offsetTop = contentElement.offsetTop - tabContainer.offsetTop;
tabContainer.scrollTop = offsetTop;
}
},
handleTabClick(tab) {
//点击后切换样式
this.activeName = tab.thename;
localStorage.setItem('activeName',this.activeName)
this.scrollToTabContent(tab.thename);
},
},
};
</script>
<style lang="scss" scoped>
.editBox {
height: 100%;
width: 100%;
display: flex;
overflow-y: auto;
.left_tab {
width: 205px;
// border: 1px solid red;
height: 100%;
overflow: auto;
scrollbar-width: none;
// box-sizing: border-box;
font-size: 14px;
.active{
background-color: #e2ebfc;
color: #2d57f2;
font-weight: 700;
border-right: 3px solid #2d57f2;
.theheaderclass{
font-size: 16px;
}
}
}
.left_tab::-webkit-scrollbar{
width: 0;
}
.left_tab::-webkit-scrollbar-thumb{
background-color:transparent;
}
}
.edit-cards {
width: 100%;
height: 80vh;
overflow-y: scroll;
scrollbar-width: none;
}
.edit-cards::-webkit-scrollbar {
width: 0;
}
.edit-cards::-webkit-scrollbar-thumb {
background-color: transparent;
}
.el-tabs--left.el-tabs--card .el-tabs__nav {
border: none;
}
.edit-cards {
height: 100%;
// overflow: hidden;
padding: 0 20px;
// margin-top: -30px;
.scroll_title {
font-size: 18px;
font-weight: 700;
margin-top: 20px;
display: flex;
align-items: center;
white-space: nowrap;
}
.themodules_container {
width: 100%;
display: grid;
grid-template-columns: repeat(4, minmax(185px, 1fr));
// grid-template-columns: repeat(4, 1fr);
gap: 16px;
// min-width: 80vw;
}
}
.activescrollTitle {
color: #454ec8;
}
.smallbox {
width: 10px;
height: 10px;
background-color: #7f4ee8;
margin-right: 20px;
}
.activebox {
background-color: #454ec8;
}
.sort-move {
transition: transform 1s;
}
.thelinkbutton {
display: flex;
align-items: center;
.linkbutton {
margin-top: 20px;
height: 20px;
margin-left: 10px;
font-size: 12px;
display: flex;
align-items: center;
padding: 3px 7px 3px 3px;
background-color: #2d57f2;
text-align: center;
color: #fff;
border-radius: 6px;
cursor: pointer;
width: fit-content !important;
white-space: nowrap;
/* 防止文本换行 */
overflow: hidden;
/* 隐藏溢出内容 */
text-overflow: ellipsis;
/* 溢出文本显示省略号 */
.linktext {
width: fit-content;
}
}
.linkTip {
flex: 1;
height: 20px;
padding-top: 26px;
// width: fit-content;
// .linkTip_content {
margin-left: 8px;
font-size: 12px;
font-weight: 400;
color: #86909c;
white-space: nowrap;
/* 防止文本换行 */
overflow: hidden;
/* 隐藏溢出内容 */
text-overflow: ellipsis;
// overflow: hidden;
// text-overflow: ellipsis;
// }
}
}
.theheaderclass {
display: flex;
height: 48px;
width: 100%;
align-items: center;
font-size: 14px;
font-family: "Noto Sans", sans-serif;
cursor: pointer;
.left_text {
line-height: 48px;
max-width: 100px;
margin-left: 25px;
white-space: nowrap;
/* 强制文本不换行 */
overflow: hidden;
/* 隐藏溢出内容 */
text-overflow: ellipsis;
/* 溢出部分显示省略号 */
}
.number_text {
line-height: 48px;
}
}
.clicked_tab {
background-color: #e2e9fd;
color: #2d57f2;
font-size: 16px;
border-radius: 10px 0 0 10px;
border-right: 1px solid #2d57f2;
font-weight: 700;
}
.bottom_text {
text-align: center;
line-height: 50px;
color: #676f7a;
font-weight: 600;
margin-top: -10px;
margin-bottom: 30px;
}
.theempty {
height: 100%;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
img {
margin-left: -12%;
}
.img_text {
color: var(---Text-4, #4e5969);
font-family: PingFang SC;
font-size: 12px;
font-style: normal;
font-weight: 400;
margin-top: 10px;
margin-left: -12.5%
}
}
.elliplice_1 {
min-width: 120px;
margin-left: -3px;
}
// .scrollable-tabs{
// height: 100px;
// overflow-y:scroll ;
// }
// .scrollable-tab-pane {
// overflow-y: auto;
// max-height: 300px; /* 根据需要设置每个标签页内容的最大高度,超出则滚动 */
// }
</style>
前端实现左右联动,置顶以及拖动小模块调整顺序
于 2025-02-12 13:37:02 首次发布