Showing
62 changed files
with
2280 additions
and
185 deletions
| @@ -4,11 +4,12 @@ SHOPRO_VERSION=v2.4.1 | @@ -4,11 +4,12 @@ SHOPRO_VERSION=v2.4.1 | ||
| 4 | # 后端接口 - 正式环境(通过 process.env.NODE_ENV 非 development) | 4 | # 后端接口 - 正式环境(通过 process.env.NODE_ENV 非 development) |
| 5 | # SHOPRO_BASE_URL=http://api-dashboard.yudao.iocoder.cn | 5 | # SHOPRO_BASE_URL=http://api-dashboard.yudao.iocoder.cn |
| 6 | # SHOPRO_BASE_URL=http://mall.hcxtec.com | 6 | # SHOPRO_BASE_URL=http://mall.hcxtec.com |
| 7 | +SHOPRO_BASE_URL=https://xunji.geaktec.com | ||
| 7 | 8 | ||
| 8 | # 后端接口 - 测试环境(通过 process.env.NODE_ENV = development) | 9 | # 后端接口 - 测试环境(通过 process.env.NODE_ENV = development) |
| 9 | -#SHOPRO_DEV_BASE_URL=http://192.168.1.200:48081 | 10 | +# SHOPRO_DEV_BASE_URL=http://192.168.1.200:48081 |
| 10 | # SHOPRO_DEV_BASE_URL=http://192.168.1.85:48080 | 11 | # SHOPRO_DEV_BASE_URL=http://192.168.1.85:48080 |
| 11 | -SHOPRO_DEV_BASE_URL=https:/xunji.geaktec.com | 12 | +SHOPRO_DEV_BASE_URL=https://xunji.geaktec.com |
| 12 | # SHOPRO_DEV_BASE_URL=http://api-dashboard.yudao.iocoder.cn/ | 13 | # SHOPRO_DEV_BASE_URL=http://api-dashboard.yudao.iocoder.cn/ |
| 13 | ### SHOPRO_DEV_BASE_URL=http://10.171.1.188:48080 | 14 | ### SHOPRO_DEV_BASE_URL=http://10.171.1.188:48080 |
| 14 | ### SHOPRO_DEV_BASE_URL = http://yunai.natapp1.cc | 15 | ### SHOPRO_DEV_BASE_URL = http://yunai.natapp1.cc |
| @@ -178,6 +178,38 @@ | @@ -178,6 +178,38 @@ | ||
| 178 | "navigationBarTitleText": "个人资料", | 178 | "navigationBarTitleText": "个人资料", |
| 179 | "navigationStyle": "default" | 179 | "navigationStyle": "default" |
| 180 | } | 180 | } |
| 181 | + }, | ||
| 182 | + { | ||
| 183 | + "path": "pages/user/wode-changjian-wenti", | ||
| 184 | + "style": { | ||
| 185 | + "navigationBarTitleText": "我的常见问题" | ||
| 186 | + } | ||
| 187 | + }, | ||
| 188 | + | ||
| 189 | + { | ||
| 190 | + "path": "pages/user/wode-guanyu-hongxing", | ||
| 191 | + "style": { | ||
| 192 | + "navigationBarTitleText": "我的关于鸿星" | ||
| 193 | + } | ||
| 194 | + }, | ||
| 195 | + { | ||
| 196 | + "path": "pages/user/wode-jiankang-ziliao", | ||
| 197 | + "style": { | ||
| 198 | + "navigationBarTitleText": "我的健康资料" | ||
| 199 | + } | ||
| 200 | + }, | ||
| 201 | + { | ||
| 202 | + "path": "pages/user/wode-lianxi-kefu", | ||
| 203 | + "style": { | ||
| 204 | + "navigationBarTitleText": "我的联系客服" | ||
| 205 | + } | ||
| 206 | + }, | ||
| 207 | + { | ||
| 208 | + "path": "pages/user/wode-shezhi", | ||
| 209 | + "style": { | ||
| 210 | + "navigationBarTitleText": "设置", | ||
| 211 | + "navigationStyle": "default" | ||
| 212 | + } | ||
| 181 | } | 213 | } |
| 182 | ] | 214 | ] |
| 183 | } | 215 | } |
| @@ -26,7 +26,7 @@ | @@ -26,7 +26,7 @@ | ||
| 26 | </view> | 26 | </view> |
| 27 | 27 | ||
| 28 | <!-- --> | 28 | <!-- --> |
| 29 | - <view class="vip-banner" hover-class="opacity-hover" @click="goAddVip"> | 29 | + <!-- <view class="vip-banner" hover-class="opacity-hover" @click="goAddVip"> |
| 30 | <view class="vip-info"> | 30 | <view class="vip-info"> |
| 31 | <uni-icons type="vip-filled" size="22" color="#f1c40f" /> | 31 | <uni-icons type="vip-filled" size="22" color="#f1c40f" /> |
| 32 | <text class="vip-text"> | 32 | <text class="vip-text"> |
| @@ -34,25 +34,25 @@ | @@ -34,25 +34,25 @@ | ||
| 34 | </text> | 34 | </text> |
| 35 | </view> | 35 | </view> |
| 36 | <view class="vip-btn">{{ userInfo.deposit === 1 ? '查看权益' : '立即开通' }}</view> | 36 | <view class="vip-btn">{{ userInfo.deposit === 1 ? '查看权益' : '立即开通' }}</view> |
| 37 | - </view> | 37 | + </view> --> |
| 38 | 38 | ||
| 39 | <!-- 课程状态快速入口 --> | 39 | <!-- 课程状态快速入口 --> |
| 40 | - <view class="section-card quick-entry"> | 40 | + <!-- <view class="section-card quick-entry"> |
| 41 | <view v-for="entry in quickEntryConfig" :key="entry.type" class="entry-item" hover-class="opacity-hover" | 41 | <view v-for="entry in quickEntryConfig" :key="entry.type" class="entry-item" hover-class="opacity-hover" |
| 42 | @click="handleQuickEntry(entry.type)"> | 42 | @click="handleQuickEntry(entry.type)"> |
| 43 | <text class="num">{{ userInfo[entry.key] || 0 }}</text> | 43 | <text class="num">{{ userInfo[entry.key] || 0 }}</text> |
| 44 | <text class="label">{{ entry.label }}</text> | 44 | <text class="label">{{ entry.label }}</text> |
| 45 | </view> | 45 | </view> |
| 46 | - </view> | 46 | + </view> --> |
| 47 | 47 | ||
| 48 | <!-- 广告位 --> | 48 | <!-- 广告位 --> |
| 49 | - <view class="banner-box" @click="goJiamen"> | 49 | + <!-- <view class="banner-box" @click="goJiamen"> |
| 50 | <image src="https://fitness-hcxtec-bucket.oss-cn-shenzhen.aliyuncs.com/20260316/4_1773627891703.png" | 50 | <image src="https://fitness-hcxtec-bucket.oss-cn-shenzhen.aliyuncs.com/20260316/4_1773627891703.png" |
| 51 | mode="aspectFill" class="banner-img" /> | 51 | mode="aspectFill" class="banner-img" /> |
| 52 | - </view> | 52 | + </view> --> |
| 53 | 53 | ||
| 54 | <!-- 核心应用区 --> | 54 | <!-- 核心应用区 --> |
| 55 | - <view class="section-card apply-section"> | 55 | + <!-- <view class="section-card apply-section"> |
| 56 | <view v-for="(item, index) in APPLY_CONFIG_LIST" :key="index" class="apply-item" | 56 | <view v-for="(item, index) in APPLY_CONFIG_LIST" :key="index" class="apply-item" |
| 57 | @click="authNavigateTo(item.url)"> | 57 | @click="authNavigateTo(item.url)"> |
| 58 | <view class="icon-bg"> | 58 | <view class="icon-bg"> |
| @@ -60,10 +60,10 @@ | @@ -60,10 +60,10 @@ | ||
| 60 | </view> | 60 | </view> |
| 61 | <text class="text">{{ item.text }}</text> | 61 | <text class="text">{{ item.text }}</text> |
| 62 | </view> | 62 | </view> |
| 63 | - </view> | 63 | + </view> --> |
| 64 | 64 | ||
| 65 | <!-- 资产账户网格区 --> | 65 | <!-- 资产账户网格区 --> |
| 66 | - <view v-if="userStore.isLogin" class="section-card"> | 66 | + <!-- <view v-if="userStore.isLogin" class="section-card"> |
| 67 | <view class="account-grid"> | 67 | <view class="account-grid"> |
| 68 | <view v-for="(acc, idx) in accountConfig" :key="idx" class="account-item" @click="authNavigateTo(acc.url)"> | 68 | <view v-for="(acc, idx) in accountConfig" :key="idx" class="account-item" @click="authNavigateTo(acc.url)"> |
| 69 | <text class="acc-lab">{{ acc.label }}</text> | 69 | <text class="acc-lab">{{ acc.label }}</text> |
| @@ -73,7 +73,7 @@ | @@ -73,7 +73,7 @@ | ||
| 73 | </text> | 73 | </text> |
| 74 | </view> | 74 | </view> |
| 75 | </view> | 75 | </view> |
| 76 | - </view> | 76 | + </view> --> |
| 77 | 77 | ||
| 78 | <!-- 功能矩阵九宫格 --> | 78 | <!-- 功能矩阵九宫格 --> |
| 79 | <view class="section-card icon-grid-box"> | 79 | <view class="section-card icon-grid-box"> |
| @@ -100,10 +100,10 @@ | @@ -100,10 +100,10 @@ | ||
| 100 | <text class="setting-text">个人设置</text> | 100 | <text class="setting-text">个人设置</text> |
| 101 | <uni-icons type="right" size="14" color="#E0E0E0" /> | 101 | <uni-icons type="right" size="14" color="#E0E0E0" /> |
| 102 | </view> | 102 | </view> |
| 103 | - <view class="setting-item" @click="authNavigateTo('/pages5/pages/user/wode-yinsishezhi')"> | 103 | + <!-- <view class="setting-item" @click="authNavigateTo('/pages5/pages/user/wode-yinsishezhi')"> |
| 104 | <text class="setting-text">隐私中心</text> | 104 | <text class="setting-text">隐私中心</text> |
| 105 | <uni-icons type="right" size="14" color="#E0E0E0" /> | 105 | <uni-icons type="right" size="14" color="#E0E0E0" /> |
| 106 | - </view> | 106 | + </view> --> |
| 107 | </view> | 107 | </view> |
| 108 | 108 | ||
| 109 | <Tabbar /> | 109 | <Tabbar /> |
| @@ -130,7 +130,30 @@ const memberLevelName = ref(''); | @@ -130,7 +130,30 @@ const memberLevelName = ref(''); | ||
| 130 | // 固定的 UI 配置 | 130 | // 固定的 UI 配置 |
| 131 | const APPLY_CONFIG_LIST = []; | 131 | const APPLY_CONFIG_LIST = []; |
| 132 | 132 | ||
| 133 | -const FUNCTION_CONFIG_LIST = []; | 133 | +const FUNCTION_CONFIG_LIST = [ |
| 134 | + { | ||
| 135 | + text: '健康资料', | ||
| 136 | + url: '/pages5/pages/user/wode-jiankang-ziliao', | ||
| 137 | + icon: '/static/icons/md-folder_open 1@1x.png', | ||
| 138 | + }, | ||
| 139 | + { | ||
| 140 | + text: '常见问题', | ||
| 141 | + url: '/pages5/pages/user/wode-changjian-wenti', | ||
| 142 | + icon: '/static/icons/iconPark-helpcenter 1@1x.png', | ||
| 143 | + }, | ||
| 144 | + { | ||
| 145 | + text: '联系客服', | ||
| 146 | + url: '/pages5/pages/user/wode-lianxi-kefu', | ||
| 147 | + icon: '/static/icons/riLine-customer-service-2-line 1@1x.png', | ||
| 148 | + }, | ||
| 149 | + | ||
| 150 | + { | ||
| 151 | + text: '关于鸿星', | ||
| 152 | + url: '/pages5/pages/user/wode-guanyu-hongxing', | ||
| 153 | + icon: '/static/icons/antOutline-exclamation-circle 1@1x.png', | ||
| 154 | + }, | ||
| 155 | +]; | ||
| 156 | + | ||
| 134 | 157 | ||
| 135 | // 课程计数状态配置映射 | 158 | // 课程计数状态配置映射 |
| 136 | const quickEntryConfig = [ | 159 | const quickEntryConfig = [ |
| @@ -191,22 +214,23 @@ const handleGridItemClick = (item) => { | @@ -191,22 +214,23 @@ const handleGridItemClick = (item) => { | ||
| 191 | */ | 214 | */ |
| 192 | const fetchPageData = async () => { | 215 | const fetchPageData = async () => { |
| 193 | try { | 216 | try { |
| 194 | - const [userRes, levelRes] = await Promise.all([ | ||
| 195 | - UserApi.getUserInfo(), | ||
| 196 | - MemberApi.getMemberLevel(), | ||
| 197 | - ]); | 217 | + // const [userRes, levelRes] = await Promise.all([ |
| 218 | + // UserApi.getUserInfo(), | ||
| 219 | + // // MemberApi.getMemberLevel(), | ||
| 220 | + // ]); | ||
| 221 | + const userRes = UserApi.getUserInfo(); | ||
| 198 | 222 | ||
| 199 | const rawUser = userRes.data || {}; | 223 | const rawUser = userRes.data || {}; |
| 200 | userInfo.value = rawUser; | 224 | userInfo.value = rawUser; |
| 201 | 225 | ||
| 202 | // 架构重构:数据拉取后一次性计算出等级映射结果,拒绝在 computed 内部循环执行实例化 | 226 | // 架构重构:数据拉取后一次性计算出等级映射结果,拒绝在 computed 内部循环执行实例化 |
| 203 | - const levels = levelRes.data?.detailList || []; | ||
| 204 | - if (rawUser.level !== undefined && levels.length > 0) { | ||
| 205 | - const target = levels.find((item) => item.id === rawUser.level); | ||
| 206 | - memberLevelName.value = target ? target.name : ''; | ||
| 207 | - } else { | ||
| 208 | - memberLevelName.value = ''; | ||
| 209 | - } | 227 | + // const levels = levelRes.data?.detailList || []; |
| 228 | + // if (rawUser.level !== undefined) { | ||
| 229 | + // // const target = levels.find((item) => item.id === rawUser.level); | ||
| 230 | + // // memberLevelName.value = target ? target.name : ''; | ||
| 231 | + // } else { | ||
| 232 | + // // memberLevelName.value = ''; | ||
| 233 | + // } | ||
| 210 | } catch (error) { | 234 | } catch (error) { |
| 211 | console.error('[API Error] 拉取个人资产信息流失败:', error); | 235 | console.error('[API Error] 拉取个人资产信息流失败:', error); |
| 212 | } | 236 | } |
| 1 | <template> | 1 | <template> |
| 2 | <view class="home-page" v-if="userStore.isLogin"> | 2 | <view class="home-page" v-if="userStore.isLogin"> |
| 3 | <view class="tab-bar" :style="{ paddingTop: menuButtonHeight + topSafeArea + 'px' }"> | 3 | <view class="tab-bar" :style="{ paddingTop: menuButtonHeight + topSafeArea + 'px' }"> |
| 4 | - <view class="tab-item" :class="{ active: currentTab === 0 }" @click="handleTabClick(0)">训记</view> | 4 | + <!-- <view class="tab-item" :class="{ active: currentTab === 0 }" @click="handleTabClick(0)">训记</view> --> |
| 5 | <view class="tab-item" :class="{ active: currentTab === 1 }" @click="handleTabClick(1)">计划</view> | 5 | <view class="tab-item" :class="{ active: currentTab === 1 }" @click="handleTabClick(1)">计划</view> |
| 6 | <view class="tab-item" :class="{ active: currentTab === 2 }" @click="handleTabClick(2)">日历</view> | 6 | <view class="tab-item" :class="{ active: currentTab === 2 }" @click="handleTabClick(2)">日历</view> |
| 7 | <view class="tab-item" :class="{ active: currentTab === 3 }" @click="handleTabClick(3)">动作</view> | 7 | <view class="tab-item" :class="{ active: currentTab === 3 }" @click="handleTabClick(3)">动作</view> |
| @@ -13,7 +13,7 @@ | @@ -13,7 +13,7 @@ | ||
| 13 | </view> | 13 | </view> |
| 14 | 14 | ||
| 15 | <view class="content"> | 15 | <view class="content"> |
| 16 | - <xunjiXunji v-if="currentTab === 0" /> | 16 | + <!-- <xunjiXunji v-if="currentTab === 0" /> --> |
| 17 | <xunjiXunlianjihua v-if="currentTab === 1" /> | 17 | <xunjiXunlianjihua v-if="currentTab === 1" /> |
| 18 | <xunjiRili v-if="currentTab === 2" /> | 18 | <xunjiRili v-if="currentTab === 2" /> |
| 19 | <xunjiDongzuo v-if="currentTab === 3" /> | 19 | <xunjiDongzuo v-if="currentTab === 3" /> |
| @@ -105,7 +105,7 @@ const trainingStore = useTrainingStore(); | @@ -105,7 +105,7 @@ const trainingStore = useTrainingStore(); | ||
| 105 | const userStore = useUserStore(); | 105 | const userStore = useUserStore(); |
| 106 | 106 | ||
| 107 | // --- 补全缺失的响应式变量定义 --- | 107 | // --- 补全缺失的响应式变量定义 --- |
| 108 | -const currentTab = ref(0); | 108 | +const currentTab = ref(1); |
| 109 | const currentComponent = shallowRef(xunjiXunji); // 用于 H5 端动态组件切换(如保留原功能逻辑) | 109 | const currentComponent = shallowRef(xunjiXunji); // 用于 H5 端动态组件切换(如保留原功能逻辑) |
| 110 | const drawer = ref(null); // uni-drawer 的组件实例引用 | 110 | const drawer = ref(null); // uni-drawer 的组件实例引用 |
| 111 | 111 |
| @@ -13,7 +13,7 @@ | @@ -13,7 +13,7 @@ | ||
| 13 | <view v-if="showMusclePicker" class="popup-overlay" @click="closeAllPopups"> | 13 | <view v-if="showMusclePicker" class="popup-overlay" @click="closeAllPopups"> |
| 14 | <view class="popup-content" @click.stop> | 14 | <view class="popup-content" @click.stop> |
| 15 | <view class="popup-header"> | 15 | <view class="popup-header"> |
| 16 | - <view class="close-btn" @click="closeAllPopups">×</view> | 16 | + <view class="close-btn" @click="closeAllPopups">x</view> |
| 17 | <view class="title">选择训练部位</view> | 17 | <view class="title">选择训练部位</view> |
| 18 | <view class="confirm-btn" @click="confirmMuscleSelection">完成</view> | 18 | <view class="confirm-btn" @click="confirmMuscleSelection">完成</view> |
| 19 | </view> | 19 | </view> |
| @@ -323,7 +323,11 @@ const openCoverSelector = () => { | @@ -323,7 +323,11 @@ const openCoverSelector = () => { | ||
| 323 | // 封面上传 | 323 | // 封面上传 |
| 324 | try { | 324 | try { |
| 325 | const result = await FileApi.uploadFile(path); | 325 | const result = await FileApi.uploadFile(path); |
| 326 | + console.log(res, 'res'); | ||
| 327 | + | ||
| 326 | coverImagePath.value = result.data; | 328 | coverImagePath.value = result.data; |
| 329 | + console.log('coverImagePath', coverImagePath.value); | ||
| 330 | + | ||
| 327 | coverUploaded.value = true; | 331 | coverUploaded.value = true; |
| 328 | uni.showToast({ | 332 | uni.showToast({ |
| 329 | title: "封面上传成功", | 333 | title: "封面上传成功", |
pages5/pages/user/wode-changjian-wenti.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <view class="level-page"> | ||
| 3 | + <!-- 导航栏 --> | ||
| 4 | + <uni-nav-bar title="华创信" left-icon="left" @click-left="goBack" :fixed="true" :status-bar="true" /> | ||
| 5 | + <view class="top-right"> | ||
| 6 | + <!-- <u-icon name="document" size="24" color="#fff" @click="showRules"></u-icon> --> | ||
| 7 | + <text class="right-text">华创信</text> | ||
| 8 | + </view> | ||
| 9 | + | ||
| 10 | + <!-- 用户信息 --> | ||
| 11 | + <view class="user-info"> | ||
| 12 | + <image src="https://fitness-hcxtec-bucket.oss-cn-shenzhen.aliyuncs.com/20260316/order-empty_1773628059920.png" | ||
| 13 | + mode="aspectFill" class="avatar"></image> | ||
| 14 | + <text class="username">华创信开发者</text> | ||
| 15 | + </view> | ||
| 16 | + | ||
| 17 | + <!-- 更多权益 --> | ||
| 18 | + <view class="more-benefits"> | ||
| 19 | + <view class="more-text">华创信开发者</view> | ||
| 20 | + <view class="more-text">系统开发中</view> | ||
| 21 | + <view class="more-text">敬请期待~</view> | ||
| 22 | + </view> | ||
| 23 | + </view> | ||
| 24 | +</template> | ||
| 25 | + | ||
| 26 | +<script> | ||
| 27 | +export default { | ||
| 28 | + methods: { | ||
| 29 | + goBack() { | ||
| 30 | + uni.navigateBack(); | ||
| 31 | + }, | ||
| 32 | + showRules() { | ||
| 33 | + uni.showToast({ title: '查看开发内容', icon: 'success' }); | ||
| 34 | + }, | ||
| 35 | + }, | ||
| 36 | +}; | ||
| 37 | +</script> | ||
| 38 | + | ||
| 39 | +<style scoped> | ||
| 40 | +.level-page { | ||
| 41 | + position: relative; | ||
| 42 | + width: 100%; | ||
| 43 | + min-height: 100vh; | ||
| 44 | + background-color: #1a1a1a; | ||
| 45 | + color: white; | ||
| 46 | + padding-bottom: 40rpx; | ||
| 47 | +} | ||
| 48 | + | ||
| 49 | +.top-right { | ||
| 50 | + position: absolute; | ||
| 51 | + top: 20rpx; | ||
| 52 | + right: 20rpx; | ||
| 53 | + display: flex; | ||
| 54 | + align-items: center; | ||
| 55 | + gap: 10rpx; | ||
| 56 | + color: white; | ||
| 57 | + font-size: 24rpx; | ||
| 58 | +} | ||
| 59 | + | ||
| 60 | +.user-info { | ||
| 61 | + display: flex; | ||
| 62 | + align-items: center; | ||
| 63 | + gap: 20rpx; | ||
| 64 | + padding: 20rpx; | ||
| 65 | + margin-top: 20rpx; | ||
| 66 | +} | ||
| 67 | + | ||
| 68 | +.avatar { | ||
| 69 | + width: 60rpx; | ||
| 70 | + height: 60rpx; | ||
| 71 | + border-radius: 50%; | ||
| 72 | + object-fit: cover; | ||
| 73 | +} | ||
| 74 | + | ||
| 75 | +.username { | ||
| 76 | + font-size: 28rpx; | ||
| 77 | +} | ||
| 78 | + | ||
| 79 | +.level-card { | ||
| 80 | + width: 600rpx; | ||
| 81 | + height: 300rpx; | ||
| 82 | + background-color: rgba(173, 216, 230, 0.3); | ||
| 83 | + border-radius: 20rpx; | ||
| 84 | + padding: 30rpx; | ||
| 85 | + margin: 20rpx auto; | ||
| 86 | + position: relative; | ||
| 87 | + overflow: hidden; | ||
| 88 | +} | ||
| 89 | + | ||
| 90 | +.level-name { | ||
| 91 | + font-size: 40rpx; | ||
| 92 | + font-weight: bold; | ||
| 93 | + margin-bottom: 10rpx; | ||
| 94 | +} | ||
| 95 | + | ||
| 96 | +.level-en { | ||
| 97 | + font-size: 36rpx; | ||
| 98 | + font-weight: bold; | ||
| 99 | + margin-bottom: 20rpx; | ||
| 100 | +} | ||
| 101 | + | ||
| 102 | +.require { | ||
| 103 | + font-size: 24rpx; | ||
| 104 | + margin-bottom: 20rpx; | ||
| 105 | +} | ||
| 106 | + | ||
| 107 | +.detail { | ||
| 108 | + font-size: 24rpx; | ||
| 109 | + color: #ccc; | ||
| 110 | +} | ||
| 111 | + | ||
| 112 | +.progress-bar { | ||
| 113 | + width: 600rpx; | ||
| 114 | + height: 20rpx; | ||
| 115 | + background-color: #333; | ||
| 116 | + border-radius: 10rpx; | ||
| 117 | + margin: 20rpx auto; | ||
| 118 | + position: relative; | ||
| 119 | + overflow: hidden; | ||
| 120 | +} | ||
| 121 | + | ||
| 122 | +.progress-track { | ||
| 123 | + width: 100%; | ||
| 124 | + height: 100%; | ||
| 125 | + background-color: #333; | ||
| 126 | + border-radius: 10rpx; | ||
| 127 | +} | ||
| 128 | + | ||
| 129 | +.progress-fill { | ||
| 130 | + width: 20%; | ||
| 131 | + height: 100%; | ||
| 132 | + background-color: #007aff; | ||
| 133 | + border-radius: 10rpx; | ||
| 134 | +} | ||
| 135 | + | ||
| 136 | +.progress-dot { | ||
| 137 | + position: absolute; | ||
| 138 | + top: 50%; | ||
| 139 | + left: 20%; | ||
| 140 | + transform: translate(-50%, -50%); | ||
| 141 | + width: 12rpx; | ||
| 142 | + height: 12rpx; | ||
| 143 | + background-color: #007aff; | ||
| 144 | + border-radius: 50%; | ||
| 145 | +} | ||
| 146 | + | ||
| 147 | +.benefits-section { | ||
| 148 | + margin: 20rpx; | ||
| 149 | + padding: 0 20rpx; | ||
| 150 | +} | ||
| 151 | + | ||
| 152 | +.section-title { | ||
| 153 | + font-size: 32rpx; | ||
| 154 | + margin-bottom: 20rpx; | ||
| 155 | + padding-left: 10rpx; | ||
| 156 | +} | ||
| 157 | + | ||
| 158 | +.benefit-list { | ||
| 159 | + display: flex; | ||
| 160 | + flex-direction: row; | ||
| 161 | + justify-content: space-between; | ||
| 162 | + gap: 16rpx; | ||
| 163 | +} | ||
| 164 | + | ||
| 165 | +.benefit-item { | ||
| 166 | + width: 180rpx; | ||
| 167 | + background-color: rgba(255, 255, 255, 0.1); | ||
| 168 | + border-radius: 12rpx; | ||
| 169 | + padding: 16rpx 12rpx; | ||
| 170 | + text-align: center; | ||
| 171 | + box-sizing: border-box; | ||
| 172 | +} | ||
| 173 | + | ||
| 174 | +.icon { | ||
| 175 | + width: 36rpx; | ||
| 176 | + height: 36rpx; | ||
| 177 | + object-fit: cover; | ||
| 178 | + margin-bottom: 8rpx; | ||
| 179 | +} | ||
| 180 | + | ||
| 181 | +.benefit-name { | ||
| 182 | + font-size: 22rpx; | ||
| 183 | + margin-bottom: 4rpx; | ||
| 184 | + font-weight: bold; | ||
| 185 | +} | ||
| 186 | + | ||
| 187 | +.benefit-desc { | ||
| 188 | + font-size: 18rpx; | ||
| 189 | + color: #ccc; | ||
| 190 | + line-height: 1.4; | ||
| 191 | +} | ||
| 192 | + | ||
| 193 | +.time-tag { | ||
| 194 | + font-size: 18rpx; | ||
| 195 | + color: white; | ||
| 196 | + background-color: #ff6b00; | ||
| 197 | + padding: 4rpx 8rpx; | ||
| 198 | + border-radius: 8rpx; | ||
| 199 | + margin-top: 8rpx; | ||
| 200 | + display: inline-block; | ||
| 201 | +} | ||
| 202 | + | ||
| 203 | +.more-benefits { | ||
| 204 | + margin: 30rpx 20rpx 0; | ||
| 205 | + padding: 20rpx; | ||
| 206 | + background-color: rgba(255, 255, 255, 0.1); | ||
| 207 | + border-radius: 12rpx; | ||
| 208 | + text-align: center; | ||
| 209 | +} | ||
| 210 | + | ||
| 211 | +.more-text { | ||
| 212 | + font-size: 24rpx; | ||
| 213 | + color: #ccc; | ||
| 214 | + margin-bottom: 10rpx; | ||
| 215 | +} | ||
| 216 | +</style> |
| @@ -2,14 +2,9 @@ | @@ -2,14 +2,9 @@ | ||
| 2 | <view class="profile-page"> | 2 | <view class="profile-page"> |
| 3 | <view class="avatar-section"> | 3 | <view class="avatar-section"> |
| 4 | <button class="avatar-edit-btn" open-type="chooseAvatar" @chooseavatar="handleChooseAvatar"> | 4 | <button class="avatar-edit-btn" open-type="chooseAvatar" @chooseavatar="handleChooseAvatar"> |
| 5 | - <image | ||
| 6 | - :src=" | ||
| 7 | - formData.avatar || | 5 | + <image :src="formData.avatar || |
| 8 | 'https://fitness-hcxtec-bucket.oss-cn-shenzhen.aliyuncs.com/20260526/默认头像_1779779926983.png' | 6 | 'https://fitness-hcxtec-bucket.oss-cn-shenzhen.aliyuncs.com/20260526/默认头像_1779779926983.png' |
| 9 | - " | ||
| 10 | - mode="aspectFill" | ||
| 11 | - class="avatar-image" | ||
| 12 | - ></image> | 7 | + " mode="aspectFill" class="avatar-image"></image> |
| 13 | </button> | 8 | </button> |
| 14 | </view> | 9 | </view> |
| 15 | 10 | ||
| @@ -23,25 +18,13 @@ | @@ -23,25 +18,13 @@ | ||
| 23 | <view class="list-item" @click="gotoSelectGender"> | 18 | <view class="list-item" @click="gotoSelectGender"> |
| 24 | <text class="item-title">性别</text> | 19 | <text class="item-title">性别</text> |
| 25 | <view class="item-value">{{ formatGender(formData.sex) }}</view> | 20 | <view class="item-value">{{ formatGender(formData.sex) }}</view> |
| 26 | - <uni-icons | ||
| 27 | - v-if="formData.isAllowUpdSex" | ||
| 28 | - type="right" | ||
| 29 | - color="#999" | ||
| 30 | - size="20" | ||
| 31 | - class="arrow-icon" | ||
| 32 | - ></uni-icons> | 21 | + <uni-icons v-if="formData.isAllowUpdSex" type="right" color="#999" size="20" class="arrow-icon"></uni-icons> |
| 33 | </view> | 22 | </view> |
| 34 | 23 | ||
| 35 | <view class="list-item"> | 24 | <view class="list-item"> |
| 36 | <text class="item-title">地区</text> | 25 | <text class="item-title">地区</text> |
| 37 | - <picker | ||
| 38 | - mode="multiSelector" | ||
| 39 | - :range="multiArray" | ||
| 40 | - range-key="name" | ||
| 41 | - :value="multiIndex" | ||
| 42 | - @change="pickerChange" | ||
| 43 | - @columnchange="pickerColumnChange" | ||
| 44 | - > | 26 | + <picker mode="multiSelector" :range="multiArray" range-key="name" :value="multiIndex" @change="pickerChange" |
| 27 | + @columnchange="pickerColumnChange"> | ||
| 45 | <view class="picker" :class="{ 'placeholder-txt': !selectedAddress }"> | 28 | <view class="picker" :class="{ 'placeholder-txt': !selectedAddress }"> |
| 46 | {{ selectedAddress || '请选择省市区' }} | 29 | {{ selectedAddress || '请选择省市区' }} |
| 47 | </view> | 30 | </view> |
| @@ -51,13 +34,8 @@ | @@ -51,13 +34,8 @@ | ||
| 51 | <view class="list-item signature-item"> | 34 | <view class="list-item signature-item"> |
| 52 | <text class="item-title">个性签名</text> | 35 | <text class="item-title">个性签名</text> |
| 53 | <view class="signature-input-wrapper"> | 36 | <view class="signature-input-wrapper"> |
| 54 | - <textarea | ||
| 55 | - v-model="formData.signature" | ||
| 56 | - placeholder="请输入个性签名..." | ||
| 57 | - :maxlength="50" | ||
| 58 | - class="signature-input" | ||
| 59 | - auto-height | ||
| 60 | - /> | 37 | + <textarea v-model="formData.signature" placeholder="请输入个性签名..." :maxlength="50" class="signature-input" |
| 38 | + auto-height /> | ||
| 61 | <text class="char-count">{{ formData.signature?.length || 0 }}/50</text> | 39 | <text class="char-count">{{ formData.signature?.length || 0 }}/50</text> |
| 62 | </view> | 40 | </view> |
| 63 | </view> | 41 | </view> |
| @@ -80,13 +58,8 @@ | @@ -80,13 +58,8 @@ | ||
| 80 | </view> | 58 | </view> |
| 81 | <view class="popup-body"> | 59 | <view class="popup-body"> |
| 82 | <view class="input-wrap"> | 60 | <view class="input-wrap"> |
| 83 | - <input | ||
| 84 | - class="nickname-input" | ||
| 85 | - placeholder="请输入新昵称" | ||
| 86 | - type="nickname" | ||
| 87 | - v-model="editCacheData.nickname" | ||
| 88 | - maxlength="20" | ||
| 89 | - /> | 61 | + <input class="nickname-input" placeholder="请输入新昵称" type="nickname" v-model="editCacheData.nickname" |
| 62 | + maxlength="20" /> | ||
| 90 | </view> | 63 | </view> |
| 91 | </view> | 64 | </view> |
| 92 | <view class="popup-footer"> | 65 | <view class="popup-footer"> |
| @@ -105,18 +78,10 @@ | @@ -105,18 +78,10 @@ | ||
| 105 | </view> | 78 | </view> |
| 106 | <view class="popup-body"> | 79 | <view class="popup-body"> |
| 107 | <view class="gender-options"> | 80 | <view class="gender-options"> |
| 108 | - <view | ||
| 109 | - class="gender-item" | ||
| 110 | - :class="{ selected: editCacheData.sex === 1 }" | ||
| 111 | - @click="selectGender(1)" | ||
| 112 | - > | 81 | + <view class="gender-item" :class="{ selected: editCacheData.sex === 1 }" @click="selectGender(1)"> |
| 113 | <text class="gender-text">男</text> | 82 | <text class="gender-text">男</text> |
| 114 | </view> | 83 | </view> |
| 115 | - <view | ||
| 116 | - class="gender-item" | ||
| 117 | - :class="{ selected: editCacheData.sex === 2 }" | ||
| 118 | - @click="selectGender(2)" | ||
| 119 | - > | 84 | + <view class="gender-item" :class="{ selected: editCacheData.sex === 2 }" @click="selectGender(2)"> |
| 120 | <text class="gender-text">女</text> | 85 | <text class="gender-text">女</text> |
| 121 | </view> | 86 | </view> |
| 122 | </view> | 87 | </view> |
| @@ -128,26 +93,26 @@ | @@ -128,26 +93,26 @@ | ||
| 128 | </template> | 93 | </template> |
| 129 | 94 | ||
| 130 | <script setup> | 95 | <script setup> |
| 131 | - import { ref, reactive, nextTick } from 'vue'; | ||
| 132 | - import { onShow, onBackPress } from '@dcloudio/uni-app'; | ||
| 133 | - import dayjs from 'dayjs'; | ||
| 134 | - import UserApi from '@/sheep/api/member/user'; | ||
| 135 | - import AreaApi from '@/sheep/api/system/area'; | ||
| 136 | - import FileApi from '@/sheep/api/infra/file'; | ||
| 137 | - import useUserStore from '@/sheep/store/user'; | ||
| 138 | - | ||
| 139 | - const userStore = useUserStore(); | ||
| 140 | - | ||
| 141 | - // 弹窗 DOM 引用声明 | ||
| 142 | - const nicknamePopupRef = ref(null); | ||
| 143 | - const genderPopupRef = ref(null); | ||
| 144 | - | ||
| 145 | - // 状态与防抖 | ||
| 146 | - const saveLoading = ref(false); | ||
| 147 | - const hasModified = ref(false); // 侦听变更状态 | ||
| 148 | - | ||
| 149 | - // 核心业务隔离表单 | ||
| 150 | - const formData = ref({ | 96 | +import { ref, reactive, nextTick } from 'vue'; |
| 97 | +import { onShow, onBackPress } from '@dcloudio/uni-app'; | ||
| 98 | +import dayjs from 'dayjs'; | ||
| 99 | +import UserApi from '@/sheep/api/member/user'; | ||
| 100 | +import AreaApi from '@/sheep/api/system/area'; | ||
| 101 | +import FileApi from '@/sheep/api/infra/file'; | ||
| 102 | +import useUserStore from '@/sheep/store/user'; | ||
| 103 | + | ||
| 104 | +const userStore = useUserStore(); | ||
| 105 | + | ||
| 106 | +// 弹窗 DOM 引用声明 | ||
| 107 | +const nicknamePopupRef = ref(null); | ||
| 108 | +const genderPopupRef = ref(null); | ||
| 109 | + | ||
| 110 | +// 状态与防抖 | ||
| 111 | +const saveLoading = ref(false); | ||
| 112 | +const hasModified = ref(false); // 侦听变更状态 | ||
| 113 | + | ||
| 114 | +// 核心业务隔离表单 | ||
| 115 | +const formData = ref({ | ||
| 151 | avatar: '', | 116 | avatar: '', |
| 152 | nickname: '', | 117 | nickname: '', |
| 153 | sex: 0, | 118 | sex: 0, |
| @@ -157,24 +122,24 @@ | @@ -157,24 +122,24 @@ | ||
| 157 | signature: '', | 122 | signature: '', |
| 158 | createTime: '', | 123 | createTime: '', |
| 159 | isAllowUpdSex: false, | 124 | isAllowUpdSex: false, |
| 160 | - }); | 125 | +}); |
| 161 | 126 | ||
| 162 | - // 深度解耦的弹窗缓存数据 | ||
| 163 | - const editCacheData = reactive({ | 127 | +// 深度解耦的弹窗缓存数据 |
| 128 | +const editCacheData = reactive({ | ||
| 164 | nickname: '', | 129 | nickname: '', |
| 165 | sex: 0, | 130 | sex: 0, |
| 166 | - }); | 131 | +}); |
| 167 | 132 | ||
| 168 | - // 省市区级联选择器状态流 | ||
| 169 | - const addressTree = ref([]); | ||
| 170 | - const multiArray = ref([[], [], []]); | ||
| 171 | - const multiIndex = ref([0, 0, 0]); | ||
| 172 | - const selectedAddress = ref(''); | 133 | +// 省市区级联选择器状态流 |
| 134 | +const addressTree = ref([]); | ||
| 135 | +const multiArray = ref([[], [], []]); | ||
| 136 | +const multiIndex = ref([0, 0, 0]); | ||
| 137 | +const selectedAddress = ref(''); | ||
| 173 | 138 | ||
| 174 | - /** | 139 | +/** |
| 175 | * 宿主生命周期钩子流 | 140 | * 宿主生命周期钩子流 |
| 176 | */ | 141 | */ |
| 177 | - onShow(async () => { | 142 | +onShow(async () => { |
| 178 | try { | 143 | try { |
| 179 | // 1. 同步加载行政地区三级树(内部已作 Session 缓存,避免重复请求) | 144 | // 1. 同步加载行政地区三级树(内部已作 Session 缓存,避免重复请求) |
| 180 | await fetchAreaTree(); | 145 | await fetchAreaTree(); |
| @@ -187,12 +152,12 @@ | @@ -187,12 +152,12 @@ | ||
| 187 | } catch (error) { | 152 | } catch (error) { |
| 188 | console.error('[Init Error] 初始化个人信息数据流失败:', error); | 153 | console.error('[Init Error] 初始化个人信息数据流失败:', error); |
| 189 | } | 154 | } |
| 190 | - }); | 155 | +}); |
| 191 | 156 | ||
| 192 | - /** | 157 | +/** |
| 193 | * 拦截非保存下的非正常退出,防止用户误触返回造成数据丢失 | 158 | * 拦截非保存下的非正常退出,防止用户误触返回造成数据丢失 |
| 194 | */ | 159 | */ |
| 195 | - onBackPress((options) => { | 160 | +onBackPress((options) => { |
| 196 | // 监听表单内容变动(仅在未保存且已有修改时提示) | 161 | // 监听表单内容变动(仅在未保存且已有修改时提示) |
| 197 | const isUnsaved = JSON.stringify(formData.value) !== JSON.stringify(userStore.userInfo); | 162 | const isUnsaved = JSON.stringify(formData.value) !== JSON.stringify(userStore.userInfo); |
| 198 | if (isUnsaved && !saveLoading.value) { | 163 | if (isUnsaved && !saveLoading.value) { |
| @@ -209,15 +174,18 @@ | @@ -209,15 +174,18 @@ | ||
| 209 | return true; // 拦截返回键 | 174 | return true; // 拦截返回键 |
| 210 | } | 175 | } |
| 211 | return false; | 176 | return false; |
| 212 | - }); | 177 | +}); |
| 213 | 178 | ||
| 214 | - /** | 179 | +/** |
| 215 | * 头像上传逻辑:增加微信ChooseAvatar路径格式预检与文件防崩溃重试 | 180 | * 头像上传逻辑:增加微信ChooseAvatar路径格式预检与文件防崩溃重试 |
| 216 | */ | 181 | */ |
| 217 | - const handleChooseAvatar = async (e) => { | 182 | +const handleChooseAvatar = async (e) => { |
| 218 | const { avatarUrl } = e.detail; | 183 | const { avatarUrl } = e.detail; |
| 184 | + | ||
| 185 | + | ||
| 219 | if (!avatarUrl) return; | 186 | if (!avatarUrl) return; |
| 220 | 187 | ||
| 188 | + | ||
| 221 | // 前置性能防御:对 H5/App 端选择本地大图片进行预警(微信自带ChooseAvatar主要回传临时压缩图,此处作跨端边界防守) | 189 | // 前置性能防御:对 H5/App 端选择本地大图片进行预警(微信自带ChooseAvatar主要回传临时压缩图,此处作跨端边界防守) |
| 222 | // #ifndef MP-WEIXIN | 190 | // #ifndef MP-WEIXIN |
| 223 | uni.getFileInfo({ | 191 | uni.getFileInfo({ |
| @@ -232,35 +200,33 @@ | @@ -232,35 +200,33 @@ | ||
| 232 | }); | 200 | }); |
| 233 | // #endif | 201 | // #endif |
| 234 | 202 | ||
| 235 | - uni.showLoading({ title: '头像上传中...', mask: true }); | 203 | + |
| 236 | try { | 204 | try { |
| 237 | const res = await FileApi.uploadFile(avatarUrl); | 205 | const res = await FileApi.uploadFile(avatarUrl); |
| 238 | - if (res?.data) { | 206 | + |
| 207 | + console.log('res----------', res); | ||
| 208 | + | ||
| 209 | + | ||
| 239 | formData.value.avatar = res.data; | 210 | formData.value.avatar = res.data; |
| 240 | - uni.showToast({ title: '头像上传成功', icon: 'success' }); | ||
| 241 | - } else { | ||
| 242 | - throw new Error('服务器未返回有效的图片URL路径'); | ||
| 243 | - } | 211 | + |
| 244 | } catch (err) { | 212 | } catch (err) { |
| 245 | - console.error('[Upload Error] 临时路径转存服务器失败:', err); | ||
| 246 | - uni.showToast({ title: '头像保存失败,请稍后重试', icon: 'none' }); | ||
| 247 | - } finally { | ||
| 248 | - uni.hideLoading(); | 213 | + console.error(err); |
| 214 | + | ||
| 249 | } | 215 | } |
| 250 | - }; | 216 | +}; |
| 251 | 217 | ||
| 252 | - /** | 218 | +/** |
| 253 | * 唤起并初始化昵称弹窗缓存 | 219 | * 唤起并初始化昵称弹窗缓存 |
| 254 | */ | 220 | */ |
| 255 | - const gotoEditNickname = () => { | 221 | +const gotoEditNickname = () => { |
| 256 | editCacheData.nickname = formData.value.nickname || ''; | 222 | editCacheData.nickname = formData.value.nickname || ''; |
| 257 | nicknamePopupRef.value.open(); | 223 | nicknamePopupRef.value.open(); |
| 258 | - }; | 224 | +}; |
| 259 | 225 | ||
| 260 | - /** | 226 | +/** |
| 261 | * 确认编辑昵称 | 227 | * 确认编辑昵称 |
| 262 | */ | 228 | */ |
| 263 | - const confirmEditNickname = () => { | 229 | +const confirmEditNickname = () => { |
| 264 | const targetNickname = editCacheData.nickname ? editCacheData.nickname.trim() : ''; | 230 | const targetNickname = editCacheData.nickname ? editCacheData.nickname.trim() : ''; |
| 265 | if (!targetNickname) { | 231 | if (!targetNickname) { |
| 266 | uni.showToast({ title: '昵称不能为空', icon: 'none' }); | 232 | uni.showToast({ title: '昵称不能为空', icon: 'none' }); |
| @@ -268,45 +234,45 @@ | @@ -268,45 +234,45 @@ | ||
| 268 | } | 234 | } |
| 269 | formData.value.nickname = targetNickname; | 235 | formData.value.nickname = targetNickname; |
| 270 | nicknamePopupRef.value.close(); | 236 | nicknamePopupRef.value.close(); |
| 271 | - }; | 237 | +}; |
| 272 | 238 | ||
| 273 | - /** | 239 | +/** |
| 274 | * 唤起并初始化性别弹窗 | 240 | * 唤起并初始化性别弹窗 |
| 275 | */ | 241 | */ |
| 276 | - const gotoSelectGender = () => { | 242 | +const gotoSelectGender = () => { |
| 277 | if (!formData.value.isAllowUpdSex) { | 243 | if (!formData.value.isAllowUpdSex) { |
| 278 | uni.showToast({ title: '性别暂不支持多次修改', icon: 'none' }); | 244 | uni.showToast({ title: '性别暂不支持多次修改', icon: 'none' }); |
| 279 | return; | 245 | return; |
| 280 | } | 246 | } |
| 281 | editCacheData.sex = formData.value.sex || 0; | 247 | editCacheData.sex = formData.value.sex || 0; |
| 282 | genderPopupRef.value.open(); | 248 | genderPopupRef.value.open(); |
| 283 | - }; | 249 | +}; |
| 284 | 250 | ||
| 285 | - /** | 251 | +/** |
| 286 | * 优化:解耦的性别变更逻辑 | 252 | * 优化:解耦的性别变更逻辑 |
| 287 | */ | 253 | */ |
| 288 | - const selectGender = (sex) => { | 254 | +const selectGender = (sex) => { |
| 289 | // 1. 临时更改缓存态而非直接写回 formData | 255 | // 1. 临时更改缓存态而非直接写回 formData |
| 290 | editCacheData.sex = sex; | 256 | editCacheData.sex = sex; |
| 291 | formData.value.sex = sex; // 仅在用户明确选定后回写,并带有 200ms 的视觉缓冲反馈 | 257 | formData.value.sex = sex; // 仅在用户明确选定后回写,并带有 200ms 的视觉缓冲反馈 |
| 292 | setTimeout(() => { | 258 | setTimeout(() => { |
| 293 | genderPopupRef.value.close(); | 259 | genderPopupRef.value.close(); |
| 294 | }, 200); | 260 | }, 200); |
| 295 | - }; | 261 | +}; |
| 296 | 262 | ||
| 297 | - /** | 263 | +/** |
| 298 | * 弹窗关闭时彻底释放和清理临时的输入脏状态 | 264 | * 弹窗关闭时彻底释放和清理临时的输入脏状态 |
| 299 | */ | 265 | */ |
| 300 | - const onNicknamePopupChange = (e) => { | 266 | +const onNicknamePopupChange = (e) => { |
| 301 | if (!e.show) { | 267 | if (!e.show) { |
| 302 | editCacheData.nickname = ''; | 268 | editCacheData.nickname = ''; |
| 303 | } | 269 | } |
| 304 | - }; | 270 | +}; |
| 305 | 271 | ||
| 306 | - /** | 272 | +/** |
| 307 | * 优化:实现会话级局部静态缓存,解决 onShow 高频请求带来的服务器资源浪费 | 273 | * 优化:实现会话级局部静态缓存,解决 onShow 高频请求带来的服务器资源浪费 |
| 308 | */ | 274 | */ |
| 309 | - const fetchAreaTree = async () => { | 275 | +const fetchAreaTree = async () => { |
| 310 | if (addressTree.value && addressTree.value.length > 0) return; | 276 | if (addressTree.value && addressTree.value.length > 0) return; |
| 311 | 277 | ||
| 312 | // 尝试拉取框架/系统底层会话级存储或内存,确保单次生命周期内仅调用一次 API | 278 | // 尝试拉取框架/系统底层会话级存储或内存,确保单次生命周期内仅调用一次 API |
| @@ -325,12 +291,12 @@ | @@ -325,12 +291,12 @@ | ||
| 325 | } catch (error) { | 291 | } catch (error) { |
| 326 | console.error('[API Error] 获取省市区行政结构树失败:', error); | 292 | console.error('[API Error] 获取省市区行政结构树失败:', error); |
| 327 | } | 293 | } |
| 328 | - }; | 294 | +}; |
| 329 | 295 | ||
| 330 | - /** | 296 | +/** |
| 331 | * 安全地同步极简Picker的三列静态节点关联数据 | 297 | * 安全地同步极简Picker的三列静态节点关联数据 |
| 332 | */ | 298 | */ |
| 333 | - const syncPickerColumnData = (pIdx = 0, cIdx = 0) => { | 299 | +const syncPickerColumnData = (pIdx = 0, cIdx = 0) => { |
| 334 | if (!addressTree.value || addressTree.value.length === 0) return; | 300 | if (!addressTree.value || addressTree.value.length === 0) return; |
| 335 | 301 | ||
| 336 | const provinces = addressTree.value; | 302 | const provinces = addressTree.value; |
| @@ -340,12 +306,12 @@ | @@ -340,12 +306,12 @@ | ||
| 340 | const regions = cSelected?.children || []; | 306 | const regions = cSelected?.children || []; |
| 341 | 307 | ||
| 342 | multiArray.value = [provinces, cities, regions]; | 308 | multiArray.value = [provinces, cities, regions]; |
| 343 | - }; | 309 | +}; |
| 344 | 310 | ||
| 345 | - /** | 311 | +/** |
| 346 | * 【关键越界重构】:修正真机由于异步滚动的时差引发的越界闪退 | 312 | * 【关键越界重构】:修正真机由于异步滚动的时差引发的越界闪退 |
| 347 | */ | 313 | */ |
| 348 | - const pickerColumnChange = (e) => { | 314 | +const pickerColumnChange = (e) => { |
| 349 | const { column, value } = e.detail; | 315 | const { column, value } = e.detail; |
| 350 | 316 | ||
| 351 | // 1. 原子化本地临时深拷贝索引指针 | 317 | // 1. 原子化本地临时深拷贝索引指针 |
| @@ -376,12 +342,12 @@ | @@ -376,12 +342,12 @@ | ||
| 376 | nextTick(() => { | 342 | nextTick(() => { |
| 377 | multiIndex.value = nextIndex; | 343 | multiIndex.value = nextIndex; |
| 378 | }); | 344 | }); |
| 379 | - }; | 345 | +}; |
| 380 | 346 | ||
| 381 | - /** | 347 | +/** |
| 382 | * 确认选择省市区,绑定数据映射 | 348 | * 确认选择省市区,绑定数据映射 |
| 383 | */ | 349 | */ |
| 384 | - const pickerChange = (e) => { | 350 | +const pickerChange = (e) => { |
| 385 | const indices = e.detail.value; | 351 | const indices = e.detail.value; |
| 386 | multiIndex.value = [...indices]; | 352 | multiIndex.value = [...indices]; |
| 387 | 353 | ||
| @@ -394,12 +360,12 @@ | @@ -394,12 +360,12 @@ | ||
| 394 | formData.value.region = rObj?.id || ''; | 360 | formData.value.region = rObj?.id || ''; |
| 395 | 361 | ||
| 396 | selectedAddress.value = [pObj?.name, cObj?.name, rObj?.name].filter(Boolean).join(' '); | 362 | selectedAddress.value = [pObj?.name, cObj?.name, rObj?.name].filter(Boolean).join(' '); |
| 397 | - }; | 363 | +}; |
| 398 | 364 | ||
| 399 | - /** | 365 | +/** |
| 400 | * 数据回显定位器:精准利用底层树定位当前用户已有地区信息 | 366 | * 数据回显定位器:精准利用底层树定位当前用户已有地区信息 |
| 401 | */ | 367 | */ |
| 402 | - const initEchoAddress = () => { | 368 | +const initEchoAddress = () => { |
| 403 | const { province, city, region } = formData.value; | 369 | const { province, city, region } = formData.value; |
| 404 | if (!province || !addressTree.value || addressTree.value.length === 0) { | 370 | if (!province || !addressTree.value || addressTree.value.length === 0) { |
| 405 | syncPickerColumnData(0, 0); | 371 | syncPickerColumnData(0, 0); |
| @@ -438,12 +404,12 @@ | @@ -438,12 +404,12 @@ | ||
| 438 | ] | 404 | ] |
| 439 | .filter(Boolean) | 405 | .filter(Boolean) |
| 440 | .join(' '); | 406 | .join(' '); |
| 441 | - }; | 407 | +}; |
| 442 | 408 | ||
| 443 | - /** | 409 | +/** |
| 444 | * 保存修改逻辑:进行脏字段过滤净化后,更新用户信息 | 410 | * 保存修改逻辑:进行脏字段过滤净化后,更新用户信息 |
| 445 | */ | 411 | */ |
| 446 | - const saveProfile = async () => { | 412 | +const saveProfile = async () => { |
| 447 | if (saveLoading.value) return; | 413 | if (saveLoading.value) return; |
| 448 | 414 | ||
| 449 | // 前置轻校验:去除尾部空隙并校验合法性 | 415 | // 前置轻校验:去除尾部空隙并校验合法性 |
| @@ -485,38 +451,38 @@ | @@ -485,38 +451,38 @@ | ||
| 485 | uni.hideLoading(); | 451 | uni.hideLoading(); |
| 486 | saveLoading.value = false; | 452 | saveLoading.value = false; |
| 487 | } | 453 | } |
| 488 | - }; | 454 | +}; |
| 489 | 455 | ||
| 490 | - // 格式化展示原子转换工具 | ||
| 491 | - const formatGender = (sex) => { | 456 | +// 格式化展示原子转换工具 |
| 457 | +const formatGender = (sex) => { | ||
| 492 | if (sex === 1) return '男'; | 458 | if (sex === 1) return '男'; |
| 493 | if (sex === 2) return '女'; | 459 | if (sex === 2) return '女'; |
| 494 | return '保密'; | 460 | return '保密'; |
| 495 | - }; | 461 | +}; |
| 496 | 462 | ||
| 497 | - const formatRegisterTime = (time) => { | 463 | +const formatRegisterTime = (time) => { |
| 498 | if (!time) return '--'; | 464 | if (!time) return '--'; |
| 499 | return dayjs(time).format('YYYY-MM-DD'); | 465 | return dayjs(time).format('YYYY-MM-DD'); |
| 500 | - }; | 466 | +}; |
| 501 | </script> | 467 | </script> |
| 502 | 468 | ||
| 503 | <style scoped lang="scss"> | 469 | <style scoped lang="scss"> |
| 504 | - $color-bg: #f5f5f5; | ||
| 505 | - $color-white: #ffffff; | ||
| 506 | - $color-text-dark: #333; | ||
| 507 | - $color-text-middle: #666; | ||
| 508 | - $color-text-light: #999; | ||
| 509 | - $color-primary: #fdd511; | ||
| 510 | - $color-border: #eee; | ||
| 511 | - $radius: 12rpx; | ||
| 512 | - $radius-lg: 24rpx; | ||
| 513 | - $shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.05); | ||
| 514 | - $spacing-sm: 20rpx; | ||
| 515 | - $spacing-md: 24rpx; | ||
| 516 | - $spacing-lg: 32rpx; | ||
| 517 | - $spacing-xl: 60rpx; | ||
| 518 | - | ||
| 519 | - .profile-page { | 470 | +$color-bg: #f5f5f5; |
| 471 | +$color-white: #ffffff; | ||
| 472 | +$color-text-dark: #333; | ||
| 473 | +$color-text-middle: #666; | ||
| 474 | +$color-text-light: #999; | ||
| 475 | +$color-primary: #fdd511; | ||
| 476 | +$color-border: #eee; | ||
| 477 | +$radius: 12rpx; | ||
| 478 | +$radius-lg: 24rpx; | ||
| 479 | +$shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.05); | ||
| 480 | +$spacing-sm: 20rpx; | ||
| 481 | +$spacing-md: 24rpx; | ||
| 482 | +$spacing-lg: 32rpx; | ||
| 483 | +$spacing-xl: 60rpx; | ||
| 484 | + | ||
| 485 | +.profile-page { | ||
| 520 | background-color: $color-bg; | 486 | background-color: $color-bg; |
| 521 | height: 100vh; | 487 | height: 100vh; |
| 522 | // #ifdef H5 | 488 | // #ifdef H5 |
| @@ -536,6 +502,7 @@ | @@ -536,6 +502,7 @@ | ||
| 536 | padding: 0; | 502 | padding: 0; |
| 537 | line-height: 0; | 503 | line-height: 0; |
| 538 | border-radius: 50%; | 504 | border-radius: 50%; |
| 505 | + | ||
| 539 | &::after { | 506 | &::after { |
| 540 | content: none; | 507 | content: none; |
| 541 | } | 508 | } |
| @@ -630,10 +597,10 @@ | @@ -630,10 +597,10 @@ | ||
| 630 | } | 597 | } |
| 631 | } | 598 | } |
| 632 | } | 599 | } |
| 633 | - } | 600 | +} |
| 634 | 601 | ||
| 635 | - // 弹出层统一样式 | ||
| 636 | - .popup-container { | 602 | +// 弹出层统一样式 |
| 603 | +.popup-container { | ||
| 637 | background-color: $color-white; | 604 | background-color: $color-white; |
| 638 | border-radius: $radius-lg $radius-lg 0 0; | 605 | border-radius: $radius-lg $radius-lg 0 0; |
| 639 | padding-bottom: calc(30rpx + env(safe-area-inset-bottom)); | 606 | padding-bottom: calc(30rpx + env(safe-area-inset-bottom)); |
| @@ -644,6 +611,7 @@ | @@ -644,6 +611,7 @@ | ||
| 644 | justify-content: center; | 611 | justify-content: center; |
| 645 | padding: $spacing-md $spacing-sm; | 612 | padding: $spacing-md $spacing-sm; |
| 646 | border-bottom: 1rpx solid #fcfcfc; | 613 | border-bottom: 1rpx solid #fcfcfc; |
| 614 | + | ||
| 647 | .popup-title { | 615 | .popup-title { |
| 648 | font-size: 32rpx; | 616 | font-size: 32rpx; |
| 649 | color: $color-text-dark; | 617 | color: $color-text-dark; |
| @@ -697,6 +665,7 @@ | @@ -697,6 +665,7 @@ | ||
| 697 | 665 | ||
| 698 | .popup-footer { | 666 | .popup-footer { |
| 699 | padding: 0 $spacing-sm; | 667 | padding: 0 $spacing-sm; |
| 668 | + | ||
| 700 | .confirm-btn { | 669 | .confirm-btn { |
| 701 | width: 100%; | 670 | width: 100%; |
| 702 | height: 88rpx; | 671 | height: 88rpx; |
| @@ -706,15 +675,17 @@ | @@ -706,15 +675,17 @@ | ||
| 706 | font-size: 28rpx; | 675 | font-size: 28rpx; |
| 707 | font-weight: 500; | 676 | font-weight: 500; |
| 708 | border-radius: $radius; | 677 | border-radius: $radius; |
| 678 | + | ||
| 709 | &:after { | 679 | &:after { |
| 710 | content: none; | 680 | content: none; |
| 711 | } | 681 | } |
| 712 | } | 682 | } |
| 713 | } | 683 | } |
| 714 | - } | 684 | +} |
| 715 | 685 | ||
| 716 | - .button-section { | 686 | +.button-section { |
| 717 | padding: $spacing-lg $spacing-sm; | 687 | padding: $spacing-lg $spacing-sm; |
| 688 | + | ||
| 718 | .save-btn { | 689 | .save-btn { |
| 719 | width: 100%; | 690 | width: 100%; |
| 720 | height: 88rpx; | 691 | height: 88rpx; |
| @@ -724,9 +695,10 @@ | @@ -724,9 +695,10 @@ | ||
| 724 | font-size: 28rpx; | 695 | font-size: 28rpx; |
| 725 | font-weight: 500; | 696 | font-weight: 500; |
| 726 | border-radius: $radius; | 697 | border-radius: $radius; |
| 698 | + | ||
| 727 | &:after { | 699 | &:after { |
| 728 | content: none; | 700 | content: none; |
| 729 | } | 701 | } |
| 730 | } | 702 | } |
| 731 | - } | 703 | +} |
| 732 | </style> | 704 | </style> |
pages5/pages/user/wode-guanyu-hongxing.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <view class="level-page"> | ||
| 3 | + <!-- 导航栏 --> | ||
| 4 | + <uni-nav-bar title="华创信" left-icon="left" @click-left="goBack" :fixed="true" :status-bar="true" /> | ||
| 5 | + <view class="top-right"> | ||
| 6 | + <!-- <u-icon name="document" size="24" color="#fff" @click="showRules"></u-icon> --> | ||
| 7 | + <text class="right-text">华创信</text> | ||
| 8 | + </view> | ||
| 9 | + | ||
| 10 | + <!-- 用户信息 --> | ||
| 11 | + <view class="user-info"> | ||
| 12 | + <image src="https://fitness-hcxtec-bucket.oss-cn-shenzhen.aliyuncs.com/20260316/order-empty_1773628059920.png" | ||
| 13 | + mode="aspectFill" class="avatar"></image> | ||
| 14 | + <text class="username">华创信开发者</text> | ||
| 15 | + </view> | ||
| 16 | + | ||
| 17 | + <!-- 更多权益 --> | ||
| 18 | + <view class="more-benefits"> | ||
| 19 | + <view class="more-text">华创信开发者</view> | ||
| 20 | + <view class="more-text">系统开发中</view> | ||
| 21 | + <view class="more-text">敬请期待~</view> | ||
| 22 | + </view> | ||
| 23 | + </view> | ||
| 24 | +</template> | ||
| 25 | + | ||
| 26 | +<script> | ||
| 27 | +export default { | ||
| 28 | + methods: { | ||
| 29 | + goBack() { | ||
| 30 | + uni.navigateBack(); | ||
| 31 | + }, | ||
| 32 | + showRules() { | ||
| 33 | + uni.showToast({ title: '查看开发内容', icon: 'success' }); | ||
| 34 | + }, | ||
| 35 | + }, | ||
| 36 | +}; | ||
| 37 | +</script> | ||
| 38 | + | ||
| 39 | +<style scoped> | ||
| 40 | +.level-page { | ||
| 41 | + position: relative; | ||
| 42 | + width: 100%; | ||
| 43 | + min-height: 100vh; | ||
| 44 | + background-color: #1a1a1a; | ||
| 45 | + color: white; | ||
| 46 | + padding-bottom: 40rpx; | ||
| 47 | +} | ||
| 48 | + | ||
| 49 | +.top-right { | ||
| 50 | + position: absolute; | ||
| 51 | + top: 20rpx; | ||
| 52 | + right: 20rpx; | ||
| 53 | + display: flex; | ||
| 54 | + align-items: center; | ||
| 55 | + gap: 10rpx; | ||
| 56 | + color: white; | ||
| 57 | + font-size: 24rpx; | ||
| 58 | +} | ||
| 59 | + | ||
| 60 | +.user-info { | ||
| 61 | + display: flex; | ||
| 62 | + align-items: center; | ||
| 63 | + gap: 20rpx; | ||
| 64 | + padding: 20rpx; | ||
| 65 | + margin-top: 20rpx; | ||
| 66 | +} | ||
| 67 | + | ||
| 68 | +.avatar { | ||
| 69 | + width: 60rpx; | ||
| 70 | + height: 60rpx; | ||
| 71 | + border-radius: 50%; | ||
| 72 | + object-fit: cover; | ||
| 73 | +} | ||
| 74 | + | ||
| 75 | +.username { | ||
| 76 | + font-size: 28rpx; | ||
| 77 | +} | ||
| 78 | + | ||
| 79 | +.level-card { | ||
| 80 | + width: 600rpx; | ||
| 81 | + height: 300rpx; | ||
| 82 | + background-color: rgba(173, 216, 230, 0.3); | ||
| 83 | + border-radius: 20rpx; | ||
| 84 | + padding: 30rpx; | ||
| 85 | + margin: 20rpx auto; | ||
| 86 | + position: relative; | ||
| 87 | + overflow: hidden; | ||
| 88 | +} | ||
| 89 | + | ||
| 90 | +.level-name { | ||
| 91 | + font-size: 40rpx; | ||
| 92 | + font-weight: bold; | ||
| 93 | + margin-bottom: 10rpx; | ||
| 94 | +} | ||
| 95 | + | ||
| 96 | +.level-en { | ||
| 97 | + font-size: 36rpx; | ||
| 98 | + font-weight: bold; | ||
| 99 | + margin-bottom: 20rpx; | ||
| 100 | +} | ||
| 101 | + | ||
| 102 | +.require { | ||
| 103 | + font-size: 24rpx; | ||
| 104 | + margin-bottom: 20rpx; | ||
| 105 | +} | ||
| 106 | + | ||
| 107 | +.detail { | ||
| 108 | + font-size: 24rpx; | ||
| 109 | + color: #ccc; | ||
| 110 | +} | ||
| 111 | + | ||
| 112 | +.progress-bar { | ||
| 113 | + width: 600rpx; | ||
| 114 | + height: 20rpx; | ||
| 115 | + background-color: #333; | ||
| 116 | + border-radius: 10rpx; | ||
| 117 | + margin: 20rpx auto; | ||
| 118 | + position: relative; | ||
| 119 | + overflow: hidden; | ||
| 120 | +} | ||
| 121 | + | ||
| 122 | +.progress-track { | ||
| 123 | + width: 100%; | ||
| 124 | + height: 100%; | ||
| 125 | + background-color: #333; | ||
| 126 | + border-radius: 10rpx; | ||
| 127 | +} | ||
| 128 | + | ||
| 129 | +.progress-fill { | ||
| 130 | + width: 20%; | ||
| 131 | + height: 100%; | ||
| 132 | + background-color: #007aff; | ||
| 133 | + border-radius: 10rpx; | ||
| 134 | +} | ||
| 135 | + | ||
| 136 | +.progress-dot { | ||
| 137 | + position: absolute; | ||
| 138 | + top: 50%; | ||
| 139 | + left: 20%; | ||
| 140 | + transform: translate(-50%, -50%); | ||
| 141 | + width: 12rpx; | ||
| 142 | + height: 12rpx; | ||
| 143 | + background-color: #007aff; | ||
| 144 | + border-radius: 50%; | ||
| 145 | +} | ||
| 146 | + | ||
| 147 | +.benefits-section { | ||
| 148 | + margin: 20rpx; | ||
| 149 | + padding: 0 20rpx; | ||
| 150 | +} | ||
| 151 | + | ||
| 152 | +.section-title { | ||
| 153 | + font-size: 32rpx; | ||
| 154 | + margin-bottom: 20rpx; | ||
| 155 | + padding-left: 10rpx; | ||
| 156 | +} | ||
| 157 | + | ||
| 158 | +.benefit-list { | ||
| 159 | + display: flex; | ||
| 160 | + flex-direction: row; | ||
| 161 | + justify-content: space-between; | ||
| 162 | + gap: 16rpx; | ||
| 163 | +} | ||
| 164 | + | ||
| 165 | +.benefit-item { | ||
| 166 | + width: 180rpx; | ||
| 167 | + background-color: rgba(255, 255, 255, 0.1); | ||
| 168 | + border-radius: 12rpx; | ||
| 169 | + padding: 16rpx 12rpx; | ||
| 170 | + text-align: center; | ||
| 171 | + box-sizing: border-box; | ||
| 172 | +} | ||
| 173 | + | ||
| 174 | +.icon { | ||
| 175 | + width: 36rpx; | ||
| 176 | + height: 36rpx; | ||
| 177 | + object-fit: cover; | ||
| 178 | + margin-bottom: 8rpx; | ||
| 179 | +} | ||
| 180 | + | ||
| 181 | +.benefit-name { | ||
| 182 | + font-size: 22rpx; | ||
| 183 | + margin-bottom: 4rpx; | ||
| 184 | + font-weight: bold; | ||
| 185 | +} | ||
| 186 | + | ||
| 187 | +.benefit-desc { | ||
| 188 | + font-size: 18rpx; | ||
| 189 | + color: #ccc; | ||
| 190 | + line-height: 1.4; | ||
| 191 | +} | ||
| 192 | + | ||
| 193 | +.time-tag { | ||
| 194 | + font-size: 18rpx; | ||
| 195 | + color: white; | ||
| 196 | + background-color: #ff6b00; | ||
| 197 | + padding: 4rpx 8rpx; | ||
| 198 | + border-radius: 8rpx; | ||
| 199 | + margin-top: 8rpx; | ||
| 200 | + display: inline-block; | ||
| 201 | +} | ||
| 202 | + | ||
| 203 | +.more-benefits { | ||
| 204 | + margin: 30rpx 20rpx 0; | ||
| 205 | + padding: 20rpx; | ||
| 206 | + background-color: rgba(255, 255, 255, 0.1); | ||
| 207 | + border-radius: 12rpx; | ||
| 208 | + text-align: center; | ||
| 209 | +} | ||
| 210 | + | ||
| 211 | +.more-text { | ||
| 212 | + font-size: 24rpx; | ||
| 213 | + color: #ccc; | ||
| 214 | + margin-bottom: 10rpx; | ||
| 215 | +} | ||
| 216 | +</style> |
pages5/pages/user/wode-jiankang-ziliao.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <view class="profile-page"> | ||
| 3 | + <up-navbar bgColor="transparent" :z-index="999" :autoBack="true"> | ||
| 4 | + <template #left> | ||
| 5 | + <view class="u-nav-slot"> | ||
| 6 | + <up-icon name="arrow-left" color="#333" size="15"></up-icon> | ||
| 7 | + </view> | ||
| 8 | + </template> | ||
| 9 | + </up-navbar> | ||
| 10 | + | ||
| 11 | + <view class="header-section"> | ||
| 12 | + <view class="header-content"> | ||
| 13 | + <view class="title">我的运动资料</view> | ||
| 14 | + <view class="subtitle">匹配专属训练计划</view> | ||
| 15 | + </view> | ||
| 16 | + <view class="header-card"> | ||
| 17 | + <view class="line"></view> | ||
| 18 | + <view class="line"></view> | ||
| 19 | + <view class="line"></view> | ||
| 20 | + <view class="line"></view> | ||
| 21 | + </view> | ||
| 22 | + </view> | ||
| 23 | + | ||
| 24 | + <view class="form-card-container"> | ||
| 25 | + <view class="form-list"> | ||
| 26 | + <view class="form-item" @click="openRadioPopup('gender', '性别')"> | ||
| 27 | + <text class="label">性别</text> | ||
| 28 | + <view class="right"> | ||
| 29 | + <text class="value" v-if="pdata.gender">{{ pdata.gender == 1 ? '男' : '女' }}</text> | ||
| 30 | + <text class="placeholder-text" v-else>请选择</text> | ||
| 31 | + <up-icon name="arrow-right" size="12" color="#cccccc"></up-icon> | ||
| 32 | + </view> | ||
| 33 | + </view> | ||
| 34 | + | ||
| 35 | + <view class="form-item" @click="Dateshow = true"> | ||
| 36 | + <text class="label">生日</text> | ||
| 37 | + <view class="right"> | ||
| 38 | + <text class="value" v-if="pdata.birthday">{{ formatDate(pdata.birthday) }}</text> | ||
| 39 | + <text class="placeholder-text" v-else>请选择</text> | ||
| 40 | + <up-icon name="arrow-right" size="12" color="#cccccc"></up-icon> | ||
| 41 | + </view> | ||
| 42 | + </view> | ||
| 43 | + | ||
| 44 | + <view class="form-item" @click="openInputPopup('height', '身高')"> | ||
| 45 | + <text class="label">身高</text> | ||
| 46 | + <view class="right"> | ||
| 47 | + <text class="value" v-if="pdata.height">{{ pdata.height }} cm</text> | ||
| 48 | + <text class="placeholder-text" v-else>未填写</text> | ||
| 49 | + <up-icon name="arrow-right" size="12" color="#cccccc"></up-icon> | ||
| 50 | + </view> | ||
| 51 | + </view> | ||
| 52 | + | ||
| 53 | + <view class="form-item" @click="openInputPopup('weight', '当前体重')"> | ||
| 54 | + <text class="label">当前体重</text> | ||
| 55 | + <view class="right"> | ||
| 56 | + <text class="value" v-if="pdata.weight">{{ pdata.weight }} kg</text> | ||
| 57 | + <text class="placeholder-text" v-else>未填写</text> | ||
| 58 | + <up-icon name="arrow-right" size="12" color="#cccccc"></up-icon> | ||
| 59 | + </view> | ||
| 60 | + </view> | ||
| 61 | + | ||
| 62 | + <view class="form-item" @click="openInputPopup('targetWeight', '目标体重')"> | ||
| 63 | + <text class="label">目标体重</text> | ||
| 64 | + <view class="right"> | ||
| 65 | + <text class="value" v-if="pdata.targetWeight">{{ pdata.targetWeight }} kg</text> | ||
| 66 | + <text class="placeholder-text" v-else>未填写</text> | ||
| 67 | + <up-icon name="arrow-right" size="12" color="#cccccc"></up-icon> | ||
| 68 | + </view> | ||
| 69 | + </view> | ||
| 70 | + | ||
| 71 | + <view class="form-item" @click="openRadioPopup('hasFitnessFoundation', '健身基础')"> | ||
| 72 | + <text class="label">健身基础</text> | ||
| 73 | + <view class="right"> | ||
| 74 | + <text class="value" v-if="pdata.hasFitnessFoundation">{{ | ||
| 75 | + pdata.hasFitnessFoundation == 1 ? '有' : '无' | ||
| 76 | + }}</text> | ||
| 77 | + <text class="placeholder-text" v-else>请选择</text> | ||
| 78 | + <up-icon name="arrow-right" size="12" color="#cccccc"></up-icon> | ||
| 79 | + </view> | ||
| 80 | + </view> | ||
| 81 | + | ||
| 82 | + <view class="form-item" @click="openRadioPopup('acceptableTrainingFrequency', '可接受的训练频次')"> | ||
| 83 | + <text class="label">可接受的训练频次</text> | ||
| 84 | + <view class="right"> | ||
| 85 | + <text class="value" v-if="pdata.acceptableTrainingFrequency"> | ||
| 86 | + {{ pdata.acceptableTrainingFrequency == 1 ? '1练/2练/3练' : '4练/5练/6练' }} | ||
| 87 | + </text> | ||
| 88 | + <text class="placeholder-text" v-else>请选择</text> | ||
| 89 | + <up-icon name="arrow-right" size="12" color="#cccccc"></up-icon> | ||
| 90 | + </view> | ||
| 91 | + </view> | ||
| 92 | + | ||
| 93 | + <view class="form-item" @click="openCheckPopup('targetMuscleParts', '想锻炼的肌肉部位')"> | ||
| 94 | + <text class="label">想锻炼的肌肉部位</text> | ||
| 95 | + <view class="right"> | ||
| 96 | + <text class="value" v-if="pdata.targetMuscleParts && pdata.targetMuscleParts.length"> | ||
| 97 | + {{ pdata.targetMuscleParts.join('、') }} | ||
| 98 | + </text> | ||
| 99 | + <text class="placeholder-text" v-else>请选择(多选)</text> | ||
| 100 | + <up-icon name="arrow-right" size="12" color="#cccccc"></up-icon> | ||
| 101 | + </view> | ||
| 102 | + </view> | ||
| 103 | + | ||
| 104 | + <view class="form-item" @click="openRadioPopup('trainingGoal', '训练目标')"> | ||
| 105 | + <text class="label">训练目标</text> | ||
| 106 | + <view class="right"> | ||
| 107 | + <text class="value" v-if="pdata.trainingGoal">{{ | ||
| 108 | + formatGoal(pdata.trainingGoal) | ||
| 109 | + }}</text> | ||
| 110 | + <text class="placeholder-text" v-else>请选择</text> | ||
| 111 | + <up-icon name="arrow-right" size="12" color="#cccccc"></up-icon> | ||
| 112 | + </view> | ||
| 113 | + </view> | ||
| 114 | + | ||
| 115 | + <view class="form-item" @click="openCheckPopup('painAreas', '身体疼痛部位')"> | ||
| 116 | + <text class="label">身体疼痛部位</text> | ||
| 117 | + <view class="right"> | ||
| 118 | + <text class="value" v-if="pdata.painAreas && pdata.painAreas.length"> | ||
| 119 | + {{ pdata.painAreas.join('、') }} | ||
| 120 | + </text> | ||
| 121 | + <text class="placeholder-text" v-else>无明显疼痛</text> | ||
| 122 | + <up-icon name="arrow-right" size="12" color="#cccccc"></up-icon> | ||
| 123 | + </view> | ||
| 124 | + </view> | ||
| 125 | + | ||
| 126 | + <view class="form-item" @click="openRadioPopup('hasDisease', '当前是否存在疾病')"> | ||
| 127 | + <text class="label">当前是否存在疾病</text> | ||
| 128 | + <view class="right"> | ||
| 129 | + <text class="value" v-if="pdata.hasDisease">{{ | ||
| 130 | + pdata.hasDisease == 1 ? '有' : '无' | ||
| 131 | + }}</text> | ||
| 132 | + <text class="placeholder-text" v-else>请选择</text> | ||
| 133 | + <up-icon name="arrow-right" size="12" color="#cccccc"></up-icon> | ||
| 134 | + </view> | ||
| 135 | + </view> | ||
| 136 | + | ||
| 137 | + <view class="form-item" @click="openRadioPopup('isTakingMedication', '当前是否在服药')"> | ||
| 138 | + <text class="label">当前是否在服药</text> | ||
| 139 | + <view class="right"> | ||
| 140 | + <text class="value" v-if="pdata.isTakingMedication">{{ | ||
| 141 | + pdata.isTakingMedication == 1 ? '是' : '否' | ||
| 142 | + }}</text> | ||
| 143 | + <text class="placeholder-text" v-else>请选择</text> | ||
| 144 | + <up-icon name="arrow-right" size="12" color="#cccccc"></up-icon> | ||
| 145 | + </view> | ||
| 146 | + </view> | ||
| 147 | + | ||
| 148 | + <view class="form-item" @click="openRadioPopup('rewardMethod', '达成目标如何奖励自己')"> | ||
| 149 | + <text class="label">达成目标如何奖励自己</text> | ||
| 150 | + <view class="right"> | ||
| 151 | + <text class="value" v-if="pdata.rewardMethod">{{ | ||
| 152 | + formatReward(pdata.rewardMethod) | ||
| 153 | + }}</text> | ||
| 154 | + <text class="placeholder-text" v-else>请选择</text> | ||
| 155 | + <up-icon name="arrow-right" size="12" color="#cccccc"></up-icon> | ||
| 156 | + </view> | ||
| 157 | + </view> | ||
| 158 | + | ||
| 159 | + <view class="form-item" @click="openRadioPopup('fitnessScene', '平常在哪里健身')"> | ||
| 160 | + <text class="label">平常在哪里健身</text> | ||
| 161 | + <view class="right"> | ||
| 162 | + <text class="value" v-if="pdata.fitnessScene">{{ | ||
| 163 | + formatScene(pdata.fitnessScene) | ||
| 164 | + }}</text> | ||
| 165 | + <text class="placeholder-text" v-else>请选择</text> | ||
| 166 | + <up-icon name="arrow-right" size="12" color="#cccccc"></up-icon> | ||
| 167 | + </view> | ||
| 168 | + </view> | ||
| 169 | + </view> | ||
| 170 | + </view> | ||
| 171 | + | ||
| 172 | + <view class="footer-action-bar"> | ||
| 173 | + <button class="confirm-btn" :loading="isSaving" @click="saveHealthInfo"> | ||
| 174 | + 生成专属训练计划 | ||
| 175 | + </button> | ||
| 176 | + </view> | ||
| 177 | + | ||
| 178 | + <up-popup :show="radioPopup" @close="closeRadioPopup" round="16rpx" mode="bottom" closeable> | ||
| 179 | + <view class="popup-box"> | ||
| 180 | + <view class="popup-header">{{ currentTitle }}</view> | ||
| 181 | + <scroll-view scroll-y class="popup-scroll-area"> | ||
| 182 | + <view class="select-list"> | ||
| 183 | + <view class="select-item" :class="{ active: item.value === bufferValue }" | ||
| 184 | + v-for="(item, index) in formOptions[currentKey]" :key="index" @click="bufferValue = item.value"> | ||
| 185 | + <text class="item-text">{{ item.label }}</text> | ||
| 186 | + <up-icon v-if="item.value === bufferValue" name="checkbox-mark" color="#ffde00" size="18"></up-icon> | ||
| 187 | + </view> | ||
| 188 | + </view> | ||
| 189 | + </scroll-view> | ||
| 190 | + <view class="popup-footer"> | ||
| 191 | + <button class="action-btn" @click="submitRadio">确 定</button> | ||
| 192 | + </view> | ||
| 193 | + </view> | ||
| 194 | + </up-popup> | ||
| 195 | + | ||
| 196 | + <up-popup :show="inputPopup" @close="closeInputPopup" round="16rpx" mode="bottom" closeable> | ||
| 197 | + <view class="popup-box"> | ||
| 198 | + <view class="popup-header">{{ currentTitle }}</view> | ||
| 199 | + <view class="input-content-area"> | ||
| 200 | + <up-input placeholder="请输入有效数字" border="surround" type="digit" v-model="bufferValue" clearable | ||
| 201 | + customStyle="background-color: #f9f9f9; padding: 24rpx;"></up-input> | ||
| 202 | + <text class="unit-text">{{ currentKey === 'height' ? 'cm' : 'kg' }}</text> | ||
| 203 | + </view> | ||
| 204 | + <view class="popup-footer"> | ||
| 205 | + <button class="action-btn" @click="submitInput">确 定</button> | ||
| 206 | + </view> | ||
| 207 | + </view> | ||
| 208 | + </up-popup> | ||
| 209 | + | ||
| 210 | + <up-popup :show="checkPopup" @close="closeCheckPopup" round="16rpx" mode="bottom" closeable> | ||
| 211 | + <view class="popup-box"> | ||
| 212 | + <view class="popup-header">{{ currentTitle }}</view> | ||
| 213 | + <scroll-view scroll-y class="popup-scroll-area"> | ||
| 214 | + <view class="select-list grid-layout"> | ||
| 215 | + <view class="select-item-chip" :class="{ active: bufferArray.includes(item.value) }" | ||
| 216 | + v-for="(item, index) in formOptions[currentKey]" :key="index" @click="toggleCheckItem(item.value)"> | ||
| 217 | + {{ item.label }} | ||
| 218 | + </view> | ||
| 219 | + </view> | ||
| 220 | + </scroll-view> | ||
| 221 | + <view class="popup-footer"> | ||
| 222 | + <button class="action-btn" @click="submitCheck">确 定</button> | ||
| 223 | + </view> | ||
| 224 | + </view> | ||
| 225 | + </up-popup> | ||
| 226 | + | ||
| 227 | + <up-datetime-picker :show="Dateshow" v-model="datePickerValue" mode="date" title="选择生日" @cancel="Dateshow = false" | ||
| 228 | + @confirm="handleSelectDate" :minDate="-1577836800000" :maxDate="Date.now()"></up-datetime-picker> | ||
| 229 | + </view> | ||
| 230 | +</template> | ||
| 231 | + | ||
| 232 | +<script setup> | ||
| 233 | +import { ref, reactive, toRaw } from 'vue'; | ||
| 234 | +import { onShow } from '@dcloudio/uni-app'; | ||
| 235 | +import UserApi from '@/sheep/api/member/user'; | ||
| 236 | +import dayjs from 'dayjs'; | ||
| 237 | + | ||
| 238 | +// ======================================================== | ||
| 239 | +// 响应式单态核心数据集 | ||
| 240 | +// ======================================================== | ||
| 241 | + | ||
| 242 | +const Dateshow = ref(false); | ||
| 243 | +const radioPopup = ref(false); | ||
| 244 | +const inputPopup = ref(false); | ||
| 245 | +const checkPopup = ref(false); | ||
| 246 | +const isSaving = ref(false); | ||
| 247 | + | ||
| 248 | +// 状态机寄存指针管理 | ||
| 249 | +const currentKey = ref(''); | ||
| 250 | +const currentTitle = ref(''); | ||
| 251 | +const bufferValue = ref(null); // 纯量缓冲区 | ||
| 252 | +const bufferArray = ref([]); // 数组队列多选缓冲区 | ||
| 253 | +const datePickerValue = ref(Date.now()); | ||
| 254 | + | ||
| 255 | +const pdata = reactive({ | ||
| 256 | + id: '', | ||
| 257 | + birthday: '', | ||
| 258 | + gender: 0, | ||
| 259 | + height: '', | ||
| 260 | + weight: '', | ||
| 261 | + targetWeight: '', | ||
| 262 | + hasFitnessFoundation: 0, | ||
| 263 | + acceptableTrainingFrequency: 0, | ||
| 264 | + targetMuscleParts: [], | ||
| 265 | + trainingGoal: 0, | ||
| 266 | + painAreas: [], | ||
| 267 | + hasDisease: 0, | ||
| 268 | + isTakingMedication: 0, | ||
| 269 | + rewardMethod: 0, | ||
| 270 | + fitnessScene: 0, | ||
| 271 | +}); | ||
| 272 | + | ||
| 273 | +// 数据字典隔离配置 | ||
| 274 | +const formOptions = { | ||
| 275 | + gender: [ | ||
| 276 | + { label: '男', value: 1 }, | ||
| 277 | + { label: '女', value: 2 }, | ||
| 278 | + ], | ||
| 279 | + hasFitnessFoundation: [ | ||
| 280 | + { label: '有', value: 1 }, | ||
| 281 | + { label: '无', value: 2 }, | ||
| 282 | + ], | ||
| 283 | + acceptableTrainingFrequency: [ | ||
| 284 | + { label: '1练/2练/3练', value: 1 }, | ||
| 285 | + { label: '4练/5练/6练', value: 2 }, | ||
| 286 | + ], | ||
| 287 | + targetMuscleParts: [ | ||
| 288 | + { label: '肩颈', value: '肩颈' }, | ||
| 289 | + { label: '斜方肌', value: '斜方肌' }, | ||
| 290 | + { label: '手臂', value: '手臂' }, | ||
| 291 | + { label: '胸部', value: '胸部' }, | ||
| 292 | + { label: '背部', value: '背部' }, | ||
| 293 | + { label: '腹部', value: '腹部' }, | ||
| 294 | + { label: '臀部', value: '臀部' }, | ||
| 295 | + { label: '腿部', value: '腿部' }, | ||
| 296 | + ], | ||
| 297 | + trainingGoal: [ | ||
| 298 | + { label: '减脂', value: 1 }, | ||
| 299 | + { label: '增肌', value: 2 }, | ||
| 300 | + { label: '塑形', value: 3 }, | ||
| 301 | + { label: '拉伸/体态调整', value: 4 }, | ||
| 302 | + ], | ||
| 303 | + painAreas: [ | ||
| 304 | + { label: '肩颈', value: '肩颈' }, | ||
| 305 | + { label: '手腕', value: '手腕' }, | ||
| 306 | + { label: '腰部', value: '腰部' }, | ||
| 307 | + { label: '脚踝', value: '脚踝' }, | ||
| 308 | + { label: '膝盖', value: '膝盖' }, | ||
| 309 | + ], | ||
| 310 | + hasDisease: [ | ||
| 311 | + { label: '有', value: 1 }, | ||
| 312 | + { label: '无', value: 2 }, | ||
| 313 | + ], | ||
| 314 | + isTakingMedication: [ | ||
| 315 | + { label: '是', value: 1 }, | ||
| 316 | + { label: '否', value: 2 }, | ||
| 317 | + ], | ||
| 318 | + rewardMethod: [ | ||
| 319 | + { label: '买件新衣服/装备', value: 1 }, | ||
| 320 | + { label: '去旅行', value: 2 }, | ||
| 321 | + { label: '和朋友聚会', value: 3 }, | ||
| 322 | + { label: '其他', value: 4 }, | ||
| 323 | + ], | ||
| 324 | + fitnessScene: [ | ||
| 325 | + { label: '健身房', value: 1 }, | ||
| 326 | + { label: '家', value: 2 }, | ||
| 327 | + { label: '宿舍', value: 3 }, | ||
| 328 | + ], | ||
| 329 | +}; | ||
| 330 | + | ||
| 331 | +// ======================================================== | ||
| 332 | +// 文本高阶转义映射器 | ||
| 333 | +// ======================================================== | ||
| 334 | +const formatDate = (val) => (val ? dayjs(val).format('YYYY-MM-DD') : ''); | ||
| 335 | +const formatGoal = (val) => ({ 1: '减脂', 2: '增肌', 3: '塑形', 4: '拉伸/体态调整' }[val] || ''); | ||
| 336 | +const formatReward = (val) => | ||
| 337 | + ({ 1: '买件新衣服/装备', 2: '去旅行', 3: '和朋友聚会', 4: '其他' }[val] || ''); | ||
| 338 | +const formatScene = (val) => ({ 1: '健身房', 2: '家', 3: '宿舍' }[val] || ''); | ||
| 339 | + | ||
| 340 | +// ======================================================== | ||
| 341 | +// 核心弹窗调度器(精细化防污染管控) | ||
| 342 | +// ======================================================== | ||
| 343 | + | ||
| 344 | +const openRadioPopup = (key, title) => { | ||
| 345 | + currentKey.value = key; | ||
| 346 | + currentTitle.value = title; | ||
| 347 | + bufferValue.value = pdata[key] || null; // 载入安全缓冲区 | ||
| 348 | + radioPopup.value = true; | ||
| 349 | +}; | ||
| 350 | + | ||
| 351 | +const closeRadioPopup = () => { | ||
| 352 | + radioPopup.value = false; | ||
| 353 | +}; | ||
| 354 | + | ||
| 355 | +const submitRadio = () => { | ||
| 356 | + if (bufferValue.value !== null) { | ||
| 357 | + pdata[currentKey.value] = bufferValue.value; // 仅在此处准许回填修改 | ||
| 358 | + } | ||
| 359 | + radioPopup.value = false; | ||
| 360 | +}; | ||
| 361 | + | ||
| 362 | +const openInputPopup = (key, title) => { | ||
| 363 | + currentKey.value = key; | ||
| 364 | + currentTitle.value = title; | ||
| 365 | + bufferValue.value = pdata[key] !== '' ? String(pdata[key]) : ''; | ||
| 366 | + inputPopup.value = true; | ||
| 367 | +}; | ||
| 368 | + | ||
| 369 | +const closeInputPopup = () => { | ||
| 370 | + inputPopup.value = false; | ||
| 371 | +}; | ||
| 372 | + | ||
| 373 | +const submitInput = () => { | ||
| 374 | + const num = parseFloat(bufferValue.value); | ||
| 375 | + // 安全阈值边界拦截校验 | ||
| 376 | + if (isNaN(num) || num <= 0 || num > 300) { | ||
| 377 | + uni.showToast({ title: '请输入合理区间值', icon: 'none' }); | ||
| 378 | + return; | ||
| 379 | + } | ||
| 380 | + pdata[currentKey.value] = num.toFixed(1); | ||
| 381 | + inputPopup.value = false; | ||
| 382 | +}; | ||
| 383 | + | ||
| 384 | +const openCheckPopup = (key, title) => { | ||
| 385 | + currentKey.value = key; | ||
| 386 | + currentTitle.value = title; | ||
| 387 | + bufferArray.value = Array.isArray(pdata[key]) ? [...pdata[key]] : []; // 解耦深拷贝 | ||
| 388 | + checkPopup.value = true; | ||
| 389 | +}; | ||
| 390 | + | ||
| 391 | +const toggleCheckItem = (val) => { | ||
| 392 | + const idx = bufferArray.value.indexOf(val); | ||
| 393 | + if (idx > -1) { | ||
| 394 | + bufferArray.value.splice(idx, 1); | ||
| 395 | + } else { | ||
| 396 | + bufferArray.value.push(val); | ||
| 397 | + } | ||
| 398 | +}; | ||
| 399 | + | ||
| 400 | +const closeCheckPopup = () => { | ||
| 401 | + checkPopup.value = false; | ||
| 402 | +}; | ||
| 403 | + | ||
| 404 | +const submitCheck = () => { | ||
| 405 | + pdata[currentKey.value] = [...bufferArray.value]; | ||
| 406 | + checkPopup.value = false; | ||
| 407 | +}; | ||
| 408 | + | ||
| 409 | +const handleSelectDate = (e) => { | ||
| 410 | + Dateshow.value = false; | ||
| 411 | + pdata.birthday = dayjs(e.value).format('YYYY-MM-DD'); | ||
| 412 | +}; | ||
| 413 | + | ||
| 414 | +// ======================================================== | ||
| 415 | +// 网络数据交互编排 | ||
| 416 | +// ======================================================== | ||
| 417 | + | ||
| 418 | +const getHealthData = async () => { | ||
| 419 | + try { | ||
| 420 | + const res = await UserApi.getHealthInfo(); | ||
| 421 | + const data = res?.data || {}; | ||
| 422 | + | ||
| 423 | + Object.keys(pdata).forEach((key) => { | ||
| 424 | + if (key === 'hasDisease' || key === 'isTakingMedication') { | ||
| 425 | + pdata[key] = data[key] === true ? 1 : data[key] === false ? 2 : 0; | ||
| 426 | + } else if (key === 'targetMuscleParts' || key === 'painAreas') { | ||
| 427 | + pdata[key] = Array.isArray(data[key]) ? data[key] : []; | ||
| 428 | + } else { | ||
| 429 | + pdata[key] = data[key] !== undefined && data[key] !== null ? data[key] : ''; | ||
| 430 | + } | ||
| 431 | + }); | ||
| 432 | + | ||
| 433 | + if (pdata.birthday) { | ||
| 434 | + datePickerValue.value = dayjs(pdata.birthday).valueOf(); | ||
| 435 | + } | ||
| 436 | + } catch (error) { | ||
| 437 | + console.error('拉取档案失败:', error); | ||
| 438 | + } | ||
| 439 | +}; | ||
| 440 | + | ||
| 441 | +const saveHealthInfo = async () => { | ||
| 442 | + // 基础必填拦截防空检测 | ||
| 443 | + if (!pdata.gender || !pdata.birthday || !pdata.height || !pdata.weight) { | ||
| 444 | + uni.showToast({ title: '请完整填写真实核心资料', icon: 'none' }); | ||
| 445 | + return; | ||
| 446 | + } | ||
| 447 | + | ||
| 448 | + if (isSaving.value) return; | ||
| 449 | + isSaving.value = true; | ||
| 450 | + | ||
| 451 | + try { | ||
| 452 | + const payload = { | ||
| 453 | + ...toRaw(pdata), | ||
| 454 | + hasDisease: pdata.hasDisease === 1, | ||
| 455 | + isTakingMedication: pdata.isTakingMedication === 1, | ||
| 456 | + }; | ||
| 457 | + | ||
| 458 | + if (pdata.id) { | ||
| 459 | + await UserApi.UpdateHealthInfo(payload); | ||
| 460 | + } else { | ||
| 461 | + await UserApi.createHealthInfo(payload); | ||
| 462 | + } | ||
| 463 | + | ||
| 464 | + uni.showToast({ title: '专属计划已生成', icon: 'success' }); | ||
| 465 | + setTimeout(() => { | ||
| 466 | + uni.navigateBack(); | ||
| 467 | + }, 1500); | ||
| 468 | + } catch (error) { | ||
| 469 | + console.error('提交健康资料异常:', error); | ||
| 470 | + uni.showToast({ title: '保存失败,请重试', icon: 'none' }); | ||
| 471 | + } finally { | ||
| 472 | + isSaving.value = false; | ||
| 473 | + } | ||
| 474 | +}; | ||
| 475 | + | ||
| 476 | +onShow(() => { | ||
| 477 | + getHealthData(); | ||
| 478 | +}); | ||
| 479 | +</script> | ||
| 480 | + | ||
| 481 | +<style lang="scss" scoped> | ||
| 482 | +.profile-page { | ||
| 483 | + background-color: #f7f8fa; | ||
| 484 | + min-height: 100vh; | ||
| 485 | + /* 解决长页面底部被悬浮动作条覆盖的问题 */ | ||
| 486 | + padding-bottom: 180rpx; | ||
| 487 | + box-sizing: border-box; | ||
| 488 | + | ||
| 489 | + .u-nav-slot { | ||
| 490 | + background-color: rgba(255, 255, 255, 0.8); | ||
| 491 | + backdrop-filter: blur(4px); | ||
| 492 | + padding: 12rpx; | ||
| 493 | + border-radius: 50%; | ||
| 494 | + display: flex; | ||
| 495 | + align-items: center; | ||
| 496 | + justify-content: center; | ||
| 497 | + } | ||
| 498 | + | ||
| 499 | + .header-section { | ||
| 500 | + width: 100%; | ||
| 501 | + height: 22vh; | ||
| 502 | + /* #ifdef MP-WEIXIN */ | ||
| 503 | + height: 26vh; | ||
| 504 | + /* #endif */ | ||
| 505 | + background: linear-gradient(135deg, #ffd166 0%, #ffb74d 100%); | ||
| 506 | + position: relative; | ||
| 507 | + padding-left: 44rpx; | ||
| 508 | + padding-bottom: 50rpx; | ||
| 509 | + display: flex; | ||
| 510 | + align-items: flex-end; | ||
| 511 | + box-sizing: border-box; | ||
| 512 | + | ||
| 513 | + .header-content { | ||
| 514 | + display: flex; | ||
| 515 | + flex-direction: column; | ||
| 516 | + z-index: 2; | ||
| 517 | + | ||
| 518 | + .title { | ||
| 519 | + font-size: 46rpx; | ||
| 520 | + font-weight: bold; | ||
| 521 | + color: #4a2c00; | ||
| 522 | + margin-bottom: 8rpx; | ||
| 523 | + } | ||
| 524 | + | ||
| 525 | + .subtitle { | ||
| 526 | + font-size: 26rpx; | ||
| 527 | + color: rgba(74, 44, 0, 0.7); | ||
| 528 | + } | ||
| 529 | + } | ||
| 530 | + | ||
| 531 | + .header-card { | ||
| 532 | + position: absolute; | ||
| 533 | + right: 30rpx; | ||
| 534 | + bottom: -10rpx; | ||
| 535 | + width: 150rpx; | ||
| 536 | + height: 180rpx; | ||
| 537 | + background: linear-gradient(135deg, #ff6b6b, #ff8e53); | ||
| 538 | + border-radius: 20rpx; | ||
| 539 | + display: flex; | ||
| 540 | + flex-direction: column; | ||
| 541 | + align-items: center; | ||
| 542 | + justify-content: center; | ||
| 543 | + gap: 16rpx; | ||
| 544 | + transform: rotate(12deg); | ||
| 545 | + box-shadow: 0 12rpx 24rpx rgba(255, 107, 107, 0.25); | ||
| 546 | + z-index: 1; | ||
| 547 | + | ||
| 548 | + .line { | ||
| 549 | + width: 55%; | ||
| 550 | + height: 8rpx; | ||
| 551 | + background-color: rgba(255, 255, 255, 0.9); | ||
| 552 | + border-radius: 6rpx; | ||
| 553 | + } | ||
| 554 | + } | ||
| 555 | + } | ||
| 556 | + | ||
| 557 | + /* 修复:移除有隐患的全局 translateY 移动,改用规范的卡片间距布局 */ | ||
| 558 | + .form-card-container { | ||
| 559 | + padding: 0 30rpx; | ||
| 560 | + margin-top: 30rpx; | ||
| 561 | + | ||
| 562 | + .form-list { | ||
| 563 | + background-color: #ffffff; | ||
| 564 | + border-radius: 24rpx; | ||
| 565 | + box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.015); | ||
| 566 | + overflow: hidden; | ||
| 567 | + /* 完美约束子项按圆角外接圆渲染 */ | ||
| 568 | + | ||
| 569 | + .form-item { | ||
| 570 | + display: flex; | ||
| 571 | + align-items: center; | ||
| 572 | + justify-content: space-between; | ||
| 573 | + padding: 36rpx 30rpx; | ||
| 574 | + border-bottom: 1rpx solid #f2f3f5; | ||
| 575 | + transition: background-color 0.2s; | ||
| 576 | + | ||
| 577 | + &:active { | ||
| 578 | + background-color: #f9f9f9; | ||
| 579 | + } | ||
| 580 | + | ||
| 581 | + &:last-child { | ||
| 582 | + border-bottom: none; | ||
| 583 | + } | ||
| 584 | + | ||
| 585 | + .label { | ||
| 586 | + font-size: 28rpx; | ||
| 587 | + color: #323233; | ||
| 588 | + font-weight: 600; | ||
| 589 | + } | ||
| 590 | + | ||
| 591 | + .right { | ||
| 592 | + display: flex; | ||
| 593 | + align-items: center; | ||
| 594 | + gap: 12rpx; | ||
| 595 | + max-width: 65%; | ||
| 596 | + | ||
| 597 | + .value { | ||
| 598 | + font-size: 28rpx; | ||
| 599 | + color: #323233; | ||
| 600 | + text-align: right; | ||
| 601 | + overflow: hidden; | ||
| 602 | + text-overflow: ellipsis; | ||
| 603 | + white-space: nowrap; | ||
| 604 | + } | ||
| 605 | + | ||
| 606 | + .placeholder-text { | ||
| 607 | + font-size: 28rpx; | ||
| 608 | + color: #c8c9cc; | ||
| 609 | + } | ||
| 610 | + } | ||
| 611 | + } | ||
| 612 | + } | ||
| 613 | + } | ||
| 614 | + | ||
| 615 | + /* 固定悬浮底部动作栏 */ | ||
| 616 | + .footer-action-bar { | ||
| 617 | + position: fixed; | ||
| 618 | + bottom: 0; | ||
| 619 | + left: 0; | ||
| 620 | + width: 100vw; | ||
| 621 | + background-color: #ffffff; | ||
| 622 | + padding: 24rpx 40rpx calc(24rpx + env(safe-area-inset-bottom)); | ||
| 623 | + box-sizing: border-box; | ||
| 624 | + box-shadow: 0 -4rpx 24rpx rgba(0, 0, 0, 0.04); | ||
| 625 | + z-index: 99; | ||
| 626 | + | ||
| 627 | + .confirm-btn { | ||
| 628 | + width: 100%; | ||
| 629 | + height: 88rpx; | ||
| 630 | + line-height: 88rpx; | ||
| 631 | + background: linear-gradient(90deg, #ffe100 0%, #ffc400 100%); | ||
| 632 | + color: #323233; | ||
| 633 | + font-size: 32rpx; | ||
| 634 | + font-weight: bold; | ||
| 635 | + border-radius: 44rpx; | ||
| 636 | + border: none; | ||
| 637 | + | ||
| 638 | + &::after { | ||
| 639 | + border: none; | ||
| 640 | + } | ||
| 641 | + } | ||
| 642 | + } | ||
| 643 | + | ||
| 644 | + /* 弹出层统一样式规范 */ | ||
| 645 | + .popup-box { | ||
| 646 | + background-color: #ffffff; | ||
| 647 | + border-radius: 24rpx 24rpx 0 0; | ||
| 648 | + padding: 30rpx 40rpx calc(30rpx + env(safe-area-inset-bottom)); | ||
| 649 | + box-sizing: border-box; | ||
| 650 | + | ||
| 651 | + .popup-header { | ||
| 652 | + font-size: 32rpx; | ||
| 653 | + font-weight: bold; | ||
| 654 | + color: #323233; | ||
| 655 | + text-align: center; | ||
| 656 | + padding-bottom: 30rpx; | ||
| 657 | + } | ||
| 658 | + | ||
| 659 | + .popup-scroll-area { | ||
| 660 | + max-height: 40vh; | ||
| 661 | + } | ||
| 662 | + | ||
| 663 | + .input-content-area { | ||
| 664 | + display: flex; | ||
| 665 | + align-items: center; | ||
| 666 | + gap: 20rpx; | ||
| 667 | + padding: 20rpx 0 40rpx; | ||
| 668 | + | ||
| 669 | + .unit-text { | ||
| 670 | + font-size: 30rpx; | ||
| 671 | + color: #323233; | ||
| 672 | + font-weight: bold; | ||
| 673 | + } | ||
| 674 | + } | ||
| 675 | + | ||
| 676 | + .select-list { | ||
| 677 | + display: flex; | ||
| 678 | + flex-direction: column; | ||
| 679 | + gap: 16rpx; | ||
| 680 | + | ||
| 681 | + &.grid-layout { | ||
| 682 | + flex-direction: row; | ||
| 683 | + flex-wrap: wrap; | ||
| 684 | + gap: 20rpx; | ||
| 685 | + } | ||
| 686 | + | ||
| 687 | + .select-item { | ||
| 688 | + display: flex; | ||
| 689 | + justify-content: space-between; | ||
| 690 | + align-items: center; | ||
| 691 | + background-color: #f7f8fa; | ||
| 692 | + padding: 30rpx 40rpx; | ||
| 693 | + border-radius: 16rpx; | ||
| 694 | + transition: all 0.2s; | ||
| 695 | + | ||
| 696 | + &.active { | ||
| 697 | + background-color: #fffdf0; | ||
| 698 | + border: 2rpx solid #ffe100; | ||
| 699 | + } | ||
| 700 | + | ||
| 701 | + .item-text { | ||
| 702 | + font-size: 28rpx; | ||
| 703 | + color: #323233; | ||
| 704 | + font-weight: 500; | ||
| 705 | + } | ||
| 706 | + } | ||
| 707 | + | ||
| 708 | + /* 多选网格纸片样式 */ | ||
| 709 | + .select-item-chip { | ||
| 710 | + padding: 20rpx 36rpx; | ||
| 711 | + background-color: #f7f8fa; | ||
| 712 | + border-radius: 40rpx; | ||
| 713 | + font-size: 26rpx; | ||
| 714 | + color: #646566; | ||
| 715 | + transition: all 0.2s; | ||
| 716 | + border: 2rpx solid transparent; | ||
| 717 | + | ||
| 718 | + &.active { | ||
| 719 | + background-color: #fffdf0; | ||
| 720 | + color: #323233; | ||
| 721 | + font-weight: bold; | ||
| 722 | + border-color: #ffe100; | ||
| 723 | + } | ||
| 724 | + } | ||
| 725 | + } | ||
| 726 | + | ||
| 727 | + .popup-footer { | ||
| 728 | + margin-top: 40rpx; | ||
| 729 | + | ||
| 730 | + .action-btn { | ||
| 731 | + width: 100%; | ||
| 732 | + height: 80rpx; | ||
| 733 | + line-height: 80rpx; | ||
| 734 | + background-color: #ffe100; | ||
| 735 | + color: #323233; | ||
| 736 | + font-size: 28rpx; | ||
| 737 | + font-weight: bold; | ||
| 738 | + border-radius: 40rpx; | ||
| 739 | + border: none; | ||
| 740 | + | ||
| 741 | + &::after { | ||
| 742 | + border: none; | ||
| 743 | + } | ||
| 744 | + } | ||
| 745 | + } | ||
| 746 | + } | ||
| 747 | +} | ||
| 748 | +</style> |
pages5/pages/user/wode-lianxi-kefu.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <view class="level-page"> | ||
| 3 | + <!-- 导航栏 --> | ||
| 4 | + <uni-nav-bar title="华创信" left-icon="left" @click-left="goBack" :fixed="true" :status-bar="true" /> | ||
| 5 | + <view class="top-right"> | ||
| 6 | + <!-- <u-icon name="document" size="24" color="#fff" @click="showRules"></u-icon> --> | ||
| 7 | + <text class="right-text">华创信</text> | ||
| 8 | + </view> | ||
| 9 | + | ||
| 10 | + <!-- 用户信息 --> | ||
| 11 | + <view class="user-info"> | ||
| 12 | + <image src="https://fitness-hcxtec-bucket.oss-cn-shenzhen.aliyuncs.com/20260316/order-empty_1773628059920.png" | ||
| 13 | + mode="aspectFill" class="avatar"></image> | ||
| 14 | + <text class="username">华创信开发者</text> | ||
| 15 | + </view> | ||
| 16 | + | ||
| 17 | + <!-- 更多权益 --> | ||
| 18 | + <view class="more-benefits"> | ||
| 19 | + <view class="more-text">华创信开发者</view> | ||
| 20 | + <view class="more-text">系统开发中</view> | ||
| 21 | + <view class="more-text">敬请期待~</view> | ||
| 22 | + </view> | ||
| 23 | + </view> | ||
| 24 | +</template> | ||
| 25 | + | ||
| 26 | +<script> | ||
| 27 | +export default { | ||
| 28 | + methods: { | ||
| 29 | + goBack() { | ||
| 30 | + uni.navigateBack(); | ||
| 31 | + }, | ||
| 32 | + showRules() { | ||
| 33 | + uni.showToast({ title: '查看开发内容', icon: 'success' }); | ||
| 34 | + }, | ||
| 35 | + }, | ||
| 36 | +}; | ||
| 37 | +</script> | ||
| 38 | + | ||
| 39 | +<style scoped> | ||
| 40 | +.level-page { | ||
| 41 | + position: relative; | ||
| 42 | + width: 100%; | ||
| 43 | + min-height: 100vh; | ||
| 44 | + background-color: #1a1a1a; | ||
| 45 | + color: white; | ||
| 46 | + padding-bottom: 40rpx; | ||
| 47 | +} | ||
| 48 | + | ||
| 49 | +.top-right { | ||
| 50 | + position: absolute; | ||
| 51 | + top: 20rpx; | ||
| 52 | + right: 20rpx; | ||
| 53 | + display: flex; | ||
| 54 | + align-items: center; | ||
| 55 | + gap: 10rpx; | ||
| 56 | + color: white; | ||
| 57 | + font-size: 24rpx; | ||
| 58 | +} | ||
| 59 | + | ||
| 60 | +.user-info { | ||
| 61 | + display: flex; | ||
| 62 | + align-items: center; | ||
| 63 | + gap: 20rpx; | ||
| 64 | + padding: 20rpx; | ||
| 65 | + margin-top: 20rpx; | ||
| 66 | +} | ||
| 67 | + | ||
| 68 | +.avatar { | ||
| 69 | + width: 60rpx; | ||
| 70 | + height: 60rpx; | ||
| 71 | + border-radius: 50%; | ||
| 72 | + object-fit: cover; | ||
| 73 | +} | ||
| 74 | + | ||
| 75 | +.username { | ||
| 76 | + font-size: 28rpx; | ||
| 77 | +} | ||
| 78 | + | ||
| 79 | +.level-card { | ||
| 80 | + width: 600rpx; | ||
| 81 | + height: 300rpx; | ||
| 82 | + background-color: rgba(173, 216, 230, 0.3); | ||
| 83 | + border-radius: 20rpx; | ||
| 84 | + padding: 30rpx; | ||
| 85 | + margin: 20rpx auto; | ||
| 86 | + position: relative; | ||
| 87 | + overflow: hidden; | ||
| 88 | +} | ||
| 89 | + | ||
| 90 | +.level-name { | ||
| 91 | + font-size: 40rpx; | ||
| 92 | + font-weight: bold; | ||
| 93 | + margin-bottom: 10rpx; | ||
| 94 | +} | ||
| 95 | + | ||
| 96 | +.level-en { | ||
| 97 | + font-size: 36rpx; | ||
| 98 | + font-weight: bold; | ||
| 99 | + margin-bottom: 20rpx; | ||
| 100 | +} | ||
| 101 | + | ||
| 102 | +.require { | ||
| 103 | + font-size: 24rpx; | ||
| 104 | + margin-bottom: 20rpx; | ||
| 105 | +} | ||
| 106 | + | ||
| 107 | +.detail { | ||
| 108 | + font-size: 24rpx; | ||
| 109 | + color: #ccc; | ||
| 110 | +} | ||
| 111 | + | ||
| 112 | +.progress-bar { | ||
| 113 | + width: 600rpx; | ||
| 114 | + height: 20rpx; | ||
| 115 | + background-color: #333; | ||
| 116 | + border-radius: 10rpx; | ||
| 117 | + margin: 20rpx auto; | ||
| 118 | + position: relative; | ||
| 119 | + overflow: hidden; | ||
| 120 | +} | ||
| 121 | + | ||
| 122 | +.progress-track { | ||
| 123 | + width: 100%; | ||
| 124 | + height: 100%; | ||
| 125 | + background-color: #333; | ||
| 126 | + border-radius: 10rpx; | ||
| 127 | +} | ||
| 128 | + | ||
| 129 | +.progress-fill { | ||
| 130 | + width: 20%; | ||
| 131 | + height: 100%; | ||
| 132 | + background-color: #007aff; | ||
| 133 | + border-radius: 10rpx; | ||
| 134 | +} | ||
| 135 | + | ||
| 136 | +.progress-dot { | ||
| 137 | + position: absolute; | ||
| 138 | + top: 50%; | ||
| 139 | + left: 20%; | ||
| 140 | + transform: translate(-50%, -50%); | ||
| 141 | + width: 12rpx; | ||
| 142 | + height: 12rpx; | ||
| 143 | + background-color: #007aff; | ||
| 144 | + border-radius: 50%; | ||
| 145 | +} | ||
| 146 | + | ||
| 147 | +.benefits-section { | ||
| 148 | + margin: 20rpx; | ||
| 149 | + padding: 0 20rpx; | ||
| 150 | +} | ||
| 151 | + | ||
| 152 | +.section-title { | ||
| 153 | + font-size: 32rpx; | ||
| 154 | + margin-bottom: 20rpx; | ||
| 155 | + padding-left: 10rpx; | ||
| 156 | +} | ||
| 157 | + | ||
| 158 | +.benefit-list { | ||
| 159 | + display: flex; | ||
| 160 | + flex-direction: row; | ||
| 161 | + justify-content: space-between; | ||
| 162 | + gap: 16rpx; | ||
| 163 | +} | ||
| 164 | + | ||
| 165 | +.benefit-item { | ||
| 166 | + width: 180rpx; | ||
| 167 | + background-color: rgba(255, 255, 255, 0.1); | ||
| 168 | + border-radius: 12rpx; | ||
| 169 | + padding: 16rpx 12rpx; | ||
| 170 | + text-align: center; | ||
| 171 | + box-sizing: border-box; | ||
| 172 | +} | ||
| 173 | + | ||
| 174 | +.icon { | ||
| 175 | + width: 36rpx; | ||
| 176 | + height: 36rpx; | ||
| 177 | + object-fit: cover; | ||
| 178 | + margin-bottom: 8rpx; | ||
| 179 | +} | ||
| 180 | + | ||
| 181 | +.benefit-name { | ||
| 182 | + font-size: 22rpx; | ||
| 183 | + margin-bottom: 4rpx; | ||
| 184 | + font-weight: bold; | ||
| 185 | +} | ||
| 186 | + | ||
| 187 | +.benefit-desc { | ||
| 188 | + font-size: 18rpx; | ||
| 189 | + color: #ccc; | ||
| 190 | + line-height: 1.4; | ||
| 191 | +} | ||
| 192 | + | ||
| 193 | +.time-tag { | ||
| 194 | + font-size: 18rpx; | ||
| 195 | + color: white; | ||
| 196 | + background-color: #ff6b00; | ||
| 197 | + padding: 4rpx 8rpx; | ||
| 198 | + border-radius: 8rpx; | ||
| 199 | + margin-top: 8rpx; | ||
| 200 | + display: inline-block; | ||
| 201 | +} | ||
| 202 | + | ||
| 203 | +.more-benefits { | ||
| 204 | + margin: 30rpx 20rpx 0; | ||
| 205 | + padding: 20rpx; | ||
| 206 | + background-color: rgba(255, 255, 255, 0.1); | ||
| 207 | + border-radius: 12rpx; | ||
| 208 | + text-align: center; | ||
| 209 | +} | ||
| 210 | + | ||
| 211 | +.more-text { | ||
| 212 | + font-size: 24rpx; | ||
| 213 | + color: #ccc; | ||
| 214 | + margin-bottom: 10rpx; | ||
| 215 | +} | ||
| 216 | +</style> |
pages5/pages/user/wode-shezhi.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <view class="settings-page"> | ||
| 3 | + <!-- 手机号设置 --> | ||
| 4 | + <view class="setting-item"> | ||
| 5 | + <view class="setting-label">手机号</view> | ||
| 6 | + <view class="setting-value">{{ phone || '未设置' }}</view> | ||
| 7 | + </view> | ||
| 8 | + | ||
| 9 | + <!-- 微信绑定状态 --> | ||
| 10 | + <view class="setting-item"> | ||
| 11 | + <view class="setting-label">微信绑定</view> | ||
| 12 | + <view class="setting-status" :class="{ bound: isBindWx === 1, unbound: isBindWx === 0 }"> | ||
| 13 | + {{ isBindWx === 1 ? '已绑定' : '未绑定' }} | ||
| 14 | + </view> | ||
| 15 | + <!-- <button v-if="isBindWx === 0" class="bind-btn" @click="bindWeChat">绑定微信</button> | ||
| 16 | + <button v-else class="unbind-btn" @click="unbindWeChat">解绑</button> --> | ||
| 17 | + </view> | ||
| 18 | + | ||
| 19 | + <!-- 推送通知开关 --> | ||
| 20 | + <!-- <view class="setting-item notice"> | ||
| 21 | + <view class="content"> | ||
| 22 | + <view class="setting-label">推送通知</view> | ||
| 23 | + <switch :checked="pushNoticeSwitch === 1" @change="onPushNoticeChange" color="#007AFF" /> | ||
| 24 | + </view> | ||
| 25 | + <view class="tip">包含订单状态、优惠促销等重要信息的推送</view> | ||
| 26 | + </view> --> | ||
| 27 | + | ||
| 28 | + <!-- 个性化推荐开关 --> | ||
| 29 | + <!-- <view class="setting-item"> | ||
| 30 | + <view class="setting-label">个性化推荐</view> | ||
| 31 | + <switch :checked="personRecommendSwitch === 1" @change="onRecommendChange" color="#007AFF" /> | ||
| 32 | + </view> --> | ||
| 33 | + | ||
| 34 | + <!-- 退出登录 --> | ||
| 35 | + <view class="logout-section"> | ||
| 36 | + <button class="logout-btn" @click="logout">退出登录</button> | ||
| 37 | + </view> | ||
| 38 | + </view> | ||
| 39 | +</template> | ||
| 40 | + | ||
| 41 | +<script setup> | ||
| 42 | +import { ref } from 'vue'; | ||
| 43 | +import { onShow } from '@dcloudio/uni-app'; | ||
| 44 | +import SettingApi from '@/sheep/api/setting/setting'; | ||
| 45 | +import AuthUtil from '@/sheep/api/member/auth'; | ||
| 46 | +import useUserStore from '@/sheep/store/user'; | ||
| 47 | +import UserApi from '@/sheep/api/member/user'; | ||
| 48 | + | ||
| 49 | +// 数据状态 | ||
| 50 | +const phone = ref(''); | ||
| 51 | +const isBindWx = ref(0); // 0:未绑定, 1:已绑定 | ||
| 52 | +const pushNoticeSwitch = ref(0); // 0:关闭, 1:开启 | ||
| 53 | +const personRecommendSwitch = ref(0); // 0:关闭, 1:开启 | ||
| 54 | +const userStore = useUserStore(); | ||
| 55 | +// 生命周期 | ||
| 56 | +onShow(() => { | ||
| 57 | + loadUserSettings(); | ||
| 58 | +}); | ||
| 59 | + | ||
| 60 | +// 加载用户设置 | ||
| 61 | +const loadUserSettings = async () => { | ||
| 62 | + // 这里调用后端接口获取设置数据 | ||
| 63 | + const res = await SettingApi.getSetting(); | ||
| 64 | + phone.value = res.data.phone; | ||
| 65 | + isBindWx.value = res.data.isBindWx; | ||
| 66 | + pushNoticeSwitch.value = res.data.pushNoticeSwitch; | ||
| 67 | + personRecommendSwitch.value = res.data.personRecommendSwitch; | ||
| 68 | +}; | ||
| 69 | + | ||
| 70 | +// // 微信绑定 | ||
| 71 | +// const bindWeChat = () => { | ||
| 72 | +// uni.showModal({ | ||
| 73 | +// title: '绑定微信', | ||
| 74 | +// content: '确定要绑定微信吗?', | ||
| 75 | +// success: async (res) => { | ||
| 76 | +// if (res.confirm) { | ||
| 77 | +// try { | ||
| 78 | +// // 这里调用绑定微信接口 | ||
| 79 | +// // await uni.request({ | ||
| 80 | +// // url: '/api/user/bind-wechat', | ||
| 81 | +// // method: 'POST' | ||
| 82 | +// // }) | ||
| 83 | + | ||
| 84 | +// isBindWx.value = 1; | ||
| 85 | +// uni.showToast({ | ||
| 86 | +// title: '绑定成功', | ||
| 87 | +// icon: 'success', | ||
| 88 | +// }); | ||
| 89 | +// } catch (error) { | ||
| 90 | +// console.error('绑定失败:', error); | ||
| 91 | +// uni.showToast({ | ||
| 92 | +// title: '绑定失败', | ||
| 93 | +// icon: 'none', | ||
| 94 | +// }); | ||
| 95 | +// } | ||
| 96 | +// } | ||
| 97 | +// }, | ||
| 98 | +// }); | ||
| 99 | +// }; | ||
| 100 | + | ||
| 101 | +// // 微信解绑 | ||
| 102 | +// const unbindWeChat = () => { | ||
| 103 | +// uni.showModal({ | ||
| 104 | +// title: '解绑微信', | ||
| 105 | +// content: '确定要解绑微信吗?', | ||
| 106 | +// success: async (res) => { | ||
| 107 | +// if (res.confirm) { | ||
| 108 | +// try { | ||
| 109 | +// // 这里调用解绑微信接口 | ||
| 110 | +// // await uni.request({ | ||
| 111 | +// // url: '/api/user/unbind-wechat', | ||
| 112 | +// // method: 'POST' | ||
| 113 | +// // }) | ||
| 114 | + | ||
| 115 | +// isBindWx.value = 0; | ||
| 116 | +// uni.showToast({ | ||
| 117 | +// title: '解绑成功', | ||
| 118 | +// icon: 'success', | ||
| 119 | +// }); | ||
| 120 | +// } catch (error) { | ||
| 121 | +// console.error('解绑失败:', error); | ||
| 122 | +// uni.showToast({ | ||
| 123 | +// title: '解绑失败', | ||
| 124 | +// icon: 'none', | ||
| 125 | +// }); | ||
| 126 | +// } | ||
| 127 | +// } | ||
| 128 | +// }, | ||
| 129 | +// }); | ||
| 130 | +// }; | ||
| 131 | + | ||
| 132 | +// 推送通知开关改变 | ||
| 133 | +const onPushNoticeChange = async (e) => { | ||
| 134 | + const newValue = e.detail.value ? 1 : 0; | ||
| 135 | + try { | ||
| 136 | + // 这里调用更新设置接口 | ||
| 137 | + await SettingApi.updateNoticeSetting({ | ||
| 138 | + pushNoticeSwitch: newValue, | ||
| 139 | + personRecommendSwitch: personRecommendSwitch.value, | ||
| 140 | + }); | ||
| 141 | + | ||
| 142 | + pushNoticeSwitch.value = newValue; | ||
| 143 | + uni.showToast({ | ||
| 144 | + title: newValue ? '已开启推送' : '已关闭推送', | ||
| 145 | + icon: 'success', | ||
| 146 | + }); | ||
| 147 | + } catch (error) { | ||
| 148 | + console.error('更新推送设置失败:', error); | ||
| 149 | + // 恢复原状态 | ||
| 150 | + pushNoticeSwitch.value = pushNoticeSwitch.value === 1 ? 0 : 1; | ||
| 151 | + uni.showToast({ | ||
| 152 | + title: '设置失败', | ||
| 153 | + icon: 'none', | ||
| 154 | + }); | ||
| 155 | + } | ||
| 156 | +}; | ||
| 157 | + | ||
| 158 | +// 个性化推荐开关改变 | ||
| 159 | +const onRecommendChange = async (e) => { | ||
| 160 | + const newValue = e.detail.value ? 1 : 0; | ||
| 161 | + try { | ||
| 162 | + // 这里调用更新设置接口 | ||
| 163 | + await SettingApi.updateNoticeSetting({ | ||
| 164 | + personRecommendSwitch: newValue, | ||
| 165 | + pushNoticeSwitch: pushNoticeSwitch.value, | ||
| 166 | + }); | ||
| 167 | + | ||
| 168 | + personRecommendSwitch.value = newValue; | ||
| 169 | + uni.showToast({ | ||
| 170 | + title: newValue ? '已开启推荐' : '已关闭推荐', | ||
| 171 | + icon: 'success', | ||
| 172 | + }); | ||
| 173 | + } catch (error) { | ||
| 174 | + console.error('更新推荐设置失败:', error); | ||
| 175 | + // 恢复原状态 | ||
| 176 | + personRecommendSwitch.value = personRecommendSwitch.value === 1 ? 0 : 1; | ||
| 177 | + uni.showToast({ | ||
| 178 | + title: '设置失败', | ||
| 179 | + icon: 'none', | ||
| 180 | + }); | ||
| 181 | + } | ||
| 182 | +}; | ||
| 183 | + | ||
| 184 | +// 退出登录 | ||
| 185 | +const logout = () => { | ||
| 186 | + uni.showModal({ | ||
| 187 | + title: '提示', | ||
| 188 | + content: '确定要退出登录吗?', | ||
| 189 | + success: (res) => { | ||
| 190 | + if (res.confirm) { | ||
| 191 | + // 调用退出登录接口 | ||
| 192 | + AuthUtil.logout().then(() => { | ||
| 193 | + // 清空用户信息 | ||
| 194 | + userStore.logout(); | ||
| 195 | + | ||
| 196 | + // 跳转到登录页 | ||
| 197 | + uni.reLaunch({ url: '/pages/index/index' }); | ||
| 198 | + }); | ||
| 199 | + } | ||
| 200 | + }, | ||
| 201 | + }); | ||
| 202 | +}; | ||
| 203 | +</script> | ||
| 204 | + | ||
| 205 | +<style lang="scss" scoped> | ||
| 206 | +// 定义全局变量,方便统一管理 | ||
| 207 | +$primary-color: #007aff; | ||
| 208 | +$danger-color: #ff4757; | ||
| 209 | +$danger-active-color: #e63946; | ||
| 210 | +$bg-color: #f5f5f5; | ||
| 211 | +$white-color: #ffffff; | ||
| 212 | +$text-primary: #333333; | ||
| 213 | +$text-secondary: #666666; | ||
| 214 | +$text-tertiary: #999999; | ||
| 215 | + | ||
| 216 | +$border-radius-base: 16rpx; | ||
| 217 | +$border-radius-small: 8rpx; | ||
| 218 | +$padding-base: 30rpx; | ||
| 219 | +$padding-small: 20rpx; | ||
| 220 | + | ||
| 221 | +.settings-page { | ||
| 222 | + background-color: $bg-color; | ||
| 223 | + padding: $padding-small; | ||
| 224 | + | ||
| 225 | + // 设置项通用样式 | ||
| 226 | + .setting-item { | ||
| 227 | + background-color: $white-color; | ||
| 228 | + margin-bottom: $padding-small; | ||
| 229 | + padding: $padding-base; | ||
| 230 | + border-radius: $border-radius-base; | ||
| 231 | + display: flex; | ||
| 232 | + align-items: center; | ||
| 233 | + justify-content: space-between; | ||
| 234 | + box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.05); | ||
| 235 | + | ||
| 236 | + // 标签样式 | ||
| 237 | + .setting-label { | ||
| 238 | + font-size: 32rpx; | ||
| 239 | + color: $text-primary; | ||
| 240 | + font-weight: 500; | ||
| 241 | + } | ||
| 242 | + | ||
| 243 | + // 值样式 | ||
| 244 | + .setting-value { | ||
| 245 | + font-size: 28rpx; | ||
| 246 | + color: $text-secondary; | ||
| 247 | + } | ||
| 248 | + | ||
| 249 | + // 状态样式 | ||
| 250 | + .setting-status { | ||
| 251 | + font-size: 28rpx; | ||
| 252 | + font-weight: 500; | ||
| 253 | + margin-right: 20rpx; | ||
| 254 | + | ||
| 255 | + &.bound { | ||
| 256 | + color: $primary-color; | ||
| 257 | + } | ||
| 258 | + | ||
| 259 | + &.unbound { | ||
| 260 | + color: $text-tertiary; | ||
| 261 | + } | ||
| 262 | + } | ||
| 263 | + | ||
| 264 | + // 绑定/解绑按钮 | ||
| 265 | + .bind-btn, | ||
| 266 | + .unbind-btn { | ||
| 267 | + background-color: $primary-color; | ||
| 268 | + color: $white-color; | ||
| 269 | + border: none; | ||
| 270 | + border-radius: $border-radius-small; | ||
| 271 | + padding: 16rpx 24rpx; | ||
| 272 | + font-size: 26rpx; | ||
| 273 | + | ||
| 274 | + &.unbind-btn { | ||
| 275 | + background-color: $danger-color; | ||
| 276 | + } | ||
| 277 | + } | ||
| 278 | + | ||
| 279 | + // 通知设置特殊样式 | ||
| 280 | + &.notice { | ||
| 281 | + display: block; | ||
| 282 | + | ||
| 283 | + .content { | ||
| 284 | + display: flex; | ||
| 285 | + align-items: center; | ||
| 286 | + justify-content: space-between; | ||
| 287 | + margin-bottom: 16rpx; | ||
| 288 | + } | ||
| 289 | + | ||
| 290 | + .tip { | ||
| 291 | + font-size: 24rpx; | ||
| 292 | + color: $text-tertiary; | ||
| 293 | + line-height: 1.4; | ||
| 294 | + } | ||
| 295 | + } | ||
| 296 | + } | ||
| 297 | + | ||
| 298 | + .notice { | ||
| 299 | + display: flex; | ||
| 300 | + flex-direction: column; | ||
| 301 | + } | ||
| 302 | + | ||
| 303 | + // 退出登录区域 | ||
| 304 | + .logout-section { | ||
| 305 | + margin-top: 60rpx; | ||
| 306 | + padding: $padding-small; | ||
| 307 | + | ||
| 308 | + .logout-btn { | ||
| 309 | + width: 100%; | ||
| 310 | + background-color: $danger-color; | ||
| 311 | + color: $white-color; | ||
| 312 | + border: none; | ||
| 313 | + border-radius: $border-radius-base; | ||
| 314 | + padding: $padding-base; | ||
| 315 | + font-size: 32rpx; | ||
| 316 | + font-weight: 500; | ||
| 317 | + | ||
| 318 | + &:active { | ||
| 319 | + background-color: $danger-active-color; | ||
| 320 | + } | ||
| 321 | + } | ||
| 322 | + } | ||
| 323 | +} | ||
| 324 | +</style> |
pages5/pages/user/wode-yinsishezhi.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <view class="privacy-settings-page"> | ||
| 3 | + <!-- 隐私设置列表 --> | ||
| 4 | + <view class="settings-container"> | ||
| 5 | + <view class="section"> | ||
| 6 | + <view class="section-title">主页展示</view> | ||
| 7 | + <!-- 运动轨迹 --> | ||
| 8 | + <view class="setting-item"> | ||
| 9 | + <view class="setting-info"> | ||
| 10 | + <view class="setting-name">运动轨迹</view> | ||
| 11 | + <view class="setting-desc">开启后,将对其他用户展示您近半年内的运动活跃程度</view> | ||
| 12 | + </view> | ||
| 13 | + <switch :checked="movementLocusSwitch === 1" @change="onMovementLocusChange" color="#007AFF" /> | ||
| 14 | + </view> | ||
| 15 | + | ||
| 16 | + <!-- 共同喜好 --> | ||
| 17 | + <view class="setting-item"> | ||
| 18 | + <view class="setting-info"> | ||
| 19 | + <view class="setting-name">共同喜好</view> | ||
| 20 | + <view class="setting-desc">开启后,将对其他用户显示你们共同喜好的教练和课程</view> | ||
| 21 | + </view> | ||
| 22 | + <switch :checked="commonInterestSwitch === 1" @change="onCommonInterestChange" color="#007AFF" /> | ||
| 23 | + </view> | ||
| 24 | + </view> | ||
| 25 | + <view class="section"> | ||
| 26 | + <view class="section-title">门店TV展示</view> | ||
| 27 | + <!-- 勋章和好友竞赛 --> | ||
| 28 | + <view class="setting-item"> | ||
| 29 | + <view class="setting-info"> | ||
| 30 | + <view class="setting-name">勋章和好友竞赛</view> | ||
| 31 | + <view class="setting-desc">开启后,门店TV电视将展示你的勋章排行、获得播报、好友竞赛情况等信息</view> | ||
| 32 | + </view> | ||
| 33 | + <switch :checked="medalFriendSwitch === 1" @change="onMedalFriendChange" color="#007AFF" /> | ||
| 34 | + </view> | ||
| 35 | + </view> | ||
| 36 | + <view class="section"> | ||
| 37 | + <view class="section-title">课程预约</view> | ||
| 38 | + <!-- 团课约课信息 --> | ||
| 39 | + <view class="setting-item"> | ||
| 40 | + <view class="setting-info"> | ||
| 41 | + <view class="setting-name">团课约课信息</view> | ||
| 42 | + <view class="setting-desc">开启后,预约团课时将对外展示您的头像和昵称</view> | ||
| 43 | + </view> | ||
| 44 | + <switch :checked="leagueClassSwitch === 1" @change="onLeagueClassChange" color="#007AFF" /> | ||
| 45 | + </view> | ||
| 46 | + | ||
| 47 | + <!-- 私教训练报告 --> | ||
| 48 | + <view class="setting-item"> | ||
| 49 | + <view class="setting-info"> | ||
| 50 | + <view class="setting-name">私教训练报告</view> | ||
| 51 | + <view class="setting-desc">开启后,将允许教练对外分享您的训练报告</view> | ||
| 52 | + </view> | ||
| 53 | + <switch :checked="personalTrainingSwitch === 1" @change="onPersonalTrainingChange" color="#007AFF" /> | ||
| 54 | + </view> | ||
| 55 | + | ||
| 56 | + <!-- 小班课战队信息 --> | ||
| 57 | + <view class="setting-item"> | ||
| 58 | + <view class="setting-info"> | ||
| 59 | + <view class="setting-name">小班课战队信息</view> | ||
| 60 | + <view class="setting-desc">开启后,战队详情将不对外展示您的信息</view> | ||
| 61 | + </view> | ||
| 62 | + <switch :checked="miniClassTeamSwitch === 1" @change="onMiniClassTeamChange" color="#007AFF" /> | ||
| 63 | + </view> | ||
| 64 | + </view> | ||
| 65 | + <view class="section"> | ||
| 66 | + <view class="section-title">账号设置</view> | ||
| 67 | + <!-- 主页私密账户 --> | ||
| 68 | + <view class="setting-item"> | ||
| 69 | + <view class="setting-info"> | ||
| 70 | + <view class="setting-name">主页私密账户</view> | ||
| 71 | + <view class="setting-desc">开启后,您的会员主页将不对外展示任何信息</view> | ||
| 72 | + </view> | ||
| 73 | + <switch :checked="homepagePrivacySwitch === 1" @change="onHomepagePrivacyChange" color="#007AFF" /> | ||
| 74 | + </view> | ||
| 75 | + | ||
| 76 | + <!-- 排行榜 --> | ||
| 77 | + <view class="setting-item"> | ||
| 78 | + <view class="setting-info"> | ||
| 79 | + <view class="setting-name">排行榜</view> | ||
| 80 | + <view class="setting-desc">开启后,在会员排行榜上将展示您的头像和昵称</view> | ||
| 81 | + </view> | ||
| 82 | + <switch :checked="rankingSwitch === 1" @change="onRankingChange" color="#007AFF" /> | ||
| 83 | + </view> | ||
| 84 | + </view> | ||
| 85 | + </view> | ||
| 86 | + </view> | ||
| 87 | +</template> | ||
| 88 | + | ||
| 89 | +<script setup> | ||
| 90 | +import SettingApi from '@/sheep/api/setting/setting'; | ||
| 91 | +import { onShow, onUnload } from '@dcloudio/uni-app'; | ||
| 92 | +import { ref, computed } from 'vue'; | ||
| 93 | + | ||
| 94 | +// 隐私设置数据状态 | ||
| 95 | +const movementLocusSwitch = ref(0); // 运动轨迹 | ||
| 96 | +const commonInterestSwitch = ref(0); // 共同喜好 | ||
| 97 | +const medalFriendSwitch = ref(0); // 勋章和好友竞赛 | ||
| 98 | +const leagueClassSwitch = ref(0); // 团课约课信息 | ||
| 99 | +const personalTrainingSwitch = ref(0); // 私教训练报告 | ||
| 100 | +const miniClassTeamSwitch = ref(0); // 小班课战队信息 | ||
| 101 | +const homepagePrivacySwitch = ref(0); // 主页私密账户 | ||
| 102 | +const rankingSwitch = ref(0); // 排行榜 | ||
| 103 | + | ||
| 104 | +// 生命周期 | ||
| 105 | +onShow(() => { | ||
| 106 | + loadPrivacySettings(); | ||
| 107 | +}); | ||
| 108 | +// 页面隐藏时保存变更 | ||
| 109 | +onUnload(() => { | ||
| 110 | + saveSettings(); | ||
| 111 | +}); | ||
| 112 | +// 获取当前设置 | ||
| 113 | +const getCurrentSettings = () => ({ | ||
| 114 | + movementLocusSwitch: movementLocusSwitch.value, | ||
| 115 | + commonInterestSwitch: commonInterestSwitch.value, | ||
| 116 | + medalFriendSwitch: medalFriendSwitch.value, | ||
| 117 | + leagueClassSwitch: leagueClassSwitch.value, | ||
| 118 | + personalTrainingSwitch: personalTrainingSwitch.value, | ||
| 119 | + miniClassTeamSwitch: miniClassTeamSwitch.value, | ||
| 120 | + homepagePrivacySwitch: homepagePrivacySwitch.value, | ||
| 121 | + rankingSwitch: rankingSwitch.value, | ||
| 122 | +}); | ||
| 123 | + | ||
| 124 | +// 加载隐私设置 | ||
| 125 | +const loadPrivacySettings = async () => { | ||
| 126 | + try { | ||
| 127 | + // 这里调用后端接口获取隐私设置 | ||
| 128 | + const res = await SettingApi.getPrivacySetting(); | ||
| 129 | + movementLocusSwitch.value = res.data.movementLocusSwitch || 0; // 运动轨迹 | ||
| 130 | + commonInterestSwitch.value = res.data.commonInterestSwitch || 0; // 共同喜好 | ||
| 131 | + medalFriendSwitch.value = res.data.medalFriendSwitch || 0; // 勋章和好友竞赛 | ||
| 132 | + leagueClassSwitch.value = res.data.leagueClassSwitch || 0; // 团课约课信息 | ||
| 133 | + personalTrainingSwitch.value = res.data.personalTrainingSwitch || 0; // 私教训练报告 | ||
| 134 | + miniClassTeamSwitch.value = res.data.miniClassTeamSwitch || 0; // 小班课战队信息 | ||
| 135 | + homepagePrivacySwitch.value = res.data.homepagePrivacySwitch || 0; // 主页私密账户 | ||
| 136 | + rankingSwitch.value = res.data.rankingSwitch || 0; // 排行榜 | ||
| 137 | + } catch (error) { | ||
| 138 | + console.error('加载隐私设置失败:', error); | ||
| 139 | + uni.showToast({ | ||
| 140 | + title: '加载设置失败', | ||
| 141 | + icon: 'none', | ||
| 142 | + }); | ||
| 143 | + } | ||
| 144 | +}; | ||
| 145 | + | ||
| 146 | +// 保存隐私设置 | ||
| 147 | +const saveSettings = async () => { | ||
| 148 | + const settings = getCurrentSettings(); | ||
| 149 | + try { | ||
| 150 | + // 这里调用后端接口保存隐私设置 | ||
| 151 | + await SettingApi.updatePrivacySetting(settings); | ||
| 152 | + } catch (error) { | ||
| 153 | + console.error('保存隐私设置失败:', error); | ||
| 154 | + uni.showToast({ | ||
| 155 | + title: '保存失败', | ||
| 156 | + icon: 'none', | ||
| 157 | + }); | ||
| 158 | + } | ||
| 159 | +}; | ||
| 160 | +// 各个开关的变更处理函数 | ||
| 161 | +const onMovementLocusChange = (e) => { | ||
| 162 | + const newValue = e.detail.value ? 1 : 0; | ||
| 163 | + updateSetting('movementLocusSwitch', newValue); | ||
| 164 | +}; | ||
| 165 | + | ||
| 166 | +const onCommonInterestChange = (e) => { | ||
| 167 | + const newValue = e.detail.value ? 1 : 0; | ||
| 168 | + updateSetting('commonInterestSwitch', newValue); | ||
| 169 | +}; | ||
| 170 | + | ||
| 171 | +const onMedalFriendChange = (e) => { | ||
| 172 | + const newValue = e.detail.value ? 1 : 0; | ||
| 173 | + updateSetting('medalFriendSwitch', newValue); | ||
| 174 | +}; | ||
| 175 | + | ||
| 176 | +const onLeagueClassChange = (e) => { | ||
| 177 | + const newValue = e.detail.value ? 1 : 0; | ||
| 178 | + updateSetting('leagueClassSwitch', newValue); | ||
| 179 | +}; | ||
| 180 | + | ||
| 181 | +const onPersonalTrainingChange = (e) => { | ||
| 182 | + const newValue = e.detail.value ? 1 : 0; | ||
| 183 | + updateSetting('personalTrainingSwitch', newValue); | ||
| 184 | +}; | ||
| 185 | + | ||
| 186 | +const onMiniClassTeamChange = (e) => { | ||
| 187 | + const newValue = e.detail.value ? 1 : 0; | ||
| 188 | + updateSetting('miniClassTeamSwitch', newValue); | ||
| 189 | +}; | ||
| 190 | + | ||
| 191 | +const onHomepagePrivacyChange = (e) => { | ||
| 192 | + const newValue = e.detail.value ? 1 : 0; | ||
| 193 | + updateSetting('homepagePrivacySwitch', newValue); | ||
| 194 | +}; | ||
| 195 | + | ||
| 196 | +const onRankingChange = (e) => { | ||
| 197 | + const newValue = e.detail.value ? 1 : 0; | ||
| 198 | + updateSetting('rankingSwitch', newValue); | ||
| 199 | +}; | ||
| 200 | + | ||
| 201 | +// 更新设置的通用方法 | ||
| 202 | +const updateSetting = (key, value) => { | ||
| 203 | + const refMap = { | ||
| 204 | + movementLocusSwitch: movementLocusSwitch, | ||
| 205 | + commonInterestSwitch: commonInterestSwitch, | ||
| 206 | + medalFriendSwitch: medalFriendSwitch, | ||
| 207 | + leagueClassSwitch: leagueClassSwitch, | ||
| 208 | + personalTrainingSwitch: personalTrainingSwitch, | ||
| 209 | + miniClassTeamSwitch: miniClassTeamSwitch, | ||
| 210 | + homepagePrivacySwitch: homepagePrivacySwitch, | ||
| 211 | + rankingSwitch: rankingSwitch, | ||
| 212 | + }; | ||
| 213 | + | ||
| 214 | + if (refMap[key]) { | ||
| 215 | + refMap[key].value = value; | ||
| 216 | + } | ||
| 217 | +}; | ||
| 218 | + | ||
| 219 | +// 返回上一页 | ||
| 220 | +// const goBack = () => { | ||
| 221 | +// if (hasChanges.value) { | ||
| 222 | +// uni.showModal({ | ||
| 223 | +// title: '提示', | ||
| 224 | +// content: '您有未保存的修改,确定要离开吗?', | ||
| 225 | +// success: (res) => { | ||
| 226 | +// if (res.confirm) { | ||
| 227 | +// uni.navigateBack(); | ||
| 228 | +// } | ||
| 229 | +// }, | ||
| 230 | +// }); | ||
| 231 | +// } else { | ||
| 232 | +// uni.navigateBack(); | ||
| 233 | +// } | ||
| 234 | +// }; | ||
| 235 | +</script> | ||
| 236 | + | ||
| 237 | +<style lang="scss" scoped> | ||
| 238 | +// 定义全局样式变量,便于统一管理和修改 | ||
| 239 | +$bg-color: #f5f5f5; | ||
| 240 | +$white-color: #ffffff; | ||
| 241 | +$text-primary: #333333; | ||
| 242 | +$text-secondary: #666666; | ||
| 243 | +$text-tertiary: #999999; | ||
| 244 | +$primary-color: #007aff; | ||
| 245 | + | ||
| 246 | +$border-radius-base: 16rpx; | ||
| 247 | +$border-radius-large: 50rpx; | ||
| 248 | +$padding-base: 30rpx; | ||
| 249 | +$padding-small: 20rpx; | ||
| 250 | +$padding-xs: 10rpx; | ||
| 251 | + | ||
| 252 | +.privacy-settings-page { | ||
| 253 | + background-color: $bg-color; | ||
| 254 | + min-height: 100vh; | ||
| 255 | + | ||
| 256 | + // 设置容器样式 | ||
| 257 | + .settings-container { | ||
| 258 | + padding: $padding-small; | ||
| 259 | + | ||
| 260 | + // 分区标题 | ||
| 261 | + .section-title { | ||
| 262 | + font-size: 28rpx; | ||
| 263 | + color: $text-tertiary; | ||
| 264 | + margin-bottom: $padding-small; | ||
| 265 | + padding-left: $padding-xs; | ||
| 266 | + } | ||
| 267 | + | ||
| 268 | + // 设置项样式 | ||
| 269 | + .setting-item { | ||
| 270 | + background-color: $white-color; | ||
| 271 | + margin-bottom: $padding-small; | ||
| 272 | + padding: $padding-base; | ||
| 273 | + border-radius: $border-radius-base; | ||
| 274 | + display: flex; | ||
| 275 | + align-items: center; | ||
| 276 | + justify-content: space-between; | ||
| 277 | + box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.05); | ||
| 278 | + | ||
| 279 | + // 设置项信息区域 | ||
| 280 | + .setting-info { | ||
| 281 | + flex: 1; | ||
| 282 | + margin-right: $padding-small; | ||
| 283 | + | ||
| 284 | + // 设置项名称 | ||
| 285 | + .setting-name { | ||
| 286 | + font-size: 32rpx; | ||
| 287 | + color: $text-primary; | ||
| 288 | + font-weight: 500; | ||
| 289 | + margin-bottom: 8rpx; | ||
| 290 | + } | ||
| 291 | + | ||
| 292 | + // 设置项描述 | ||
| 293 | + .setting-desc { | ||
| 294 | + font-size: 26rpx; | ||
| 295 | + color: $text-tertiary; | ||
| 296 | + line-height: 1.4; | ||
| 297 | + } | ||
| 298 | + } | ||
| 299 | + } | ||
| 300 | + } | ||
| 301 | + | ||
| 302 | + // 保存提示框样式 | ||
| 303 | + // .save-notice { | ||
| 304 | + // position: fixed; | ||
| 305 | + // bottom: 60rpx; | ||
| 306 | + // left: 40rpx; | ||
| 307 | + // right: 40rpx; | ||
| 308 | + // background-color: $white-color; | ||
| 309 | + // border-radius: $border-radius-large; | ||
| 310 | + // padding: $padding-small $padding-base; | ||
| 311 | + // display: flex; | ||
| 312 | + // align-items: center; | ||
| 313 | + // justify-content: space-between; | ||
| 314 | + // box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.1); | ||
| 315 | + | ||
| 316 | + // .notice-content { | ||
| 317 | + // display: flex; | ||
| 318 | + // align-items: center; | ||
| 319 | + | ||
| 320 | + // .notice-icon { | ||
| 321 | + // font-size: 32rpx; | ||
| 322 | + // margin-right: 16rpx; | ||
| 323 | + // } | ||
| 324 | + | ||
| 325 | + // .notice-text { | ||
| 326 | + // font-size: 28rpx; | ||
| 327 | + // color: $text-secondary; | ||
| 328 | + // } | ||
| 329 | + // } | ||
| 330 | + | ||
| 331 | + // .save-text { | ||
| 332 | + // font-size: 28rpx; | ||
| 333 | + // color: $primary-color; | ||
| 334 | + // font-weight: 500; | ||
| 335 | + // } | ||
| 336 | + // } | ||
| 337 | +} | ||
| 338 | +</style> |
| @@ -7,6 +7,8 @@ const FileApi = { | @@ -7,6 +7,8 @@ const FileApi = { | ||
| 7 | uni.showLoading({ | 7 | uni.showLoading({ |
| 8 | title: '上传中', | 8 | title: '上传中', |
| 9 | }); | 9 | }); |
| 10 | + console.log(file, 'file'); | ||
| 11 | + | ||
| 10 | return new Promise((resolve, reject) => { | 12 | return new Promise((resolve, reject) => { |
| 11 | uni.uploadFile({ | 13 | uni.uploadFile({ |
| 12 | url: baseUrl + apiPath + '/infra/file/upload', | 14 | url: baseUrl + apiPath + '/infra/file/upload', |
| @@ -21,6 +23,8 @@ const FileApi = { | @@ -21,6 +23,8 @@ const FileApi = { | ||
| 21 | directory, | 23 | directory, |
| 22 | }, | 24 | }, |
| 23 | success: (uploadFileRes) => { | 25 | success: (uploadFileRes) => { |
| 26 | + console.log(uploadFileRes, 'uploadFileRes-'); | ||
| 27 | + | ||
| 24 | let result = JSON.parse(uploadFileRes.data); | 28 | let result = JSON.parse(uploadFileRes.data); |
| 25 | if (result.error === 1) { | 29 | if (result.error === 1) { |
| 26 | uni.showToast({ | 30 | uni.showToast({ |
| @@ -250,7 +250,7 @@ const UserApi = { | @@ -250,7 +250,7 @@ const UserApi = { | ||
| 250 | // 获得我的信息 | 250 | // 获得我的信息 |
| 251 | getUserInfo: () => { | 251 | getUserInfo: () => { |
| 252 | return request({ | 252 | return request({ |
| 253 | - url: '/app/student/myInfo', | 253 | + url: '/app/user/myInfo', |
| 254 | method: 'GET', | 254 | method: 'GET', |
| 255 | custom: { | 255 | custom: { |
| 256 | showLoading: false, | 256 | showLoading: false, |
static/icons/antFill-money-collect 1@1x.png
0 → 100644
529 Bytes
734 Bytes
static/icons/antOutline-gift 1@1x.png
0 → 100644
538 Bytes
static/icons/antOutline-history 1@1x.png
0 → 100644
725 Bytes
static/icons/code.png
0 → 100644
3.24 KB
static/icons/fa5-id-card-fas 1@1x.png
0 → 100644
442 Bytes
static/icons/fa5-tags-fas 1@1x.png
0 → 100644
490 Bytes
static/icons/fast.png
0 → 100644
4.01 KB
static/icons/folder.png
0 → 100644
3.72 KB
static/icons/iconPark-add-user 1@1x.png
0 → 100644
713 Bytes
static/icons/iconPark-city-one 1@1x.png
0 → 100644
396 Bytes
static/icons/iconPark-coupon 1@1x.png
0 → 100644
521 Bytes
static/icons/iconPark-currency 1@1x.png
0 → 100644
681 Bytes
static/icons/iconPark-deposit 1@1x.png
0 → 100644
423 Bytes
static/icons/iconPark-editor 1@1x.png
0 → 100644
495 Bytes
static/icons/iconPark-exchange-four 1@1x.png
0 → 100644
467 Bytes
static/icons/iconPark-finance 1@1x.png
0 → 100644
797 Bytes
static/icons/iconPark-helpcenter 1@1x.png
0 → 100644
494 Bytes
611 Bytes
static/icons/iconPark-message-emoji 1@1x.png
0 → 100644
494 Bytes
static/icons/iconPark-navigation 1@1x.png
0 → 100644
649 Bytes
static/icons/iconPark-schedule 1@1x.png
0 → 100644
414 Bytes
static/icons/iconPark-schedule 2@1x.png
0 → 100644
414 Bytes
static/icons/iconPark-ticket-one 1@1x.png
0 → 100644
530 Bytes
453 Bytes
static/icons/iconPark-transport 1@1x.png
0 → 100644
487 Bytes
432 Bytes
static/icons/iconPark-weixin-market 1@1x.png
0 → 100644
417 Bytes
static/icons/md-face 1@1x.png
0 → 100644
684 Bytes
static/icons/md-folder_open 1@1x.png
0 → 100644
280 Bytes
static/icons/peoples.png
0 → 100644
4.89 KB
static/icons/photograph.png
0 → 100644
5.45 KB
static/icons/report.png
0 → 100644
3 KB
593 Bytes
static/icons/riLine-feedback-line 1@1x.png
0 → 100644
278 Bytes
static/icons/riLine-hearts-line 1@1x.png
0 → 100644
645 Bytes
398 Bytes
static/icons/st-shop 1@1x.png
0 → 100644
372 Bytes
static/icons/stLine-light-l 1@1x.png
0 → 100644
660 Bytes
static/icons/ze-balance-pay 1@1x.png
0 → 100644
492 Bytes
static/icons/ze-diamond-o 1@1x.png
0 → 100644
550 Bytes
static/icons/ze-discount 1@1x.png
0 → 100644
783 Bytes
static/icons/ze-points 1@1x.png
0 → 100644
822 Bytes
static/icons/包月团课@1x.png
0 → 100644
240 Bytes
static/icons/快速约课@1x.png
0 → 100644
455 Bytes
static/icons/礼品卡商城@1x.png
0 → 100644
267 Bytes
static/icons/超值课包@1x.png
0 → 100644
322 Bytes
static/icons/鸿星月卡@1x.png
0 → 100644
411 Bytes
-
Please register or login to post a comment