fix: 首页和我的应用排序按 seq 排列
This commit is contained in:
@@ -73,14 +73,14 @@ export default {
|
||||
</view>
|
||||
</view>
|
||||
<!-- 余额、优惠券 -->
|
||||
<view class="acea-row balance-coupon">
|
||||
<!-- <view class="acea-row balance-coupon">
|
||||
<view class="item" v-for="(item, index) in property" @tap="goMenuPage(item.url)" :key="index">
|
||||
<view class="value num-fa-semi">{{ item.value || 0 }}</view>
|
||||
<view>{{ item.label }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view> -->
|
||||
<!-- 会员中心、积分商城 -->
|
||||
<view class="acea-row member-points">
|
||||
<!-- <view class="acea-row member-points">
|
||||
<view class="acea-row row-middle row-center item" @tap="intoPage(userInfo.level_status == 1 ? '/pages/users/user_vip/index' : '/pages/annex/vip_grade_active/index')">
|
||||
<view>
|
||||
<view>会员中心</view>
|
||||
@@ -101,7 +101,7 @@ export default {
|
||||
</view>
|
||||
<image src="@/static/images/user-points.png" class="image"></image>
|
||||
</view>
|
||||
</view>
|
||||
</view> -->
|
||||
</view>
|
||||
</template>
|
||||
|
||||
|
||||
435
pages/user/components/myApps/index.vue
Normal file
435
pages/user/components/myApps/index.vue
Normal file
@@ -0,0 +1,435 @@
|
||||
<template>
|
||||
<view class="my-apps-wrap">
|
||||
<!-- 展示模式 -->
|
||||
<template v-if="!editing">
|
||||
<!-- 顶部:标题 + 编辑按钮 -->
|
||||
<view class="pt-34 pr-30 pb-20 pl-32 bg--w111-fff rd-t-16rpx mt-20 service ml-20 mr-20">
|
||||
<view class="flex-row-between">
|
||||
<view class="fs-30 fw-500 lh-42rpx text--w111-333">我的应用</view>
|
||||
<view class="edit-btn" @click="enterEdit">
|
||||
<text class="fs-24 text--w111-1890ff">编辑首页应用</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 应用列表 -->
|
||||
<view class="pt-10 pr-30 pb-32 pl-32 bg--w111-fff rd-b-16rpx service ml-20 mr-20" v-if="allApps.length">
|
||||
<view class="grid-column-4 grid-gap-x-76rpx grid-gap-y-54rpx">
|
||||
<view v-for="(item, index) in allApps" :key="index">
|
||||
<view class="flex-col flex-center" @click="onAppTap(item)">
|
||||
<image :src="item.logo" class="app-icon rd-16rpx" v-if="item.logo"></image>
|
||||
<view class="empty-box" v-else></view>
|
||||
<text class="fs-26 lh-36rpx text--w111-282828 pt-22">{{ item.name }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<!-- 编辑模式 -->
|
||||
<template v-else>
|
||||
<!-- 编辑卡片:整合头栏 + 首页展示栏 + 全部应用 -->
|
||||
<view class="bg--w111-fff rd-16rpx mt-20 ml-20 mr-20">
|
||||
<!-- 顶部操作栏 -->
|
||||
<view class="edit-header">
|
||||
<view class="edit-header-inner">
|
||||
<view class="header-btn btn-cancel" @click="cancelEdit">取消</view>
|
||||
<view class="fs-30 fw-500 text--w111-333">编辑首页展示</view>
|
||||
<view class="header-btn btn-save" @click="saveEdit">保存</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 首页展示栏(横向滚动) -->
|
||||
<view class="home-bar-wrap" v-if="editSelectedIds.length">
|
||||
<view class="home-bar-label fs-28 text--w111-333">首页展示栏</view>
|
||||
<scroll-view class="home-bar-scroll" scroll-x enhanced show-scrollbar="false">
|
||||
<view class="home-bar-inner">
|
||||
<view
|
||||
class="home-bar-item"
|
||||
v-for="(item, index) in editSelectedList"
|
||||
:key="item.id"
|
||||
>
|
||||
<view class="home-bar-icon-wrap">
|
||||
<image :src="item.logo" class="home-bar-icon rd-16rpx" v-if="item.logo"></image>
|
||||
<view class="empty-box-sm" v-else></view>
|
||||
<!-- 删除标记 -->
|
||||
<view class="badge badge-remove" @click="removeFromHome(item.id)">✕</view>
|
||||
</view>
|
||||
<text class="home-bar-name">{{ item.name }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
|
||||
<!-- 全部应用列表 -->
|
||||
<view class="all-apps-list">
|
||||
<view class="fs-28 text--w111-333 mb-20">全部应用</view>
|
||||
<view class="grid-column-4 grid-gap-x-76rpx grid-gap-y-54rpx">
|
||||
<view v-for="(item, index) in allApps" :key="index">
|
||||
<view
|
||||
class="flex-col flex-center pos-relative"
|
||||
@click="toggleAppSelect(item)"
|
||||
>
|
||||
<view class="app-icon-wrap">
|
||||
<image :src="item.logo" class="app-icon rd-16rpx" v-if="item.logo"></image>
|
||||
<view class="empty-box" v-else></view>
|
||||
<!-- 已选遮罩 -->
|
||||
<view class="selected-overlay" v-if="isSelected(item.id)">
|
||||
<text class="selected-check">✓</text>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 添加标记(未选中时) -->
|
||||
<view
|
||||
class="badge badge-add"
|
||||
v-if="!isSelected(item.id) && editSelectedIds.length < 6"
|
||||
@click.stop="addToHome(item)"
|
||||
>+</view>
|
||||
<text
|
||||
class="fs-26 lh-36rpx pt-22"
|
||||
:class="isSelected(item.id) ? 'text--w111-ccc' : 'text--w111-282828'"
|
||||
>{{ item.name }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const STORAGE_KEY = 'MY_HOME_APPS'
|
||||
const MAX_HOME_APPS = 6
|
||||
|
||||
export default {
|
||||
name: 'userMyApps',
|
||||
data() {
|
||||
return {
|
||||
allApps: [],
|
||||
// Storage 数据
|
||||
homeApps: {
|
||||
showOnHome: true,
|
||||
appIds: []
|
||||
},
|
||||
editing: false,
|
||||
// 编辑中的临时副本
|
||||
editAppIds: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
editSelectedIds() {
|
||||
return this.editAppIds
|
||||
},
|
||||
// 编辑模式中已选应用的完整对象列表(按 allApps 顺序排列)
|
||||
editSelectedList() {
|
||||
const idSet = new Set(this.editAppIds)
|
||||
const filtered = this.allApps.filter(item => idSet.has(item.id))
|
||||
const indexMap = new Map(this.allApps.map((item, i) => [item.id, i]))
|
||||
filtered.sort((a, b) => (indexMap.get(a.id) ?? 999) - (indexMap.get(b.id) ?? 999))
|
||||
return filtered
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.loadData()
|
||||
this.fetchApps()
|
||||
},
|
||||
// 从首页"更多"跳转过来时刷新数据
|
||||
onShow() {
|
||||
this.loadData()
|
||||
},
|
||||
methods: {
|
||||
// ---------- 数据层 ----------
|
||||
loadData() {
|
||||
try {
|
||||
const raw = uni.getStorageSync(STORAGE_KEY)
|
||||
if (raw) {
|
||||
this.homeApps = raw
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('[myApps] loadData error:', e)
|
||||
}
|
||||
},
|
||||
saveData() {
|
||||
try {
|
||||
uni.setStorageSync(STORAGE_KEY, this.homeApps)
|
||||
} catch (e) {
|
||||
console.error('[myApps] saveData error:', e)
|
||||
}
|
||||
},
|
||||
fetchApps() {
|
||||
uni.request({
|
||||
url: 'https://mp.yizhezhe.com/api/mp/apps',
|
||||
data: {
|
||||
isPublished: 1,
|
||||
pageSize: 50
|
||||
},
|
||||
success: (res) => {
|
||||
if (res.data?.code === 200 && res.data?.result?.items) {
|
||||
this.allApps = res.data.result.items
|
||||
} else if (res.data?.status === 200 && res.data?.data) {
|
||||
this.allApps = res.data.data
|
||||
} else {
|
||||
return
|
||||
}
|
||||
this.autoFillHomeApps()
|
||||
},
|
||||
fail: () => {
|
||||
this.allApps = []
|
||||
}
|
||||
})
|
||||
},
|
||||
// 自动填充首页展示应用(与 appCenter 逻辑一致)
|
||||
autoFillHomeApps() {
|
||||
const ids = this.homeApps.appIds || []
|
||||
const currentCount = ids.length
|
||||
if (currentCount >= 6) return
|
||||
|
||||
const idSet = new Set(ids)
|
||||
const recommended = this.allApps
|
||||
.filter(item => item.isRecommended && !idSet.has(item.id))
|
||||
|
||||
if (!recommended.length) return
|
||||
|
||||
const slots = 6 - currentCount
|
||||
const toAdd = recommended.slice(0, slots).map(item => item.id)
|
||||
|
||||
this.homeApps.appIds = [...ids, ...toAdd]
|
||||
this.saveData()
|
||||
},
|
||||
|
||||
// ---------- 展示模式 ----------
|
||||
onAppTap(item) {
|
||||
if (!item.url) return
|
||||
this.$util.JumpPath(item.url)
|
||||
},
|
||||
|
||||
// ---------- 编辑模式 ----------
|
||||
enterEdit() {
|
||||
// 复制当前 appIds 作为编辑副本
|
||||
this.editAppIds = [...(this.homeApps.appIds || [])]
|
||||
this.editing = true
|
||||
},
|
||||
cancelEdit() {
|
||||
this.editing = false
|
||||
this.editAppIds = []
|
||||
},
|
||||
saveEdit() {
|
||||
this.homeApps.appIds = [...this.editAppIds]
|
||||
this.saveData()
|
||||
this.editing = false
|
||||
},
|
||||
// 判断应用是否已选
|
||||
isSelected(id) {
|
||||
return this.editAppIds.includes(id)
|
||||
},
|
||||
// 添加到首页栏(从全部应用点击+)
|
||||
addToHome(item) {
|
||||
if (this.editAppIds.length >= MAX_HOME_APPS) {
|
||||
uni.showToast({ title: `最多选择${MAX_HOME_APPS}个应用`, icon: 'none' })
|
||||
return
|
||||
}
|
||||
if (!this.editAppIds.includes(item.id)) {
|
||||
this.editAppIds.push(item.id)
|
||||
}
|
||||
},
|
||||
// 从首页栏移除(点击✕)
|
||||
removeFromHome(id) {
|
||||
this.editAppIds = this.editAppIds.filter(i => i !== id)
|
||||
},
|
||||
// 点击应用图标切换选中状态
|
||||
toggleAppSelect(item) {
|
||||
if (this.isSelected(item.id)) {
|
||||
this.removeFromHome(item.id)
|
||||
} else {
|
||||
this.addToHome(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.my-apps-wrap {
|
||||
// 左右布局
|
||||
.flex-row-between {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
// 应用图标(展示模式 + 编辑模式通用)
|
||||
.app-icon {
|
||||
width: 96rpx;
|
||||
height: 96rpx;
|
||||
}
|
||||
.empty-box {
|
||||
width: 96rpx;
|
||||
height: 96rpx;
|
||||
background-color: #f3f9ff;
|
||||
border-radius: 8rpx;
|
||||
}
|
||||
|
||||
.app-icon-wrap {
|
||||
position: relative;
|
||||
width: 96rpx;
|
||||
height: 96rpx;
|
||||
}
|
||||
|
||||
// 编辑按钮
|
||||
.edit-btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
padding: 6rpx 20rpx;
|
||||
border: 2rpx solid #1890ff;
|
||||
border-radius: 10rpx;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
// ---------- 编辑模式 ----------
|
||||
.edit-header {
|
||||
padding: 24rpx 30rpx 0;
|
||||
|
||||
.edit-header-inner {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.header-btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 56rpx;
|
||||
padding: 0 28rpx;
|
||||
border-radius: 28rpx;
|
||||
font-size: 26rpx;
|
||||
font-weight: 500;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.btn-cancel {
|
||||
color: #666;
|
||||
background: #f5f5f5;
|
||||
}
|
||||
|
||||
.btn-save {
|
||||
color: #fff;
|
||||
background: linear-gradient(135deg, #1890ff, #096dd9);
|
||||
box-shadow: 0 4rpx 12rpx rgba(24, 144, 255, 0.35);
|
||||
}
|
||||
}
|
||||
|
||||
// 首页展示栏
|
||||
.home-bar-wrap {
|
||||
padding: 24rpx 30rpx 0;
|
||||
margin-top: 20rpx;
|
||||
|
||||
.home-bar-label {
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.home-bar-scroll {
|
||||
white-space: nowrap;
|
||||
overflow: visible !important;
|
||||
|
||||
.home-bar-inner {
|
||||
display: flex;
|
||||
gap: 24rpx;
|
||||
|
||||
.home-bar-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
flex-shrink: 0;
|
||||
width: 100rpx;
|
||||
padding-top: 12rpx;
|
||||
|
||||
.home-bar-icon-wrap {
|
||||
position: relative;
|
||||
width: 90rpx;
|
||||
height: 90rpx;
|
||||
overflow: visible;
|
||||
|
||||
.home-bar-icon {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 16rpx;
|
||||
}
|
||||
|
||||
.empty-box-sm {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: #f3f9ff;
|
||||
border-radius: 16rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.home-bar-name {
|
||||
font-size: 22rpx;
|
||||
color: #333;
|
||||
margin-top: 8rpx;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
max-width: 100rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 全部应用列表
|
||||
.all-apps-list {
|
||||
padding: 30rpx 30rpx 34rpx;
|
||||
}
|
||||
|
||||
// ---------- 通用徽标 ----------
|
||||
.badge {
|
||||
position: absolute;
|
||||
width: 36rpx;
|
||||
height: 36rpx;
|
||||
border-radius: 50%;
|
||||
font-size: 20rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #fff;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.badge-remove {
|
||||
top: -8rpx;
|
||||
right: -8rpx;
|
||||
background: #ff4d4f;
|
||||
}
|
||||
|
||||
.badge-add {
|
||||
top: -8rpx;
|
||||
right: 6rpx;
|
||||
background: #52c41a;
|
||||
}
|
||||
|
||||
.selected-overlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0, 0, 0, 0.35);
|
||||
border-radius: 8rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 1;
|
||||
|
||||
.selected-check {
|
||||
color: #fff;
|
||||
font-size: 28rpx;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.pos-relative {
|
||||
position: relative;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user