This commit is contained in:
那些花儿
2025-09-11 20:01:45 +08:00
parent 32d5791c0a
commit 0777e2f4f7
23 changed files with 922 additions and 460 deletions
@@ -1,7 +1,7 @@
const apps = {
template: /*language=HTML*/ `
<div class="apps-container">
<van-nav-bar title="代表阅览" placeholder fixed></van-nav-bar>
<van-nav-bar title="应用中心" placeholder fixed></van-nav-bar>
<!-- 搜索栏 -->
<van-sticky offset-top="46px">
<van-search
@@ -13,14 +13,25 @@ const apps = {
></van-search>
</van-sticky>
<!-- 使用TreeSelect组件 -->
<van-tree-select
:items="treeSelectItems"
:main-active-index.sync="activeTab"
@click-nav="onClickNav"
>
<template #content>
<div class="custom-tree-select">
<!-- 左侧导航 -->
<div class="tree-nav">
<div
v-for="(category, index) in allCategories"
:key="category.id"
:class="['nav-item', { active: activeTab === index }]"
@click="onClickNav(index)"
>
<div class="nav-icon" v-if="category.icon">
<i :class="category.icon"></i>
</div>
<div class="nav-text">{{ category.name }}</div>
<div class="nav-indicator" v-if="activeTab === index"></div>
</div>
</div>
<!-- 右侧内容 -->
<div class="tree-content">
<!-- 应用列表 -->
<div class="app-list" v-if="applications.length > 0">
<div
@@ -50,15 +61,39 @@ const apps = {
:name="app.isFavorite ? 'star' : 'star-o'"
:class="['favorite-icon', app.isFavorite ? 'active' : '']"
@click.stop="toggleFavorite(app.id)"
/>
></van-icon>
</div>
</div>
</div>
<!-- 空状态 -->
<van-empty v-else description="暂无应用"></van-empty>
</template>
</van-tree-select>
</div>
</div>
<!-- 应用菜单弹框 -->
<van-popup v-model="showMenuPopup" position="bottom" :style="{ width: '100%', maxHeight: '60%' }" round>
<div class="menu-popup">
<div class="popup-header">
<div class="popup-title">{{ currentApp.name }}</div>
<van-icon name="cross" @click="showMenuPopup = false" class="close-icon"></van-icon>
</div>
<div class="menu-grid">
<div
v-for="menu in currentMenus"
:key="menu.id"
class="grid-item"
@click="navigateToMenu(menu)"
>
<div class="grid-icon">
<van-icon :name="menu.icon || 'apps-o'" size="24"></van-icon>
</div>
<div class="grid-name">{{ menu.name }}</div>
<div class="grid-desc" v-if="menu.aliasName">{{ menu.aliasName }}</div>
</div>
</div>
</div>
</van-popup>
</div>
`,
data() {
@@ -67,9 +102,9 @@ const apps = {
applications: [],
// 固定分类列表
categories: [
{id: "all", name: "全部应用", icon: "apps-o"},
{id: "favorites", name: "我的收藏", icon: "star-o"},
{id: "recommended", name: "推荐应用", icon: "like-o"}
{id: "all", name: "全部应用", icon: "fa fa-th-large"},
{id: "favorites", name: "我的收藏", icon: "fa fa-star-o"},
{id: "recommended", name: "推荐应用", icon: "fa fa-thumbs-o-up"}
],
// 动态加载的分类
dynamicCategories: [],
@@ -78,7 +113,11 @@ const apps = {
// 搜索关键词
searchKeyword: "",
// 列表相关
loading: true
loading: true,
// 弹框相关
showMenuPopup: false,
currentApp: {},
currentMenus: []
}
},
computed: {
@@ -90,13 +129,7 @@ const apps = {
currentCategoryId() {
return this.allCategories[this.activeTab]?.id || "all"
},
// TreeSelect组件所需的数据格式
treeSelectItems() {
return this.allCategories.map(category => ({
text: category.name,
className: 'category-item'
}))
}
},
mounted() {
// 页面加载时获取分类和应用数据
@@ -106,17 +139,13 @@ const apps = {
methods: {
// 加载分类数据
loadCategories() {
$.get("/platform/v4/apps/categories", {platform: "H5"})
.then((result) => {
if (result.code === 0) {
this.dynamicCategories = result.data || []
} else {
console.error("获取应用分类失败:", result.msg)
}
})
.fail((error) => {
console.error("获取应用分类异常:", error)
})
this.$axios.post("/platform/v4/apps/categories", {platform: "H5"}).then((res) => {
if (res.code === 0) {
this.dynamicCategories = res.data || []
} else {
console.error("获取应用分类失败:", res.msg)
}
})
},
// 加载应用数据
@@ -147,24 +176,19 @@ const apps = {
// 如果是"推荐应用"分类
if (this.currentCategoryId === "recommended") {
$.get("/platform/v4/apps/recommended")
.then((result) => {
if (result.code === 0) {
this.applications = result.data.list || []
} else {
console.error("获取推荐应用失败:", result.msg)
}
this.loading = false
})
.fail((error) => {
console.error("获取推荐应用异常:", error)
this.loading = false
})
this.$axios.post("/platform/v4/apps/recommended").then((result) => {
if (result.code === 0) {
this.applications = result.data.list || []
} else {
console.error("获取推荐应用失败:", result.msg)
}
this.loading = false
})
return
}
// 发送请求获取普通应用列表
$.get("/platform/v4/apps/list?" + queryString)
this.$axios.post("/platform/v4/apps/list?" + queryString)
.then((result) => {
if (result.code === 0) {
this.applications = result.data || []
@@ -173,15 +197,11 @@ const apps = {
}
this.loading = false
})
.fail((error) => {
console.error("获取应用列表异常:", error)
this.loading = false
})
},
// 加载收藏的应用
loadFavorites() {
$.get("/platform/v4/apps/favorite")
this.$axios.post("/platform/v4/apps/favorite")
.then((result) => {
if (result.code === 0) {
this.applications = result.data || []
@@ -190,10 +210,6 @@ const apps = {
}
this.loading = false
})
.fail((error) => {
console.error("获取收藏应用异常:", error)
this.loading = false
})
},
// 切换应用收藏状态
@@ -239,10 +255,48 @@ const apps = {
// 打开应用
openApp(app) {
// 储存到缓存
window.sessionStorage.setItem("zhgh_sub_app", JSON.stringify(app))
// 新标签页打开
window.open("/platform/v4/subApp?appId=" + app.id, "_blank")
this.$axios.post("/platform/sys/user/subAppMenus", {appId: app.id}).then((res) => {
if (res.code === 0) {
this.showAppMenus(app, res.data)
}
})
},
// 显示应用菜单弹框
showAppMenus(app, menus) {
if (!menus || menus.length === 0) {
this.$toast('该应用暂无可用功能')
return
}
// 如果只有一个菜单项,直接跳转
if (menus.length === 1) {
this.navigateToMenu(menus[0])
return
}
// 多个菜单项时显示popup弹框
this.currentApp = app
this.currentMenus = menus
this.showMenuPopup = true
},
// 导航到菜单
navigateToMenu(menu) {
// 关闭弹框
this.showMenuPopup = false
if (menu.href) {
// 如果是H5平台,直接跳转
if (menu.platform === 'H5') {
window.location.href = menu.href
} else {
// 其他平台可能需要特殊处理
window.open(menu.href, '_blank')
}
} else {
this.$toast('该功能暂不可用')
}
}
},
style: /*language=CSS*/ `
@@ -252,20 +306,81 @@ const apps = {
height: 100%;
}
.van-tree-select {
height: calc(100vh - 150px) !important;
/* 自定义树形选择组件样式 */
.custom-tree-select {
display: flex;
height: calc(100vh - 150px);
background: #fff;
}
.van-tree-select__nav {
.tree-nav {
flex: 0 0 90px;
background: #f7f8fa;
border-right: 1px solid #ebedf0;
overflow-y: auto;
}
.van-tree-select__content {
padding: 0;
.nav-item {
position: relative;
padding: 12px 8px;
cursor: pointer;
transition: all 0.2s ease;
border-bottom: 1px solid #ebedf0;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.category-item {
font-size: 14px;
.nav-item:hover {
background: #f2f3f5;
}
.nav-item.active {
background: #fff;
color: var(--color-primary);
}
.nav-item.active::before {
content: '';
position: absolute;
left: 0;
top: 0;
bottom: 0;
width: 3px;
background: #1989fa;
}
.nav-icon {
font-size: 18px;
margin-bottom: 6px;
color: inherit;
}
.nav-text {
font-size: 12px;
font-weight: 500;
text-align: center;
line-height: 1.2;
word-break: break-all;
}
.nav-indicator {
position: absolute;
right: 0;
top: 50%;
transform: translateY(-50%);
width: 0;
height: 0;
border-left: 6px solid #1989fa;
border-top: 6px solid transparent;
border-bottom: 6px solid transparent;
}
.tree-content {
flex: 1;
overflow-y: auto;
background: #fff;
}
.app-list {
@@ -327,5 +442,107 @@ const apps = {
padding: 20px 0;
text-align: center;
}
/* 菜单弹框样式 */
::v-deep .menu-popup {
height: 100%;
display: flex;
flex-direction: column;
border-radius: 8px;
overflow: hidden;
}
::v-deep .popup-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 16px 20px;
border-bottom: 1px solid #ebedf0;
background: #fff;
}
::v-deep .popup-title {
font-size: 16px;
font-weight: 500;
color: #323233;
}
::v-deep .close-icon {
font-size: 18px;
color: #969799;
cursor: pointer;
}
::v-deep .menu-grid {
flex: 1;
overflow-y: auto;
display: grid;
grid-template-columns: repeat(3, 1fr);
}
::v-deep .grid-item {
display: flex;
flex-direction: column;
align-items: center;
padding: 20px 12px;
background: #fff;
cursor: pointer;
transition: all 0.2s ease;
min-width: 0;
}
::v-deep .grid-item:active {
transform: scale(0.95);
background: #f2f3f5;
}
::v-deep .grid-icon {
width: 48px;
height: 48px;
border-radius: 12px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 12px;
color: #fff;
}
::v-deep .grid-name {
font-size: 14px;
font-weight: 500;
color: #323233;
text-align: center;
margin-bottom: 4px;
line-height: 1.2;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 100%;
min-width: 0;
}
::v-deep .grid-desc {
font-size: 12px;
color: #969799;
text-align: center;
line-height: 1.2;
}
::v-deep .menu-name {
font-size: 16px;
color: #323233;
margin-bottom: 4px;
}
::v-deep .menu-desc {
font-size: 12px;
color: #969799;
}
::v-deep .menu-arrow {
font-size: 16px;
color: #c8c9cc;
}
`
}