upload project source code
This commit is contained in:
433
前端源码/uni-app/components/screens/ProfileSettings.vue
Normal file
433
前端源码/uni-app/components/screens/ProfileSettings.vue
Normal file
@@ -0,0 +1,433 @@
|
||||
<template>
|
||||
<view class="settings-screen">
|
||||
<view class="settings-bg"></view>
|
||||
<!-- 状态栏占位 -->
|
||||
<view class="status-bar-placeholder"></view>
|
||||
|
||||
<!-- Header -->
|
||||
<view class="settings-header">
|
||||
<view class="settings-back-btn" @click="handleBack">
|
||||
<text class="settings-back-icon">‹</text>
|
||||
</view>
|
||||
<text class="settings-title">设置与反馈</text>
|
||||
<view class="settings-header-placeholder"></view>
|
||||
</view>
|
||||
|
||||
<!-- Content -->
|
||||
<scroll-view scroll-y class="settings-content">
|
||||
<view class="settings-content-inner">
|
||||
|
||||
<!-- Section 1: 偏好设置 -->
|
||||
<!-- <view class="settings-section">
|
||||
<view class="settings-item settings-item-border">
|
||||
<view class="settings-item-left">
|
||||
<text class="settings-item-icon">🔔</text>
|
||||
<text class="settings-item-label">推送通知</text>
|
||||
</view>
|
||||
<view class="settings-switch" :class="{ 'settings-switch-active': pushEnabled }"
|
||||
@click="togglePush">
|
||||
<view class="settings-switch-thumb"
|
||||
:class="{ 'settings-switch-thumb-active': pushEnabled }"></view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="settings-item">
|
||||
<view class="settings-item-left">
|
||||
<text class="settings-item-icon">🔊</text>
|
||||
<text class="settings-item-label">音效反馈</text>
|
||||
</view>
|
||||
<view class="settings-switch" :class="{ 'settings-switch-active': soundEnabled }"
|
||||
@click="toggleSound">
|
||||
<view class="settings-switch-thumb"
|
||||
:class="{ 'settings-switch-thumb-active': soundEnabled }"></view>
|
||||
</view>
|
||||
</view>
|
||||
</view> -->
|
||||
|
||||
<!-- Section 2: 支持 -->
|
||||
<view class="settings-section">
|
||||
<view class="settings-item settings-item-border settings-item-clickable" @click="handleFeedback">
|
||||
<view class="settings-item-left">
|
||||
<text class="settings-item-icon">💬</text>
|
||||
<text class="settings-item-label">意见反馈</text>
|
||||
</view>
|
||||
<text class="settings-item-arrow">›</text>
|
||||
</view>
|
||||
|
||||
<view class="settings-item settings-item-border settings-item-clickable" @click="handleFAQ">
|
||||
<view class="settings-item-left">
|
||||
<text class="settings-item-icon">❓</text>
|
||||
<text class="settings-item-label">常见问题</text>
|
||||
</view>
|
||||
<text class="settings-item-arrow">›</text>
|
||||
</view>
|
||||
|
||||
<view class="settings-item settings-item-clickable" @click="handlePrivacy">
|
||||
<view class="settings-item-left">
|
||||
<text class="settings-item-icon">🛡️</text>
|
||||
<text class="settings-item-label">隐私政策</text>
|
||||
</view>
|
||||
<text class="settings-item-arrow">›</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- Section 3: 快速反馈 -->
|
||||
<view class="settings-feedback-section">
|
||||
<text class="settings-feedback-title">快速反馈</text>
|
||||
<textarea class="settings-feedback-textarea" v-model="feedbackText" placeholder="您遇到的问题或建议..."
|
||||
:maxlength="500" />
|
||||
<view class="settings-feedback-btn" @click="submitFeedback">
|
||||
<text class="settings-feedback-btn-text">提交反馈</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 退出登录 -->
|
||||
<view class="settings-logout-btn" @click="handleLogout">
|
||||
<text class="settings-logout-text">退出登录</text>
|
||||
</view>
|
||||
|
||||
<!-- 版本信息 -->
|
||||
<view class="settings-version">
|
||||
<text class="settings-version-text">当前版本 v1.0.2</text>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from "vue";
|
||||
import { userApi } from "@/api";
|
||||
import { logout } from "@/utils/auth";
|
||||
|
||||
declare const uni: any;
|
||||
|
||||
const emit = defineEmits<{
|
||||
back: [];
|
||||
navigate: [screen: string];
|
||||
}>();
|
||||
|
||||
const pushEnabled = ref(true);
|
||||
const soundEnabled = ref(true);
|
||||
const feedbackText = ref("");
|
||||
|
||||
const togglePush = () => {
|
||||
pushEnabled.value = !pushEnabled.value;
|
||||
uni.showToast({
|
||||
title: pushEnabled.value ? "已开启推送通知" : "已关闭推送通知",
|
||||
icon: "none"
|
||||
});
|
||||
};
|
||||
|
||||
const toggleSound = () => {
|
||||
soundEnabled.value = !soundEnabled.value;
|
||||
uni.showToast({
|
||||
title: soundEnabled.value ? "已开启音效反馈" : "已关闭音效反馈",
|
||||
icon: "none"
|
||||
});
|
||||
};
|
||||
|
||||
const handleFeedback = () => {
|
||||
emit('navigate', 'feedback');
|
||||
};
|
||||
|
||||
const handleFAQ = () => {
|
||||
emit('navigate', 'faq');
|
||||
};
|
||||
|
||||
const handlePrivacy = () => {
|
||||
emit('navigate', 'privacy');
|
||||
};
|
||||
|
||||
const submitFeedback = async () => {
|
||||
if (!feedbackText.value.trim()) {
|
||||
uni.showToast({ title: "请输入反馈内容", icon: "none" });
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await userApi.submitFeedback({
|
||||
content: feedbackText.value.trim(),
|
||||
feedback_type: 'other'
|
||||
});
|
||||
uni.showToast({ title: "感谢您的反馈!", icon: "success" });
|
||||
feedbackText.value = "";
|
||||
} catch (error: any) {
|
||||
uni.showToast({
|
||||
title: error.msg || "提交失败,请稍后重试",
|
||||
icon: "none"
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const handleLogout = () => {
|
||||
// Web 环境使用 confirm,uni-app 环境使用 showModal
|
||||
if (typeof uni?.showModal === "function") {
|
||||
uni.showModal({
|
||||
title: "提示",
|
||||
content: "确定要退出登录吗?",
|
||||
success: (res: any) => {
|
||||
if (res.confirm) {
|
||||
logout();
|
||||
uni.showToast({ title: "已退出登录", icon: "success" });
|
||||
}
|
||||
},
|
||||
});
|
||||
} else {
|
||||
const confirmed = confirm("确定要退出登录吗?");
|
||||
if (confirmed) {
|
||||
logout();
|
||||
if (typeof uni?.showToast === "function") {
|
||||
uni.showToast({ title: "已退出登录", icon: "success" });
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleBack = () => {
|
||||
emit('back');
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.settings-screen {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: #f0efe9;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.status-bar-placeholder {
|
||||
height: var(--status-bar-height, 0);
|
||||
width: 100%;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.settings-bg {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
pointer-events: none;
|
||||
opacity: 0.3;
|
||||
background-image: url("https://www.transparenttextures.com/patterns/rice-paper.png");
|
||||
}
|
||||
|
||||
/* Header */
|
||||
.settings-header {
|
||||
position: relative;
|
||||
z-index: 10;
|
||||
height: 88rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0 32rpx;
|
||||
border-bottom: 1rpx solid #dcd3c9;
|
||||
background-color: rgba(253, 251, 247, 0.8);
|
||||
backdrop-filter: blur(10rpx);
|
||||
}
|
||||
|
||||
.settings-back-btn {
|
||||
width: 64rpx;
|
||||
height: 64rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: transparent;
|
||||
border: none;
|
||||
padding: 0;
|
||||
margin-left: -16rpx;
|
||||
}
|
||||
|
||||
.settings-back-icon {
|
||||
font-size: 48rpx;
|
||||
color: #5a5a5a;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
.settings-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: 700;
|
||||
color: #2c2c2c;
|
||||
letter-spacing: 0.2em;
|
||||
}
|
||||
|
||||
.settings-header-placeholder {
|
||||
width: 64rpx;
|
||||
}
|
||||
|
||||
/* Content */
|
||||
.settings-content {
|
||||
flex: 1;
|
||||
height: 0;
|
||||
position: relative;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.settings-content-inner {
|
||||
padding: 32rpx;
|
||||
}
|
||||
|
||||
/* Section */
|
||||
.settings-section {
|
||||
background-color: #fffdf9;
|
||||
border-radius: 24rpx;
|
||||
border: 1rpx solid #e5e5e5;
|
||||
overflow: hidden;
|
||||
margin-bottom: 32rpx;
|
||||
}
|
||||
|
||||
.settings-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 24rpx 32rpx;
|
||||
}
|
||||
|
||||
.settings-item-border {
|
||||
border-bottom: 1rpx solid #f0f0f0;
|
||||
}
|
||||
|
||||
.settings-item-clickable {
|
||||
transition: background-color 0.2s;
|
||||
}
|
||||
|
||||
.settings-item-clickable:active {
|
||||
background-color: #fafafa;
|
||||
}
|
||||
|
||||
.settings-item-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 24rpx;
|
||||
}
|
||||
|
||||
.settings-item-icon {
|
||||
font-size: 32rpx;
|
||||
}
|
||||
|
||||
.settings-item-label {
|
||||
font-size: 28rpx;
|
||||
color: #2c2c2c;
|
||||
}
|
||||
|
||||
.settings-item-arrow {
|
||||
font-size: 32rpx;
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
/* Switch */
|
||||
.settings-switch {
|
||||
width: 80rpx;
|
||||
height: 40rpx;
|
||||
border-radius: 40rpx;
|
||||
background-color: #ccc;
|
||||
position: relative;
|
||||
transition: background-color 0.3s;
|
||||
}
|
||||
|
||||
.settings-switch-active {
|
||||
background-color: #8b2323;
|
||||
}
|
||||
|
||||
.settings-switch-thumb {
|
||||
position: absolute;
|
||||
top: 4rpx;
|
||||
left: 4rpx;
|
||||
width: 32rpx;
|
||||
height: 32rpx;
|
||||
border-radius: 50%;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 2rpx 4rpx rgba(0, 0, 0, 0.2);
|
||||
transition: left 0.3s;
|
||||
}
|
||||
|
||||
.settings-switch-thumb-active {
|
||||
left: 44rpx;
|
||||
}
|
||||
|
||||
/* Feedback Section */
|
||||
.settings-feedback-section {
|
||||
margin-bottom: 32rpx;
|
||||
}
|
||||
|
||||
.settings-feedback-title {
|
||||
font-size: 24rpx;
|
||||
font-weight: 700;
|
||||
color: #8b2323;
|
||||
margin-bottom: 16rpx;
|
||||
display: block;
|
||||
padding: 0 8rpx;
|
||||
}
|
||||
|
||||
.settings-feedback-textarea {
|
||||
width: 100%;
|
||||
height: 192rpx;
|
||||
background-color: #fffdf9;
|
||||
border: 1rpx solid #e5e5e5;
|
||||
border-radius: 24rpx;
|
||||
padding: 24rpx;
|
||||
font-size: 28rpx;
|
||||
color: #2c2c2c;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.settings-feedback-btn {
|
||||
width: 100%;
|
||||
margin-top: 16rpx;
|
||||
padding: 24rpx 0;
|
||||
background-color: #2c2c2c;
|
||||
border-radius: 16rpx;
|
||||
border: none;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.settings-feedback-btn-text {
|
||||
font-size: 24rpx;
|
||||
font-weight: 700;
|
||||
color: #f2e6d8;
|
||||
}
|
||||
|
||||
/* Logout Button */
|
||||
.settings-logout-btn {
|
||||
width: 100%;
|
||||
padding: 24rpx 0;
|
||||
background-color: #fffdf9;
|
||||
border: 1rpx solid #e5e5e5;
|
||||
border-radius: 24rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 16rpx;
|
||||
margin-bottom: 32rpx;
|
||||
transition: background-color 0.2s;
|
||||
}
|
||||
|
||||
.settings-logout-btn:active {
|
||||
background-color: #fff5f5;
|
||||
}
|
||||
|
||||
.settings-logout-icon {
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.settings-logout-text {
|
||||
font-size: 28rpx;
|
||||
font-weight: 700;
|
||||
color: #8b2323;
|
||||
}
|
||||
|
||||
/* Version */
|
||||
.settings-version {
|
||||
text-align: center;
|
||||
padding: 32rpx 0;
|
||||
}
|
||||
|
||||
.settings-version-text {
|
||||
font-size: 20rpx;
|
||||
color: #ccc;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user