初始化移动端提交
This commit is contained in:
227
pages/index/category.vue
Normal file
227
pages/index/category.vue
Normal file
@@ -0,0 +1,227 @@
|
||||
<!-- 商品分类列表 -->
|
||||
<template>
|
||||
<s-layout :bgStyle="{ color: '#fff' }" tabbar="/pages/index/category" title="分类">
|
||||
<view class="s-category">
|
||||
<view class="three-level-wrap ss-flex ss-col-top">
|
||||
<!-- 商品分类(左) -->
|
||||
<view class="side-menu-wrap" :style="[{ top: Number(statusBarHeight + 88) + 'rpx' }]">
|
||||
<scroll-view scroll-y :style="[{ height: pageHeight + 'px' }]">
|
||||
<view
|
||||
class="menu-item ss-flex"
|
||||
v-for="(item, index) in state.categoryList"
|
||||
:key="item.id"
|
||||
:class="[{ 'menu-item-active': index === state.activeMenu }]"
|
||||
@tap="onMenu(index)"
|
||||
>
|
||||
<view class="menu-title ss-line-1">
|
||||
{{ item.name }}
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
<!-- 商品分类(右) -->
|
||||
<view class="goods-list-box" v-if="state.categoryList?.length">
|
||||
<scroll-view scroll-y :style="[{ height: pageHeight + 'px' }]">
|
||||
<image
|
||||
v-if="state.categoryList[state.activeMenu].picUrl"
|
||||
class="banner-img"
|
||||
:src="sheep.$url.cdn(state.categoryList[state.activeMenu].picUrl)"
|
||||
mode="widthFix"
|
||||
/>
|
||||
<first-one v-if="state.style === 'first_one'" :pagination="state.pagination" />
|
||||
<first-two v-if="state.style === 'first_two'" :pagination="state.pagination" />
|
||||
<second-one
|
||||
v-if="state.style === 'second_one'"
|
||||
:data="state.categoryList"
|
||||
:activeMenu="state.activeMenu"
|
||||
/>
|
||||
<uni-load-more
|
||||
v-if="
|
||||
(state.style === 'first_one' || state.style === 'first_two') &&
|
||||
state.pagination.total > 0
|
||||
"
|
||||
:status="state.loadStatus"
|
||||
:content-text="{
|
||||
contentdown: '点击查看更多',
|
||||
}"
|
||||
@tap="loadMore"
|
||||
/>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</s-layout>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import secondOne from './components/second-one.vue';
|
||||
import firstOne from './components/first-one.vue';
|
||||
import firstTwo from './components/first-two.vue';
|
||||
import sheep from '@/sheep';
|
||||
import { onLoad } from '@dcloudio/uni-app';
|
||||
import { computed, reactive } from 'vue';
|
||||
import _ from 'lodash-es';
|
||||
import { handleTree } from '@/sheep/helper/utils';
|
||||
|
||||
const state = reactive({
|
||||
style: 'second_one', // first_one(一级 - 样式一), first_two(二级 - 样式二), second_one(二级)
|
||||
categoryList: [], // 商品分类树
|
||||
activeMenu: 0, // 选中的一级菜单,在 categoryList 的下标
|
||||
|
||||
pagination: {
|
||||
// 商品分页
|
||||
list: [], // 商品列表
|
||||
total: [], // 商品总数
|
||||
pageNo: 1,
|
||||
pageSize: 6,
|
||||
},
|
||||
loadStatus: '',
|
||||
});
|
||||
|
||||
const { safeArea } = sheep.$platform.device;
|
||||
const pageHeight = computed(() => safeArea.height - 44 - 50);
|
||||
const statusBarHeight = sheep.$platform.device.statusBarHeight * 2;
|
||||
|
||||
// 加载商品分类
|
||||
async function getList() {
|
||||
// API已被移除,返回空数据
|
||||
state.categoryList = [];
|
||||
}
|
||||
|
||||
// 选中菜单
|
||||
const onMenu = (val) => {
|
||||
state.activeMenu = val;
|
||||
if (state.style === 'first_one' || state.style === 'first_two') {
|
||||
state.pagination.pageNo = 1;
|
||||
state.pagination.list = [];
|
||||
state.pagination.total = 0;
|
||||
getGoodsList();
|
||||
}
|
||||
};
|
||||
|
||||
// 加载商品列表
|
||||
async function getGoodsList() {
|
||||
// 加载列表
|
||||
state.loadStatus = 'loading';
|
||||
// API已被移除,返回空数据
|
||||
state.pagination.list = [];
|
||||
state.pagination.total = 0;
|
||||
state.loadStatus = 'noMore';
|
||||
}
|
||||
|
||||
// 加载更多商品
|
||||
function loadMore() {
|
||||
if (state.loadStatus === 'noMore') {
|
||||
return;
|
||||
}
|
||||
state.pagination.pageNo++;
|
||||
getGoodsList();
|
||||
}
|
||||
|
||||
onLoad(async (params) => {
|
||||
await getList();
|
||||
|
||||
// 首页点击分类的处理:查找满足条件的分类
|
||||
const foundCategory = state.categoryList.find((category) => category.id === Number(params.id));
|
||||
// 如果找到则调用 onMenu 自动勾选相应分类,否则调用 onMenu(0) 勾选第一个分类
|
||||
onMenu(foundCategory ? state.categoryList.indexOf(foundCategory) : 0);
|
||||
});
|
||||
|
||||
function handleScrollToLower() {
|
||||
loadMore();
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.s-category {
|
||||
:deep() {
|
||||
.side-menu-wrap {
|
||||
width: 200rpx;
|
||||
height: 100%;
|
||||
padding-left: 12rpx;
|
||||
background-color: #f6f6f6;
|
||||
position: fixed;
|
||||
left: 0;
|
||||
|
||||
.menu-item {
|
||||
width: 100%;
|
||||
height: 88rpx;
|
||||
position: relative;
|
||||
transition: all linear 0.2s;
|
||||
|
||||
.menu-title {
|
||||
line-height: 32rpx;
|
||||
font-size: 30rpx;
|
||||
font-weight: 400;
|
||||
color: #333;
|
||||
margin-left: 28rpx;
|
||||
position: relative;
|
||||
z-index: 0;
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
width: 64rpx;
|
||||
height: 12rpx;
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
var(--ui-BG-Main-gradient),
|
||||
var(--ui-BG-Main-light)
|
||||
) !important;
|
||||
position: absolute;
|
||||
left: -64rpx;
|
||||
bottom: 0;
|
||||
z-index: -1;
|
||||
transition: all linear 0.2s;
|
||||
}
|
||||
}
|
||||
|
||||
&.menu-item-active {
|
||||
background-color: #fff;
|
||||
border-radius: 20rpx 0 0 20rpx;
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: -20rpx;
|
||||
width: 20rpx;
|
||||
height: 20rpx;
|
||||
background: radial-gradient(circle at 0 100%, transparent 20rpx, #fff 0);
|
||||
}
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: -20rpx;
|
||||
right: 0;
|
||||
width: 20rpx;
|
||||
height: 20rpx;
|
||||
background: radial-gradient(circle at 0% 0%, transparent 20rpx, #fff 0);
|
||||
}
|
||||
|
||||
.menu-title {
|
||||
font-weight: 600;
|
||||
|
||||
&::before {
|
||||
left: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.goods-list-box {
|
||||
background-color: #fff;
|
||||
width: calc(100vw - 200rpx);
|
||||
padding: 10px;
|
||||
margin-left: 200rpx;
|
||||
}
|
||||
|
||||
.banner-img {
|
||||
width: calc(100vw - 130px);
|
||||
border-radius: 5px;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
23
pages/index/components/first-one.vue
Normal file
23
pages/index/components/first-one.vue
Normal file
@@ -0,0 +1,23 @@
|
||||
<!-- 分类展示:first-one 风格 -->
|
||||
<template>
|
||||
<view class="ss-flex-col">
|
||||
<!-- 商品组件已被移除 -->
|
||||
<view class="empty-message" style="text-align: center; padding: 50px; color: #999;">
|
||||
暂无商品数据
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import sheep from '@/sheep';
|
||||
|
||||
const props = defineProps({
|
||||
pagination: Object,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.goods-box {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
66
pages/index/components/first-two.vue
Normal file
66
pages/index/components/first-two.vue
Normal file
@@ -0,0 +1,66 @@
|
||||
<!-- 分类展示:first-two 风格 -->
|
||||
<template>
|
||||
<view>
|
||||
<view class="ss-flex flex-wrap">
|
||||
<view class="goods-box" v-for="item in pagination?.list" :key="item.id">
|
||||
<view @click="sheep.$router.go('/pages/goods/index', { id: item.id })">
|
||||
<view class="goods-img">
|
||||
<image class="goods-img" :src="item.picUrl" mode="aspectFit" />
|
||||
</view>
|
||||
<view class="goods-content">
|
||||
<view class="goods-title ss-line-1 ss-m-b-28">{{ item.name }}</view>
|
||||
<view class="goods-price">¥{{ fen2yuan(item.price) }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import sheep from '@/sheep';
|
||||
import { fen2yuan } from '@/sheep/hooks/useGoods';
|
||||
|
||||
const props = defineProps({
|
||||
pagination: Object,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.goods-box {
|
||||
width: calc((100% - 20rpx) / 2);
|
||||
margin-bottom: 20rpx;
|
||||
|
||||
.goods-img {
|
||||
width: 100%;
|
||||
height: 246rpx;
|
||||
border-radius: 10rpx 10rpx 0px 0px;
|
||||
}
|
||||
|
||||
.goods-content {
|
||||
width: 100%;
|
||||
background: #ffffff;
|
||||
box-shadow: 0px 0px 20rpx 4rpx rgba(199, 199, 199, 0.22);
|
||||
padding: 20rpx 0 32rpx 16rpx;
|
||||
box-sizing: border-box;
|
||||
border-radius: 0 0 10rpx 10rpx;
|
||||
|
||||
.goods-title {
|
||||
font-size: 26rpx;
|
||||
font-weight: bold;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.goods-price {
|
||||
font-size: 24rpx;
|
||||
font-family: OPPOSANS;
|
||||
font-weight: 500;
|
||||
color: #e1212b;
|
||||
}
|
||||
}
|
||||
|
||||
&:nth-child(2n + 1) {
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
80
pages/index/components/second-one.vue
Normal file
80
pages/index/components/second-one.vue
Normal file
@@ -0,0 +1,80 @@
|
||||
<!-- 分类展示:second-one 风格 -->
|
||||
<template>
|
||||
<view>
|
||||
<!-- 一级分类的名字 -->
|
||||
<view class="title-box ss-flex ss-col-center ss-row-center ss-p-b-30">
|
||||
<view class="title-line-left" />
|
||||
<view class="title-text ss-p-x-20">{{ props.data[activeMenu].name }}</view>
|
||||
<view class="title-line-right" />
|
||||
</view>
|
||||
<!-- 二级分类的名字 -->
|
||||
<view class="goods-item-box ss-flex ss-flex-wrap ss-p-b-20">
|
||||
<view
|
||||
class="goods-item"
|
||||
v-for="item in props.data[activeMenu].children"
|
||||
:key="item.id"
|
||||
@tap="
|
||||
sheep.$router.go('/pages/goods/list', {
|
||||
categoryId: item.id,
|
||||
})
|
||||
"
|
||||
>
|
||||
<image class="goods-img" :src="item.picUrl" mode="aspectFill" />
|
||||
<view class="ss-p-10">
|
||||
<view class="goods-title ss-line-1">{{ item.name }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import sheep from '@/sheep';
|
||||
|
||||
const props = defineProps({
|
||||
data: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
activeMenu: [Number, String],
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.title-box {
|
||||
.title-line-left,
|
||||
.title-line-right {
|
||||
width: 15px;
|
||||
height: 1px;
|
||||
background: #d2d2d2;
|
||||
}
|
||||
}
|
||||
|
||||
.goods-item {
|
||||
width: calc((100% - 20px) / 3);
|
||||
margin-right: 10px;
|
||||
margin-bottom: 10px;
|
||||
|
||||
&:nth-of-type(3n) {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.goods-img {
|
||||
width: calc((100vw - 140px) / 3);
|
||||
height: calc((100vw - 140px) / 3);
|
||||
}
|
||||
|
||||
.goods-title {
|
||||
font-size: 26rpx;
|
||||
font-weight: bold;
|
||||
color: #333333;
|
||||
line-height: 40rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.goods-price {
|
||||
color: $red;
|
||||
line-height: 40rpx;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
547
pages/index/index.vue
Normal file
547
pages/index/index.vue
Normal file
@@ -0,0 +1,547 @@
|
||||
<!-- 首页 - 重新设计 -->
|
||||
<template>
|
||||
<view class="container">
|
||||
<s-layout
|
||||
title="首页"
|
||||
navbar="custom"
|
||||
tabbar="/pages/index/index"
|
||||
onShareAppMessage
|
||||
>
|
||||
<!-- 用户信息区域 - 使用 uview-plus Card 组件 -->
|
||||
<u-card
|
||||
v-if="isLogin"
|
||||
:show-head="false"
|
||||
:show-foot="false"
|
||||
margin="30rpx"
|
||||
>
|
||||
<template #body>
|
||||
<view class="user-info-section">
|
||||
<view class="user-avatar">
|
||||
<s-avatar
|
||||
:src="userInfo.avatar"
|
||||
:nickname="userInfo.nickname || userInfo.username"
|
||||
:size="60"
|
||||
:bg-color="getAvatarBgColor(userInfo.nickname || userInfo.username)"
|
||||
@click="handleUserClick"
|
||||
/>
|
||||
</view>
|
||||
<view class="user-details">
|
||||
<u-text
|
||||
:text="userInfo.nickname || '用户'"
|
||||
size="18"
|
||||
color="#333"
|
||||
bold
|
||||
/>
|
||||
<u-text
|
||||
:text="userInfo.mobile || '欢迎使用系统'"
|
||||
size="14"
|
||||
color="#999"
|
||||
margin="6rpx 0 0 0"
|
||||
/>
|
||||
</view>
|
||||
<view class="user-actions">
|
||||
<u-button
|
||||
text="个人中心"
|
||||
size="mini"
|
||||
type="primary"
|
||||
plain
|
||||
@click="navigateTo('/pages/index/user')"
|
||||
margin="0 0 10rpx 0"
|
||||
/>
|
||||
<u-button
|
||||
text="退出登录"
|
||||
size="mini"
|
||||
type="error"
|
||||
plain
|
||||
@click="handleLogout"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</u-card>
|
||||
|
||||
<!-- 未登录提示区域 - 使用 uview-plus Card 和 Button -->
|
||||
<u-card
|
||||
v-else
|
||||
:show-head="false"
|
||||
:show-foot="false"
|
||||
margin="30rpx"
|
||||
>
|
||||
<template #body>
|
||||
<view class="login-prompt">
|
||||
<view class="prompt-content">
|
||||
<u-text text="欢迎使用" size="20" color="#333" bold />
|
||||
<u-text
|
||||
text="请先登录以使用完整功能"
|
||||
size="14"
|
||||
color="#999"
|
||||
margin="10rpx 0 30rpx 0"
|
||||
/>
|
||||
<u-button
|
||||
text="立即登录"
|
||||
type="primary"
|
||||
size="normal"
|
||||
@click="goToLogin"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</u-card>
|
||||
|
||||
<!-- 功能模块入口 - 使用 uview-plus Grid 组件 -->
|
||||
<u-card
|
||||
v-if="isLogin"
|
||||
:show-head="false"
|
||||
:show-foot="false"
|
||||
margin="30rpx"
|
||||
>
|
||||
<template #body>
|
||||
<view class="function-modules">
|
||||
<view class="section-title">
|
||||
<u-text text="功能模块" size="16" color="#333" bold />
|
||||
</view>
|
||||
<u-grid :col="3" :border="false">
|
||||
<u-grid-item
|
||||
v-for="module in functionModules"
|
||||
:key="module.id"
|
||||
@click="handleModuleClick(module)"
|
||||
>
|
||||
<view class="module-content">
|
||||
<view class="module-icon" :style="{ backgroundColor: module.color + '20' }">
|
||||
<u-icon :name="module.icon" size="24" :color="module.color" />
|
||||
</view>
|
||||
<u-text
|
||||
:text="module.name"
|
||||
size="12"
|
||||
color="#666"
|
||||
margin="10rpx 0 0 0"
|
||||
/>
|
||||
</view>
|
||||
</u-grid-item>
|
||||
</u-grid>
|
||||
</view>
|
||||
</template>
|
||||
</u-card>
|
||||
|
||||
</s-layout>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { onLoad, onPullDownRefresh, onShow } from '@dcloudio/uni-app';
|
||||
import { computed, ref } from 'vue';
|
||||
import sheep from '@/sheep';
|
||||
import { getAvatarBgColor } from '@/sheep/utils/avatar.js';
|
||||
|
||||
// 隐藏原生tabBar
|
||||
uni.hideTabBar({
|
||||
fail: () => {},
|
||||
});
|
||||
|
||||
// 跳转到登录页
|
||||
function goToLogin() {
|
||||
uni.navigateTo({
|
||||
url: '/pages/login/index'
|
||||
});
|
||||
}
|
||||
|
||||
const isLogin = computed(() => sheep.$store('user').isLogin);
|
||||
const userInfo = computed(() => sheep.$store('user').userInfo);
|
||||
|
||||
// 用于防止重复验证
|
||||
let isValidating = false;
|
||||
|
||||
// 用户头像点击事件
|
||||
function handleUserClick() {
|
||||
if (!isLogin.value) {
|
||||
goToLogin();
|
||||
return;
|
||||
}
|
||||
uni.navigateTo({
|
||||
url: '/pages/index/user'
|
||||
});
|
||||
}
|
||||
|
||||
// 格式化最后登录时间
|
||||
const formatLastLoginTime = computed(() => {
|
||||
const now = new Date();
|
||||
return `${now.getMonth() + 1}月${now.getDate()}日 ${now.getHours()}:${now.getMinutes().toString().padStart(2, '0')}`;
|
||||
});
|
||||
|
||||
// 功能模块数据
|
||||
const functionModules = ref([
|
||||
{
|
||||
id: 'profile',
|
||||
name: '个人资料',
|
||||
icon: 'account',
|
||||
color: 'var(--ui-BG-Main)', // 主题色
|
||||
path: '/pages/index/user'
|
||||
},
|
||||
{
|
||||
id: 'settings',
|
||||
name: '系统设置',
|
||||
icon: 'setting',
|
||||
color: '#666666', // $dark-6
|
||||
action: 'showSettings'
|
||||
},
|
||||
{
|
||||
id: 'security',
|
||||
name: '安全中心',
|
||||
icon: 'lock',
|
||||
color: '#d10019', // $red
|
||||
action: 'showSecurity'
|
||||
},
|
||||
{
|
||||
id: 'feedback',
|
||||
name: '意见反馈',
|
||||
icon: 'chat',
|
||||
color: '#8dc63f', // $green
|
||||
action: 'showFeedback'
|
||||
}
|
||||
]);
|
||||
|
||||
// 快捷操作数据
|
||||
const quickActions = ref([
|
||||
|
||||
{
|
||||
id: 'logout',
|
||||
title: '退出登录',
|
||||
desc: '安全退出当前账户',
|
||||
icon: 'logout',
|
||||
action: 'logout'
|
||||
}
|
||||
]);
|
||||
|
||||
onLoad((options) => {
|
||||
console.log('首页加载完成');
|
||||
checkLoginStatus();
|
||||
});
|
||||
|
||||
onShow(() => {
|
||||
// 只有在页面从后台返回前台时才需要重新验证登录状态
|
||||
// 避免首次加载时的重复验证
|
||||
console.log('页面显示,检查是否需要验证登录状态');
|
||||
|
||||
// 延迟一点时间,确保不与onLoad的验证冲突
|
||||
setTimeout(() => {
|
||||
checkLoginStatus();
|
||||
}, 100);
|
||||
});
|
||||
|
||||
onPullDownRefresh(async () => {
|
||||
console.log('下拉刷新');
|
||||
try {
|
||||
// 刷新用户信息
|
||||
if (isLogin.value) {
|
||||
await sheep.$store('user').getInfo();
|
||||
console.log('用户信息刷新成功');
|
||||
}
|
||||
} catch (error) {
|
||||
console.log('刷新用户信息失败,可能登录已过期', error);
|
||||
// 如果刷新失败,可能是登录过期,重新验证登录状态
|
||||
await checkLoginStatus();
|
||||
} finally {
|
||||
setTimeout(() => {
|
||||
uni.stopPullDownRefresh();
|
||||
}, 1000);
|
||||
}
|
||||
});
|
||||
|
||||
// 检查登录状态
|
||||
async function checkLoginStatus() {
|
||||
// 防止重复验证
|
||||
if (isValidating) {
|
||||
console.log('正在验证中,跳过重复验证');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('检查登录状态...');
|
||||
|
||||
// 如果本地显示未登录,直接跳转到登录页
|
||||
if (!isLogin.value) {
|
||||
console.log('本地状态未登录,跳转到登录页');
|
||||
setTimeout(() => {
|
||||
goToLogin();
|
||||
}, 500);
|
||||
return;
|
||||
}
|
||||
|
||||
// 如果本地显示已登录,需要验证token是否还有效
|
||||
console.log('本地状态已登录,验证token有效性...');
|
||||
isValidating = true;
|
||||
|
||||
try {
|
||||
// 尝试获取用户信息来验证token是否有效
|
||||
await sheep.$store('user').getInfo();
|
||||
console.log('Token有效,用户已登录');
|
||||
} catch (error) {
|
||||
console.log('Token已失效,需要重新登录', error);
|
||||
// 清除本地登录状态
|
||||
sheep.$store('user').logout(false);
|
||||
// 延迟显示登录弹窗,确保页面渲染完成
|
||||
setTimeout(() => {
|
||||
uni.showToast({
|
||||
title: '登录已过期,请重新登录',
|
||||
icon: 'none',
|
||||
duration: 2000
|
||||
});
|
||||
setTimeout(() => {
|
||||
goToLogin();
|
||||
}, 2000);
|
||||
}, 500);
|
||||
} finally {
|
||||
// 验证完成,重置标志
|
||||
setTimeout(() => {
|
||||
isValidating = false;
|
||||
}, 1000);
|
||||
}
|
||||
}
|
||||
|
||||
// 导航到指定页面
|
||||
function navigateTo(path) {
|
||||
uni.navigateTo({
|
||||
url: path
|
||||
});
|
||||
}
|
||||
|
||||
// 处理退出登录
|
||||
function handleLogout() {
|
||||
uni.showModal({
|
||||
title: '退出登录',
|
||||
content: '确定要退出登录吗?',
|
||||
showCancel: true,
|
||||
confirmText: '确定',
|
||||
cancelText: '取消',
|
||||
success: async (res) => {
|
||||
if (res.confirm) {
|
||||
try {
|
||||
// 显示加载提示
|
||||
uni.showLoading({
|
||||
title: '退出中...',
|
||||
mask: true
|
||||
});
|
||||
|
||||
// 调用退出登录API
|
||||
await sheep.$store('user').logout(true);
|
||||
|
||||
// 隐藏加载提示
|
||||
uni.hideLoading();
|
||||
|
||||
// 显示退出成功提示
|
||||
uni.showToast({
|
||||
title: '退出成功',
|
||||
icon: 'success',
|
||||
duration: 1500
|
||||
});
|
||||
|
||||
// 延迟跳转到登录页
|
||||
setTimeout(() => {
|
||||
goToLogin();
|
||||
}, 1500);
|
||||
|
||||
} catch (error) {
|
||||
// 隐藏加载提示
|
||||
uni.hideLoading();
|
||||
|
||||
console.error('退出登录失败:', error);
|
||||
uni.showToast({
|
||||
title: '退出失败,请重试',
|
||||
icon: 'none',
|
||||
duration: 2000
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 处理模块点击
|
||||
function handleModuleClick(module) {
|
||||
if (module.path) {
|
||||
navigateTo(module.path);
|
||||
} else if (module.action) {
|
||||
handleAction(module.action);
|
||||
}
|
||||
}
|
||||
|
||||
// 处理快捷操作点击
|
||||
function handleActionClick(action) {
|
||||
handleAction(action.action);
|
||||
}
|
||||
|
||||
// 处理各种操作
|
||||
function handleAction(action) {
|
||||
switch (action) {
|
||||
case 'showSettings':
|
||||
uni.showToast({
|
||||
title: '系统设置功能开发中',
|
||||
icon: 'none'
|
||||
});
|
||||
break;
|
||||
case 'showSecurity':
|
||||
uni.showToast({
|
||||
title: '安全中心功能开发中',
|
||||
icon: 'none'
|
||||
});
|
||||
break;
|
||||
case 'showFeedback':
|
||||
uni.showToast({
|
||||
title: '意见反馈功能开发中',
|
||||
icon: 'none'
|
||||
});
|
||||
break;
|
||||
case 'showAbout':
|
||||
uni.showModal({
|
||||
title: '关于应用',
|
||||
content: '应用版本:v1.0.0\n开发者:Yudao Team\n更新时间:2024年',
|
||||
showCancel: false
|
||||
});
|
||||
break;
|
||||
case 'scanCode':
|
||||
uni.scanCode({
|
||||
success: (res) => {
|
||||
uni.showModal({
|
||||
title: '扫描结果',
|
||||
content: res.result,
|
||||
showCancel: false
|
||||
});
|
||||
},
|
||||
fail: (err) => {
|
||||
uni.showToast({
|
||||
title: '扫描失败',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
});
|
||||
break;
|
||||
case 'shareApp':
|
||||
uni.share({
|
||||
provider: 'weixin',
|
||||
scene: 'WXSceneSession',
|
||||
type: 0,
|
||||
href: '',
|
||||
title: '推荐一个好用的应用',
|
||||
summary: '快来试试这个应用吧!',
|
||||
imageUrl: ''
|
||||
});
|
||||
break;
|
||||
case 'clearCache':
|
||||
uni.showModal({
|
||||
title: '清理缓存',
|
||||
content: '确定要清理应用缓存吗?',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
// 这里可以添加清理缓存的逻辑
|
||||
uni.clearStorageSync();
|
||||
uni.showToast({
|
||||
title: '缓存清理完成',
|
||||
icon: 'success'
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
break;
|
||||
case 'logout':
|
||||
handleLogout();
|
||||
break;
|
||||
default:
|
||||
uni.showToast({
|
||||
title: '功能开发中',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.container {
|
||||
min-height: 100vh;
|
||||
background: #f5f5f5;
|
||||
}
|
||||
|
||||
/* 用户信息区域 */
|
||||
.user-info-section {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 20rpx;
|
||||
}
|
||||
|
||||
.user-avatar {
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
|
||||
.user-details {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.user-actions {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10rpx;
|
||||
}
|
||||
|
||||
/* 未登录提示区域 */
|
||||
.login-prompt {
|
||||
text-align: center;
|
||||
padding: 40rpx 20rpx;
|
||||
}
|
||||
|
||||
.prompt-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 10rpx;
|
||||
}
|
||||
|
||||
/* 功能模块 */
|
||||
.function-modules {
|
||||
padding: 20rpx;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.module-content {
|
||||
text-align: center;
|
||||
padding: 20rpx 10rpx;
|
||||
}
|
||||
|
||||
.module-icon {
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin: 0 auto 10rpx;
|
||||
}
|
||||
|
||||
/* 快捷操作 */
|
||||
.quick-actions {
|
||||
padding: 20rpx;
|
||||
}
|
||||
|
||||
.action-icon {
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-right: 15rpx;
|
||||
background: #f0f0f0;
|
||||
border-radius: 8rpx;
|
||||
}
|
||||
|
||||
/* 系统信息 */
|
||||
.system-info {
|
||||
padding: 20rpx;
|
||||
}
|
||||
|
||||
.info-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 15rpx 0;
|
||||
}
|
||||
</style>
|
||||
39
pages/index/login.vue
Normal file
39
pages/index/login.vue
Normal file
@@ -0,0 +1,39 @@
|
||||
<!-- 微信公众号的登录回调页 -->
|
||||
<template>
|
||||
<!-- 空登陆页 -->
|
||||
<view />
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import sheep from '@/sheep';
|
||||
import { onLoad } from '@dcloudio/uni-app';
|
||||
|
||||
onLoad(async (options) => {
|
||||
// #ifdef H5
|
||||
// 将 search 参数赋值到 options 中,方便下面解析
|
||||
new URLSearchParams(location.search).forEach((value, key) => {
|
||||
options[key] = value;
|
||||
});
|
||||
// 执行登录 or 绑定,注意需要 await 绑定
|
||||
const event = options.event;
|
||||
const code = options.code;
|
||||
const state = options.state;
|
||||
if (event === 'login') { // 场景一:登录
|
||||
await sheep.$platform.useProvider().login(code, state);
|
||||
} else if (event === 'bind') { // 场景二:绑定
|
||||
await sheep.$platform.useProvider().bind(code, state);
|
||||
}
|
||||
|
||||
// 检测 H5 登录回调
|
||||
let returnUrl = uni.getStorageSync('returnUrl');
|
||||
if (returnUrl) {
|
||||
uni.removeStorage({key:'returnUrl'});
|
||||
location.replace(returnUrl);
|
||||
} else {
|
||||
uni.switchTab({
|
||||
url: '/',
|
||||
});
|
||||
}
|
||||
// #endif
|
||||
});
|
||||
</script>
|
||||
266
pages/index/menu.vue
Normal file
266
pages/index/menu.vue
Normal file
@@ -0,0 +1,266 @@
|
||||
<!-- 菜单页面 -->
|
||||
<template>
|
||||
<s-layout
|
||||
title="菜单"
|
||||
tabbar="/pages/index/menu"
|
||||
navbar="custom"
|
||||
onShareAppMessage
|
||||
>
|
||||
<view class="menu-container">
|
||||
<!-- 轮播图 -->
|
||||
<view class="swiper-section">
|
||||
<swiper
|
||||
class="swiper-container"
|
||||
:indicator-dots="true"
|
||||
:autoplay="true"
|
||||
:interval="3000"
|
||||
:duration="500"
|
||||
indicator-color="rgba(255, 255, 255, 0.3)"
|
||||
indicator-active-color="#fff"
|
||||
circular
|
||||
>
|
||||
<swiper-item v-for="(item, index) in swiperList" :key="index">
|
||||
<view class="swiper-item">
|
||||
<image :src="item.image" mode="aspectFill" class="swiper-image" />
|
||||
</view>
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
</view>
|
||||
|
||||
<!-- 工作台 -->
|
||||
<view class="section">
|
||||
<view class="section-title">工作台</view>
|
||||
<view class="grid-container">
|
||||
<view
|
||||
class="grid-item"
|
||||
v-for="(item, index) in quickMenuList"
|
||||
:key="index"
|
||||
@click="handleMenuClick(item)"
|
||||
>
|
||||
<view class="item-icon" :style="{ background: item.bg }">
|
||||
<u-icon
|
||||
:name="item.icon"
|
||||
size="24"
|
||||
:color="item.color"
|
||||
/>
|
||||
</view>
|
||||
<view class="item-title">{{ item.title }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</s-layout>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import sheep from '@/sheep';
|
||||
|
||||
export default {
|
||||
onShow() {
|
||||
const userStore = sheep.$store('user');
|
||||
if (!userStore.isLogin) {
|
||||
sheep.$router.redirect('/pages/login/index');
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// 轮播图数据
|
||||
swiperList: [
|
||||
{
|
||||
image: '/static/images/swiper/bg1.png',
|
||||
title: '轮播图1'
|
||||
},
|
||||
{
|
||||
image: '/static/images/swiper/bg2.png',
|
||||
title: '轮播图2'
|
||||
},
|
||||
{
|
||||
image: '/static/images/swiper/bg3.png',
|
||||
title: '轮播图3'
|
||||
}
|
||||
],
|
||||
|
||||
// 工作台功能数据
|
||||
quickMenuList: [
|
||||
{
|
||||
title: 'Demo',
|
||||
icon: 'file-text',
|
||||
color: '#fff',
|
||||
bg: '#3c9cff',
|
||||
path: '/pages/app/democontract/index'
|
||||
},
|
||||
|
||||
]
|
||||
};
|
||||
},
|
||||
|
||||
methods: {
|
||||
// 处理菜单点击
|
||||
handleMenuClick(item) {
|
||||
sheep.$router.go(item.path);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.menu-container {
|
||||
min-height: 100vh;
|
||||
background-color: #f8f9fa;
|
||||
padding: 20rpx;
|
||||
}
|
||||
|
||||
/* 轮播图样式 */
|
||||
.swiper-section {
|
||||
margin-bottom: 30rpx;
|
||||
|
||||
.swiper-container {
|
||||
height: 300rpx;
|
||||
border-radius: 20rpx;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1);
|
||||
|
||||
.swiper-item {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
.swiper-image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.section {
|
||||
margin-bottom: 40rpx;
|
||||
|
||||
.section-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
margin-bottom: 30rpx;
|
||||
padding-left: 10rpx;
|
||||
}
|
||||
}
|
||||
|
||||
/* 快捷功能网格布局 */
|
||||
.grid-container {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 20rpx;
|
||||
|
||||
.grid-item {
|
||||
background: #fff;
|
||||
border-radius: 16rpx;
|
||||
padding: 30rpx 20rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.05);
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&:active {
|
||||
transform: translateY(2rpx);
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.item-icon {
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
border-radius: 20rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.item-title {
|
||||
font-size: 24rpx;
|
||||
color: #606266;
|
||||
text-align: center;
|
||||
line-height: 1.2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 管理功能列表布局 */
|
||||
.list-container {
|
||||
background: #fff;
|
||||
border-radius: 16rpx;
|
||||
padding: 0 30rpx;
|
||||
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.05);
|
||||
|
||||
.list-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 30rpx 0;
|
||||
border-bottom: 1px solid #f5f5f5;
|
||||
transition: background-color 0.3s ease;
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
&:active {
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
|
||||
.item-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex: 1;
|
||||
|
||||
.item-icon-small {
|
||||
width: 64rpx;
|
||||
height: 64rpx;
|
||||
border-radius: 12rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-right: 24rpx;
|
||||
}
|
||||
|
||||
.item-info {
|
||||
flex: 1;
|
||||
|
||||
.item-title {
|
||||
font-size: 28rpx;
|
||||
color: #303133;
|
||||
margin-bottom: 8rpx;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.item-desc {
|
||||
font-size: 22rpx;
|
||||
color: #909399;
|
||||
line-height: 1.3;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 响应式调整 */
|
||||
@media screen and (max-width: 750rpx) {
|
||||
.grid-container {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 16rpx;
|
||||
}
|
||||
|
||||
.grid-item {
|
||||
padding: 24rpx 16rpx;
|
||||
|
||||
.item-icon {
|
||||
width: 64rpx;
|
||||
height: 64rpx;
|
||||
}
|
||||
|
||||
.item-title {
|
||||
font-size: 22rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
51
pages/index/page.vue
Normal file
51
pages/index/page.vue
Normal file
@@ -0,0 +1,51 @@
|
||||
<!-- 自定义页面:支持装修 -->
|
||||
<template>
|
||||
<s-layout
|
||||
:title="state.name"
|
||||
navbar="custom"
|
||||
:bgStyle="state.page"
|
||||
:navbarStyle="state.navigationBar"
|
||||
onShareAppMessage
|
||||
showLeftButton
|
||||
>
|
||||
<s-block v-for="(item, index) in state.components" :key="index" :styles="item.property.style">
|
||||
<s-block-item :type="item.id" :data="item.property" :styles="item.property.style" />
|
||||
</s-block>
|
||||
</s-layout>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { reactive } from 'vue';
|
||||
import { onLoad, onPageScroll } from '@dcloudio/uni-app';
|
||||
// Diy API removed with promotion module
|
||||
|
||||
const state = reactive({
|
||||
name: '',
|
||||
components: [],
|
||||
navigationBar: {},
|
||||
page: {},
|
||||
});
|
||||
onLoad(async (options) => {
|
||||
let id = options.id
|
||||
|
||||
// #ifdef MP
|
||||
// 小程序预览自定义页面
|
||||
if (options.scene) {
|
||||
const sceneParams = decodeURIComponent(options.scene).split('=');
|
||||
id = sceneParams[1];
|
||||
}
|
||||
// #endif
|
||||
|
||||
const { code, data } = await DiyApi.getDiyPage(id);
|
||||
if (code === 0) {
|
||||
state.name = data.name;
|
||||
state.components = data.property?.components;
|
||||
state.navigationBar = data.property?.navigationBar;
|
||||
state.page = data.property?.page;
|
||||
}
|
||||
});
|
||||
|
||||
onPageScroll(() => {});
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
144
pages/index/search.vue
Normal file
144
pages/index/search.vue
Normal file
@@ -0,0 +1,144 @@
|
||||
<!-- 搜索界面 -->
|
||||
<template>
|
||||
<s-layout :bgStyle="{ color: '#FFF' }" class="set-wrap" title="搜索">
|
||||
<view class="search-container">
|
||||
<view class="search-input-wrapper">
|
||||
<u-search
|
||||
v-model="searchText"
|
||||
placeholder="请输入关键字"
|
||||
:show-action="false"
|
||||
:focus="true"
|
||||
shape="square"
|
||||
@search="onSearch"
|
||||
@confirm="onSearch"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<!-- 搜索历史标题 -->
|
||||
<view class="search-section">
|
||||
<view class="section-header">
|
||||
<u-text text="搜索历史" size="16" bold color="#333" />
|
||||
<u-button
|
||||
text="清除搜索历史"
|
||||
size="mini"
|
||||
type="error"
|
||||
plain
|
||||
@click="onDelete"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<!-- 历史标签 -->
|
||||
<view class="history-tags" v-if="state.historyList.length">
|
||||
<u-tag
|
||||
v-for="(item, index) in state.historyList"
|
||||
:key="index"
|
||||
:text="item"
|
||||
type="info"
|
||||
plain
|
||||
size="medium"
|
||||
closable
|
||||
@click="onSearch(item)"
|
||||
@close="removeHistoryItem(index)"
|
||||
:custom-style="{ margin: '5rpx 10rpx 5rpx 0' }"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<!-- 无历史提示 -->
|
||||
<u-empty
|
||||
v-else
|
||||
mode="search"
|
||||
text="暂无搜索历史"
|
||||
textSize="14"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
</s-layout>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { reactive, ref } from 'vue';
|
||||
import sheep from '@/sheep';
|
||||
import { onLoad } from '@dcloudio/uni-app';
|
||||
|
||||
const searchText = ref('');
|
||||
const state = reactive({
|
||||
historyList: [],
|
||||
});
|
||||
|
||||
// 搜索
|
||||
function onSearch(keyword = '') {
|
||||
const searchKeyword = keyword || searchText.value;
|
||||
if (!searchKeyword) {
|
||||
return;
|
||||
}
|
||||
saveSearchHistory(searchKeyword);
|
||||
// 前往商品列表(带搜索条件)
|
||||
sheep.$router.go('/pages/goods/list', { keyword: searchKeyword });
|
||||
}
|
||||
|
||||
// 移除单个历史记录
|
||||
function removeHistoryItem(index) {
|
||||
state.historyList.splice(index, 1);
|
||||
uni.setStorageSync('searchHistory', state.historyList);
|
||||
}
|
||||
|
||||
// 保存搜索历史
|
||||
function saveSearchHistory(keyword) {
|
||||
// 如果关键词在搜索历史中,则把此关键词先移除
|
||||
if (state.historyList.includes(keyword)) {
|
||||
state.historyList.splice(state.historyList.indexOf(keyword), 1);
|
||||
}
|
||||
// 置顶关键词
|
||||
state.historyList.unshift(keyword);
|
||||
|
||||
// 最多保留 10 条记录
|
||||
if (state.historyList.length >= 10) {
|
||||
state.historyList.length = 10;
|
||||
}
|
||||
uni.setStorageSync('searchHistory', state.historyList);
|
||||
}
|
||||
|
||||
function onDelete() {
|
||||
uni.$u.modal({
|
||||
title: '提示',
|
||||
content: '确认清除搜索历史吗?',
|
||||
showCancelButton: true,
|
||||
confirmText: '确定',
|
||||
cancelText: '取消'
|
||||
}).then(res => {
|
||||
if (res) {
|
||||
state.historyList = [];
|
||||
uni.removeStorageSync('searchHistory');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
onLoad(() => {
|
||||
state.historyList = uni.getStorageSync('searchHistory') || [];
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.search-container {
|
||||
padding: 30rpx;
|
||||
}
|
||||
|
||||
.search-input-wrapper {
|
||||
margin-bottom: 40rpx;
|
||||
}
|
||||
|
||||
.search-section {
|
||||
.section-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.history-tags {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: flex-start;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
258
pages/index/user.vue
Normal file
258
pages/index/user.vue
Normal file
@@ -0,0 +1,258 @@
|
||||
<!-- 个人中心 -->
|
||||
<template>
|
||||
<s-layout
|
||||
title="我的"
|
||||
tabbar="/pages/index/user"
|
||||
navbar="custom"
|
||||
onShareAppMessage
|
||||
>
|
||||
<view class="user-container">
|
||||
<!-- 用户信息卡片 -->
|
||||
<view class="user-card">
|
||||
<view class="user-info">
|
||||
<view class="avatar-section" @click="handleAvatarClick">
|
||||
<s-avatar
|
||||
:src="userInfo.avatar"
|
||||
:nickname="userInfo.nickname || userInfo.username"
|
||||
:size="80"
|
||||
:bg-color="getAvatarBgColor(userInfo.nickname || userInfo.username)"
|
||||
/>
|
||||
<view class="user-details">
|
||||
<view class="user-name">{{ userInfo.nickname || userInfo.username || '未登录' }}</view>
|
||||
<view class="user-desc">{{ userInfo.mobile || '点击登录获取更多功能' }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 功能菜单 -->
|
||||
<view class="menu-section">
|
||||
<view class="menu-group">
|
||||
<view class="group-title">账户管理</view>
|
||||
<view class="menu-list">
|
||||
<view class="menu-item" @click="goToUserInfo">
|
||||
<view class="item-left">
|
||||
<view class="item-icon" style="background: var(--ui-BG-Main-opacity-1);">
|
||||
<u-icon name="account" size="20" color="var(--ui-BG-Main)"/>
|
||||
</view>
|
||||
<view class="item-title">个人信息</view>
|
||||
</view>
|
||||
<u-icon name="arrow-right" size="16" color="#c0c4cc"/>
|
||||
</view>
|
||||
<view class="menu-item" @click="goToAbout">
|
||||
<view class="item-left">
|
||||
<view class="item-icon" style="background: var(--ui-BG-Main-opacity-1);">
|
||||
<u-icon name="info-circle" size="20" color="var(--ui-BG-Main)"/>
|
||||
</view>
|
||||
<view class="item-title">关于我们</view>
|
||||
</view>
|
||||
<u-icon name="arrow-right" size="16" color="#c0c4cc"/>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 退出登录按钮 -->
|
||||
<view class="logout-section" v-if="isLogin">
|
||||
<view class="logout-btn" @click="handleLogout">
|
||||
退出登录
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</s-layout>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed } from 'vue';
|
||||
import { onShow, onPullDownRefresh } from '@dcloudio/uni-app';
|
||||
import sheep from '@/sheep';
|
||||
import { getAvatarBgColor } from '@/sheep/utils/avatar.js';
|
||||
|
||||
// 用户信息
|
||||
const userInfo = computed(() => sheep.$store('user').userInfo);
|
||||
const isLogin = computed(() => sheep.$store('user').isLogin);
|
||||
|
||||
// 页面事件
|
||||
onShow(() => {
|
||||
// 先检查登录状态,未登录则会自动跳转到登录页
|
||||
if (!sheep.$store('user').isLogin) {
|
||||
return;
|
||||
}
|
||||
// 已登录时更新用户数据
|
||||
sheep.$store('user').updateUserData();
|
||||
});
|
||||
|
||||
onPullDownRefresh(() => {
|
||||
sheep.$store('user').updateUserData();
|
||||
setTimeout(() => {
|
||||
uni.stopPullDownRefresh();
|
||||
}, 1000);
|
||||
});
|
||||
|
||||
// 头像点击事件
|
||||
function handleAvatarClick() {
|
||||
// 跳转到个人信息页面编辑头像
|
||||
uni.navigateTo({
|
||||
url: '/pages/user/info'
|
||||
});
|
||||
}
|
||||
|
||||
// 方法
|
||||
function goToUserInfo() {
|
||||
uni.navigateTo({
|
||||
url: '/pages/user/info'
|
||||
});
|
||||
}
|
||||
|
||||
function goToAbout() {
|
||||
uni.navigateTo({
|
||||
url: '/pages/public/about'
|
||||
});
|
||||
}
|
||||
|
||||
function handleLogout() {
|
||||
uni.showModal({
|
||||
title: '提示',
|
||||
content: '确定要退出登录吗?',
|
||||
confirmText: '确定',
|
||||
cancelText: '取消',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
sheep.$store('user').logout();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.user-container {
|
||||
min-height: 100vh;
|
||||
background-color: #f8f9fa;
|
||||
padding: 20rpx;
|
||||
}
|
||||
|
||||
/* 用户信息卡片 */
|
||||
.user-card {
|
||||
background: var(--gradient-diagonal-primary, linear-gradient(135deg, #0055A2, rgba(0, 85, 162, 0.6)));
|
||||
border-radius: 20rpx;
|
||||
padding: 40rpx 30rpx;
|
||||
margin-bottom: 30rpx;
|
||||
box-shadow: 0 8rpx 20rpx rgba(0, 85, 162, 0.3);
|
||||
|
||||
.user-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
.avatar-section {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex: 1;
|
||||
|
||||
.user-details {
|
||||
margin-left: 20rpx;
|
||||
|
||||
.user-name {
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
color: #fff;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.user-desc {
|
||||
font-size: 24rpx;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.user-actions {
|
||||
padding: 10rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 菜单区域 */
|
||||
.menu-section {
|
||||
.menu-group {
|
||||
margin-bottom: 30rpx;
|
||||
|
||||
.group-title {
|
||||
font-size: 28rpx;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
margin-bottom: 20rpx;
|
||||
padding-left: 10rpx;
|
||||
}
|
||||
|
||||
.menu-list {
|
||||
background: #fff;
|
||||
border-radius: 16rpx;
|
||||
padding: 0 30rpx;
|
||||
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.05);
|
||||
|
||||
.menu-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 30rpx 0;
|
||||
border-bottom: 1px solid #f5f5f5;
|
||||
transition: background-color 0.3s ease;
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
&:active {
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
|
||||
.item-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex: 1;
|
||||
|
||||
.item-icon {
|
||||
width: 64rpx;
|
||||
height: 64rpx;
|
||||
border-radius: 12rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-right: 24rpx;
|
||||
}
|
||||
|
||||
.item-title {
|
||||
font-size: 28rpx;
|
||||
color: #303133;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 退出登录按钮 */
|
||||
.logout-section {
|
||||
margin-top: 40rpx;
|
||||
|
||||
.logout-btn {
|
||||
background: #fff;
|
||||
border-radius: 16rpx;
|
||||
padding: 30rpx;
|
||||
text-align: center;
|
||||
font-size: 28rpx;
|
||||
color: #f56c6c;
|
||||
font-weight: 500;
|
||||
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.05);
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&:active {
|
||||
background-color: #fef0f0;
|
||||
transform: translateY(2rpx);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user