Files
klp-oa/klp-ui/src/views/components/AllApplications.vue

396 lines
10 KiB
Vue
Raw Normal View History

2025-07-22 16:28:43 +08:00
<template>
<div class="all-applications-container">
2025-08-22 14:28:10 +08:00
<!-- 常用应用区域 -->
<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">
2025-07-22 16:28:43 +08:00
<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"
>
2025-08-22 14:28:10 +08:00
<!-- @click="handleAppClick(menu, child)" -->
2025-07-22 16:28:43 +08:00
<div class="app-icon-wrapper">
<svg-icon :icon-class="child.meta.icon || 'documentation'" class="app-icon" />
2025-08-22 14:28:10 +08:00
<!-- 添加到常用按钮 -->
<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>
2025-07-22 16:28:43 +08:00
</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: [],
2025-08-22 14:28:10 +08:00
activeTabName: '',
frequentlyUsedApps: [], // 存储常用应用
isEditingFavorites: false // 是否处于编辑常用应用模式
2025-07-22 16:28:43 +08:00
}
},
computed: {
filteredMenus() {
const filterHidden = (menus) => {
return menus
2025-08-22 14:28:10 +08:00
.filter(menu => menu.hidden!== true)
2025-07-22 16:28:43 +08:00
.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()
2025-08-22 14:28:10 +08:00
this.loadFrequentlyUsedApps()
2025-07-22 16:28:43 +08:00
},
methods: {
fetchMenus() {
getRouters().then(response => {
this.allMenus = response.data
if (this.filteredMenus.length > 0) {
this.activeTabName = this.filteredMenus[0].path
}
})
},
2025-08-22 14:28:10 +08:00
// 加载常用应用从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 null
},
2025-07-22 16:28:43 +08:00
handleAppClick(parentMenu, childMenu) {
2025-08-22 14:28:10 +08:00
if (!childMenu) return
2025-07-22 16:28:43 +08:00
const basePath = parentMenu.path
const fullPath = path.resolve(basePath, childMenu.path)
this.$router.push(fullPath)
}
}
}
</script>
<style lang="scss" scoped>
.all-applications-container {
background-color: #fff;
2025-08-22 14:28:10 +08:00
padding: 16px; /* 调整间距,更贴近飞书紧凑感 */
border-radius: 12px; /* 飞书常用较大圆角 */
margin-top: 24px;
2025-07-22 16:28:43 +08:00
}
2025-08-22 14:28:10 +08:00
// 常用应用样式
.frequently-used-section {
margin-bottom: 32px; /* 增大间距 */
padding-bottom: 20px;
border-bottom: 1px solid #ebeef5; /* 飞书浅灰边框色 */
}
.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: #1f2329; /* 深一点的标题色 */
}
.edit-btn {
color: #0078ff; /* 飞书常用的主题蓝 */
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: #f7f8fa; /* 飞书卡片常用浅灰底色 */
&:hover {
background-color: #eaeef7; /* hover 时的浅灰 */
}
}
// 全部应用标题
2025-07-22 16:28:43 +08:00
.title {
2025-08-22 14:28:10 +08:00
font-size: 16px;
font-weight: 500;
margin-bottom: 20px;
color: #1f2329;
2025-07-22 16:28:43 +08:00
}
2025-08-22 14:28:10 +08:00
// 应用网格布局
2025-07-22 16:28:43 +08:00
.app-grid {
display: grid;
2025-08-22 14:28:10 +08:00
grid-template-columns: repeat(auto-fill, minmax(128px, 1fr)); /* 调整卡片宽度 */
gap: 24px; /* 增大间距 */
padding-top: 16px;
2025-07-22 16:28:43 +08:00
}
.app-item {
display: flex;
flex-direction: column;
align-items: center;
cursor: pointer;
2025-08-22 14:28:10 +08:00
padding: 16px;
border-radius: 12px;
2025-07-22 16:28:43 +08:00
transition: background-color 0.3s ease;
2025-08-22 14:28:10 +08:00
position: relative;
background-color: #f7f8fa;
2025-07-22 16:28:43 +08:00
&:hover {
2025-08-22 14:28:10 +08:00
background-color: #eaeef7;
2025-07-22 16:28:43 +08:00
}
}
2025-08-22 14:28:10 +08:00
// 应用图标样式
2025-07-22 16:28:43 +08:00
.app-icon-wrapper {
2025-08-22 14:28:10 +08:00
width: 48px; /* 稍小图标容器 */
height: 48px;
border-radius: 10px; /* 图标容器圆角 */
2025-07-22 16:28:43 +08:00
display: flex;
align-items: center;
justify-content: center;
2025-08-22 14:28:10 +08:00
margin-bottom: 12px;
background-color: #e6f0ff; /* 飞书风格的浅蓝底色 */
position: relative;
2025-07-22 16:28:43 +08:00
}
.app-icon {
2025-08-22 14:28:10 +08:00
font-size: 24px; /* 调整图标大小 */
color: #0078ff; /* 主题蓝 */
2025-07-22 16:28:43 +08:00
}
2025-08-22 14:28:10 +08:00
// 应用名称样式
2025-07-22 16:28:43 +08:00
.app-name {
2025-08-22 14:28:10 +08:00
font-size: 14px;
color: #515767; /* 飞书常用的文本色 */
2025-07-22 16:28:43 +08:00
text-align: center;
2025-08-22 14:28:10 +08:00
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;
}
2025-07-22 16:28:43 +08:00
}
2025-08-22 14:28:10 +08:00
// 已在常用中的标识
.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);
}
}
// 标签页样式
2025-07-22 16:28:43 +08:00
::v-deep .el-tabs__header {
margin-bottom: 0;
}
::v-deep .el-tabs__nav-wrap::after {
height: 1px;
}
2025-08-22 14:28:10 +08:00
</style>