397 lines
10 KiB
Vue
397 lines
10 KiB
Vue
<template>
|
||
<div class="all-applications-container">
|
||
<!-- 常用应用区域 -->
|
||
<div class="frequently-used-section">
|
||
<div class="frequently-used-header">
|
||
<h3 class="frequently-title">常用应用</h3>
|
||
<el-button
|
||
type="text"
|
||
size="small"
|
||
class="edit-btn"
|
||
@click="isEditingFavorites = !isEditingFavorites"
|
||
>
|
||
{{ isEditingFavorites ? '完成' : '编辑' }}
|
||
</el-button>
|
||
</div>
|
||
|
||
<div class="frequently-used-grid" v-if="frequentlyUsedApps.length > 0">
|
||
<div
|
||
v-for="app in frequentlyUsedApps"
|
||
:key="`fav-${app.parentPath}-${app.childPath}`"
|
||
class="frequently-app-item"
|
||
@click="handleAppClick(getParentMenu(app.parentPath), getChildMenu(app.parentPath, app.childPath))"
|
||
>
|
||
<div class="app-icon-wrapper">
|
||
<svg-icon :icon-class="getChildMenu(app.parentPath, app.childPath).meta.icon || 'documentation'" class="app-icon" />
|
||
</div>
|
||
<span class="app-name">{{ getChildMenu(app.parentPath, app.childPath).meta.title }}</span>
|
||
|
||
<!-- 删除按钮 - 仅在编辑模式显示 -->
|
||
<div
|
||
class="remove-btn"
|
||
v-if="isEditingFavorites"
|
||
@click.stop="removeFromFavorites(app.parentPath, app.childPath)"
|
||
>
|
||
<i class="el-icon-close"></i>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div v-else>
|
||
<el-empty description="暂无常用应用" />
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 原有全部应用区域 -->
|
||
<h3 class="title" v-if="isEditingFavorites">全部应用</h3>
|
||
<el-tabs v-model="activeTabName" class="app-tabs" v-if="isEditingFavorites">
|
||
<el-tab-pane
|
||
v-for="menu in filteredMenus"
|
||
:key="menu.path"
|
||
:label="menu.meta.title"
|
||
:name="menu.path"
|
||
>
|
||
<div class="app-grid">
|
||
<div
|
||
v-for="child in menu.children"
|
||
:key="child.path"
|
||
class="app-item"
|
||
>
|
||
<!-- @click="handleAppClick(menu, child)" -->
|
||
<div class="app-icon-wrapper">
|
||
<svg-icon :icon-class="child.meta.icon || 'documentation'" class="app-icon" />
|
||
|
||
<!-- 添加到常用按钮 -->
|
||
<div
|
||
class="add-to-favorite-btn"
|
||
@click.stop="addToFavorites(menu.path, child.path)"
|
||
v-if="!isInFavorites(menu.path, child.path)"
|
||
>
|
||
<i class="el-icon-star-off"></i>
|
||
</div>
|
||
|
||
<!-- 已在常用中的标识 -->
|
||
<div
|
||
class="in-favorite-indicator"
|
||
v-if="isInFavorites(menu.path, child.path)"
|
||
>
|
||
<i class="el-icon-star-on"></i>
|
||
</div>
|
||
</div>
|
||
<span class="app-name">{{ child.meta.title }}</span>
|
||
</div>
|
||
</div>
|
||
</el-tab-pane>
|
||
</el-tabs>
|
||
</div>
|
||
</template>
|
||
|
||
<script>
|
||
import { getRouters } from '@/api/menu'
|
||
import path from 'path'
|
||
|
||
export default {
|
||
name: 'AllApplications',
|
||
data() {
|
||
return {
|
||
allMenus: [],
|
||
activeTabName: '',
|
||
frequentlyUsedApps: [], // 存储常用应用
|
||
isEditingFavorites: false // 是否处于编辑常用应用模式
|
||
}
|
||
},
|
||
computed: {
|
||
filteredMenus() {
|
||
const filterHidden = (menus) => {
|
||
return menus
|
||
.filter(menu => menu.hidden !== true)
|
||
.map(menu => {
|
||
if (menu.children) {
|
||
menu.children = filterHidden(menu.children)
|
||
}
|
||
return menu
|
||
})
|
||
}
|
||
const topLevelMenus = filterHidden(this.allMenus).filter(
|
||
menu => menu.children && menu.children.length > 0
|
||
)
|
||
return topLevelMenus
|
||
}
|
||
},
|
||
created() {
|
||
this.fetchMenus()
|
||
this.loadFrequentlyUsedApps()
|
||
},
|
||
methods: {
|
||
fetchMenus() {
|
||
getRouters().then(response => {
|
||
this.allMenus = response.data
|
||
if (this.filteredMenus.length > 0) {
|
||
this.activeTabName = this.filteredMenus[0].path
|
||
}
|
||
})
|
||
},
|
||
|
||
// 加载常用应用(从localStorage)
|
||
loadFrequentlyUsedApps() {
|
||
const saved = localStorage.getItem('frequentlyUsedApps')
|
||
if (saved) {
|
||
try {
|
||
this.frequentlyUsedApps = JSON.parse(saved)
|
||
} catch (e) {
|
||
console.error('Failed to parse frequently used apps', e)
|
||
this.frequentlyUsedApps = []
|
||
}
|
||
}
|
||
},
|
||
|
||
// 保存常用应用到localStorage
|
||
saveFrequentlyUsedApps() {
|
||
localStorage.setItem('frequentlyUsedApps', JSON.stringify(this.frequentlyUsedApps))
|
||
},
|
||
|
||
// 添加到常用应用
|
||
addToFavorites(parentPath, childPath) {
|
||
if (!this.isInFavorites(parentPath, childPath)) {
|
||
// 限制最多10个常用应用
|
||
if (this.frequentlyUsedApps.length >= 10) {
|
||
this.$message.warning('常用应用最多只能添加10个')
|
||
return
|
||
}
|
||
|
||
this.frequentlyUsedApps.unshift({ parentPath, childPath })
|
||
this.saveFrequentlyUsedApps()
|
||
this.$message.success('已添加到常用应用')
|
||
}
|
||
},
|
||
|
||
// 从常用应用中移除
|
||
removeFromFavorites(parentPath, childPath) {
|
||
this.frequentlyUsedApps = this.frequentlyUsedApps.filter(
|
||
app =>!(app.parentPath === parentPath && app.childPath === childPath)
|
||
)
|
||
this.saveFrequentlyUsedApps()
|
||
},
|
||
|
||
// 检查应用是否在常用列表中
|
||
isInFavorites(parentPath, childPath) {
|
||
return this.frequentlyUsedApps.some(
|
||
app => app.parentPath === parentPath && app.childPath === childPath
|
||
)
|
||
},
|
||
|
||
// 根据路径获取父菜单
|
||
getParentMenu(parentPath) {
|
||
return this.filteredMenus.find(menu => menu.path === parentPath)
|
||
},
|
||
|
||
// 根据路径获取子菜单
|
||
getChildMenu(parentPath, childPath) {
|
||
const parent = this.getParentMenu(parentPath)
|
||
if (parent && parent.children) {
|
||
return parent.children.find(child => child.path === childPath)
|
||
}
|
||
return {
|
||
meta: {}
|
||
}
|
||
},
|
||
|
||
handleAppClick(parentMenu, childMenu) {
|
||
if (!childMenu) return
|
||
|
||
const basePath = parentMenu.path
|
||
const fullPath = path.resolve(basePath, childMenu.path)
|
||
this.$router.push(fullPath)
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
.all-applications-container {
|
||
padding: 16px; /* 调整间距,更贴近飞书紧凑感 */
|
||
border-radius: 12px; /* 飞书常用较大圆角 */
|
||
margin-top: 24px;
|
||
}
|
||
|
||
// 常用应用样式
|
||
.frequently-used-section {
|
||
margin-bottom: 32px; /* 增大间距 */
|
||
padding-bottom: 20px;
|
||
border-bottom: 1px solid #ddd; /* 飞书浅灰边框色 */
|
||
}
|
||
|
||
.frequently-used-header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
// margin-bottom: 20px;
|
||
}
|
||
|
||
.frequently-title {
|
||
font-size: 16px; /* 稍小字体,飞书风格更简洁 */
|
||
font-weight: 500; /* 调整 FontWeight */
|
||
color: #111; /* 深一点的标题色 */
|
||
}
|
||
|
||
.edit-btn {
|
||
color: #687b98; /* 飞书常用的主题蓝 */
|
||
padding: 0;
|
||
font-size: 14px;
|
||
}
|
||
|
||
.frequently-used-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fill, minmax(112px, 1fr)); /* 调整卡片宽度 */
|
||
gap: 20px; /* 增大间距 */
|
||
}
|
||
|
||
.frequently-app-item {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
cursor: pointer;
|
||
padding: 16px; /* 调整内边距 */
|
||
border-radius: 12px; /* 大圆角 */
|
||
transition: all 0.3s ease;
|
||
position: relative;
|
||
// background-color: ; /* 飞书卡片常用浅灰底色 */
|
||
|
||
&:hover {
|
||
background-color: #fff; /* hover 时的浅灰 */
|
||
}
|
||
}
|
||
|
||
// 全部应用标题
|
||
.title {
|
||
font-size: 16px;
|
||
font-weight: 500;
|
||
margin-bottom: 20px;
|
||
color: #ddd;
|
||
}
|
||
|
||
// 应用网格布局
|
||
.app-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fill, minmax(128px, 1fr)); /* 调整卡片宽度 */
|
||
gap: 24px; /* 增大间距 */
|
||
padding-top: 16px;
|
||
}
|
||
|
||
.app-item {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
cursor: pointer;
|
||
padding: 16px;
|
||
border-radius: 12px;
|
||
transition: background-color 0.3s ease;
|
||
position: relative;
|
||
// background-color: #222;
|
||
|
||
&:hover {
|
||
background-color: #fff;
|
||
}
|
||
}
|
||
|
||
// 应用图标样式
|
||
.app-icon-wrapper {
|
||
width: 48px; /* 稍小图标容器 */
|
||
height: 48px;
|
||
border-radius: 10px; /* 图标容器圆角 */
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
margin-bottom: 12px;
|
||
background-color: #fff; /* 飞书风格的浅蓝底色 */
|
||
position: relative;
|
||
}
|
||
|
||
.app-icon {
|
||
font-size: 24px; /* 调整图标大小 */
|
||
color: #687b98; /* 主题蓝 */
|
||
}
|
||
|
||
// 应用名称样式
|
||
.app-name {
|
||
font-size: 14px;
|
||
color: #687b98; /* 飞书常用的文本色 */
|
||
text-align: center;
|
||
white-space: nowrap;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
width: 100%;
|
||
}
|
||
|
||
// 添加到常用按钮
|
||
.add-to-favorite-btn {
|
||
position: absolute;
|
||
bottom: 4px;
|
||
right: 4px;
|
||
width: 24px; /* 稍大按钮 */
|
||
height: 24px;
|
||
border-radius: 6px; /* 小圆角 */
|
||
background-color: rgba(255, 255, 255, 0.9);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
cursor: pointer;
|
||
font-size: 14px;
|
||
color: #c0c4cc;
|
||
transition: all 0.2s;
|
||
|
||
&:hover {
|
||
color: #ffb400; /* 飞书常用的强调色 */
|
||
background-color: #fff;
|
||
}
|
||
}
|
||
|
||
// 已在常用中的标识
|
||
.in-favorite-indicator {
|
||
position: absolute;
|
||
bottom: 4px;
|
||
right: 4px;
|
||
width: 24px;
|
||
height: 24px;
|
||
border-radius: 6px;
|
||
background-color: rgba(255, 255, 255, 0.9);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 14px;
|
||
color: #ffb400;
|
||
}
|
||
|
||
// 删除常用应用按钮
|
||
.remove-btn {
|
||
position: absolute;
|
||
top: -6px;
|
||
right: -6px;
|
||
width: 24px;
|
||
height: 24px;
|
||
border-radius: 6px;
|
||
background-color: #ff4d4f; /* 飞书删除按钮红 */
|
||
color: white;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
cursor: pointer;
|
||
font-size: 14px;
|
||
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
|
||
transition: all 0.2s;
|
||
|
||
&:hover {
|
||
background-color: #ff3839;
|
||
transform: scale(1.05);
|
||
}
|
||
}
|
||
|
||
// 标签页样式
|
||
::v-deep .el-tabs__header {
|
||
margin-bottom: 0;
|
||
}
|
||
|
||
::v-deep .el-tabs__nav-wrap::after {
|
||
height: 1px;
|
||
}
|
||
</style> |