feat: 重构个人中心页面并新增功能模块

This commit is contained in:
Ray.Hao
2026-03-08 23:42:47 +08:00
parent c9c66e4239
commit b881b79384
7 changed files with 960 additions and 514 deletions

View File

@@ -30,6 +30,7 @@
</view>
<view class="custom-navbar__right" :style="{ width: rightWidth + 'px' }">
<view class="custom-navbar__capsule-space" :style="{ width: capsuleSpaceWidth + 'px' }" />
<slot name="right" />
</view>
</view>
@@ -91,6 +92,18 @@ const menuButtonWidth = computed(() => navbar.menuButtonWidth.value);
const menuButtonRightGap = computed(() => navbar.menuButtonRightGap.value);
const menuButtonLeft = computed(() => navbar.menuButtonLeft.value);
const capsuleSpaceWidth = computed(() => {
let width = 0;
// #ifdef MP-WEIXIN
if (menuButtonWidth.value > 0) {
width = menuButtonWidth.value + menuButtonRightGap.value;
}
// #endif
return width;
});
const rightContentWidth = computed(() => 96);
const leftWidth = computed(() => {
let width = 80;
// #ifdef MP-WEIXIN
@@ -102,9 +115,7 @@ const leftWidth = computed(() => {
const rightWidth = computed(() => {
let width = 80;
// #ifdef MP-WEIXIN
if (menuButtonWidth.value > 0) {
width = menuButtonWidth.value + menuButtonRightGap.value * 2;
}
width = capsuleSpaceWidth.value + rightContentWidth.value;
// #endif
return width;
});
@@ -209,4 +220,9 @@ export default {
align-items: center;
justify-content: flex-end;
}
.custom-navbar__capsule-space {
flex: 0 0 auto;
height: 1px;
}
</style>

View File

@@ -44,6 +44,17 @@
"path": "pages/mine/account/index",
"type": "page"
},
{
"path": "pages/mine/feedback/index",
"type": "page",
"name": "feedback",
"style": {
"navigationBarTitleText": "意见反馈"
},
"meta": {
"requireAuth": true
}
},
{
"path": "pages/mine/official/index",
"type": "page",
@@ -60,6 +71,14 @@
"path": "pages/mine/profile/index",
"type": "page"
},
{
"path": "pages/mine/settings/index",
"type": "page",
"name": "settings",
"style": {
"navigationBarTitleText": "设置"
}
},
{
"path": "pages/work/config/index",
"type": "page",

File diff suppressed because it is too large Load Diff

View File

@@ -1,43 +1,54 @@
<template>
<view class="page-container dark:text-[var(--wot-color-text)]">
<wd-card v-if="userProfile" custom-style="margin-top: 20rpx">
<wd-cell-group border>
<wd-cell class="avatar-cell" title="头像" center is-link>
<view class="avatar">
<view v-if="!userProfile.avatar" class="img" @click="avatarUpload">
<wd-icon name="fill-camera" custom-class="img-icon" />
</view>
<wd-img
v-if="userProfile.avatar"
round
width="80px"
height="80px"
:src="userProfile.avatar"
mode="aspectFit"
custom-class="profile-img"
@click="avatarUpload"
<view class="page-container page-container--auto dark:text-[var(--wot-color-text)]">
<view class="profile-content">
<view class="pt-20rpx">
<wd-card v-if="userProfile">
<wd-cell-group border>
<wd-cell class="avatar-cell" title="头像" center is-link>
<view class="avatar">
<view v-if="!userProfile.avatar" class="img" @click="handleAvatarUpload">
<wd-icon name="fill-camera" custom-class="img-icon" />
</view>
<wd-img
v-if="userProfile.avatar"
round
width="80px"
height="80px"
:src="userProfile.avatar"
mode="aspectFit"
custom-class="profile-img"
@click="handleAvatarUpload"
/>
</view>
</wd-cell>
<wd-cell title="昵称" :value="userProfile.nickname" is-link @click="openDialog()" />
<wd-cell
title="性别"
:value="userProfile.gender === 1 ? '男' : userProfile.gender === 2 ? '女' : '未知'"
is-link
@click="openDialog()"
/>
</view>
</wd-cell>
<wd-cell title="昵称" :value="userProfile.nickname" is-link @click="handleOpenDialog()" />
<wd-cell
title="性别"
:value="userProfile.gender === 1 ? '男' : userProfile.gender === 2 ? '女' : '未知'"
is-link
@click="handleOpenDialog()"
/>
<wd-cell title="用户名" :value="userProfile.username" />
<wd-cell title="部门" :value="userProfile.deptName" />
<wd-cell title="角色" :value="userProfile.roleNames" />
<wd-cell title="创建日期" :value="userProfile.createTime" />
</wd-cell-group>
</wd-card>
<wd-cell title="用户名" :value="userProfile.username" />
<wd-cell title="部门" :value="userProfile.deptName" />
<wd-cell title="角色" :value="userProfile.roleNames" />
<view class="profile-last-cell-wrap">
<wd-cell title="创建日期" :value="userProfile.createTime" />
</view>
</wd-cell-group>
</wd-card>
</view>
</view>
<!--头像裁剪-->
<wd-img-cropper v-model="avatarShow" :img-src="originalSrc" @confirm="handleAvatarConfirm" />
<wd-img-cropper
v-if="avatarShow"
v-model="avatarShow"
:img-src="originalSrc"
@confirm="handleAvatarConfirm"
/>
<!--用户信息编辑弹出框-->
<wd-popup v-model="dialog.visible" position="bottom">
<wd-popup v-if="dialogState.visible" v-model="dialogState.visible" position="bottom">
<wd-form ref="userProfileFormRef" :model="userProfileForm" custom-class="edit-form">
<wd-cell-group border>
<wd-input
@@ -77,7 +88,7 @@ const loadUserProfile = async () => {
};
// 头像选择
function avatarUpload() {
function handleAvatarUpload() {
uni.chooseImage({
count: 1,
success: (res) => {
@@ -107,7 +118,7 @@ const rules = reactive({
gender: [{ required: true, message: "请选择性别" }],
});
const dialog = reactive({
const dialogState = reactive({
visible: false,
});
@@ -118,8 +129,8 @@ const userProfileFormRef = ref();
* 打开弹窗
* @param type 弹窗类型 ACCOUNT: 账号资料 PASSWORD: 修改密码 MOBILE: 绑定手机 EMAIL: 绑定邮箱
*/
const handleOpenDialog = () => {
dialog.visible = true;
const openDialog = () => {
dialogState.visible = true;
// 初始化表单数据
userProfileForm.nickname = userProfile.value?.nickname;
userProfileForm.gender = userProfile.value?.gender;
@@ -131,7 +142,7 @@ function handleSubmit() {
if (valid) {
UserAPI.updateProfile(userProfileForm).then(() => {
uni.showToast({ title: "账号资料修改成功", icon: "none" });
dialog.visible = false;
dialogState.visible = false;
loadUserProfile();
});
}
@@ -143,8 +154,8 @@ onLoad(() => {
if (!checkLogin()) return;
// #ifdef H5
document.addEventListener("touchstart", touchstartListener, { passive: false });
document.addEventListener("touchmove", touchmoveListener, { passive: false });
document.addEventListener("touchstart", handleTouchStart, { passive: false });
document.addEventListener("touchmove", handleTouchMove, { passive: false });
// #endif
loadUserProfile();
});
@@ -157,26 +168,24 @@ onMounted(() => {
// 页面销毁前移除事件监听
onBeforeUnmount(() => {
// #ifdef H5
document.removeEventListener("touchstart", touchstartListener);
document.removeEventListener("touchmove", touchmoveListener);
document.removeEventListener("touchstart", handleTouchStart);
document.removeEventListener("touchmove", handleTouchMove);
// #endif
});
// 禁用浏览器双指缩放,使头像裁剪时双指缩放能够起作用
function touchstartListener(event: TouchEvent) {
function handleTouchStart(event: TouchEvent) {
if (event.touches.length > 1) {
event.preventDefault();
}
}
// 禁用浏览器下拉刷新,使头像裁剪时能够移动图片
function touchmoveListener(event: TouchEvent) {
function handleTouchMove(event: TouchEvent) {
event.preventDefault();
}
function handleBack() {
uni.navigateBack();
}
</script>
<style lang="scss" scoped>
.avatar-cell {
:deep(.wd-cell__body) {
align-items: center;

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

View File

@@ -0,0 +1,63 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="360" viewBox="0 0 1200 360" preserveAspectRatio="xMidYMid slice">
<defs>
<linearGradient id="g" x1="0" y1="0" x2="1" y2="0">
<stop offset="0" stop-color="#7CB6FF"/>
<stop offset="0.55" stop-color="#C9D4FF"/>
<stop offset="1" stop-color="#FFD1E8"/>
</linearGradient>
<radialGradient id="glowA" cx="30%" cy="35%" r="60%">
<stop offset="0" stop-color="#FFFFFF" stop-opacity="0.65"/>
<stop offset="0.55" stop-color="#FFFFFF" stop-opacity="0.10"/>
<stop offset="1" stop-color="#FFFFFF" stop-opacity="0"/>
</radialGradient>
<radialGradient id="glowB" cx="78%" cy="28%" r="65%">
<stop offset="0" stop-color="#FFFFFF" stop-opacity="0.40"/>
<stop offset="0.6" stop-color="#FFFFFF" stop-opacity="0.06"/>
<stop offset="1" stop-color="#FFFFFF" stop-opacity="0"/>
</radialGradient>
<filter id="blur" x="-20%" y="-20%" width="140%" height="140%">
<feGaussianBlur stdDeviation="14"/>
</filter>
</defs>
<rect width="1200" height="360" fill="url(#g)"/>
<path d="M -40 280 C 220 180, 520 210, 820 160 C 980 132, 1110 120, 1260 140" fill="none" stroke="#FFFFFF" stroke-opacity="0.18" stroke-width="3"/>
<path d="M -60 310 C 220 230, 520 252, 820 208 C 1020 180, 1140 176, 1280 186" fill="none" stroke="#FFFFFF" stroke-opacity="0.10" stroke-width="2"/>
<circle cx="320" cy="120" r="180" fill="url(#glowA)" filter="url(#blur)"/>
<circle cx="900" cy="90" r="200" fill="url(#glowB)" filter="url(#blur)"/>
<g fill="#FFFFFF" opacity="0.75">
<circle cx="86" cy="74" r="1.4"/>
<circle cx="124" cy="132" r="1.1"/>
<circle cx="182" cy="66" r="1.2"/>
<circle cx="210" cy="156" r="1.0"/>
<circle cx="268" cy="110" r="1.2"/>
<circle cx="312" cy="74" r="1.0"/>
<circle cx="356" cy="148" r="1.3"/>
<circle cx="418" cy="98" r="1.1"/>
<circle cx="472" cy="66" r="1.4"/>
<circle cx="512" cy="128" r="1.0"/>
<circle cx="562" cy="90" r="1.2"/>
<circle cx="612" cy="56" r="1.0"/>
<circle cx="652" cy="120" r="1.4"/>
<circle cx="702" cy="92" r="1.1"/>
<circle cx="742" cy="60" r="1.2"/>
<circle cx="786" cy="138" r="1.0"/>
<circle cx="826" cy="86" r="1.3"/>
<circle cx="872" cy="54" r="1.1"/>
<circle cx="922" cy="132" r="1.4"/>
<circle cx="972" cy="92" r="1.0"/>
<circle cx="1016" cy="58" r="1.2"/>
<circle cx="1062" cy="110" r="1.3"/>
<circle cx="1112" cy="72" r="1.1"/>
</g>
<g fill="#FFFFFF" opacity="0.28">
<circle cx="160" cy="210" r="2.4"/>
<circle cx="520" cy="240" r="2.0"/>
<circle cx="880" cy="220" r="2.2"/>
<circle cx="1040" cy="250" r="1.8"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@@ -22,14 +22,29 @@ body,
}
// ==========================================================================
// 页面容器
// 页面容器 - 分类方案
// ==========================================================================
// 基础容器(无强制高度,适用于大多数页面)
.page-container {
min-height: 100%;
background-color: var(--color-bg);
}
// 全屏容器(需要撑满视口的页面,如登录页、启动页)
.page-container--full {
min-height: 100vh;
}
// 自适应容器(内容少的页面,如详情页、表单页)
.page-container--auto {
min-height: auto;
}
// 渐变背景页面(用于个人中心等页面)
.page-container--gradient {
background: linear-gradient(180deg, #f4f8ff 0, #f8fafc 320rpx, var(--wot-color-bg, #f8fafc) 100%);
}
// ==========================================================================
// 快捷类
// ==========================================================================