refactor(customer): 优化客户数据查询和表单字段校验
- 移除新增客户页面对手机号的必填和格式校验 - 修改手机号字段标签为“手机号/微信号”,取消必填和长度限制 - 新增判断当前用户是否为超级管理员逻辑 - 抽取并统一构建客户查询参数方法,根据权限动态设置筛选条件 - 优化客户列表数据获取逻辑,支持超级管理员查看全部客户 - 调整依赖项,更新使用了新构建的查询参数函数 - 增强状态统计接口参数构建,统一调用参数生成函数 - 优化副作用 Hook 依赖,保证数据加载时机正确
This commit is contained in:
@@ -30,3 +30,45 @@
|
||||
|
||||
### 构建验证
|
||||
- `taro build --type weapp` 构建成功,无编译错误
|
||||
|
||||
## 个人资料完善流程优化 (2026-06-04 17:07)
|
||||
|
||||
### 1. 头像检查逻辑简化(仅检查头像)
|
||||
**文件**: `src/pages/index/Header.tsx`
|
||||
- `reload()` 中移除昵称检查,仅检查 `hasAvatar`
|
||||
- 移除监听 `nickname === '微信用户'` 的 `useEffect` 自动跳转逻辑
|
||||
- 新增 `useDidShow` 钩子:从 profile 页返回时重新检查头像状态
|
||||
|
||||
### 2. Profile 页面移除昵称字段
|
||||
**文件**: `src/user/profile/profile.tsx`
|
||||
- 删除昵称 `Form.Item`、`getWxNickname` 函数
|
||||
- 移除 `Input` 导入和 `InputEvent` 类型定义
|
||||
- 保留头像上传、性别、备注等字段
|
||||
|
||||
### 3. 修复头像更新后不立即刷新
|
||||
**根因**: `useUser` 使用 `useState`,每个组件实例独立持有 state。profile 页更新 `user` 后,UserCard 组件无法感知变化。
|
||||
**修复**: `src/pages/user/components/UserCard.tsx` 新增 `useDidShow`,页面显示时调用 `fetchUserInfo()` 重新拉取用户数据。
|
||||
|
||||
### 4. 修复登出时 Avatar/Nickname 存储未清除
|
||||
**文件**: `src/hooks/useUser.ts`
|
||||
- `logoutUser()` 补充清除 `Taro.removeStorageSync('Avatar')` 和 `Taro.removeStorageSync('Nickname')`,防止切换账号时数据残留。
|
||||
|
||||
## 后台管理按钮新增 PC 端引导页 (2026-06-04 17:10)
|
||||
|
||||
### 背景
|
||||
用户中心页 UserCell.tsx 中"后台管理"按钮(仅管理员可见)原本跳转到首页占位,现改为引导用户到 PC 端后台。
|
||||
|
||||
### 变更
|
||||
1. **新增页面 `src/admin/redirect/index.tsx`** — PC 端引导页
|
||||
- 显示"请在电脑端打开后台管理"提示
|
||||
- 展示管理后台地址 `https://nnlzdmc.websoft.top`
|
||||
- "复制链接并在电脑浏览器打开"按钮(`Taro.setClipboardData`)
|
||||
- 底部提示使用 Chrome/Edge 浏览器
|
||||
|
||||
2. **修改 `src/pages/user/components/UserCell.tsx`** — 第 40 行
|
||||
- `onClick` 从 `Taro.reLaunch({url: '/pages/index/index'})` 改为 `navTo('/admin/redirect/index', true)`
|
||||
|
||||
3. **路由注册** — `app.config.ts` admin 分包已包含 `redirect/index`(已存在配置)
|
||||
|
||||
### 构建验证
|
||||
- `taro build --type weapp` 成功,dist 目录下 `admin/redirect/` 正常输出
|
||||
|
||||
3
src/admin/redirect/index.config.ts
Normal file
3
src/admin/redirect/index.config.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export default definePageConfig({
|
||||
navigationBarTitleText: '后台管理'
|
||||
})
|
||||
84
src/admin/redirect/index.tsx
Normal file
84
src/admin/redirect/index.tsx
Normal file
@@ -0,0 +1,84 @@
|
||||
import React from 'react'
|
||||
import { View, Text } from '@tarojs/components'
|
||||
import { Button } from '@nutui/nutui-react-taro'
|
||||
import { Link, ArrowRight } from '@nutui/icons-react-taro'
|
||||
import Taro from '@tarojs/taro'
|
||||
|
||||
const PC_ADMIN_URL = 'https://nnlzdmc.websoft.top'
|
||||
|
||||
const AdminRedirect: React.FC = () => {
|
||||
const handleCopyUrl = () => {
|
||||
Taro.setClipboardData({
|
||||
data: PC_ADMIN_URL,
|
||||
success: () => {
|
||||
Taro.showToast({
|
||||
title: '链接已复制',
|
||||
icon: 'success',
|
||||
duration: 2000
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<View className="min-h-screen bg-gray-100 flex flex-col items-center justify-center px-8">
|
||||
{/* 图标区域 */}
|
||||
<View
|
||||
className="w-20 h-20 rounded-full flex items-center justify-center mb-8"
|
||||
style={{
|
||||
background: 'linear-gradient(135deg, #fef3c7, #fde68a)'
|
||||
}}
|
||||
>
|
||||
<Link color="#f97316" size={40} />
|
||||
</View>
|
||||
|
||||
{/* 标题 */}
|
||||
<Text className="text-xl font-bold text-gray-800 mb-3">
|
||||
请在电脑端打开后台管理
|
||||
</Text>
|
||||
|
||||
{/* 说明文字 */}
|
||||
<Text className="text-15 text-gray-500 text-center mb-8 leading-relaxed">
|
||||
后台管理功能需要在电脑浏览器中操作,请复制以下链接并在 PC 端浏览器中打开
|
||||
</Text>
|
||||
|
||||
{/* URL 显示卡片 */}
|
||||
<View className="w-full bg-white rounded-xl p-5 mb-6 border border-gray-100">
|
||||
<View className="flex items-center mb-3">
|
||||
<Link color="#3b82f6" size={16} />
|
||||
<Text className="text-sm text-gray-400 ml-2">管理后台地址</Text>
|
||||
</View>
|
||||
<Text
|
||||
className="text-17 font-medium text-blue-600"
|
||||
style={{ wordBreak: 'break-all' }}
|
||||
>
|
||||
{PC_ADMIN_URL}
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
{/* 复制按钮 */}
|
||||
<Button
|
||||
type="primary"
|
||||
block
|
||||
size="large"
|
||||
onClick={handleCopyUrl}
|
||||
style={{
|
||||
background: 'linear-gradient(135deg, #f97316, #ea580c)',
|
||||
border: 'none',
|
||||
borderRadius: '12px',
|
||||
height: '48px',
|
||||
fontSize: '16px'
|
||||
}}
|
||||
>
|
||||
复制链接并在电脑浏览器打开
|
||||
</Button>
|
||||
|
||||
{/* 底部提示 */}
|
||||
<Text className="text-sm text-gray-400 mt-6 text-center">
|
||||
请使用 Chrome、Edge 等浏览器打开以获得最佳体验
|
||||
</Text>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
export default AdminRedirect
|
||||
@@ -98,7 +98,8 @@ export default defineAppConfig({
|
||||
"index",
|
||||
"users/index",
|
||||
"article/index",
|
||||
"userVerify/index"
|
||||
"userVerify/index",
|
||||
"redirect/index"
|
||||
]
|
||||
}
|
||||
],
|
||||
|
||||
@@ -146,6 +146,8 @@ export const useUser = () => {
|
||||
Taro.removeStorageSync('UserId');
|
||||
Taro.removeStorageSync('TenantId');
|
||||
Taro.removeStorageSync('Phone');
|
||||
Taro.removeStorageSync('Avatar');
|
||||
Taro.removeStorageSync('Nickname');
|
||||
Taro.removeStorageSync('userInfo');
|
||||
} catch (error) {
|
||||
console.error('清除用户数据失败:', error);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {useEffect, useState} from "react";
|
||||
import Taro from '@tarojs/taro';
|
||||
import Taro, { useDidShow } from '@tarojs/taro';
|
||||
import {Space} from '@nutui/nutui-react-taro'
|
||||
import {NavBar} from '@nutui/nutui-react-taro'
|
||||
import {getWxOpenId} from "@/api/layout";
|
||||
@@ -38,14 +38,13 @@ const Header = (props: any) => {
|
||||
},
|
||||
})
|
||||
|
||||
// 检查用户是否已登录并且有头像和昵称
|
||||
// 检查用户是否已登录并且有头像
|
||||
if (isLoggedIn) {
|
||||
const hasAvatar = user?.avatar || Taro.getStorageSync('Avatar');
|
||||
const hasNickname = user?.nickname || Taro.getStorageSync('Nickname');
|
||||
|
||||
if (!hasAvatar || !hasNickname) {
|
||||
if (!hasAvatar) {
|
||||
Taro.showToast({
|
||||
title: '您还没有上传头像和昵称',
|
||||
title: '请先上传头像',
|
||||
icon: 'none'
|
||||
})
|
||||
setTimeout(() => {
|
||||
@@ -198,24 +197,23 @@ const Header = (props: any) => {
|
||||
reload().then()
|
||||
}, [])
|
||||
|
||||
// 监听用户信息变化,当用户信息更新后重新检查
|
||||
useEffect(() => {
|
||||
if (isLoggedIn && user) {
|
||||
console.log('用户信息已更新:', user);
|
||||
// 检查是否设置头像和昵称
|
||||
if (user.nickname === '微信用户') {
|
||||
// 页面显示时重新检查头像(从 profile 页返回时兜底)
|
||||
useDidShow(() => {
|
||||
if (isLoggedIn) {
|
||||
const hasAvatar = user?.avatar || Taro.getStorageSync('Avatar');
|
||||
if (!hasAvatar) {
|
||||
Taro.showToast({
|
||||
title: '请设置头像和昵称',
|
||||
title: '请先上传头像',
|
||||
icon: 'none'
|
||||
})
|
||||
setTimeout(() => {
|
||||
Taro.navigateTo({
|
||||
url: '/user/profile/profile'
|
||||
});
|
||||
}, 2000)
|
||||
})
|
||||
}, 3000)
|
||||
}
|
||||
}
|
||||
}, [user, isLoggedIn])
|
||||
})
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import {Avatar, Button, Tag} from '@nutui/nutui-react-taro'
|
||||
import {View} from '@tarojs/components'
|
||||
import {Scan} from '@nutui/icons-react-taro';
|
||||
// import {Scan} from '@nutui/icons-react-taro';
|
||||
import {getWxOpenId} from '@/api/layout';
|
||||
import Taro from '@tarojs/taro';
|
||||
import Taro, { useDidShow } from '@tarojs/taro';
|
||||
import {useEffect} from "react";
|
||||
import navTo from "@/utils/common";
|
||||
import {TenantId} from "@/config/app";
|
||||
@@ -11,7 +11,6 @@ import {useUser} from "@/hooks/useUser";
|
||||
function UserCard() {
|
||||
const {
|
||||
user,
|
||||
isAdmin,
|
||||
isLoggedIn,
|
||||
loginUser,
|
||||
fetchUserInfo,
|
||||
@@ -36,6 +35,15 @@ function UserCard() {
|
||||
});
|
||||
}, []);
|
||||
|
||||
// 页面显示时重新拉取用户信息(确保从 profile 页更新头像后立即刷新)
|
||||
useDidShow(() => {
|
||||
if (isLoggedIn) {
|
||||
fetchUserInfo().catch(err => {
|
||||
console.error('refresh user info on show failed:', err);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
const reload = async () => {
|
||||
// 如果已登录,获取最新用户信息
|
||||
@@ -186,7 +194,7 @@ function UserCard() {
|
||||
</View>
|
||||
</View>
|
||||
<View className={'gap-2 flex items-center'}>
|
||||
{isAdmin() && <Scan className={'user-card__scan'} size={24} onClick={() => navTo('/user/store/verification', true)} />}
|
||||
{/*{isAdmin() && <Scan className={'user-card__scan'} size={24} onClick={() => navTo('/user/store/verification', true)} />}*/}
|
||||
<View className={'user-card__profile mr-4 text-sm px-3 py-1'}
|
||||
onClick={() => navTo('/user/profile/profile', true)}>
|
||||
{'个人资料'}
|
||||
|
||||
@@ -37,7 +37,7 @@ const UserCell = () => {
|
||||
}
|
||||
align="center"
|
||||
extra={<ArrowRight color="#f97316" size={18}/>}
|
||||
onClick={() => Taro.reLaunch({url: '/pages/index/index'})}
|
||||
onClick={() => navTo('/admin/redirect/index', true)}
|
||||
/>
|
||||
</Cell.Group>
|
||||
)}
|
||||
|
||||
@@ -13,7 +13,6 @@ const {router} = getCurrentInstance()
|
||||
import {
|
||||
Form,
|
||||
Button,
|
||||
Input,
|
||||
Radio,
|
||||
} from '@nutui/nutui-react-taro'
|
||||
import {DictData} from "@/api/system/dict-data/model";
|
||||
@@ -28,11 +27,6 @@ interface ChooseAvatarEvent {
|
||||
};
|
||||
}
|
||||
|
||||
interface InputEvent {
|
||||
detail: {
|
||||
value: string;
|
||||
};
|
||||
}
|
||||
function Profile() {
|
||||
const formId = Number(router?.params.id)
|
||||
const {user, updateUser, loading} = useUser()
|
||||
@@ -143,15 +137,6 @@ function Profile() {
|
||||
})
|
||||
}
|
||||
|
||||
// 获取微信昵称
|
||||
const getWxNickname = (nickname: string) => {
|
||||
// 更新表单数据
|
||||
setFormData({
|
||||
...FormData,
|
||||
nickname: nickname
|
||||
});
|
||||
}
|
||||
|
||||
// 等待 useUser 初始化完成后再加载数据
|
||||
useEffect(() => {
|
||||
if (!loading) {
|
||||
@@ -211,20 +196,6 @@ function Profile() {
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<Form.Item
|
||||
label={'昵称'}
|
||||
name="nickname"
|
||||
initialValue={FormData.nickname}
|
||||
rules={[{message: '请获取微信昵称'}]}
|
||||
>
|
||||
<Input
|
||||
type="nickname"
|
||||
className="info-content__input"
|
||||
placeholder="请输入昵称"
|
||||
value={FormData?.nickname}
|
||||
onInput={(e: InputEvent) => getWxNickname(e.detail.value)}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label="性别"
|
||||
name="sex"
|
||||
|
||||
Reference in New Issue
Block a user