feat: 商品详情支付交互调试

This commit is contained in:
duanshuwen
2025-08-06 21:43:08 +08:00
parent 5292ede3c5
commit e482ea5393
10 changed files with 673 additions and 137 deletions

View File

@@ -0,0 +1,71 @@
# AgreePopup 用户协议同意弹窗组件
## 组件概述
AgreePopup 是一个用于登录流程中的用户协议同意弹窗组件,用于向用户展示隐私政策和用户协议,并获取用户的同意确认。
## 功能需求
### 界面设计
- **弹窗标题**:显示"温馨提示"标题,居中显示
- **关闭按钮**:右上角显示"×"关闭按钮,点击可关闭弹窗
- **内容区域**
- 主要说明文字:"您在使用朵花温泉服务前,请仔细阅读用户隐私条款及用户注册须知,当您点击同意,即表示您已经理解并同意该条款,该条款将构成对您具有法律约束力的文件。"
- 注意事项:"请您注意:如果您不同意上述用户注册须知、隐私政策或其中任何约定,请您停止注册。如您阅读并点击同意即表示您已充分阅读理解并接受其全部内容,并表明您也同意朵花温泉可以依据以上隐私政策来处理您的个人信息。"
### 交互功能
- **复选框**
- 显示蓝色勾选框
- 文字说明:"本人已仔细阅读《用户协议》和《隐私协议》,知悉并诺遵守该内容。"
- 支持点击切换选中/未选中状态
- **确认按钮**
- 显示"我知道了"按钮
- 蓝色背景,白色文字
- 圆角设计
- 点击后触发同意事件并关闭弹窗
### 技术要求
- 使用 Vue 3 Composition API
- 支持弹窗显示/隐藏控制
- 提供事件回调:同意、关闭
- 响应式设计,适配移动端
- 使用 uni-app 框架
### 样式规范
- 弹窗背景:白色
- 圆角设计
- 文字颜色:深灰色
- 按钮:蓝色主题色
- 复选框:蓝色选中状态
- 适当的内边距和间距
### 使用场景
- 用户首次登录时显示
- 隐私政策更新后重新确认
- 注册流程中的协议确认
## 组件接口
### Props
- `visible`: Boolean - 控制弹窗显示/隐藏
- `title`: String - 弹窗标题,默认"温馨提示"
### Events
- `@agree`: 用户点击同意时触发
- `@close`: 用户关闭弹窗时触发
- `@cancel`: 用户取消操作时触发
### Methods
- `show()`: 显示弹窗
- `hide()`: 隐藏弹窗
## 文件结构
```
AgreePopup/
├── README.md # 组件说明文档
├── index.vue # 组件主文件
├── styles/
│ └── index.scss # 组件样式文件
└── images/
└── 登录授权1.png # 设计稿参考图
```

View File

@@ -0,0 +1,133 @@
<template>
<view class="demo-container">
<view class="demo-header">
<text class="demo-title">AgreePopup 组件演示</text>
</view>
<view class="demo-content">
<button class="demo-btn" @click="showPopup">显示用户协议弹窗</button>
<view class="demo-info">
<text class="info-title">组件状态</text>
<text class="info-text">弹窗可见{{ popupVisible }}</text>
<text class="info-text">用户操作{{ userAction }}</text>
</view>
</view>
<!-- AgreePopup 组件 -->
<AgreePopup
:visible="popupVisible"
title="温馨提示"
@agree="handleAgree"
@close="handleClose"
@cancel="handleCancel"
/>
</view>
</template>
<script setup>
import { ref } from 'vue'
import AgreePopup from './index.vue'
// 响应式数据
const popupVisible = ref(false)
const userAction = ref('无')
// 方法定义
const showPopup = () => {
popupVisible.value = true
userAction.value = '显示弹窗'
}
const handleAgree = () => {
popupVisible.value = false
userAction.value = '用户同意协议'
console.log('用户同意了协议')
}
const handleClose = () => {
popupVisible.value = false
userAction.value = '用户关闭弹窗'
console.log('用户关闭了弹窗')
}
const handleCancel = () => {
popupVisible.value = false
userAction.value = '用户取消操作'
console.log('用户取消了操作')
}
</script>
<style scoped lang="scss">
.demo-container {
padding: 20px;
min-height: 100vh;
background: #f5f5f5;
.demo-header {
text-align: center;
margin-bottom: 40px;
.demo-title {
font-size: 24px;
font-weight: 600;
color: #333333;
}
}
.demo-content {
display: flex;
flex-direction: column;
align-items: center;
.demo-btn {
width: 200px;
height: 44px;
background: #007AFF;
color: #ffffff;
border: none;
border-radius: 8px;
font-size: 16px;
font-weight: 500;
margin-bottom: 40px;
cursor: pointer;
&:hover {
background: #0056CC;
}
&:active {
background: #004499;
transform: scale(0.98);
}
}
.demo-info {
background: #ffffff;
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
min-width: 300px;
.info-title {
font-size: 16px;
font-weight: 600;
color: #333333;
display: block;
margin-bottom: 12px;
}
.info-text {
font-size: 14px;
color: #666666;
display: block;
margin-bottom: 8px;
&:last-child {
margin-bottom: 0;
}
}
}
}
}
</style>

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

View File

@@ -0,0 +1,91 @@
<template>
<uni-popup ref="popup" type="center" :mask-click="false">
<view class="agree-popup">
<!-- 弹窗头部 -->
<view class="popup-header">
<view class="popup-title">{{ title }}</view>
<view class="close-btn" @click="handleClose">
<uni-icons type="closeempty" size="24" color="#999" />
</view>
</view>
<!-- 弹窗内容 -->
<view class="popup-content">
<view class="content-text">
<text class="main-text">
您在使用朵花温泉服务前请仔细阅读用户隐私条款及用户注册须知当您点击同意即表示您已经理解并同意该条款该条款将构成对您具有法律约束力的文件
</text>
</view>
<view class="notice-text">
<text>
请您注意如果您不同意上述用户注册须知隐私政策或其中任何约定请您停止注册如您阅读并点击同意即表示您已充分阅读理解并接受其全部内容并表明您也同意朵花温泉可以依据以上隐私政策来处理您的个人信息
</text>
</view>
</view>
<!-- 确认按钮 -->
<view class="button-area">
<view class="confirm-btn" @click="handleClose"> 我知道了 </view>
</view>
</view>
</uni-popup>
</template>
<script setup>
import { ref, watch, defineProps, defineEmits, defineExpose } from "vue";
// Props定义
const props = defineProps({
visible: {
type: Boolean,
default: false,
},
title: {
type: String,
default: "温馨提示",
},
});
// Events定义
const emits = defineEmits(["agree", "close", "cancel"]);
// 响应式数据
const popup = ref(null);
// 监听visible变化
watch(
() => props.visible,
(newVal) => {
if (newVal) {
show();
} else {
hide();
}
}
);
// 方法定义
const show = () => {
popup.value?.open();
};
const hide = () => {
popup.value?.close();
};
const handleClose = () => {
hide();
emits("close");
};
// 暴露方法给父组件
defineExpose({
show,
hide,
});
</script>
<style scoped lang="scss">
@import "./styles/index.scss";
</style>

View File

@@ -0,0 +1,95 @@
// AgreePopup 组件样式
.agree-popup {
width: 327px;
background: #ffffff;
border-radius: 12px;
overflow: hidden;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
// 弹窗头部
.popup-header {
position: relative;
padding: 20px 20px 0 20px;
.popup-title {
font-size: 18px;
font-weight: 600;
color: #333333;
text-align: center;
line-height: 24px;
}
.close-btn {
position: absolute;
top: 16px;
right: 16px;
width: 28px;
height: 28px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
&:hover {
background: #f5f5f5;
border-radius: 50%;
}
}
}
// 弹窗内容
.popup-content {
padding: 20px;
.content-text {
margin-bottom: 16px;
.main-text {
font-size: 14px;
color: #333;
line-height: 22px;
display: block;
}
}
.notice-text {
text {
font-size: 13px;
color: #333;
line-height: 20px;
display: block;
}
}
}
// 按钮区域
.button-area {
padding: 0 20px 20px 20px;
display: flex;
justify-content: center;
align-items: center;
.confirm-btn {
width: 148px;
height: 44px;
background: linear-gradient(90deg, #22a7ff 0%, #2567ff 100%);
display: flex;
align-items: center;
justify-content: center;
color: #ffffff;
border-radius: 50px;
font-size: 16px;
font-weight: 500;
transition: all 0.3s ease;
&:hover {
background: #0056cc;
}
&:active {
background: #004499;
transform: scale(0.98);
}
}
}
}

View File

@@ -42,29 +42,33 @@
<view class="login-agreement">
<CheckBox v-model="isAgree">
<text class="login-agreement-text">阅读并同意</text>
<navigator
url="/pages/service-agreement/service-agreement"
<text
class="login-agreement-link"
>服务协议</navigator
@click.stop="handleAgreeClick('service')"
>服务协议</text
>
<text class="login-agreement-text"></text>
<navigator
url="/pages/privacy-policy/privacy-policy"
<text
class="login-agreement-link"
>隐私协议</navigator
@click.stop="handleAgreeClick('privacy')"
>隐私协议</text
>
</CheckBox>
</view>
<AgreePopup ref="agreePopup" :visible="visible" @close="visible = false" />
</view>
</template>
<script setup>
import { ref } from "vue";
import CheckBox from "@/components/CheckBox/index.vue";
import AgreePopup from "./components/AgreePopup/index.vue";
import { loginAuth, bindPhone, checkPhone } from "@/manager/LoginManager";
import { goHome } from "@/hooks/useGoHome";
const isAgree = ref(false);
const visible = ref(false);
// 同意隐私协议并获取手机号
const handleAgreeAndGetPhone = () => {
@@ -103,6 +107,11 @@ const onLogin = (e) => {
console.error("登录失败", err);
});
};
// 处理同意协议点击事件
const handleAgreeClick = (type) => {
visible.value = true;
};
</script>
<style lang="scss" scoped>