diff --git a/miniprogram/src/components/PrivacyAgree.jsx b/miniprogram/src/components/PrivacyAgree.jsx
new file mode 100644
index 0000000..715ae40
--- /dev/null
+++ b/miniprogram/src/components/PrivacyAgree.jsx
@@ -0,0 +1,22 @@
+import { View, Text } from '@tarojs/components';
+import Taro from '@tarojs/taro';
+import './PrivacyAgree.scss';
+
+/**
+ * 协议授权同意勾选(审核合规):未同意前禁止登录/绑定手机号等收集用户信息操作。
+ * 复用组件,保证所有登录入口一致提供《用户服务协议》《隐私政策》入口。
+ */
+export default function PrivacyAgree({ agreed, onToggle, label }) {
+ const open = (url) => { Taro.navigateTo({ url }); };
+ return (
+
+ {agreed ? '✓' : ''}
+
+ {label || '我已阅读并同意'}
+ { e.stopPropagation(); open('/pages-extra/agreement/index'); }}>《用户服务协议》
+ 与
+ { e.stopPropagation(); open('/pages-extra/privacy/index'); }}>《隐私政策》
+
+
+ );
+}
diff --git a/miniprogram/src/components/PrivacyAgree.scss b/miniprogram/src/components/PrivacyAgree.scss
new file mode 100644
index 0000000..c4f65b6
--- /dev/null
+++ b/miniprogram/src/components/PrivacyAgree.scss
@@ -0,0 +1,5 @@
+.pa-agree { display: flex; align-items: flex-start; gap: 12rpx; margin-top: 18rpx; width: 100%; box-sizing: border-box; }
+.pa-box { width: 34rpx; height: 34rpx; border-radius: 8rpx; border: 2rpx solid #b8c0dd; display: flex; align-items: center; justify-content: center; font-size: 22rpx; color: #fff; flex-shrink: 0; background: #fff; margin-top: 2rpx; }
+.pa-box.on { background: linear-gradient(135deg, #6b8bff, #8f7bff); border-color: transparent; }
+.pa-txt { font-size: 24rpx; color: #7a86b0; line-height: 1.6; }
+.pa-link { color: #6b8bff; }
diff --git a/miniprogram/src/pages-extra/event-detail/index.jsx b/miniprogram/src/pages-extra/event-detail/index.jsx
index 0c23258..9896191 100644
--- a/miniprogram/src/pages-extra/event-detail/index.jsx
+++ b/miniprogram/src/pages-extra/event-detail/index.jsx
@@ -19,6 +19,7 @@ import { isAuthed, getUser, wxLogin, wxPhoneBind, phoneLogin, bindPhone, sendCod
import coverWide from '@/assets/huodong-wide.png';
import Skeleton from '@/components/skeleton';
import './index.scss';
+import PrivacyAgree from '@/components/PrivacyAgree';
import { PageHeader } from '@/components/TopInset';
/* 活动报名状态(5 态) */
@@ -70,6 +71,7 @@ export default function EventDetail() {
/* 登录态 & 我的报名状态:登录/绑号后需重渲染,故用 state 而非渲染期一次性读取 */
const [myBook, setMyBook] = useState(null); // {booked, auditStatus, checkinAt}
const [authed, setAuthed] = useState(isAuthed());
+ const [agree, setAgree] = useState(false); // 协议/隐私同意(登录与绑定手机号前必勾)
const [phoneBound, setPhoneBound] = useState(() => !!(getUser() && getUser().phoneBound));
const [showSms, setShowSms] = useState(false); // 短信兜底开关
const [gatePhone, setGatePhone] = useState('');
@@ -103,6 +105,7 @@ export default function EventDetail() {
/* 微信一键登录:wx.login + 昵称头像 → 后端建/查 wxid 账号 */
const onWxLogin = async () => {
+ if (!agree) { Taro.showToast({ title: '请先阅读并同意《用户服务协议》和《隐私政策》', icon: 'none' }); return; }
setErr(''); setBusy(true);
try {
let nickName = '', avatarUrl = '';
@@ -117,6 +120,7 @@ export default function EventDetail() {
/* 微信一键绑定手机号(getPhoneNumber 回调 code) */
const onWxPhone = async (e) => {
+ if (!agree) { Taro.showToast({ title: '请先阅读并同意《用户服务协议》和《隐私政策》', icon: 'none' }); return; }
const pcode = e.detail && e.detail.code;
if (!pcode) { setErr('已取消授权绑定'); return; }
setErr(''); setBusy(true);
@@ -130,6 +134,7 @@ export default function EventDetail() {
/* 短信兜底:未登录 → phoneLogin(登录即绑号);已登录未绑号 → bindPhone */
const gateSmsLogin = async () => {
+ if (!agree) { Taro.showToast({ title: '请先阅读并同意《用户服务协议》和《隐私政策》', icon: 'none' }); return; }
setErr('');
if (!/^1\d{10}$/.test(gatePhone)) { setErr('请输入正确的 11 位手机号'); return; }
if (!gateCode) { setErr('请输入验证码'); return; }
@@ -336,6 +341,7 @@ export default function EventDetail() {
登录后报名
报名需登录并绑定手机号,用于接收活动通知。
+ setAgree(!agree)} />
{!showSms && (
)}
@@ -360,6 +366,7 @@ export default function EventDetail() {
绑定手机号
绑定后即可报名,用于接收活动通知。
+ setAgree(!agree)} />
{!showSms && (
)}
diff --git a/miniprogram/src/pages/mine/index.jsx b/miniprogram/src/pages/mine/index.jsx
index 2060b21..5be2b00 100644
--- a/miniprogram/src/pages/mine/index.jsx
+++ b/miniprogram/src/pages/mine/index.jsx
@@ -7,6 +7,7 @@ import { getMyBookings, parseIso } from '@/utils/booking';
import { API_BASE } from '@/utils/api';
import { ensureUploadSize } from '@/utils/upload';
import CountdownBox from '@/components/CountdownBox';
+import PrivacyAgree from '@/components/PrivacyAgree';
import './index.scss';
import { PageHeader } from '@/components/TopInset';
@@ -37,6 +38,7 @@ export default function Mine() {
/* 手机号登录 */
const [showPhone, setShowPhone] = useState(false);
+ const [agree, setAgree] = useState(false); // 协议/隐私同意(登录与绑定手机号前必勾)
const [pPhone, setPPhone] = useState('');
const [pCode, setPCode] = useState('');
const [pCd, setPCd] = useState(0);
@@ -69,6 +71,7 @@ export default function Mine() {
/* 微信一键登录 */
const onWxLogin = async () => {
+ if (!agree) { Taro.showToast({ title: '请先阅读并同意《用户服务协议》和《隐私政策》', icon: 'none' }); return; }
setErr('');
setBusy(true);
try {
@@ -121,6 +124,7 @@ export default function Mine() {
/* 微信官方一键绑定手机号(getPhoneNumber 回调) */
const onWxPhone = async (e) => {
+ if (!agree) { Taro.showToast({ title: '请先阅读并同意《用户服务协议》和《隐私政策》', icon: 'none' }); return; }
const detail = (e.detail && e.detail) || {};
const pcode = detail.code;
if (!pcode) { Taro.showToast({ title: '已取消授权', icon: 'none' }); return; }
@@ -150,6 +154,7 @@ export default function Mine() {
};
const doPhoneLogin = async () => {
+ if (!agree) { Taro.showToast({ title: '请先阅读并同意《用户服务协议》和《隐私政策》', icon: 'none' }); return; }
if (!/^1\d{10}$/.test(pPhone)) { setErr('请输入正确的 11 位手机号'); return; }
if (!pCode) { setErr('请输入验证码'); return; }
setErr(''); setBusy(true);
@@ -242,10 +247,11 @@ export default function Mine() {
if (!user || !isAuthed()) {
return (
-
+
+ setAgree(!agree)} />
登录后可绑定手机、查看报名场次与活动签到
setShowPhone(!showPhone)}>{showPhone ? '收起手机号登录' : '或用手机号登录'}
@@ -269,7 +275,7 @@ export default function Mine() {
{err && {err}}
云南省首个由政府主办的免费大学生创业服务平台
- 云南派音人工智能科技有限公司 && 云南汇浙青创科技有限公司
+ 昆明市大学生创业园 · 云超服 YunOPC-Hub
像素字体 BubbledotICG-FinePos · CC BY 4.0
@@ -280,7 +286,7 @@ export default function Mine() {
/* ============ 已登录:资料 + 我的报名 ============ */
return (
-
+
{/* 资料卡 */}