This commit is contained in:
2025-11-11 17:07:13 +08:00
commit be86799071
2224 changed files with 271177 additions and 0 deletions

View File

@@ -0,0 +1,191 @@
<template>
<view class="history-game">
<view class="game-list">
<view class="game-item" v-for="item in 2" :key="item">
<view class="game-info">
<view class="game-type">单人-1237房间</view>
<view class="game-date">2025-06-12 12:00</view>
<view class="del-btn">
<uni-icons type="trash" size="30"></uni-icons>
</view>
</view>
<view class="game-user">
<view class="game-user-item" v-for="(user, index) in userList" :key="index">
<view class="user-avatar">
<image :src="user.avatar" mode="aspectFill"></image>
</view>
<view class="user-name">{{user.name}}</view>
<view class="user-score">{{user.score}}</view>
</view>
</view>
<view class="game-foot">
<view class="game-status">
已结束
</view>
<view class="check-detail">
<uni-icons type="right" size="25" color="#748cec"></uni-icons>
</view>
</view>
</view>
</view>
</view>
</template>
<script setup>
import { ref, getCurrentInstance } from 'vue'
import { onLoad, onShow, onHide } from '@dcloudio/uni-app'
const proxy = getCurrentInstance().proxy;
// 过滤相关
const filterActive = ref('all'); // all:全部win:胜场lose:负场
const filterClick = (type) => {
filterActive.value = type;
};
// 参与人
const userList = ref([
{
avatar: 'https://q3.itc.cn/q_70/images03/20250110/1e71eecf56b34344bcae6a5b85c0bec2.jpeg',
name: '赵云',
score: 100
},
{
avatar: 'https://q1.itc.cn/q_70/images03/20241119/197701bb9ef34b20b6497720081a9972.jpeg',
name: '张飞',
score: -50
},
{
avatar: 'https://img1.baidu.com/it/u=3612220943,2414740890&fm=253&app=138&f=JPEG?w=526&h=500',
name: '刘备',
score: 30
},
{
avatar: 'https://c-ssl.dtstatic.com/uploads/blog/202206/12/20220612135738_992b1.thumb.1000_0.jpg',
name: '诸葛亮',
score: -80
}
]);
</script>
<style lang="less" scoped>
.history-game {
width: 750rpx;
margin: 0;
padding: 0;
box-sizing: border-box;
}
.filter-tab {
--filter-height: 80rpx;
--filter-color: #748cec;
--filter-border: 1rpx;
width: 700rpx;
height: var(--filter-height);
margin: 20rpx auto;
display: flex;
.filter-item {
flex: 1;
text-align: center;
line-height: calc(var(--filter-height) - 2 * var(--filter-border));
font-size: 32rpx;
color: #333333;
border: var(--filter-border) solid var(--filter-color);
}
.filter-active {
background-color: var(--filter-color);
color: #ffffff;
}
}
.game-list {
width: 700rpx;
margin: 0 auto;
.game-item {
width: 100%;
background-color: #ffffff;
margin: 20rpx 0;
box-shadow: 0 0 10rpx 0 rgba(0, 0, 0, 0.1);
border-radius: 20rpx;
padding: 20rpx;
box-sizing: border-box;
.game-info {
width: 100%;
height: 80rpx;
display: flex;
align-items: center;
justify-content: space-between;
.game-type {
font-size: 32rpx;
color: #333333;
}
.game-date {
font-size: 32rpx;
color: #bbbbbb;
}
.del-btn {
width: 80rpx;
height: 80rpx;
display: flex;
align-items: center;
justify-content: center;
border-left: 1rpx solid #cccccc;
}
}
.game-user {
width: 100%;
display: flex;
align-items: center;
justify-content: flex-start;
overflow: auto;
padding: 20rpx 0;
.game-user-item {
width: 140rpx;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
flex-shrink: 0;
.user-avatar {
width: 80rpx;
height: 80rpx;
border-radius: 10%;
overflow: hidden;
image {
width: 100%;
height: 100%;
}
}
.user-name {
font-size: 32rpx;
color: #000000;
}
.user-score {
font-size: 32rpx;
color: #fa5d5d;
margin-top: 10rpx;
}
}
}
.game-foot {
width: 100%;
height: 80rpx;
display: flex;
align-items: center;
justify-content: space-between;
.game-status {
font-size: 32rpx;
color: #57bcef;
}
.check-detail {
width: 80rpx;
height: 80rpx;
display: flex;
align-items: center;
justify-content: center;
}
}
}
}
</style>

View File

@@ -0,0 +1,537 @@
<template>
<view class="feedback-page">
<view class="feedback-content">
<!-- 常见问题 -->
<view class="section">
<view class="section-title">常见问题</view>
<view class="faq-list">
<view class="faq-item" v-for="(faq, index) in faqList" :key="index" @click="toggleFaq(index)">
<view class="faq-header">
<text class="faq-question">{{faq.question}}</text>
<uni-icons
:type="expandedIndex === index ? 'up' : 'down'"
size="24"
color="#999"
></uni-icons>
</view>
<view class="faq-answer" v-if="expandedIndex === index">
<text>{{faq.answer}}</text>
</view>
</view>
</view>
</view>
<!-- 问题类型选择 -->
<view class="section" v-if="!showSubmitForm">
<view class="section-title">问题类型</view>
<view class="problem-types">
<view
class="problem-type"
v-for="(type, index) in problemTypes"
:key="index"
@click="selectProblemType(type)"
>
<view class="type-icon">
<image :src="type.img" alt="问题类型图标" class="type-icon-image" mode="aspectFit"></image>
</view>
<text class="type-name">{{type.name}}</text>
</view>
</view>
</view>
<!-- 意见反馈表单 -->
<view class="section" v-if="showSubmitForm">
<view class="section-title">意见反馈</view>
<view class="form-group">
<view class="form-label">反馈内容</view>
<textarea
v-model="feedbackContent"
class="feedback-textarea"
placeholder="请详细描述您遇到的问题或建议"
maxlength="500"
rows="6"
></textarea>
<view class="word-count">{{feedbackContent.length}}/500</view>
</view>
<!-- 图片上传 -->
<view class="form-group">
<view class="form-label">上传截图选填</view>
<view class="image-upload">
<view class="upload-btn" @click="chooseImage" v-if="images.length < 3">
<uni-icons type="plus" size="40" color="#999"></uni-icons>
</view>
<view class="image-item" v-for="(image, index) in images" :key="index">
<image :src="image" mode="aspectFill" class="preview-image"></image>
<view class="delete-btn" @click="deleteImage(index)">
<uni-icons type="close" size="20" color="white"></uni-icons>
</view>
</view>
</view>
<view class="upload-text">最多上传3张图片每张不超过5MB</view>
</view>
<!-- 联系方式 -->
<view class="form-group">
<view class="form-label">联系方式选填</view>
<input
v-model="contactInfo"
class="contact-input"
placeholder="请留下您的邮箱或手机号,方便我们联系您"
/>
</view>
<!-- 提交按钮 -->
<button
class="submit-btn"
:disabled="!feedbackContent.trim()"
@click="submitFeedback"
>提交反馈</button>
</view>
</view>
<!-- 联系方式 -->
<view class="contact-options">
<view class="contact-item">
<view class="contact-icon">
<image src="/static/emile.png" alt="客服邮箱" class="contact-icon-image" mode="aspectFit"></image>
</view>
<view class="contact-info">
<view class="contact-label">客服邮箱</view>
<view class="contact-value" @click="copyEmail">support@example.com</view>
</view>
</view>
<view class="contact-item">
<view class="contact-icon">
<uni-icons type="chat" size="32" color="#4cd964"></uni-icons>
</view>
<view class="contact-info">
<view class="contact-label">在线客服</view>
<view class="contact-value">立即联系</view>
</view>
</view>
</view>
</view>
</template>
<script setup>
import { ref } from 'vue'
// 响应式数据
const expandedIndex = ref(-1)
const showSubmitForm = ref(false)
const selectedType = ref('')
const feedbackContent = ref('')
const images = ref([])
const contactInfo = ref('')
// 常见问题数据
const faqList = [
{
question: '如何添加新玩家?',
answer: '在游戏开始页面,点击"添加玩家"按钮,输入玩家名称即可添加新玩家。您可以添加多个玩家参与计分。'
},
{
question: '如何修改玩家分数?',
answer: '点击玩家对应的分数区域,会弹出数字键盘,输入新的分数后点击"提交"即可更新玩家分数。'
},
{
question: '如何查看历史对局记录?',
answer: '在首页点击"历史记录"图标,进入历史记录页面即可查看所有保存的对局记录。'
},
{
question: '如何清除应用缓存?',
answer: '在"我的"页面,点击"设置",然后选择"清除缓存"选项即可清除应用缓存数据。'
},
{
question: '计分数据会同步到云端吗?',
answer: '目前计分数据仅保存在本地,不会自动同步到云端。如需备份,请定期导出数据。'
}
]
// 问题类型数据
const problemTypes = [
{
name: '功能建议',
img: '/static/advise.png',
color: '#ffcc00'
},
{
name: 'bug反馈',
img: '/static/bug.png',
color: '#ff3b30'
},
{
name: '界面优化',
img: '/static/optimize.png',
color: '#34aadc'
},
{
name: '其他问题',
img: '/static/other.png',
color: '#999999'
}
]
// 切换FAQ展开状态
const toggleFaq = (index) => {
expandedIndex.value = expandedIndex.value === index ? -1 : index
}
// 选择问题类型
const selectProblemType = (type) => {
selectedType.value = type.name
showSubmitForm.value = true
}
// 选择图片
const chooseImage = () => {
uni.chooseImage({
count: 3 - images.value.length,
sizeType: ['compressed'],
sourceType: ['album', 'camera'],
success: (res) => {
images.value = [...images.value, ...res.tempFilePaths]
}
})
}
// 删除图片
const deleteImage = (index) => {
images.value.splice(index, 1)
}
// 提交反馈
const submitFeedback = () => {
if (!feedbackContent.value.trim()) {
uni.showToast({
title: '请输入反馈内容',
icon: 'none'
})
return
}
// 模拟提交
uni.showLoading({
title: '提交中...'
})
setTimeout(() => {
uni.hideLoading()
uni.showToast({
title: '反馈提交成功',
icon: 'success'
})
// 重置表单
feedbackContent.value = ''
images.value = []
contactInfo.value = ''
showSubmitForm.value = false
}, 1500)
}
// 移除多余的返回函数,使用默认的导航返回
// 复制邮箱
const copyEmail = () => {
uni.setClipboardData({
data: 'support@example.com',
success: () => {
uni.showToast({
title: '邮箱已复制',
icon: 'success'
})
}
})
}
</script>
<style scoped>
.feedback-page {
background-color: #f5f5f5;
min-height: 100vh;
padding-bottom: 40rpx;
}
/* 简化的页面标题 */
.page-title {
font-size: 34rpx;
font-weight: bold;
color: #333;
background-color: #fff;
padding: 30rpx;
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
text-align: center;
}
/* 内容区域 */
.feedback-content {
padding: 30rpx;
}
.section {
background-color: #fff;
border-radius: 20rpx;
padding: 30rpx;
margin-bottom: 30rpx;
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
}
.section-title {
font-size: 32rpx;
font-weight: bold;
color: #333;
margin-bottom: 30rpx;
}
/* 常见问题样式 */
.faq-list {
width: 100%;
}
.faq-item {
border-bottom: 1rpx solid #f0f0f0;
}
.faq-item:last-child {
border-bottom: none;
}
.faq-header {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
padding: 25rpx 0;
}
.faq-question {
font-size: 28rpx;
color: #333;
flex: 1;
}
.faq-answer {
font-size: 26rpx;
color: #666;
padding: 0 0 25rpx 0;
line-height: 1.6;
}
/* 问题类型样式 */
.problem-types {
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: space-between;
}
.problem-type {
width: 45%;
background-color: #f8f8f8;
border-radius: 15rpx;
padding: 30rpx 0;
margin-bottom: 20rpx;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
transition: all 0.3s ease;
}
.problem-type:active {
background-color: #e8e8e8;
transform: scale(0.98);
}
.type-icon {
width: 80rpx;
height: 80rpx;
border-radius: 40rpx;
background-color: #fff;
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 15rpx;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.05);
}
.type-name {
font-size: 28rpx;
color: #333;
}
/* 表单样式 */
.form-group {
margin-bottom: 30rpx;
}
.form-label {
font-size: 28rpx;
color: #333;
margin-bottom: 15rpx;
display: block;
}
.feedback-textarea {
width: 100%;
height: 240rpx;
border: 1rpx solid #e0e0e0;
border-radius: 10rpx;
padding: 20rpx;
box-sizing: border-box;
font-size: 28rpx;
color: #333;
background-color: #fafafa;
resize: none;
}
.word-count {
font-size: 24rpx;
color: #999;
text-align: right;
margin-top: 10rpx;
}
/* 优化的图片上传样式 */
.image-upload {
display: flex;
flex-direction: row;
flex-wrap: wrap;
margin: 0 -10rpx;
}
.upload-btn {
width: 200rpx;
height: 200rpx;
border: 2rpx dashed #007aff;
border-radius: 12rpx;
display: flex;
align-items: center;
justify-content: center;
margin: 10rpx;
background-color: #f0f8ff;
transition: all 0.2s ease;
}
.upload-btn:active {
background-color: #e0e8ff;
transform: scale(0.98);
}
.upload-text {
font-size: 24rpx;
color: #999;
margin-top: 10rpx;
}
.image-item {
width: 200rpx;
height: 200rpx;
position: relative;
margin: 10rpx;
border-radius: 12rpx;
overflow: hidden;
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.08);
}
.preview-image {
width: 100%;
height: 100%;
border-radius: 12rpx;
object-fit: cover;
}
.delete-btn {
position: absolute;
top: -10rpx;
right: -10rpx;
width: 44rpx;
height: 44rpx;
background-color: rgba(255, 0, 0, 0.8);
border-radius: 22rpx;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.15);
}
.contact-input {
width: 100%;
height: 80rpx;
font-size: 30rpx;
color: #333;
border: 1rpx solid #e0e0e0;
border-radius: 10rpx;
padding: 0 20rpx;
box-sizing: border-box;
background-color: #fafafa;
}
.submit-btn {
margin: 40rpx 30rpx 20rpx;
background-color: #007aff;
color: #fff;
border-radius: 40rpx;
font-size: 32rpx;
}
.submit-btn[disabled] {
background-color: #cccccc;
}
/* 联系方式样式 */
.contact-options {
padding: 0 30rpx 30rpx;
}
.contact-item {
display: flex;
flex-direction: row;
align-items: center;
padding: 20rpx 0;
border-bottom: 1rpx solid #f0f0f0;
}
.contact-item:last-child {
border-bottom: none;
}
.contact-icon {
width: 60rpx;
height: 60rpx;
background-color: #f0f8ff;
border-radius: 30rpx;
display: flex;
align-items: center;
justify-content: center;
margin-right: 20rpx;
overflow: hidden;
}
.contact-icon-image {
width: 80%;
height: 80%;
object-fit: contain;
}
.contact-info {
flex: 1;
}
.contact-label {
font-size: 28rpx;
color: #666;
display: block;
}
.contact-value {
font-size: 30rpx;
color: #007aff;
display: block;
margin-top: 5rpx;
}
</style>

495
scoring/pages/my/my.vue Normal file
View File

@@ -0,0 +1,495 @@
<template>
<view class="my">
<!-- 用户信息区域 -->
<view class="user-info">
<view class="background">
</view>
<view class="info-content">
<view class="top-user-name" :style="{'height': topHeight, 'line-height': topHeight}">
{{userInfo.nickName}}
</view>
<view class="avatars">
<image class="avatar-img" :src="userInfo.avatarUrl ? userInfo.avatarUrl : 'https://pic.rmb.bdstatic.com/bjh/down/1742bc3845cbbcf0c78c01eb59bb1c1a.jpeg'" @click="updateAvatar"></image>
</view>
<view class="hello-text">
<p>你好{{userInfo.nickName}}</p>
<p>欢迎使用计分小程序</p>
</view>
</view>
</view>
<!-- 数据统计区域 -->
<view class="data-section">
<view class="data-item" @click="navigateToHistory">
<text class="data-label">总对局数</text>
<text class="data-number">{{totalGames || 0}}</text>
</view>
<view class="data-divider"></view>
<view class="data-item" @click="navigateToHistory">
<text class="data-label">胜利局数</text>
<text class="data-number">{{totalWins || 0}}</text>
</view>
<view class="data-divider"></view>
<view class="data-item" @click="navigateToHistory">
<text class="data-label">胜率</text>
<text class="data-number">{{winRate || '0%'}}</text>
</view>
</view>
<!-- 功能菜单区域 -->
<view class="menu-section">
<!-- 第一组菜单 -->
<view class="menu-group">
<view class="menu-item" @click="navigateToFavorites">
<view class="menu-left">
<image src="/static/favorites.png" alt="收藏的对局" class="menu-icon" mode="aspectFit"></image>
<text class="menu-text">收藏的对局</text>
</view>
<uni-icons type="right" size="24" color="#999"></uni-icons>
</view>
</view>
<!-- 第二组菜单 -->
<view class="menu-group">
<view class="menu-item" @click="openSettings">
<view class="menu-left">
<image src="/static/setting.png" alt="设置" class="menu-icon" mode="aspectFit"></image>
<text class="menu-text">设置</text>
</view>
<uni-icons type="right" size="24" color="#999"></uni-icons>
</view>
<view class="menu-item" @click="openFeedback">
<view class="menu-left">
<image src="/static/feedback.png" alt="帮助与反馈" class="menu-icon" mode="aspectFit"></image>
<text class="menu-text">帮助与反馈</text>
</view>
<uni-icons type="right" size="24" color="#999"></uni-icons>
</view>
<view class="menu-item" @click="aboutUs">
<view class="menu-left">
<image src="/static/about.png" alt="关于我们" class="menu-icon" mode="aspectFit"></image>
<text class="menu-text">关于我们</text>
</view>
<uni-icons type="right" size="24" color="#999"></uni-icons>
</view>
</view>
</view>
<!-- 版本信息 -->
<view class="version-info">
<text>版本 {{version || '1.0.0'}}</text>
</view>
</view>
</template>
<script setup>
import { onMounted, onUnmounted, ref, getCurrentInstance } from 'vue'
import { onLoad, onShow, onHide } from '@dcloudio/uni-app'
import { getOpenId } from '@/utils/wxutils.js'
import { register, login } from '@/api/user.js'
const proxy = getCurrentInstance().proxy;
// 小程序胶囊高度
const topHeight = ref(proxy.$StaticValue.getTopHeight());
// 用户信息相关
const userInfo = ref({});
const totalGames = ref(0);
const totalWins = ref(0);
const winRate = ref('0%');
const unreadCount = ref(0);
const version = ref('1.0.0');
// 获取用户信息
const getUserInfo = async () => {
// 从本地获取用户信息
userInfo.value = proxy.$StaticValue.getUserInfo();
if(!userInfo.value?.userId) {
// 如果没有登录, 获取到当前用户的openid
const openIdRes = await getOpenId();
const openId = openIdRes.openid;
userInfo.value = {
openId: openId,
nickName: '用户'+openId.substring(0, 6)
};
register(userInfo.value).then(res => {
// 注册成功就执行登录
login(userInfo.value).then(loginRes => {
userInfo.value = loginRes.data;
// 存储用户信息到本地
proxy.$StaticValue.setUserInfo(userInfo.value);
// 获取用户统计数据
fetchUserStats();
});
});
} else {
// 已登录,获取用户统计数据
fetchUserStats();
}
}
// 获取用户统计数据
const fetchUserStats = () => {
// 实际项目中应该调用API获取真实数据
// 这里使用模拟数据
totalGames.value = 42;
totalWins.value = 28;
winRate.value = '66.7%';
unreadCount.value = 2;
// 实际API调用示例
// getUserStats(userInfo.value.userId).then(res => {
// totalGames.value = res.data.totalGames;
// totalWins.value = res.data.totalWins;
// winRate.value = res.data.winRate;
// unreadCount.value = res.data.unreadCount;
// });
}
// 更新头像
const updateAvatar = () => {
/* #ifdef MP-WEIXIN */
wx.chooseMedia({
count: 1,
mediaType: ['image'],
sourceType: ['album', 'camera'],
sizeType: ['compressed'],
success: (res) => {
if (res.tempFiles && res.tempFiles.length > 0) {
const tempFilePath = res.tempFiles[0].tempFilePath;
// 预览选择的头像
wx.previewImage({
urls: [tempFilePath],
success: () => {
// 更新头像
userInfo.value.avatarUrl = tempFilePath;
// 在实际项目中应该上传头像到服务器
proxy.$StaticValue.setUserInfo(userInfo.value);
uni.showToast({
title: '头像更新成功',
icon: 'success'
});
}
});
}
},
fail: (err) => {
console.log('选择头像失败', err);
if (err.errMsg !== 'chooseMedia:fail cancel') {
uni.showToast({
title: '选择头像失败',
icon: 'none'
});
}
}
});
/* #endif */
/* #ifndef MP-WEIXIN */
uni.chooseImage({
count: 1,
success: (res) => {
if (res.tempFilePaths && res.tempFilePaths.length > 0) {
userInfo.value.avatarUrl = res.tempFilePaths[0];
proxy.$StaticValue.setUserInfo(userInfo.value);
uni.showToast({
title: '头像更新成功',
icon: 'success'
});
}
}
});
/* #endif */
}
// 导航到历史对局页面
const navigateToHistory = () => {
uni.navigateTo({
url: '/pages/history-game/history-game'
});
}
// 导航到收藏对局页面
const navigateToFavorites = () => {
// 如果收藏页面不存在,可以创建一个或跳转到历史页面并筛选
uni.navigateTo({
url: '/pages/my/favorites'
});
}
// 打开设置页面
const openSettings = () => {
uni.navigateTo({
url: '/pages/my/setting'
});
}
// 打开帮助与反馈
const openFeedback = () => {
uni.navigateTo({
url: '/pages/my/feedback'
});
}
// 关于我们
const aboutUs = () => {
uni.showModal({
title: '关于计分小程序',
content: '计分小程序 v' + version.value + '\n\n一款便捷的计分工具支持多种游戏模式。\n\n© 2023 计分小程序团队',
showCancel: false,
confirmText: '确定'
});
}
// 退出登录
const logout = () => {
uni.showModal({
title: '确认退出',
content: '确定要退出登录吗?',
success: (res) => {
if (res.confirm) {
// 清除本地存储的用户信息
proxy.$StaticValue.clearUserInfo();
// 重置用户信息
userInfo.value = {};
totalGames.value = 0;
totalWins.value = 0;
winRate.value = '0%';
// 重新获取用户信息(会自动重新登录)
getUserInfo();
uni.showToast({
title: '已退出登录',
icon: 'success'
});
}
}
});
}
onMounted(() => {
getUserInfo();
// 获取版本信息
/* #ifdef MP-WEIXIN */
const appInfo = wx.getAccountInfoSync();
version.value = appInfo.miniProgram.version || '1.0.0';
/* #endif */
});
onShow(() => {
// 每次显示页面时刷新数据
fetchUserStats();
});
</script>
<style lang="less" scoped>
.my {
width: 750rpx;
margin: 0;
padding: 0;
min-height: 100vh;
background-color: #f8f8f8;
}
/* 用户信息区域样式 */
.user-info {
--user-height: 500rpx;
width: 750rpx;
height: var(--user-height);
position: relative;
.background {
width: 100%;
height: 100%;
background-image: linear-gradient(rgb(87, 255, 87), rgb(144, 251, 144));
position: absolute;
top: 0;
left: 0;
z-index: 0;
}
.info-content {
width: 100%;
height: 100%;
position: relative;
z-index: 1;
padding-top: calc(var(--top-margin) + 20rpx);
.top-user-name {
width: 100%;
font-size: 40rpx;
font-weight: bold;
color: #000000;
padding: 0 20rpx;
box-sizing: border-box;
ttext-align: center;
}
.avatars {
width: 100%;
display: flex;
justify-content: center;
margin-top: 20rpx;
.avatar-img {
width: 150rpx;
height: 150rpx;
border-radius: 75rpx;
border: 4rpx solid #ffffff;
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1);
// 添加点击效果
&:active {
opacity: 0.8;
transform: scale(0.95);
}
}
}
.hello-text {
width: 100%;
text-align: center;
margin-top: 20rpx;
font-size: 30rpx;
color: #000000;
p {
margin: 5rpx 0;
}
}
}
}
/* 数据统计区域样式 */
.data-section {
width: 100%;
height: 160rpx;
background-color: #ffffff;
margin-top: -30rpx;
border-radius: 20rpx;
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.05);
display: flex;
align-items: center;
justify-content: space-around;
padding: 0 40rpx;
margin-bottom: 30rpx;
.data-item {
flex: 1;
text-align: center;
.data-number {
font-size: 40rpx;
font-weight: bold;
color: #333;
display: block;
margin-bottom: 10rpx;
}
.data-label {
font-size: 24rpx;
color: #666;
}
// 添加点击效果
&:active {
opacity: 0.7;
}
}
.data-divider {
width: 1rpx;
height: 80rpx;
background-color: #eee;
}
}
/* 功能菜单区域样式 */
.menu-section {
width: 100%;
padding: 0 20rpx;
box-sizing: border-box;
.menu-group {
background-color: #ffffff;
border-radius: 16rpx;
margin-bottom: 30rpx;
overflow: hidden;
.menu-item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 30rpx;
height: 100rpx;
border-bottom: 1rpx solid #f5f5f5;
// 最后一个菜单项不需要底边框
&:last-child {
border-bottom: none;
}
.menu-left {
display: flex;
align-items: center;
.menu-icon {
width: 40rpx;
height: 40rpx;
vertical-align: middle;
}
.menu-text {
font-size: 32rpx;
color: #333;
margin-left: 20rpx;
}
}
.menu-right {
display: flex;
align-items: center;
.menu-badge {
background-color: #FF3B30;
color: #ffffff;
font-size: 20rpx;
padding: 2rpx 10rpx;
border-radius: 10rpx;
margin-right: 10rpx;
min-width: 20rpx;
text-align: center;
}
}
// 添加点击效果
&:active {
background-color: #f8f8f8;
}
}
}
}
/* 退出登录按钮样式 */
.logout-section {
width: 100%;
padding: 0 40rpx;
box-sizing: border-box;
margin-bottom: 40rpx;
.logout-btn {
width: 100%;
height: 90rpx;
line-height: 90rpx;
border-radius: 45rpx;
font-size: 34rpx;
background-color: #ffffff;
color: #FF3B30;
border: 1rpx solid #FF3B30;
}
}
/* 版本信息样式 */
.version-info {
width: 100%;
text-align: center;
padding-bottom: 60rpx;
text {
font-size: 24rpx;
color: #999;
}
}
/* 安全区域适配 */
/* #ifdef MP-WEIXIN */
.my {
padding-bottom: calc(30rpx + env(safe-area-inset-bottom));
}
/* #endif */
</style>

View File

@@ -0,0 +1,383 @@
<template>
<view class="setting-page">
<view class="setting-content">
<!-- 账户设置 -->
<view class="setting-section">
<view class="section-title">账户设置</view>
<view class="setting-list">
<view class="setting-item" @click="navigateToProfile">
<view class="item-left">
<text class="item-title">个人资料</text>
</view>
<view class="item-right">
<text class="item-value">查看</text>
<uni-icons type="right" size="24" color="#ccc"></uni-icons>
</view>
</view>
<view class="setting-item" @click="navigateToSecurity">
<view class="item-left">
<text class="item-title">账户安全</text>
</view>
<view class="item-right">
<text class="item-value">设置</text>
<uni-icons type="right" size="24" color="#ccc"></uni-icons>
</view>
</view>
</view>
</view>
<!-- 应用设置 -->
<view class="setting-section">
<view class="section-title">应用设置</view>
<view class="setting-list">
<view class="setting-item" @click="toggleNotifications">
<view class="item-left">
<text class="item-title">消息通知</text>
</view>
<view class="item-right">
<uni-switch
:checked="notificationsEnabled"
activeColor="#007aff"
@change="toggleNotifications"
></uni-switch>
</view>
</view>
<view class="setting-item" @click="toggleDarkMode">
<view class="item-left">
<text class="item-title">深色模式</text>
</view>
<view class="item-right">
<uni-switch
:checked="darkModeEnabled"
activeColor="#007aff"
@change="toggleDarkMode"
></uni-switch>
</view>
</view>
<view class="setting-item" @click="clearCache">
<view class="item-left">
<text class="item-title">清除缓存</text>
</view>
<view class="item-right">
<text class="item-value">{{cacheSize}}</text>
<uni-icons type="right" size="24" color="#ccc"></uni-icons>
</view>
</view>
</view>
</view>
<!-- 关于 -->
<view class="setting-section">
<view class="section-title">关于</view>
<view class="setting-list">
<view class="setting-item" @click="navigateToAbout">
<view class="item-left">
<text class="item-title">关于我们</text>
</view>
<view class="item-right">
<text class="item-value">{{appVersion}}</text>
<uni-icons type="right" size="24" color="#ccc"></uni-icons>
</view>
</view>
<view class="setting-item" @click="navigateToPrivacy">
<view class="item-left">
<text class="item-title">隐私政策</text>
</view>
<view class="item-right">
<uni-icons type="right" size="24" color="#ccc"></uni-icons>
</view>
</view>
<view class="setting-item" @click="navigateToTerms">
<view class="item-left">
<text class="item-title">用户协议</text>
</view>
<view class="item-right">
<uni-icons type="right" size="24" color="#ccc"></uni-icons>
</view>
</view>
</view>
</view>
<!-- 退出登录 -->
<view class="logout-section">
<button class="logout-btn" @click="logout">退出登录</button>
</view>
</view>
</view>
</template>
<script setup>
import { ref, onMounted } from 'vue'
// 响应式数据
const notificationsEnabled = ref(true)
const darkModeEnabled = ref(false)
const cacheSize = ref('12.3MB')
const appVersion = ref('1.0.0')
// 生命周期
onMounted(() => {
// 初始化时检查缓存大小等信息
checkCacheSize()
})
// 切换通知开关
const toggleNotifications = (e) => {
notificationsEnabled.value = e.detail.checked || !notificationsEnabled.value
uni.showToast({
title: notificationsEnabled.value ? '通知已开启' : '通知已关闭',
icon: 'none'
})
}
// 切换深色模式
const toggleDarkMode = (e) => {
darkModeEnabled.value = e.detail.checked || !darkModeEnabled.value
uni.showToast({
title: darkModeEnabled.value ? '深色模式已开启' : '深色模式已关闭',
icon: 'none'
})
// 这里可以添加实际的深色模式切换逻辑
// 例如document.body.classList.toggle('dark-mode')
}
// 检查缓存大小
const checkCacheSize = () => {
// 模拟获取缓存大小
// 实际项目中可以调用uni.getStorageInfoSync()等API获取
}
// 清除缓存
const clearCache = () => {
uni.showModal({
title: '清除缓存',
content: '确定要清除所有缓存数据吗?',
success: (res) => {
if (res.confirm) {
// 模拟清除缓存
setTimeout(() => {
cacheSize.value = '0KB'
uni.showToast({
title: '缓存清除成功',
icon: 'success'
})
}, 500)
}
}
})
}
// 导航到个人资料页面
const navigateToProfile = () => {
// 实际项目中添加导航逻辑
uni.showToast({
title: '跳转到个人资料页面',
icon: 'none'
})
}
// 导航到账户安全页面
const navigateToSecurity = () => {
// 实际项目中添加导航逻辑
uni.showToast({
title: '跳转到账户安全页面',
icon: 'none'
})
}
// 导航到关于页面
const navigateToAbout = () => {
// 实际项目中添加导航逻辑
uni.showToast({
title: '跳转到关于页面',
icon: 'none'
})
}
// 导航到隐私政策页面
const navigateToPrivacy = () => {
// 实际项目中添加导航逻辑
uni.showToast({
title: '跳转到隐私政策页面',
icon: 'none'
})
}
// 导航到用户协议页面
const navigateToTerms = () => {
// 实际项目中添加导航逻辑
uni.showToast({
title: '跳转到用户协议页面',
icon: 'none'
})
}
// 退出登录
const logout = () => {
uni.showModal({
title: '退出登录',
content: '确定要退出登录吗?',
success: (res) => {
if (res.confirm) {
// 模拟退出登录
setTimeout(() => {
uni.showToast({
title: '已退出登录',
icon: 'success'
})
// 实际项目中可以添加跳转到登录页面的逻辑
}, 500)
}
}
})
}
</script>
<style scoped>
.setting-page {
background-color: #f5f5f5;
min-height: 100vh;
padding-bottom: 40rpx;
}
/* 页面标题 */
.page-title {
font-size: 34rpx;
font-weight: bold;
color: #333;
background-color: #fff;
padding: 30rpx;
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
text-align: center;
}
/* 内容区域 */
.setting-content {
padding: 20rpx 0;
}
/* 设置分组 */
.setting-section {
margin-bottom: 30rpx;
}
/* 分组标题 */
.section-title {
font-size: 26rpx;
color: #999;
padding: 0 30rpx 10rpx;
}
/* 设置列表 */
.setting-list {
background-color: #fff;
border-radius: 12rpx;
margin: 0 30rpx;
overflow: hidden;
}
/* 设置项 */
.setting-item {
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
padding: 30rpx;
position: relative;
transition: background-color 0.2s ease;
}
.setting-item:active {
background-color: #f8f8f8;
}
.setting-item:not(:last-child)::after {
content: '';
position: absolute;
bottom: 0;
left: 30rpx;
right: 30rpx;
height: 1rpx;
background-color: #f0f0f0;
}
/* 左侧内容 */
.item-left {
display: flex;
flex-direction: row;
align-items: center;
}
/* 图标容器 */
.item-icon {
width: 60rpx;
height: 60rpx;
border-radius: 12rpx;
background-color: #f0f8ff;
display: flex;
align-items: center;
justify-content: center;
margin-right: 20rpx;
}
/* 标题文本 */
.item-title {
font-size: 30rpx;
color: #333;
}
/* 右侧内容 */
.item-right {
display: flex;
flex-direction: row;
align-items: center;
}
/* 值文本 */
.item-value {
font-size: 28rpx;
color: #999;
margin-right: 10rpx;
}
/* 退出登录区域 */
.logout-section {
padding: 40rpx 30rpx 0;
}
/* 退出登录按钮 */
.logout-btn {
background-color: #fff;
color: #ff3b30;
border-radius: 80rpx;
font-size: 32rpx;
height: 90rpx;
line-height: 90rpx;
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
}
.logout-btn:active {
background-color: #f8f8f8;
}
/* 微信小程序特定样式优化 */
/* #ifdef MP-WEIXIN */
.setting-item {
-webkit-tap-highlight-color: rgba(0, 0, 0, 0.05);
}
.item-icon {
background-color: #f8f8f8;
}
.setting-list {
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.03);
}
/* #endif */
</style>