From 574f70be75fb9a76dd76a3e027c63dbf9cc78fd8 Mon Sep 17 00:00:00 2001
From: lion <120344285@qq.com>
Date: Fri, 10 Apr 2026 11:24:41 +0800
Subject: [PATCH] =?UTF-8?q?=E4=BF=A1=E6=81=AF=E7=BC=BA=E5=A4=B1=E6=8F=90?=
=?UTF-8?q?=E7=A4=BA?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
packages/my/index.vue | 28 +++-
packages/register/index.vue | 54 ++++++-
pages/book/index.vue | 106 ++++++++++++-
pages/index/index.vue | 291 +++++++++++++++++++++++++++++++++++-
4 files changed, 473 insertions(+), 6 deletions(-)
diff --git a/packages/my/index.vue b/packages/my/index.vue
index d69cc23..8a85fc5 100644
--- a/packages/my/index.vue
+++ b/packages/my/index.vue
@@ -236,6 +236,27 @@
required: true,
message: '请选择出生日期',
trigger: ['blur', 'change'],
+ }, {
+ validator: (rule, value, callback) => {
+ if (this.base.isNull(value)) return true;
+ const s = String(value).trim();
+ // 仅年月、缺日
+ if (/^\d{4}-\d{1,2}$/.test(s)) return false;
+ if (!/^\d{4}-\d{1,2}-\d{1,2}$/.test(s)) return false;
+ const parts = s.split('-');
+ const y = parseInt(parts[0], 10);
+ const mo = parseInt(parts[1], 10);
+ const da = parseInt(parts[2], 10);
+ if (mo < 1 || mo > 12 || da < 1 || da > 31) return false;
+ const dt = new Date(y, mo - 1, da);
+ return (
+ dt.getFullYear() === y &&
+ dt.getMonth() === mo - 1 &&
+ dt.getDate() === da
+ );
+ },
+ message: '出生日期须为完整年月日(例如 1993-01-15)',
+ trigger: ['blur', 'change'],
}]
}
}
@@ -269,9 +290,12 @@
url:'/packages/avatarUpload/index'
})
},
- // 日期
+ // 日期(规范为 yyyy-MM-dd,保证含年月日)
dateConfirm(e) {
- this.form.birthday = e.year + '-' + e.month + '-' + e.day
+ const y = e.year;
+ const m = String(e.month).padStart(2, '0');
+ const d = String(e.day).padStart(2, '0');
+ this.form.birthday = `${y}-${m}-${d}`;
},
addMobile() {
this.myMobile = this.form.mobile
diff --git a/packages/register/index.vue b/packages/register/index.vue
index 22c3649..c563f3c 100644
--- a/packages/register/index.vue
+++ b/packages/register/index.vue
@@ -185,6 +185,23 @@
required: true,
message: '请选择出生日期',
trigger: ['blur', 'change'],
+ }, {
+ validator: (rule, value, callback) => {
+ if (this.base.isNull(value)) return true;
+ const s = String(value).trim();
+ // 仅年月(如 1993-01)视为不完整
+ if (/^\d{4}-\d{1,2}$/.test(s)) return false;
+ if (!/^\d{4}-\d{1,2}-\d{1,2}$/.test(s)) return false;
+ const parts = s.split('-');
+ const y = parseInt(parts[0], 10);
+ const mo = parseInt(parts[1], 10);
+ const da = parseInt(parts[2], 10);
+ if (mo < 1 || mo > 12 || da < 1 || da > 31) return false;
+ const dt = new Date(y, mo - 1, da);
+ return dt.getFullYear() === y && dt.getMonth() === mo - 1 && dt.getDate() === da;
+ },
+ message: '出生日期须为完整年月日(例如 1993-01-15)',
+ trigger: ['blur', 'change'],
}]
}
}
@@ -209,7 +226,39 @@
}
},
methods: {
+ isBirthdayMonthOnly(birthday) {
+ if (this.base.isNull(birthday)) return false;
+ return /^\d{4}-\d{1,2}$/.test(String(birthday).trim());
+ },
+ isBirthdayYmd(birthday) {
+ if (this.base.isNull(birthday)) return false;
+ const s = String(birthday).trim();
+ if (!/^\d{4}-\d{1,2}-\d{1,2}$/.test(s)) return false;
+ const parts = s.split('-');
+ const y = parseInt(parts[0], 10);
+ const mo = parseInt(parts[1], 10);
+ const da = parseInt(parts[2], 10);
+ if (mo < 1 || mo > 12 || da < 1 || da > 31) return false;
+ const dt = new Date(y, mo - 1, da);
+ return dt.getFullYear() === y && dt.getMonth() === mo - 1 && dt.getDate() === da;
+ },
+ isBasicInfoIncomplete() {
+ const f = this.form || {};
+ if (this.base.isNull(f.username)) return true;
+ if (this.base.isNull(f.sex)) return true;
+ if (this.base.isNull(f.email)) return true;
+ if (this.base.isNull(f.company_name)) return true;
+ if (this.base.isNull(f.company_position)) return true;
+ if (this.base.isNull(f.birthday)) return true;
+ if (this.isBirthdayMonthOnly(f.birthday)) return true;
+ if (!this.isBirthdayYmd(f.birthday)) return true;
+ return false;
+ },
addMobile() {
+ if (this.isBasicInfoIncomplete()) {
+ this.base.toast('请先完善基础信息后再绑定');
+ return;
+ }
// this.myMobile = this.form.mobile
this.showMobile = true
},
@@ -271,7 +320,10 @@
},
// 日期
dateConfirm(e) {
- this.form.birthday = e.year + '-' + e.month + '-' + e.day
+ const y = e.year;
+ const m = String(e.month).padStart(2, '0');
+ const d = String(e.day).padStart(2, '0');
+ this.form.birthday = `${y}-${m}-${d}`;
},
// 处理公司选择确认事件
handleCompanyConfirm(company) {
diff --git a/pages/book/index.vue b/pages/book/index.vue
index 22f0658..6c30f8e 100644
--- a/pages/book/index.vue
+++ b/pages/book/index.vue
@@ -40,6 +40,27 @@
-->
+
+
+
+
+
+ 提示
+ 关闭
+
+
+ 如您已是我方校友,请先绑定账号
+
+ 去绑定
+
+ 如您还不是我方校友,请先注册
+
+ 去注册
+
+
+
+
+
@@ -53,7 +74,9 @@
data() {
return {
user: {},
- enter_schoolmate: 0
+ enter_schoolmate: 0,
+ showRegister: false,
+ hasMobile: false
}
},
onShareAppMessage() {
@@ -69,16 +92,41 @@
}
},
onShow() {
+ this.showRegister = false
this.getUser()
},
onLoad() {
},
methods: {
+ ensureMobileOrPrompt() {
+ if (!this.hasMobile) {
+ this.base.toast("请先绑定或注册")
+ this.showRegister = true
+ return false
+ }
+ return true
+ },
+ goBind() {
+ uni.navigateTo({
+ url: '/packages/register/login'
+ })
+ },
+ toRegister() {
+ uni.navigateTo({
+ url: '/packages/register/index'
+ })
+ },
getUser() {
this.$u.api.user().then(res => {
console.log("res", res)
this.enter_schoolmate = res.enter_schoolmate
this.$u.vuex('vuex_user', res.user)
+ if (this.base.isNull(res.user.mobile)) {
+ this.hasMobile = false
+ } else {
+ this.showRegister = false
+ this.hasMobile = true
+ }
})
},
goToProfile() {
@@ -87,6 +135,9 @@
});
},
handleButtonClick(type) {
+ if (!this.ensureMobileOrPrompt()) {
+ return
+ }
switch (type) {
case 'alumni':
if (this.enter_schoolmate) {
@@ -227,5 +278,58 @@
font-weight: bold;
color: #8f6e4d;
}
+
+ .modal {
+ ::v-deep .u-drawer-bottom {
+ border-radius: 40rpx;
+ }
+
+ .modal-tip-wrap {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 30rpx;
+ }
+
+ .modal-tip {
+ font-size: 32rpx;
+ }
+
+ .modal-close {
+ color: #409eff;
+ font-size: 28rpx;
+ }
+
+ .modal-content {
+ height: 450rpx;
+ padding: 0 30rpx;
+ font-size: 32rpx;
+ text-align: center;
+
+ &>view {
+ margin: 30rpx auto;
+ }
+ }
+
+ .modal-bind {
+ width: 45%;
+ text-align: center;
+ margin: 0 auto;
+ color: #fff;
+ border-radius: 30rpx;
+ padding: 20rpx;
+ background: linear-gradient(to right, #e4cdb4, #c69c6d);
+ }
+
+ .modal-register {
+ width: 45%;
+ text-align: center;
+ margin: 0 auto;
+ color: #fff;
+ border-radius: 30rpx;
+ padding: 20rpx;
+ background: linear-gradient(to right, #5e5fbc, #0d0398);
+ }
+ }
}
\ No newline at end of file
diff --git a/pages/index/index.vue b/pages/index/index.vue
index d493853..3752eff 100644
--- a/pages/index/index.vue
+++ b/pages/index/index.vue
@@ -108,6 +108,32 @@
返回首页
+
+
+
+
+
+
+
+
+ 提示
+ 关闭
+
+
+ 如您已是我方校友,请先绑定账号
+ 去绑定
+ 如您还不是我方校友,请先注册
+ 去注册
+
+
+
+
@@ -118,6 +144,11 @@ import topBanner from "@/components/topBanner.vue";
import PrivacyPopup from "@/components/privacy-popup/privacy-popup.vue";
import CalendarWidget from "@/components/calendar-widget/calendar-widget.vue";
+/** 点遮罩关闭资料缺失提示时写入,值为当天 yyyy-MM-dd,当天内不再弹出 */
+const PROFILE_INCOMPLETE_DISMISSED_KEY = "stbc1_profileIncompleteDismissedDate";
+/** 手机号缺失提醒:当天首次进入首页仅弹出一次(展示过即记) */
+const MOBILE_MISSING_PROMPT_DATE_KEY = "stbc1_mobileMissingPromptDate";
+
export default {
components: {
tabbar,
@@ -137,6 +168,11 @@ export default {
can_appointment: false,
is_birthday: false,
hasShowBirthday: false,
+ showProfileIncomplete: false,
+ showRegister: false,
+ pendingProfileIncomplete: false,
+ pendingMobileMissing: false,
+ isFirstShow: true,
};
},
onShareAppMessage() {
@@ -170,6 +206,25 @@ export default {
this.getNoticesList();
this.getBannerList();
},
+ onShow() {
+ if (this.isFirstShow) {
+ this.isFirstShow = false;
+ return;
+ }
+ this.showRegister = false;
+ let token = uni.getStorageSync("stbc1_lifeData")
+ ? uni.getStorageSync("stbc1_lifeData").vuex_token
+ : "";
+ if (this.base.isNull(token)) return;
+ this.$u.api.user().then((res) => {
+ this.$u.vuex("vuex_user", res.user);
+ if (!this.isProfileIncomplete(res.user)) {
+ this.showProfileIncomplete = false;
+ this.pendingProfileIncomplete = false;
+ this.pendingMobileMissing = false;
+ }
+ });
+ },
methods: {
onAgreePrivacy() {
// 用户同意隐私政策
@@ -183,6 +238,108 @@ export default {
// wx.exitMiniProgram();
console.log("User rejected the privacy policy");
},
+ /** 出生日期仅有年月、无具体日期(如 1993-01)视为未完善 */
+ isBirthdayMonthOnly(birthday) {
+ if (this.base.isNull(birthday)) return false;
+ const s = String(birthday).trim();
+ return /^\d{4}-\d{1,2}$/.test(s);
+ },
+ isEmptyProfileField(v) {
+ if (this.base.isNull(v)) return true;
+ if (typeof v === "string" && v.trim() === "") return true;
+ return false;
+ },
+ getTodayYmd() {
+ const d = new Date();
+ const y = d.getFullYear();
+ const m = String(d.getMonth() + 1).padStart(2, "0");
+ const day = String(d.getDate()).padStart(2, "0");
+ return `${y}-${m}-${day}`;
+ },
+ /** 当天是否已通过点遮罩关闭过资料缺失提示 */
+ isProfileIncompleteDismissedToday() {
+ return uni.getStorageSync(PROFILE_INCOMPLETE_DISMISSED_KEY) === this.getTodayYmd();
+ },
+ isMobileMissing(user) {
+ return !user || this.isEmptyProfileField(user.mobile);
+ },
+ isMobileMissingPromptShownToday() {
+ return uni.getStorageSync(MOBILE_MISSING_PROMPT_DATE_KEY) === this.getTodayYmd();
+ },
+ markMobileMissingPromptShownToday() {
+ uni.setStorageSync(MOBILE_MISSING_PROMPT_DATE_KEY, this.getTodayYmd());
+ },
+ /** 已绑定手机的前提下,资料是否不完整 */
+ isProfileIncomplete(user) {
+ if (!user || this.isEmptyProfileField(user.mobile)) return false;
+ if (this.isEmptyProfileField(user.company_name)) return true;
+ if (this.isEmptyProfileField(user.company_position)) return true;
+ if (this.isEmptyProfileField(user.email)) return true;
+ if (this.isEmptyProfileField(user.sex)) return true;
+ if (this.isEmptyProfileField(user.birthday)) return true;
+ if (this.isBirthdayMonthOnly(user.birthday)) return true;
+ return false;
+ },
+ maybeShowProfileIncomplete(user, isBirthdayFlag) {
+ if (!user || !this.isProfileIncomplete(user)) {
+ this.pendingProfileIncomplete = false;
+ return;
+ }
+ if (this.isProfileIncompleteDismissedToday()) {
+ this.pendingProfileIncomplete = false;
+ return;
+ }
+ const showBirthdayLayer =
+ isBirthdayFlag && !this.hasShowBirthday;
+ if (showBirthdayLayer) {
+ this.pendingProfileIncomplete = true;
+ } else {
+ this.showProfileIncomplete = true;
+ this.pendingProfileIncomplete = false;
+ }
+ },
+ maybeShowHomeReminder(user, isBirthdayFlag) {
+ if (this.isMobileMissing(user) && !this.isMobileMissingPromptShownToday()) {
+ const showBirthdayLayer = isBirthdayFlag && !this.hasShowBirthday;
+ if (showBirthdayLayer) {
+ this.pendingMobileMissing = true;
+ } else {
+ this.base.toast("请先绑定或注册");
+ this.showRegister = true;
+ this.markMobileMissingPromptShownToday();
+ }
+ this.pendingProfileIncomplete = false;
+ return;
+ }
+ this.maybeShowProfileIncomplete(user, isBirthdayFlag);
+ },
+ /** 点遮罩或点「去完善」后,当天冷启动不再弹出资料缺失提示 */
+ markProfileIncompleteDismissedToday() {
+ uni.setStorageSync(PROFILE_INCOMPLETE_DISMISSED_KEY, this.getTodayYmd());
+ },
+ goCompleteProfile() {
+ this.showProfileIncomplete = false;
+ this.markProfileIncompleteDismissedToday();
+ uni.navigateTo({
+ url: "/packages/my/index",
+ });
+ },
+ closeProfileIncomplete() {
+ this.showProfileIncomplete = false;
+ this.markProfileIncompleteDismissedToday();
+ },
+ goBind() {
+ this.showRegister = false;
+ uni.navigateTo({
+ url: "/packages/register/login",
+ });
+ },
+ toRegister() {
+ this.showRegister = false;
+ uni.navigateTo({
+ url: "/packages/register/index",
+ });
+ },
changeCurrent(e) {
this.show_current_swiper = e.detail.current + 1;
},
@@ -233,11 +390,17 @@ export default {
vuex_token: tokenResult,
vuex_user: result1.data.user,
});
-
+ this.$u.vuex("vuex_token", tokenResult);
+ this.$u.vuex("vuex_user", result1.data.user);
+
// 登录成功后检查用户生日
if (result1.data.is_birthday && !this.hasShowBirthday) {
this.is_birthday = true;
}
+ this.maybeShowHomeReminder(
+ result1.data.user,
+ result1.data.is_birthday
+ );
},
fail(err) {
console.log("uesr-error", err);
@@ -253,11 +416,12 @@ export default {
// }
// this.door_appointments = res.door_appointments ? true : false
this.$u.vuex("vuex_user", res.user);
-
+
// 检查用户是否今天生日(使用接口返回的is_birthday参数)
if (res.is_birthday && !this.hasShowBirthday) {
this.is_birthday = true;
}
+ this.maybeShowHomeReminder(res.user, res.is_birthday);
});
},
@@ -267,6 +431,27 @@ export default {
// 标记今天已经显示过生日弹窗
uni.setStorageSync("hasShowBirthday", true);
this.hasShowBirthday = true;
+ if (this.pendingProfileIncomplete) {
+ const life = uni.getStorageSync("stbc1_lifeData") || {};
+ const u = life.vuex_user || this.vuex_user || {};
+ if (
+ !this.isProfileIncompleteDismissedToday() &&
+ this.isProfileIncomplete(u)
+ ) {
+ this.showProfileIncomplete = true;
+ }
+ this.pendingProfileIncomplete = false;
+ }
+ if (this.pendingMobileMissing) {
+ const life = uni.getStorageSync("stbc1_lifeData") || {};
+ const u = life.vuex_user || this.vuex_user || {};
+ if (this.isMobileMissing(u) && !this.isMobileMissingPromptShownToday()) {
+ this.base.toast("请先绑定或注册");
+ this.showRegister = true;
+ this.markMobileMissingPromptShownToday();
+ }
+ this.pendingMobileMissing = false;
+ }
},
async getBannerList() {
@@ -575,4 +760,106 @@ export default {
transition: all 0.3s ease;
}
}
+
+.profile-incomplete-popup {
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100vw;
+ height: 100vh;
+ z-index: 9998;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.profile-incomplete-mask {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ background: rgba(0, 0, 0, 0.45);
+}
+
+.profile-incomplete-dialog {
+ position: relative;
+ width: 620rpx;
+ padding: 56rpx 44rpx 46rpx;
+ background: #fff;
+ border-radius: 30rpx;
+ box-shadow: 0 8rpx 40rpx rgba(0, 0, 0, 0.12);
+}
+
+.profile-incomplete-text {
+ font-size: 32rpx;
+ color: #333;
+ line-height: 1.6;
+ text-align: center;
+ margin-bottom: 46rpx;
+}
+
+.profile-incomplete-btn {
+ width: 70%;
+ margin: 0 auto;
+ color: #fff;
+ text-align: center;
+ padding: 20rpx 0;
+ border-radius: 30rpx;
+ font-size: 30rpx;
+ background: linear-gradient(to right, #5e5fbc, #0d0398);
+}
+
+.modal {
+ ::v-deep .u-drawer-bottom {
+ border-radius: 40rpx;
+ }
+
+ &-tip-wrap {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 30rpx;
+ }
+
+ &-tip {
+ font-size: 32rpx;
+ }
+
+ &-close {
+ color: #409eff;
+ font-size: 28rpx;
+ }
+
+ &-content {
+ height: 450rpx;
+ padding: 0 30rpx;
+ font-size: 32rpx;
+ text-align: center;
+
+ & > view {
+ margin: 30rpx auto;
+ }
+ }
+
+ &-bind {
+ width: 45%;
+ text-align: center;
+ margin: 0 auto;
+ color: #fff;
+ border-radius: 30rpx;
+ padding: 20rpx;
+ background: linear-gradient(to right, #e4cdb4, #c69c6d);
+ }
+
+ &-register {
+ width: 45%;
+ text-align: center;
+ margin: 0 auto;
+ color: #fff;
+ border-radius: 30rpx;
+ padding: 20rpx;
+ background: linear-gradient(to right, #5e5fbc, #0d0398);
+ }
+}
\ No newline at end of file