refactor: ♻️ 页面优化调整
This commit is contained in:
@@ -89,10 +89,9 @@
|
||||
"@dcloudio/uni-mp-weixin": "3.0.0-4020420240722002",
|
||||
"@dcloudio/uni-mp-xhs": "3.0.0-4020420240722002",
|
||||
"@dcloudio/uni-quickapp-webview": "3.0.0-4020420240722002",
|
||||
"@qiun/uni-ucharts": "2.5.0-20230101",
|
||||
"pinia": "^2.2.2",
|
||||
"vue": "^3.4.21",
|
||||
"wot-design-uni": "^1.3.11"
|
||||
"vue": "^3.5.13",
|
||||
"wot-design-uni": "^1.4.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@commitlint/cli": "^19.5.0",
|
||||
@@ -117,7 +116,7 @@
|
||||
"postcss-html": "^1.7.0",
|
||||
"postcss-scss": "^4.0.9",
|
||||
"prettier": "^3.3.3",
|
||||
"sass": "1.79.3",
|
||||
"sass": "1.78.0",
|
||||
"sass-loader": "^16.0.2",
|
||||
"stylelint": "^16.9.0",
|
||||
"stylelint-config-html": "^1.1.0",
|
||||
|
||||
@@ -33,21 +33,33 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/mine/user-agreement/index",
|
||||
"path": "pages/mine/settings/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "设置"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/mine/settings/account/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "账号和安全"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/mine/settings/agreement/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "用户协议"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/mine/privacy/index",
|
||||
"path": "pages/mine/settings/privacy/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "隐私政策"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/mine/network-test/index",
|
||||
"path": "pages/mine/settings/network/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "网络测试"
|
||||
"navigationBarTitleText": "网络检测"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -62,6 +74,7 @@
|
||||
"navigationBarTitleText": "个人资料"
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"path": "pages/work/user/index",
|
||||
"style": {
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
<!-- 通知公告 -->
|
||||
<wd-notice-bar
|
||||
class="mt-2"
|
||||
custom-style="margin-top:10rpx"
|
||||
text="这是一条消息提示信息,这是一条消息提示信息,这是一条消息提示信息"
|
||||
prefix="check-outline"
|
||||
color="#34D19D"
|
||||
@@ -35,7 +35,7 @@
|
||||
/>
|
||||
|
||||
<!-- 数据统计 -->
|
||||
<wd-grid :column="2" class="mt-2" :gutter="2">
|
||||
<wd-grid :column="2" custom-style="margin-top:10rpx" :gutter="2">
|
||||
<wd-grid-item
|
||||
v-for="(item, index) in visitStatsData"
|
||||
:key="index"
|
||||
@@ -47,7 +47,7 @@
|
||||
<image class="w-80rpx h-80rpx rounded-8rpx" :src="item.icon" />
|
||||
<view class="ml-5 text-left">
|
||||
<view class="font-bold">{{ item.title }}</view>
|
||||
<view class="mt-1">{{ item.todayCount }}</view>
|
||||
<view class="mt-2">{{ item.todayCount }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -136,7 +136,10 @@ const chartData = ref({});
|
||||
// 日期范围
|
||||
const recentDaysRange = ref(7);
|
||||
|
||||
const swiperList = ref(["https://oss.youlai.tech/blog/banner3.png"]);
|
||||
const swiperList = ref([
|
||||
"https://oss.youlai.tech/blog/banner9.png",
|
||||
"https://oss.youlai.tech/blog/banner8.png",
|
||||
]);
|
||||
|
||||
// 快捷导航列表
|
||||
const navList = reactive([
|
||||
|
||||
@@ -32,13 +32,9 @@
|
||||
<view class="agreement-text">
|
||||
<view class="agreement-links">
|
||||
<text class="normal-text">登录即同意</text>
|
||||
<text class="link" @click="goToUserAgreement">《用户协议》</text>
|
||||
<text class="link" @click="navigateToUserAgreement">《用户协议》</text>
|
||||
<text class="normal-text">和</text>
|
||||
<text class="link" @click="goToPrivacy">《隐私政策》</text>
|
||||
</view>
|
||||
<view class="copyright">
|
||||
<text class="copyright-text">Copyright © {{ getYear() }} 有来开源组织</text>
|
||||
<text class="copyright-text">All Rights Reserved</text>
|
||||
<text class="link" @click="navigateToPrivacy">《隐私政策》</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -75,19 +71,16 @@ const handleLogin = () => {
|
||||
}
|
||||
});
|
||||
};
|
||||
const goToUserAgreement = () => {
|
||||
const navigateToUserAgreement = () => {
|
||||
uni.navigateTo({
|
||||
url: "/pages/mine/user-agreement/index",
|
||||
});
|
||||
};
|
||||
const goToPrivacy = () => {
|
||||
const navigateToPrivacy = () => {
|
||||
uni.navigateTo({
|
||||
url: "/pages/mine/privacy/index",
|
||||
});
|
||||
};
|
||||
const getYear = () => {
|
||||
return new Date().getFullYear();
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
@@ -1,269 +1,121 @@
|
||||
<template>
|
||||
<view class="mine">
|
||||
<!-- 个人资料 -->
|
||||
<view class="header">
|
||||
<view class="mine-container">
|
||||
<view class="mine-header">
|
||||
<view class="flex items-center">
|
||||
<!-- 头像 -->
|
||||
<image
|
||||
class="w-100rpx h-100rpx rounded-full"
|
||||
:src="isLogin ? userInfo!.avatar : defaultAvatar"
|
||||
/>
|
||||
<view class="ml-20rpx text-32rpx">
|
||||
<text v-if="isLogin">{{ userInfo!.nickname }}</text>
|
||||
<view v-else @click="goToLoginPage">
|
||||
<text>您还未登录,请先</text>
|
||||
<text class="cursor-pointer">
|
||||
登录
|
||||
<wd-icon name="arrow-right" />
|
||||
</text>
|
||||
<!-- 用户信息 -->
|
||||
<view class="ml-20rpx">
|
||||
<!-- 已登录 -->
|
||||
<view v-if="isLogin">
|
||||
<view class="text-32rpx">
|
||||
{{ userInfo!.nickname }}
|
||||
</view>
|
||||
<view class="text-28rpx mt2">{{ userInfo?.username }}</view>
|
||||
</view>
|
||||
<!-- 未登录 -->
|
||||
<view v-else @click="navigateToLoginPage">
|
||||
<view class="login-tip">您还未登录,请先登录</view>
|
||||
<view class="w180rpx mt-2">
|
||||
<button class="login-btn" @click="navigateToLoginPage">登录</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view>
|
||||
<text v-if="isLogin" class="cursor-pointer" @click="goToProfile">
|
||||
个人信息
|
||||
<!-- 编辑资料 -->
|
||||
<view v-if="isLogin" class="cursor-pointer">
|
||||
<wd-icon name="setting" />
|
||||
</view>
|
||||
</view>
|
||||
<!-- 功能操作 -->
|
||||
<wd-grid clickable custom-class="rounded-[10rpx] bg-white">
|
||||
<wd-grid-item text="我的消息" icon="mail" @itemclick="handleItemclick" />
|
||||
<wd-grid-item text="我的待办" icon="list" @itemclick="handleItemclick" />
|
||||
<wd-grid-item text="我的收藏" icon="star" @itemclick="handleItemclick" />
|
||||
<wd-grid-item text="浏览历史" icon="view" @itemclick="handleItemclick" />
|
||||
</wd-grid>
|
||||
<!-- 菜单列表 -->
|
||||
<view class="mt40rpx">
|
||||
<wd-cell-group border>
|
||||
<wd-cell title="关于我们" icon="info-circle" clickable @click="navigateToAbout">
|
||||
<wd-icon name="arrow-right" />
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="relative -top-[50px] p-[40rpx]">
|
||||
<!-- 功能操作 -->
|
||||
<wd-grid clickable class="rounded-[10rpx] bg-white">
|
||||
<wd-grid-item :to="{ path: '/group' }" icon="setting" text="交流群" />
|
||||
<wd-grid-item :to="{ path: '/customer-service' }" icon="setting" text="在线客服" />
|
||||
<wd-grid-item :to="{ path: '/feedback' }" icon="setting" text="反馈社区" />
|
||||
<wd-grid-item :to="{ path: '/like-us' }" icon="setting" text="点赞我们" />
|
||||
</wd-grid>
|
||||
<!-- 菜单列表 -->
|
||||
<view class="mt50rpx">
|
||||
<wd-cell-group border>
|
||||
<wd-cell title="常见问题" icon="help-circle" @click="goToFAQ">
|
||||
<wd-icon name="arrow-right" />
|
||||
</wd-cell>
|
||||
<wd-cell title="关于我们" icon="warning" clickable @click="goToAbout">
|
||||
<wd-icon name="arrow-right" />
|
||||
</wd-cell>
|
||||
<wd-cell title="用户协议" icon="user" clickable @click="goToUserAgreement">
|
||||
<wd-icon name="arrow-right" />
|
||||
</wd-cell>
|
||||
<wd-cell title="隐私政策" icon="folder" clickable @click="goToPrivacy">
|
||||
<wd-icon name="arrow-right" />
|
||||
</wd-cell>
|
||||
<wd-cell title="网络检测" icon="wifi" clickable @click="goToNetworkTest">
|
||||
<wd-icon name="arrow-right" />
|
||||
</wd-cell>
|
||||
<wd-cell
|
||||
title="清除缓存"
|
||||
icon="delete"
|
||||
:value="cacheSize"
|
||||
clickable
|
||||
@click="handleClearCache"
|
||||
/>
|
||||
<wd-cell title="应用设置" icon="setting" clickable @click="goToSettings">
|
||||
<wd-icon name="arrow-right" />
|
||||
</wd-cell>
|
||||
<wd-cell title="退出登录" icon="logout" clickable @click="handleLogout">
|
||||
<wd-icon name="arrow-right" />
|
||||
</wd-cell>
|
||||
</wd-cell-group>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 全屏 loading -->
|
||||
<view v-if="clearing" class="loading-mask">
|
||||
<view class="loading-content">
|
||||
<view class="loading-icon" />
|
||||
<text class="loading-text">正在清理...</text>
|
||||
</view>
|
||||
</wd-cell>
|
||||
<wd-cell title="常见问题" icon="help-circle" @click="navigateToFAQ">
|
||||
<wd-icon name="arrow-right" />
|
||||
</wd-cell>
|
||||
<wd-cell title="问题反馈" icon="check-circle" clickable @click="navigateToAbout">
|
||||
<wd-icon name="arrow-right" />
|
||||
</wd-cell>
|
||||
<wd-cell title="设置" icon="setting1" clickable @click="navigateToSettings">
|
||||
<wd-icon name="arrow-right" />
|
||||
</wd-cell>
|
||||
</wd-cell-group>
|
||||
</view>
|
||||
|
||||
<wd-toast />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { useToast } from "wot-design-uni";
|
||||
import { useUserStore } from "@/store/modules/user";
|
||||
|
||||
const toast = useToast();
|
||||
const userStore = useUserStore();
|
||||
const userInfo = computed(() => userStore.userInfo);
|
||||
const isLogin = computed(() => !!userInfo.value);
|
||||
const defaultAvatar = "/static/images/default-avatar.png";
|
||||
|
||||
// 登录
|
||||
const goToLoginPage = () => {
|
||||
const navigateToLoginPage = () => {
|
||||
uni.navigateTo({ url: "/pages/login/index" });
|
||||
};
|
||||
// 个人信息
|
||||
const goToProfile = () => {
|
||||
const navigateToProfile = () => {
|
||||
uni.navigateTo({ url: "/pages/mine/profile/index" });
|
||||
};
|
||||
|
||||
// 用户协议
|
||||
const goToUserAgreement = () => {
|
||||
uni.navigateTo({ url: "/pages/mine/user-agreement/index" });
|
||||
};
|
||||
// 隐私政策
|
||||
const goToPrivacy = () => {
|
||||
uni.navigateTo({ url: "/pages/mine/privacy/index" });
|
||||
};
|
||||
// 网络测试
|
||||
const goToNetworkTest = () => {
|
||||
uni.navigateTo({ url: "/pages/mine/network-test/index" });
|
||||
};
|
||||
// 常见问题
|
||||
const goToFAQ = () => {
|
||||
const navigateToFAQ = () => {
|
||||
uni.navigateTo({ url: "/pages/faq/index" });
|
||||
};
|
||||
// 关于我们
|
||||
const goToAbout = () => {
|
||||
const navigateToAbout = () => {
|
||||
uni.navigateTo({ url: "/pages/mine/about/index" });
|
||||
};
|
||||
// 应用设置
|
||||
const goToSettings = () => {
|
||||
uni.showToast({
|
||||
title: "建设中...",
|
||||
icon: "none",
|
||||
});
|
||||
//uni.navigateTo({ url: "/pages/settings/index" });
|
||||
};
|
||||
// 退出登录
|
||||
const handleLogout = () => {
|
||||
userStore.logout().then(() => {
|
||||
uni.showToast({ title: "已退出登录", icon: "success" });
|
||||
});
|
||||
};
|
||||
// 是否正在清理
|
||||
const clearing = ref(false);
|
||||
// 缓存大小
|
||||
const cacheSize = ref<any>("计算中...");
|
||||
// 获取缓存大小
|
||||
const getCacheSize = async () => {
|
||||
try {
|
||||
// #ifdef MP-WEIXIN
|
||||
const res = await uni.getStorageInfo();
|
||||
cacheSize.value = formatSize(res.currentSize);
|
||||
// #endif
|
||||
// #ifdef H5
|
||||
cacheSize.value = formatSize(
|
||||
Object.keys(localStorage).reduce((size, key) => size + localStorage[key].length, 0)
|
||||
);
|
||||
// #endif
|
||||
if (!cacheSize.value) {
|
||||
cacheSize.value = "0B";
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("获取缓存大小失败:", error);
|
||||
cacheSize.value = "获取失败";
|
||||
}
|
||||
const navigateToSettings = () => {
|
||||
uni.navigateTo({ url: "/pages/mine/settings/index" });
|
||||
};
|
||||
|
||||
// 格式化存储大小
|
||||
const formatSize = (size: number) => {
|
||||
if (size < 1024) {
|
||||
return size + "B";
|
||||
} else if (size < 1024 * 1024) {
|
||||
return (size / 1024).toFixed(2) + "KB";
|
||||
} else {
|
||||
return (size / 1024 / 1024).toFixed(2) + "MB";
|
||||
}
|
||||
const handleItemclick = (item: any) => {
|
||||
toast.show("建设中...");
|
||||
};
|
||||
|
||||
// 处理清除缓存
|
||||
const handleClearCache = async () => {
|
||||
if (cacheSize.value === "获取失败") {
|
||||
uni.showToast({
|
||||
title: "获取缓存信息失败,请稍后重试",
|
||||
icon: "none",
|
||||
duration: 2000,
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (cacheSize.value === "0B") {
|
||||
uni.showToast({
|
||||
title: "暂无缓存需要清理",
|
||||
icon: "none",
|
||||
duration: 2000,
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (clearing.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
clearing.value = true;
|
||||
// 模拟清理过程
|
||||
await new Promise((resolve) => setTimeout(resolve, 1500));
|
||||
// 清除缓存
|
||||
await uni.clearStorage();
|
||||
// 更新缓存大小显示
|
||||
await getCacheSize();
|
||||
// 提示清理成功
|
||||
uni.showToast({
|
||||
title: "清理成功",
|
||||
icon: "success",
|
||||
});
|
||||
} catch (error) {
|
||||
uni.showToast({
|
||||
title: "清理失败",
|
||||
icon: "error",
|
||||
});
|
||||
} finally {
|
||||
clearing.value = false;
|
||||
}
|
||||
};
|
||||
onShow(() => {
|
||||
getCacheSize();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
/* stylelint-disable selector-type-no-unknown */
|
||||
page {
|
||||
background: #f8f8f8;
|
||||
}
|
||||
/* stylelint-enable selector-type-no-unknown */
|
||||
|
||||
.mine {
|
||||
height: 100%;
|
||||
.header {
|
||||
.mine-container {
|
||||
.mine-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
align-items: start;
|
||||
justify-content: space-between;
|
||||
padding: 50rpx 20rpx 100rpx 20rpx;
|
||||
|
||||
padding: 60rpx 20rpx;
|
||||
color: #fff;
|
||||
background: linear-gradient(60deg, #165dff, #6aa1ff);
|
||||
}
|
||||
}
|
||||
.loading-mask {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: 9999;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: rgba(0, 0, 0, 0.4);
|
||||
background: linear-gradient(60deg, #517cf0, #769ef5);
|
||||
|
||||
.loading-content {
|
||||
padding: 30rpx 40rpx;
|
||||
text-align: center;
|
||||
background-color: rgba(255, 255, 255, 0.95);
|
||||
border-radius: 12rpx;
|
||||
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.15);
|
||||
|
||||
.loading-icon {
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
margin: 0 auto 20rpx;
|
||||
border: 4rpx solid #f3f3f3;
|
||||
border-top: 4rpx solid #409eff;
|
||||
border-radius: 50%;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
.loading-text {
|
||||
.login-tip {
|
||||
font-size: 28rpx;
|
||||
font-weight: 500;
|
||||
color: #333;
|
||||
color: #fff;
|
||||
}
|
||||
.login-btn {
|
||||
line-height: 60rpx;
|
||||
color: #4d80f0;
|
||||
background-color: #fff;
|
||||
border-radius: 10rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,17 +19,12 @@
|
||||
/>
|
||||
</view>
|
||||
</wd-cell>
|
||||
<wd-cell
|
||||
title="昵称"
|
||||
:value="userProfile.nickname"
|
||||
is-link
|
||||
@click="handleOpenDialog(DialogType.ACCOUNT)"
|
||||
/>
|
||||
<wd-cell title="昵称" :value="userProfile.nickname" is-link @click="handleOpenDialog()" />
|
||||
<wd-cell
|
||||
title="性别"
|
||||
:value="userProfile.gender === 1 ? '男' : userProfile.gender === 2 ? '女' : '未知'"
|
||||
is-link
|
||||
@click="handleOpenDialog(DialogType.ACCOUNT)"
|
||||
@click="handleOpenDialog()"
|
||||
/>
|
||||
<wd-cell title="用户名" :value="userProfile.username" />
|
||||
<wd-cell title="部门" :value="userProfile.deptName" />
|
||||
@@ -38,41 +33,12 @@
|
||||
</wd-cell-group>
|
||||
</view>
|
||||
|
||||
<view class="profile-card">
|
||||
<wd-cell-group border>
|
||||
<wd-cell
|
||||
title="账户密码"
|
||||
label="定期修改密码有助于保护账户安全"
|
||||
value="修改"
|
||||
is-link
|
||||
@click="handleOpenDialog(DialogType.PASSWORD)"
|
||||
/>
|
||||
<wd-cell
|
||||
title="绑定手机"
|
||||
:value="userProfile?.mobile"
|
||||
is-link
|
||||
@click="handleOpenDialog(DialogType.MOBILE)"
|
||||
/>
|
||||
<wd-cell
|
||||
title="绑定邮箱"
|
||||
:value="userProfile?.email ? userProfile.email : '未绑定邮箱'"
|
||||
is-link
|
||||
@click="handleOpenDialog(DialogType.EMAIL)"
|
||||
/>
|
||||
</wd-cell-group>
|
||||
</view>
|
||||
|
||||
<!--头像裁剪-->
|
||||
<wd-img-cropper v-model="avatarShow" :img-src="originalSrc" @confirm="handleAvatarConfirm" />
|
||||
|
||||
<!--用户信息编辑弹出框-->
|
||||
<wd-popup v-model="dialog.visible" position="bottom">
|
||||
<wd-form
|
||||
v-if="dialog.type === DialogType.ACCOUNT"
|
||||
ref="userProfileFormRef"
|
||||
:model="userProfileForm"
|
||||
custom-class="edit-form"
|
||||
>
|
||||
<wd-form ref="userProfileFormRef" :model="userProfileForm" custom-class="edit-form">
|
||||
<wd-cell-group border>
|
||||
<wd-input
|
||||
v-model="userProfileForm.nickname"
|
||||
@@ -93,128 +59,6 @@
|
||||
<wd-button type="primary" size="large" block @click="handleSubmit">提交</wd-button>
|
||||
</view>
|
||||
</wd-form>
|
||||
<wd-form
|
||||
v-if="dialog.type === DialogType.PASSWORD"
|
||||
ref="passwordChangeFormRef"
|
||||
:model="passwordChangeForm"
|
||||
custom-class="edit-form"
|
||||
>
|
||||
<wd-cell-group border>
|
||||
<wd-input
|
||||
v-model="passwordChangeForm.oldPassword"
|
||||
label="原密码"
|
||||
label-width="160rpx"
|
||||
show-password
|
||||
clearable
|
||||
placeholder="请输入原密码"
|
||||
prop="oldPassword"
|
||||
:rules="rules.oldPassword"
|
||||
/>
|
||||
<wd-input
|
||||
v-model="passwordChangeForm.newPassword"
|
||||
label="新密码"
|
||||
label-width="160rpx"
|
||||
show-password
|
||||
clearable
|
||||
placeholder="请输入新密码"
|
||||
prop="newPassword"
|
||||
:rules="rules.newPassword"
|
||||
/>
|
||||
<wd-input
|
||||
v-model="passwordChangeForm.confirmPassword"
|
||||
label="确认密码"
|
||||
label-width="160rpx"
|
||||
show-password
|
||||
clearable
|
||||
placeholder="请确认新密码"
|
||||
prop="confirmPassword"
|
||||
:rules="rules.confirmPassword"
|
||||
/>
|
||||
</wd-cell-group>
|
||||
<view class="footer">
|
||||
<wd-button type="primary" size="large" block @click="handleSubmit">提交</wd-button>
|
||||
</view>
|
||||
</wd-form>
|
||||
<wd-form
|
||||
v-if="dialog.type === DialogType.MOBILE"
|
||||
ref="mobileBindingFormRef"
|
||||
:model="mobileBindingForm"
|
||||
custom-class="edit-form"
|
||||
>
|
||||
<wd-cell-group border>
|
||||
<wd-input
|
||||
v-model="mobileBindingForm.mobile"
|
||||
label="手机号码"
|
||||
label-width="160rpx"
|
||||
clearable
|
||||
placeholder="请输入手机号码"
|
||||
prop="mobile"
|
||||
:rules="rules.mobile"
|
||||
/>
|
||||
<wd-input
|
||||
v-model="mobileBindingForm.code"
|
||||
label="验证码"
|
||||
label-width="160rpx"
|
||||
clearable
|
||||
placeholder="请输入验证码"
|
||||
prop="code"
|
||||
:rules="rules.code"
|
||||
>
|
||||
<template #suffix>
|
||||
<wd-button
|
||||
plain
|
||||
:disabled="mobileCountdown > 0"
|
||||
@click="handleSendVerificationCode('MOBILE')"
|
||||
>
|
||||
{{ mobileCountdown > 0 ? `${mobileCountdown}s后重新发送` : "发送验证码" }}
|
||||
</wd-button>
|
||||
</template>
|
||||
</wd-input>
|
||||
</wd-cell-group>
|
||||
<view class="footer">
|
||||
<wd-button type="primary" size="large" block @click="handleSubmit">提交</wd-button>
|
||||
</view>
|
||||
</wd-form>
|
||||
<wd-form
|
||||
v-if="dialog.type === DialogType.EMAIL"
|
||||
ref="emailBindingFormRef"
|
||||
:model="emailBindingForm"
|
||||
custom-class="edit-form"
|
||||
>
|
||||
<wd-cell-group border>
|
||||
<wd-input
|
||||
v-model="emailBindingForm.email"
|
||||
label="邮箱"
|
||||
label-width="160rpx"
|
||||
clearable
|
||||
placeholder="请输入邮箱"
|
||||
prop="email"
|
||||
:rules="rules.email"
|
||||
/>
|
||||
<wd-input
|
||||
v-model="emailBindingForm.code"
|
||||
label="验证码"
|
||||
label-width="160rpx"
|
||||
clearable
|
||||
placeholder="请输入验证码"
|
||||
prop="code"
|
||||
:rules="rules.code"
|
||||
>
|
||||
<template #suffix>
|
||||
<wd-button
|
||||
plain
|
||||
:disabled="emailCountdown > 0"
|
||||
@click="handleSendVerificationCode('EMAIL')"
|
||||
>
|
||||
{{ emailCountdown > 0 ? `${emailCountdown}s后重新发送` : "发送验证码" }}
|
||||
</wd-button>
|
||||
</template>
|
||||
</wd-input>
|
||||
</wd-cell-group>
|
||||
<view class="footer">
|
||||
<wd-button type="primary" size="large" block @click="handleSubmit">提交</wd-button>
|
||||
</view>
|
||||
</wd-form>
|
||||
</wd-popup>
|
||||
</view>
|
||||
</template>
|
||||
@@ -222,7 +66,6 @@
|
||||
import UserAPI, {
|
||||
type UserProfileVO,
|
||||
UserProfileForm,
|
||||
PasswordChangeForm,
|
||||
MobileBindingForm,
|
||||
EmailBindingForm,
|
||||
} from "@/api/system/user";
|
||||
@@ -262,173 +105,41 @@ function handleAvatarConfirm(event) {
|
||||
});
|
||||
}
|
||||
|
||||
const validatorConfirmPassword = (value) => {
|
||||
if (!value) {
|
||||
return Promise.reject("请确认密码");
|
||||
} else {
|
||||
if (value !== passwordChangeForm.newPassword) {
|
||||
return Promise.reject("两次输入的密码不一致");
|
||||
} else {
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
};
|
||||
// 本页面中所有的校验规则
|
||||
const rules = reactive({
|
||||
nickname: [{ required: true, message: "请填写昵称" }],
|
||||
gender: [{ required: true, message: "请选择性别" }],
|
||||
oldPassword: [{ required: true, message: "请填写原密码" }],
|
||||
newPassword: [{ required: true, message: "请填写新密码" }],
|
||||
confirmPassword: [{ required: true, message: "请确认密码", validator: validatorConfirmPassword }],
|
||||
mobile: [{ required: true, pattern: /^1[3-9]\d{9}$/, message: "请填写正确的手机号码" }],
|
||||
code: [{ required: true, message: "请填写验证码" }],
|
||||
email: [
|
||||
{
|
||||
required: true,
|
||||
pattern: /\w[-\w.+]*@([A-Za-z0-9][-A-Za-z0-9]+\.)+[A-Za-z]{2,14}/,
|
||||
message: "请填写正确的邮箱地址",
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
enum DialogType {
|
||||
ACCOUNT = "account",
|
||||
PASSWORD = "password",
|
||||
MOBILE = "mobile",
|
||||
EMAIL = "email",
|
||||
}
|
||||
|
||||
const dialog = reactive({
|
||||
visible: false,
|
||||
type: "" as DialogType, // 修改账号资料,修改密码、绑定手机、绑定邮箱
|
||||
});
|
||||
|
||||
const userProfileForm = reactive<UserProfileForm>({});
|
||||
const passwordChangeForm = reactive<PasswordChangeForm>({});
|
||||
const mobileBindingForm = reactive<MobileBindingForm>({});
|
||||
const emailBindingForm = reactive<EmailBindingForm>({});
|
||||
const userProfileFormRef = ref();
|
||||
const passwordChangeFormRef = ref();
|
||||
const mobileBindingFormRef = ref();
|
||||
const emailBindingFormRef = ref();
|
||||
|
||||
const mobileCountdown = ref(0);
|
||||
const mobileTimer = ref<NodeJS.Timeout | null>(null);
|
||||
|
||||
const emailCountdown = ref(0);
|
||||
const emailTimer = ref<NodeJS.Timeout | null>(null);
|
||||
/**
|
||||
* 打开弹窗
|
||||
* @param type 弹窗类型 ACCOUNT: 账号资料 PASSWORD: 修改密码 MOBILE: 绑定手机 EMAIL: 绑定邮箱
|
||||
*/
|
||||
const handleOpenDialog = (type: DialogType) => {
|
||||
dialog.type = type;
|
||||
const handleOpenDialog = () => {
|
||||
dialog.visible = true;
|
||||
switch (type) {
|
||||
case DialogType.ACCOUNT:
|
||||
// 初始化表单数据
|
||||
userProfileForm.nickname = userProfile.value?.nickname;
|
||||
userProfileForm.gender = userProfile.value?.gender;
|
||||
break;
|
||||
case DialogType.PASSWORD:
|
||||
passwordChangeForm.oldPassword = "";
|
||||
passwordChangeForm.newPassword = "";
|
||||
passwordChangeForm.confirmPassword = "";
|
||||
break;
|
||||
case DialogType.MOBILE:
|
||||
mobileBindingForm.mobile = "";
|
||||
mobileBindingForm.code = "";
|
||||
break;
|
||||
case DialogType.EMAIL:
|
||||
emailBindingForm.email = "";
|
||||
emailBindingForm.code = "";
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 发送验证码
|
||||
*
|
||||
* @param contactType 联系方式类型 MOBILE: 手机号码 EMAIL: 邮箱
|
||||
*/
|
||||
const handleSendVerificationCode = async (contactType: string) => {
|
||||
if (contactType === "MOBILE") {
|
||||
mobileBindingFormRef.value.validate("mobile").then(({ valid }) => {
|
||||
if (valid) {
|
||||
UserAPI.sendVerificationCode(mobileBindingForm.mobile, "MOBILE").then(() => {
|
||||
uni.showToast({ title: "验证码已发送", icon: "none" });
|
||||
mobileCountdown.value = 60;
|
||||
mobileTimer.value = setInterval(() => {
|
||||
if (mobileCountdown.value > 0) {
|
||||
mobileCountdown.value -= 1;
|
||||
} else {
|
||||
clearInterval(mobileTimer.value!);
|
||||
}
|
||||
}, 1000);
|
||||
});
|
||||
}
|
||||
});
|
||||
} else if (contactType === "EMAIL") {
|
||||
emailBindingFormRef.value.validate("email").then(({ valid }) => {
|
||||
if (valid) {
|
||||
UserAPI.sendVerificationCode(emailBindingForm.email, "EMAIL").then(() => {
|
||||
uni.showToast({ title: "验证码已发送", icon: "none" });
|
||||
emailCountdown.value = 60;
|
||||
emailTimer.value = setInterval(() => {
|
||||
if (emailCountdown.value > 0) {
|
||||
emailCountdown.value -= 1;
|
||||
} else {
|
||||
clearInterval(emailTimer.value!);
|
||||
}
|
||||
}, 1000);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
// 初始化表单数据
|
||||
userProfileForm.nickname = userProfile.value?.nickname;
|
||||
userProfileForm.gender = userProfile.value?.gender;
|
||||
};
|
||||
|
||||
// 提交表单
|
||||
function handleSubmit() {
|
||||
if (dialog.type === DialogType.ACCOUNT) {
|
||||
userProfileFormRef.value.validate().then(({ valid }) => {
|
||||
if (valid) {
|
||||
UserAPI.updateProfile(userProfileForm).then(() => {
|
||||
uni.showToast({ title: "账号资料修改成功", icon: "none" });
|
||||
dialog.visible = false;
|
||||
loadUserProfile();
|
||||
});
|
||||
}
|
||||
});
|
||||
} else if (dialog.type === DialogType.PASSWORD) {
|
||||
passwordChangeFormRef.value.validate().then(({ valid }) => {
|
||||
if (valid) {
|
||||
UserAPI.changePassword(passwordChangeForm).then(() => {
|
||||
uni.showToast({ title: "密码修改成功", icon: "none" });
|
||||
dialog.visible = false;
|
||||
});
|
||||
}
|
||||
});
|
||||
} else if (dialog.type === DialogType.MOBILE) {
|
||||
mobileBindingFormRef.value.validate().then(({ valid }) => {
|
||||
if (valid) {
|
||||
UserAPI.bindMobile(mobileBindingForm).then(() => {
|
||||
uni.showToast({ title: "手机号绑定成功", icon: "none" });
|
||||
dialog.visible = false;
|
||||
loadUserProfile();
|
||||
});
|
||||
}
|
||||
});
|
||||
} else if (dialog.type === DialogType.EMAIL) {
|
||||
emailBindingFormRef.value.validate().then(({ valid }) => {
|
||||
if (valid) {
|
||||
UserAPI.bindEmail(emailBindingForm).then(() => {
|
||||
uni.showToast({ title: "邮箱绑定成功", icon: "none" });
|
||||
dialog.visible = false;
|
||||
loadUserProfile();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
userProfileFormRef.value.validate().then(({ valid }) => {
|
||||
if (valid) {
|
||||
UserAPI.updateProfile(userProfileForm).then(() => {
|
||||
uni.showToast({ title: "账号资料修改成功", icon: "none" });
|
||||
dialog.visible = false;
|
||||
loadUserProfile();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
@@ -485,10 +196,7 @@ function touchmoveListener(event) {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
font-size: 60px;
|
||||
color: #fff;
|
||||
-webkit-transform: translate(-50%, -50%);
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
343
src/pages/mine/settings/account/index.vue
Normal file
343
src/pages/mine/settings/account/index.vue
Normal file
@@ -0,0 +1,343 @@
|
||||
<template>
|
||||
<view class="profile">
|
||||
<view class="profile-card">
|
||||
<wd-cell-group border>
|
||||
<wd-cell
|
||||
title="账户密码"
|
||||
label="定期修改密码有助于保护账户安全"
|
||||
value="修改"
|
||||
is-link
|
||||
@click="handleOpenDialog(DialogType.PASSWORD)"
|
||||
/>
|
||||
<wd-cell
|
||||
title="绑定手机"
|
||||
:value="userProfile?.mobile"
|
||||
is-link
|
||||
@click="handleOpenDialog(DialogType.MOBILE)"
|
||||
/>
|
||||
<wd-cell
|
||||
title="绑定邮箱"
|
||||
:value="userProfile?.email ? userProfile.email : '未绑定邮箱'"
|
||||
is-link
|
||||
@click="handleOpenDialog(DialogType.EMAIL)"
|
||||
/>
|
||||
</wd-cell-group>
|
||||
</view>
|
||||
|
||||
<!--用户信息编辑弹出框-->
|
||||
<wd-popup v-model="dialog.visible" position="bottom">
|
||||
<wd-form
|
||||
v-if="dialog.type === DialogType.PASSWORD"
|
||||
ref="passwordChangeFormRef"
|
||||
:model="passwordChangeForm"
|
||||
custom-class="edit-form"
|
||||
>
|
||||
<wd-cell-group border>
|
||||
<wd-input
|
||||
v-model="passwordChangeForm.oldPassword"
|
||||
label="原密码"
|
||||
label-width="160rpx"
|
||||
show-password
|
||||
clearable
|
||||
placeholder="请输入原密码"
|
||||
prop="oldPassword"
|
||||
:rules="rules.oldPassword"
|
||||
/>
|
||||
<wd-input
|
||||
v-model="passwordChangeForm.newPassword"
|
||||
label="新密码"
|
||||
label-width="160rpx"
|
||||
show-password
|
||||
clearable
|
||||
placeholder="请输入新密码"
|
||||
prop="newPassword"
|
||||
:rules="rules.newPassword"
|
||||
/>
|
||||
<wd-input
|
||||
v-model="passwordChangeForm.confirmPassword"
|
||||
label="确认密码"
|
||||
label-width="160rpx"
|
||||
show-password
|
||||
clearable
|
||||
placeholder="请确认新密码"
|
||||
prop="confirmPassword"
|
||||
:rules="rules.confirmPassword"
|
||||
/>
|
||||
</wd-cell-group>
|
||||
<view class="footer">
|
||||
<wd-button type="primary" size="large" block @click="handleSubmit">提交</wd-button>
|
||||
</view>
|
||||
</wd-form>
|
||||
<wd-form
|
||||
v-if="dialog.type === DialogType.MOBILE"
|
||||
ref="mobileBindingFormRef"
|
||||
:model="mobileBindingForm"
|
||||
custom-class="edit-form"
|
||||
>
|
||||
<wd-cell-group border>
|
||||
<wd-input
|
||||
v-model="mobileBindingForm.mobile"
|
||||
label="手机号码"
|
||||
label-width="160rpx"
|
||||
clearable
|
||||
placeholder="请输入手机号码"
|
||||
prop="mobile"
|
||||
:rules="rules.mobile"
|
||||
/>
|
||||
<wd-input
|
||||
v-model="mobileBindingForm.code"
|
||||
label="验证码"
|
||||
label-width="160rpx"
|
||||
clearable
|
||||
placeholder="请输入验证码"
|
||||
prop="code"
|
||||
:rules="rules.code"
|
||||
>
|
||||
<template #suffix>
|
||||
<wd-button
|
||||
plain
|
||||
:disabled="mobileCountdown > 0"
|
||||
@click="handleSendVerificationCode('MOBILE')"
|
||||
>
|
||||
{{ mobileCountdown > 0 ? `${mobileCountdown}s后重新发送` : "发送验证码" }}
|
||||
</wd-button>
|
||||
</template>
|
||||
</wd-input>
|
||||
</wd-cell-group>
|
||||
<view class="footer">
|
||||
<wd-button type="primary" size="large" block @click="handleSubmit">提交</wd-button>
|
||||
</view>
|
||||
</wd-form>
|
||||
<wd-form
|
||||
v-if="dialog.type === DialogType.EMAIL"
|
||||
ref="emailBindingFormRef"
|
||||
:model="emailBindingForm"
|
||||
custom-class="edit-form"
|
||||
>
|
||||
<wd-cell-group border>
|
||||
<wd-input
|
||||
v-model="emailBindingForm.email"
|
||||
label="邮箱"
|
||||
label-width="160rpx"
|
||||
clearable
|
||||
placeholder="请输入邮箱"
|
||||
prop="email"
|
||||
:rules="rules.email"
|
||||
/>
|
||||
<wd-input
|
||||
v-model="emailBindingForm.code"
|
||||
label="验证码"
|
||||
label-width="160rpx"
|
||||
clearable
|
||||
placeholder="请输入验证码"
|
||||
prop="code"
|
||||
:rules="rules.code"
|
||||
>
|
||||
<template #suffix>
|
||||
<wd-button
|
||||
plain
|
||||
:disabled="emailCountdown > 0"
|
||||
@click="handleSendVerificationCode('EMAIL')"
|
||||
>
|
||||
{{ emailCountdown > 0 ? `${emailCountdown}s后重新发送` : "发送验证码" }}
|
||||
</wd-button>
|
||||
</template>
|
||||
</wd-input>
|
||||
</wd-cell-group>
|
||||
<view class="footer">
|
||||
<wd-button type="primary" size="large" block @click="handleSubmit">提交</wd-button>
|
||||
</view>
|
||||
</wd-form>
|
||||
</wd-popup>
|
||||
</view>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import UserAPI, {
|
||||
PasswordChangeForm,
|
||||
MobileBindingForm,
|
||||
EmailBindingForm,
|
||||
UserProfileVO,
|
||||
} from "@/api/system/user";
|
||||
|
||||
const validatorConfirmPassword = (value: string) => {
|
||||
if (!value) {
|
||||
return Promise.reject("请确认密码");
|
||||
} else {
|
||||
if (value !== passwordChangeForm.newPassword) {
|
||||
return Promise.reject("两次输入的密码不一致");
|
||||
} else {
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
};
|
||||
// 本页面中所有的校验规则
|
||||
const rules = reactive({
|
||||
oldPassword: [{ required: true, message: "请填写原密码" }],
|
||||
newPassword: [{ required: true, message: "请填写新密码" }],
|
||||
confirmPassword: [{ required: true, message: "请确认密码", validator: validatorConfirmPassword }],
|
||||
mobile: [{ required: true, pattern: /^1[3-9]\d{9}$/, message: "请填写正确的手机号码" }],
|
||||
code: [{ required: true, message: "请填写验证码" }],
|
||||
email: [
|
||||
{
|
||||
required: true,
|
||||
pattern: /\w[-\w.+]*@([A-Za-z0-9][-A-Za-z0-9]+\.)+[A-Za-z]{2,14}/,
|
||||
message: "请填写正确的邮箱地址",
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
enum DialogType {
|
||||
PASSWORD = "password",
|
||||
MOBILE = "mobile",
|
||||
EMAIL = "email",
|
||||
}
|
||||
|
||||
const dialog = reactive({
|
||||
visible: false,
|
||||
type: "" as DialogType, // 修改账号资料,修改密码、绑定手机、绑定邮箱
|
||||
});
|
||||
|
||||
const userProfile = ref<UserProfileVO>(); //用户信息
|
||||
const passwordChangeForm = reactive<PasswordChangeForm>({});
|
||||
const mobileBindingForm = reactive<MobileBindingForm>({});
|
||||
const emailBindingForm = reactive<EmailBindingForm>({});
|
||||
const passwordChangeFormRef = ref();
|
||||
const mobileBindingFormRef = ref();
|
||||
const emailBindingFormRef = ref();
|
||||
|
||||
const mobileCountdown = ref(0);
|
||||
const mobileTimer = ref<ReturnType<typeof setInterval> | null>(null);
|
||||
|
||||
const emailCountdown = ref(0);
|
||||
const emailTimer = ref<ReturnType<typeof setTimeout> | null>(null);
|
||||
|
||||
/** 加载用户信息 */
|
||||
const loadUserProfile = async () => {
|
||||
userProfile.value = await UserAPI.getProfile();
|
||||
};
|
||||
|
||||
/**
|
||||
* 打开弹窗
|
||||
* @param type 弹窗类型 ACCOUNT: 账号资料 PASSWORD: 修改密码 MOBILE: 绑定手机 EMAIL: 绑定邮箱
|
||||
*/
|
||||
const handleOpenDialog = (type: DialogType) => {
|
||||
dialog.type = type;
|
||||
dialog.visible = true;
|
||||
switch (type) {
|
||||
case DialogType.PASSWORD:
|
||||
passwordChangeForm.oldPassword = "";
|
||||
passwordChangeForm.newPassword = "";
|
||||
passwordChangeForm.confirmPassword = "";
|
||||
break;
|
||||
case DialogType.MOBILE:
|
||||
mobileBindingForm.mobile = "";
|
||||
mobileBindingForm.code = "";
|
||||
break;
|
||||
case DialogType.EMAIL:
|
||||
emailBindingForm.email = "";
|
||||
emailBindingForm.code = "";
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 发送验证码
|
||||
*
|
||||
* @param contactType 联系方式类型 MOBILE: 手机号码 EMAIL: 邮箱
|
||||
*/
|
||||
const handleSendVerificationCode = async (contactType: string) => {
|
||||
if (contactType === "MOBILE") {
|
||||
mobileBindingFormRef.value.validate("mobile").then(({ valid }: { valid: boolean }) => {
|
||||
if (valid) {
|
||||
UserAPI.sendVerificationCode(mobileBindingForm.mobile!, "MOBILE").then(() => {
|
||||
uni.showToast({ title: "验证码已发送", icon: "none" });
|
||||
mobileCountdown.value = 60;
|
||||
mobileTimer.value = setInterval(() => {
|
||||
if (mobileCountdown.value > 0) {
|
||||
mobileCountdown.value -= 1;
|
||||
} else {
|
||||
clearInterval(mobileTimer.value!);
|
||||
}
|
||||
}, 1000);
|
||||
});
|
||||
}
|
||||
});
|
||||
} else if (contactType === "EMAIL") {
|
||||
emailBindingFormRef.value.validate("email").then(({ valid }: { valid: boolean }) => {
|
||||
if (valid) {
|
||||
UserAPI.sendVerificationCode(emailBindingForm.email!, "EMAIL").then(() => {
|
||||
uni.showToast({ title: "验证码已发送", icon: "none" });
|
||||
emailCountdown.value = 60;
|
||||
emailTimer.value = setInterval(() => {
|
||||
if (emailCountdown.value > 0) {
|
||||
emailCountdown.value -= 1;
|
||||
} else {
|
||||
clearInterval(emailTimer.value!);
|
||||
}
|
||||
}, 1000);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 提交表单
|
||||
function handleSubmit() {
|
||||
if (dialog.type === DialogType.PASSWORD) {
|
||||
passwordChangeFormRef.value.validate().then(({ valid }: { valid: boolean }) => {
|
||||
if (valid) {
|
||||
UserAPI.changePassword(passwordChangeForm).then(() => {
|
||||
uni.showToast({ title: "密码修改成功", icon: "none" });
|
||||
dialog.visible = false;
|
||||
});
|
||||
}
|
||||
});
|
||||
} else if (dialog.type === DialogType.MOBILE) {
|
||||
mobileBindingFormRef.value.validate().then(({ valid }: { valid: boolean }) => {
|
||||
if (valid) {
|
||||
UserAPI.bindMobile(mobileBindingForm).then(() => {
|
||||
uni.showToast({ title: "手机号绑定成功", icon: "none" });
|
||||
dialog.visible = false;
|
||||
loadUserProfile();
|
||||
});
|
||||
}
|
||||
});
|
||||
} else if (dialog.type === DialogType.EMAIL) {
|
||||
emailBindingFormRef.value.validate().then(({ valid }: { valid: boolean }) => {
|
||||
if (valid) {
|
||||
UserAPI.bindEmail(emailBindingForm).then(() => {
|
||||
uni.showToast({ title: "邮箱绑定成功", icon: "none" });
|
||||
dialog.visible = false;
|
||||
loadUserProfile();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
loadUserProfile();
|
||||
});
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.profile {
|
||||
.profile-card {
|
||||
padding: 10rpx;
|
||||
margin-bottom: 24rpx;
|
||||
line-height: 1.1;
|
||||
background-color: rgb(255, 255, 255);
|
||||
border-radius: 16px;
|
||||
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
.edit-form {
|
||||
padding-top: 40rpx;
|
||||
.ef-radio-group {
|
||||
line-height: 1;
|
||||
text-align: left;
|
||||
}
|
||||
.footer {
|
||||
padding: 24rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
193
src/pages/mine/settings/index.vue
Normal file
193
src/pages/mine/settings/index.vue
Normal file
@@ -0,0 +1,193 @@
|
||||
<template>
|
||||
<view class="settings-container">
|
||||
<wd-cell-group>
|
||||
<wd-cell title="账号和安全" icon="secured" is-link @click="navigateToAccount" />
|
||||
<wd-cell title="用户协议" icon="user" is-link @click="navigateToUserAgreement" />
|
||||
<wd-cell title="隐私政策" icon="folder" is-link @click="navigateToPrivacy" />
|
||||
</wd-cell-group>
|
||||
|
||||
<wd-cell-group custom-style="margin-top:40rpx">
|
||||
<wd-cell title="网络测试" icon="wifi" is-link @click="navigateToNetworkTest" />
|
||||
<wd-cell
|
||||
title="清空缓存"
|
||||
icon="delete1"
|
||||
:value="cacheSize"
|
||||
clickable
|
||||
@click="handleClearCache"
|
||||
/>
|
||||
</wd-cell-group>
|
||||
|
||||
<wd-cell-group v-if="isLogin" custom-style="margin-top:40rpx">
|
||||
<wd-cell title="退出" icon="logout" is-link @click="handleLogout" />
|
||||
</wd-cell-group>
|
||||
|
||||
<!-- 全屏 loading -->
|
||||
<view v-if="clearing" class="loading-mask">
|
||||
<view class="loading-content">
|
||||
<view class="loading-icon" />
|
||||
<text class="loading-text">正在清理...</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { useUserStore } from "@/store/modules/user";
|
||||
const userStore = useUserStore();
|
||||
|
||||
const isLogin = computed(() => !!userStore.userInfo);
|
||||
|
||||
// 账号和安全
|
||||
const navigateToAccount = () => {
|
||||
uni.navigateTo({ url: "/pages/mine/settings/account/index" });
|
||||
};
|
||||
|
||||
// 用户协议
|
||||
const navigateToUserAgreement = () => {
|
||||
uni.navigateTo({ url: "/pages/mine/settings/agreement/index" });
|
||||
};
|
||||
// 隐私政策
|
||||
const navigateToPrivacy = () => {
|
||||
uni.navigateTo({ url: "/pages/mine/settings/privacy/index" });
|
||||
};
|
||||
// 网络测试
|
||||
const navigateToNetworkTest = () => {
|
||||
uni.navigateTo({ url: "/pages/mine/settings/network/index" });
|
||||
};
|
||||
|
||||
// 是否正在清理
|
||||
const clearing = ref(false);
|
||||
// 缓存大小
|
||||
const cacheSize = ref<any>("计算中...");
|
||||
// 获取缓存大小
|
||||
const getCacheSize = async () => {
|
||||
try {
|
||||
// #ifdef MP-WEIXIN
|
||||
const res = await uni.getStorageInfo();
|
||||
cacheSize.value = formatSize(res.currentSize);
|
||||
// #endif
|
||||
// #ifdef H5
|
||||
cacheSize.value = formatSize(
|
||||
Object.keys(localStorage).reduce((size, key) => size + localStorage[key].length, 0)
|
||||
);
|
||||
// #endif
|
||||
if (!cacheSize.value) {
|
||||
cacheSize.value = "0B";
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("获取缓存大小失败:", error);
|
||||
cacheSize.value = "获取失败";
|
||||
}
|
||||
};
|
||||
|
||||
// 格式化存储大小
|
||||
const formatSize = (size: number) => {
|
||||
if (size < 1024) {
|
||||
return size + "B";
|
||||
} else if (size < 1024 * 1024) {
|
||||
return (size / 1024).toFixed(2) + "KB";
|
||||
} else {
|
||||
return (size / 1024 / 1024).toFixed(2) + "MB";
|
||||
}
|
||||
};
|
||||
|
||||
// 处理清除缓存
|
||||
const handleClearCache = async () => {
|
||||
if (cacheSize.value === "获取失败") {
|
||||
uni.showToast({
|
||||
title: "获取缓存信息失败,请稍后重试",
|
||||
icon: "none",
|
||||
duration: 2000,
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (cacheSize.value === "0B") {
|
||||
uni.showToast({
|
||||
title: "暂无缓存需要清理",
|
||||
icon: "none",
|
||||
duration: 2000,
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (clearing.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
clearing.value = true;
|
||||
// 模拟清理过程
|
||||
await new Promise((resolve) => setTimeout(resolve, 1500));
|
||||
// 清除缓存
|
||||
await uni.clearStorage();
|
||||
// 更新缓存大小显示
|
||||
await getCacheSize();
|
||||
// 提示清理成功
|
||||
uni.showToast({
|
||||
title: "清理成功",
|
||||
icon: "success",
|
||||
});
|
||||
} catch (error) {
|
||||
uni.showToast({
|
||||
title: "清理失败",
|
||||
icon: "error",
|
||||
});
|
||||
} finally {
|
||||
clearing.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 退出登录
|
||||
const handleLogout = () => {
|
||||
userStore.logout().then(() => {
|
||||
uni.showToast({ title: "已退出登录", icon: "success" });
|
||||
// 跳转到登录页
|
||||
uni.reLaunch({ url: "/pages/mine/index" });
|
||||
});
|
||||
};
|
||||
|
||||
onLoad(() => {
|
||||
getCacheSize();
|
||||
});
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.settings-container {
|
||||
padding: 20px;
|
||||
|
||||
.loading-mask {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: 9999;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: rgba(0, 0, 0, 0.4);
|
||||
|
||||
.loading-content {
|
||||
padding: 30rpx 40rpx;
|
||||
text-align: center;
|
||||
background-color: rgba(255, 255, 255, 0.95);
|
||||
border-radius: 12rpx;
|
||||
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.15);
|
||||
|
||||
.loading-icon {
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
margin: 0 auto 20rpx;
|
||||
border: 4rpx solid #f3f3f3;
|
||||
border-top: 4rpx solid #409eff;
|
||||
border-radius: 50%;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
.loading-text {
|
||||
font-size: 28rpx;
|
||||
font-weight: 500;
|
||||
color: #333;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<view class="network-test">
|
||||
<view class="network-container">
|
||||
<!-- 网络状态展示 -->
|
||||
<view class="status-card">
|
||||
<view class="status-header">
|
||||
@@ -193,7 +193,7 @@ onBeforeUnmount(() => {
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.network-test {
|
||||
.network-container {
|
||||
min-height: 100vh;
|
||||
padding: 20px;
|
||||
background-color: #f5f5f5;
|
||||
@@ -39,16 +39,6 @@ const gridList = reactive([
|
||||
url: "/pages/work/role/index",
|
||||
prem: "sys:role:query",
|
||||
},
|
||||
{
|
||||
icon: "/static/icons/dept.png",
|
||||
title: "部门管理",
|
||||
prem: "sys:dept:query",
|
||||
},
|
||||
{
|
||||
icon: "/static/icons/dict.png",
|
||||
title: "字典管理",
|
||||
prem: "sys:dict:query",
|
||||
},
|
||||
{
|
||||
icon: "/static/icons/config.png",
|
||||
title: "系统配置",
|
||||
@@ -66,13 +56,9 @@ const gridList = reactive([
|
||||
{
|
||||
title: "系统监控",
|
||||
children: [
|
||||
{
|
||||
icon: "/static/icons/monitor.png",
|
||||
title: "实时监控",
|
||||
},
|
||||
{
|
||||
icon: "/static/icons/log.png",
|
||||
title: "日志管理",
|
||||
title: "系统日志",
|
||||
url: "/pages/work/log/index",
|
||||
prem: "sys:log:query",
|
||||
},
|
||||
|
||||
@@ -168,19 +168,19 @@ onReachBottom(() => {
|
||||
|
||||
// 操作按钮
|
||||
const handleAction = (item: RolePageVO) => {
|
||||
const actions = ["删除", "分配权限", "编辑"];
|
||||
const actions = ["编辑", "分配权限", "删除"];
|
||||
uni.showActionSheet({
|
||||
itemList: actions,
|
||||
success: ({ tapIndex }) => {
|
||||
switch (actions[tapIndex]) {
|
||||
case "删除":
|
||||
handleDelete(item.id);
|
||||
case "编辑":
|
||||
handleOpenDialog(item.id);
|
||||
break;
|
||||
case "分配权限":
|
||||
handleAssignPerm(item.id);
|
||||
break;
|
||||
case "编辑":
|
||||
handleOpenDialog(item.id);
|
||||
case "删除":
|
||||
handleDelete(item.id);
|
||||
break;
|
||||
}
|
||||
},
|
||||
@@ -288,6 +288,15 @@ onLoad(() => {
|
||||
});
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
// https://wot-design-uni.pages.dev/guide/common-problems#%E5%B0%8F%E7%A8%8B%E5%BA%8F%E6%A0%B7%E5%BC%8F%E9%9A%94%E7%A6%BB
|
||||
export default {
|
||||
options: {
|
||||
styleIsolation: "shared",
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.role {
|
||||
:deep(.wd-drop-menu .wd-drop-menu__item) {
|
||||
@@ -307,6 +316,15 @@ onLoad(() => {
|
||||
}
|
||||
}
|
||||
}
|
||||
:deep(.wd-cell__wrapper) {
|
||||
padding: 4rpx 0;
|
||||
}
|
||||
|
||||
:deep(.wd-cell) {
|
||||
padding-right: 10rpx;
|
||||
background: #f8f8f8;
|
||||
}
|
||||
|
||||
:deep(.wd-fab__trigger) {
|
||||
width: 80rpx !important;
|
||||
height: 80rpx !important;
|
||||
|
||||
@@ -1,21 +1,26 @@
|
||||
<template>
|
||||
<view class="user">
|
||||
<view style="width: 100%; height: var(--status-bar-height)" />
|
||||
<!-- 自定义导航栏的占位 -->
|
||||
<view style="width: 100%; height: var(--status-bar-height)" />
|
||||
|
||||
<view class="user-container">
|
||||
<!-- 自定义导航栏 -->
|
||||
<wd-navbar title="用户管理">
|
||||
<template #left>
|
||||
<wd-icon name="thin-arrow-left" @click="handleNavigateback()" />
|
||||
</template>
|
||||
</wd-navbar>
|
||||
|
||||
<!-- 排序筛选 -->
|
||||
<view class="mb-24rpx">
|
||||
<view class="filter-container">
|
||||
<wd-drop-menu>
|
||||
<wd-drop-menu-item
|
||||
v-model="sortValue"
|
||||
:options="sortOptions"
|
||||
title="排序"
|
||||
icon="unfold-more"
|
||||
@change="handleSortChange"
|
||||
/>
|
||||
<wd-drop-menu-item ref="filterDropMenu" title="筛选">
|
||||
<wd-drop-menu-item ref="filterDropMenu" title="筛选" icon="filter">
|
||||
<view>
|
||||
<wd-input
|
||||
v-model="queryParams.keywords"
|
||||
@@ -26,69 +31,84 @@
|
||||
<cu-date-query v-model="queryParams.createTime" label="创建时间" />
|
||||
|
||||
<view class="flex-between py-2">
|
||||
<wd-button custom-class="w-20per" type="info" @click="handleResetQuery">
|
||||
重置
|
||||
</wd-button>
|
||||
<wd-button custom-class="w-70per" @click="handleQuery">查询</wd-button>
|
||||
<wd-button type="info" @click="handleResetQuery">重置</wd-button>
|
||||
<wd-button @click="handleQuery">查询</wd-button>
|
||||
</view>
|
||||
</view>
|
||||
</wd-drop-menu-item>
|
||||
</wd-drop-menu>
|
||||
</view>
|
||||
|
||||
<!-- 用户卡片 -->
|
||||
<wd-card v-for="item in pageData" :key="item.id">
|
||||
<template #title>
|
||||
<view class="flex-between">
|
||||
<view class="flex-center">
|
||||
<wd-img :width="50" :height="50" round :src="item.avatar" />
|
||||
<view class="ml-2">
|
||||
<view class="font-bold">
|
||||
{{ item.nickname }}
|
||||
<wd-icon v-if="item.gender == 1" name="gender-male" class="color-#4D80F0" />
|
||||
<wd-icon v-else-if="item.gender == 2" name="gender-female" class="color-#FA4350" />
|
||||
<!-- 数据列表 -->
|
||||
<view class="data-container">
|
||||
<wd-card v-for="item in pageData" :key="item.id">
|
||||
<template #title>
|
||||
<view class="flex-between">
|
||||
<view class="flex-center">
|
||||
<wd-img :width="50" :height="50" round :src="item.avatar" />
|
||||
<view class="ml-2">
|
||||
<view class="font-bold">
|
||||
{{ item.nickname }}
|
||||
<wd-icon v-if="item.gender == 1" name="gender-male" class="color-#4D80F0" />
|
||||
<wd-icon
|
||||
v-else-if="item.gender == 2"
|
||||
name="gender-female"
|
||||
class="color-#FA4350"
|
||||
/>
|
||||
</view>
|
||||
<view class="mt-1"><wd-text :text="item.deptName" size="12px" /></view>
|
||||
</view>
|
||||
<view class="mt-1"><wd-text :text="item.deptName" size="12px" /></view>
|
||||
</view>
|
||||
<view>
|
||||
<wd-tag v-if="item.status === 1" type="success" plain>正常</wd-tag>
|
||||
<wd-tag v-else-if="item.status === 0" plain>禁用</wd-tag>
|
||||
</view>
|
||||
</view>
|
||||
<view>
|
||||
<wd-tag v-if="item.status === 1" type="success" plain>正常</wd-tag>
|
||||
<wd-tag v-else-if="item.status === 0" plain>禁用</wd-tag>
|
||||
</template>
|
||||
|
||||
<wd-cell-group>
|
||||
<wd-cell title="用户名" :value="item.username" icon="user" />
|
||||
<wd-cell title="角色" :value="item.roleNames" icon="usergroup" />
|
||||
<wd-cell title="手机号码" :value="item.mobile" icon="mobile" />
|
||||
<wd-cell title="邮箱" :value="item.email" icon="mail" />
|
||||
</wd-cell-group>
|
||||
|
||||
<template #footer>
|
||||
<view class="flex-between">
|
||||
<view class="text-left">
|
||||
<wd-text text="创建时间:" size="small" class="font-bold" />
|
||||
<wd-text :text="item.createTime" size="small" />
|
||||
</view>
|
||||
<view class="text-right">
|
||||
<wd-button
|
||||
type="primary"
|
||||
size="small"
|
||||
plain
|
||||
:v-has-perm="'sys:user:edit'"
|
||||
@click="handleOpenDialog(item.id)"
|
||||
>
|
||||
编辑
|
||||
</wd-button>
|
||||
|
||||
<wd-button
|
||||
type="error"
|
||||
size="small"
|
||||
plain
|
||||
:v-has-perm="'sys:user:delete'"
|
||||
@click="handleDelete(item.id)"
|
||||
>
|
||||
删除
|
||||
</wd-button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</template>
|
||||
</wd-card>
|
||||
|
||||
<wd-cell-group>
|
||||
<wd-cell title="用户名" :value="item.username" icon="user" />
|
||||
<wd-cell title="角色" :value="item.roleNames" icon="usergroup" />
|
||||
<wd-cell title="手机号码" :value="item.mobile" icon="mobile" />
|
||||
<wd-cell title="邮箱" :value="item.email" icon="mail" />
|
||||
</wd-cell-group>
|
||||
<wd-loadmore v-if="total > 0" :state="loadMoreState" @reload="loadmore" />
|
||||
<wd-status-tip v-else-if="total == 0" image="search" tip="当前搜索无结果" />
|
||||
</view>
|
||||
|
||||
<template #footer>
|
||||
<view class="flex-between">
|
||||
<view class="text-left">
|
||||
<wd-text text="创建时间:" size="small" class="font-bold" />
|
||||
<wd-text :text="item.createTime" size="small" />
|
||||
</view>
|
||||
<view class="text-right">
|
||||
<wd-button type="primary" size="small" plain @click="handleOpenDialog(item.id)">
|
||||
编辑
|
||||
</wd-button>
|
||||
|
||||
<wd-button type="error" size="small" plain @click="handleDelete(item.id)">
|
||||
删除
|
||||
</wd-button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</wd-card>
|
||||
|
||||
<wd-loadmore v-if="total > 0" :state="loadMoreState" @reload="loadmore" />
|
||||
<wd-status-tip v-else-if="total == 0" image="search" tip="当前搜索无结果" />
|
||||
<wd-message-box />
|
||||
|
||||
<!-- 编辑弹窗 -->
|
||||
<!-- 弹窗表单 -->
|
||||
<wd-popup v-model="dialog.visible" position="bottom" @close="hancleCloseDialog">
|
||||
<wd-form ref="userFormRef" :model="formData" :rules="rules">
|
||||
<wd-cell-group border>
|
||||
@@ -113,17 +133,21 @@
|
||||
</wd-cell>
|
||||
</wd-cell-group>
|
||||
</wd-form>
|
||||
<view class="footer">
|
||||
<view class="popup-footer">
|
||||
<wd-button type="primary" block @click="handleSubmit">提交</wd-button>
|
||||
</view>
|
||||
</wd-popup>
|
||||
|
||||
<!-- 悬浮操作按钮 -->
|
||||
<wd-fab
|
||||
:v-has-perm="'sys:user:add'"
|
||||
position="left-bottom"
|
||||
:expandable="false"
|
||||
customStyle="width: 1rem; height: 1rem; line-height: 1rem;z-index:9"
|
||||
custom-style="z-index: 9"
|
||||
@click="handleOpenDialog"
|
||||
/>
|
||||
|
||||
<wd-message-box />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
@@ -368,24 +392,38 @@ onLoad(() => {
|
||||
});
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
// https://wot-design-uni.pages.dev/guide/common-problems#%E5%B0%8F%E7%A8%8B%E5%BA%8F%E6%A0%B7%E5%BC%8F%E9%9A%94%E7%A6%BB
|
||||
export default {
|
||||
options: {
|
||||
styleIsolation: "shared",
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.user {
|
||||
.user-container {
|
||||
:deep(.wd-cell__wrapper) {
|
||||
padding: 4rpx 0;
|
||||
}
|
||||
|
||||
:deep(.wd-cell) {
|
||||
padding-right: 10rpx;
|
||||
background: #f8f8f8;
|
||||
}
|
||||
|
||||
:deep(.wd-fab__trigger) {
|
||||
width: 80rpx !important;
|
||||
height: 80rpx !important;
|
||||
}
|
||||
:deep(.w-20per) {
|
||||
width: 20%;
|
||||
|
||||
.filter-container {
|
||||
padding: 10rpx;
|
||||
background: #fff;
|
||||
}
|
||||
:deep(.w-70per) {
|
||||
width: 70%;
|
||||
|
||||
.data-container {
|
||||
margin-top: 20rpx;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 4.6 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 3.8 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 3.8 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 5.1 KiB |
Reference in New Issue
Block a user