refactor(user): 优化用户权限检查和界面显示逻辑

- 移除邀请人ID表单项并注释相关代码
- 注释掉邀请信息检测成功提示弹窗功能
- 在开发、生产、测试环境中添加本地API调试配置选项
- 添加分销商角色权限检查,非分销商无法查看客户列表
- 使用useRef避免重复显示无权限提示
- 在客户列表页面添加权限验证和加载状态处理
- 移除用户卡片中的余额、积分、优惠券、礼品卡等显示组件
- 简化用户角色名称获取逻辑,优先使用用户角色数组第一个角色名称
- 优化用户信息加载和权限验证流程
This commit is contained in:
2026-02-03 16:54:09 +08:00
parent 217f3556fc
commit 07d35d48d7
6 changed files with 72 additions and 63 deletions

View File

@@ -3,18 +3,21 @@ export const ENV_CONFIG = {
// 开发环境 // 开发环境
development: { development: {
API_BASE_URL: 'https://cms-api.websoft.top/api', API_BASE_URL: 'https://cms-api.websoft.top/api',
// API_BASE_URL: 'http://127.0.0.1:9200/api',
APP_NAME: '开发环境', APP_NAME: '开发环境',
DEBUG: 'true', DEBUG: 'true',
}, },
// 生产环境 // 生产环境
production: { production: {
API_BASE_URL: 'https://cms-api.websoft.top/api', API_BASE_URL: 'https://cms-api.websoft.top/api',
// API_BASE_URL: 'http://127.0.0.1:9200/api',
APP_NAME: '南南佐顿门窗', APP_NAME: '南南佐顿门窗',
DEBUG: 'false', DEBUG: 'false',
}, },
// 测试环境 // 测试环境
test: { test: {
API_BASE_URL: 'https://cms-api.websoft.top/api', API_BASE_URL: 'https://cms-api.websoft.top/api',
// API_BASE_URL: 'http://127.0.0.1:9200/api',
APP_NAME: '测试环境', APP_NAME: '测试环境',
DEBUG: 'true', DEBUG: 'true',
} }

View File

@@ -74,13 +74,13 @@ function App(props: { children: any; }) {
trackInviteSource(inviteParams.source || 'unknown', parseInt(inviteParams.inviter || '0')) trackInviteSource(inviteParams.source || 'unknown', parseInt(inviteParams.inviter || '0'))
// 显示邀请提示 // 显示邀请提示
setTimeout(() => { // setTimeout(() => {
Taro.showToast({ // Taro.showToast({
title: `检测到邀请信息 ID:${inviteParams.inviter}`, // title: `检测到邀请信息 ID:${inviteParams.inviter}`,
icon: 'success', // icon: 'success',
duration: 3000 // duration: 3000
}) // })
}, 1000) // }, 1000)
} else { } else {
console.log('❌ 未检测到邀请参数') console.log('❌ 未检测到邀请参数')

View File

@@ -411,9 +411,9 @@ const AddUserAddress = () => {
> >
<View className={'bg-gray-100 h-3'}></View> <View className={'bg-gray-100 h-3'}></View>
<CellGroup style={{padding: '4px 0'}}> <CellGroup style={{padding: '4px 0'}}>
<Form.Item name="refereeId" label="邀请人ID" initialValue={FormData?.refereeId} required> {/*<Form.Item name="refereeId" label="邀请人ID" initialValue={FormData?.refereeId} required>*/}
<Input placeholder="邀请人ID"/> {/* <Input placeholder="邀请人ID"/>*/}
</Form.Item> {/*</Form.Item>*/}
<Form.Item name="phone" label="手机号" initialValue={FormData?.phone} required> <Form.Item name="phone" label="手机号" initialValue={FormData?.phone} required>
<View className="flex items-center justify-between"> <View className="flex items-center justify-between">
<Input <Input

View File

@@ -1,4 +1,4 @@
import {useState, useEffect, useCallback} from 'react' import {useState, useEffect, useCallback, useRef} from 'react'
import {View, Text} from '@tarojs/components' import {View, Text} from '@tarojs/components'
import Taro, {useDidShow} from '@tarojs/taro' import Taro, {useDidShow} from '@tarojs/taro'
import {Loading, InfiniteLoading, Empty, Space, Tabs, TabPane, Tag, Button, SearchBar} from '@nutui/nutui-react-taro' import {Loading, InfiniteLoading, Empty, Space, Tabs, TabPane, Tag, Button, SearchBar} from '@nutui/nutui-react-taro'
@@ -16,6 +16,7 @@ import FixedButton from "@/components/FixedButton";
import navTo from "@/utils/common"; import navTo from "@/utils/common";
import {pageShopDealerApply, removeShopDealerApply, updateShopDealerApply} from "@/api/shop/shopDealerApply"; import {pageShopDealerApply, removeShopDealerApply, updateShopDealerApply} from "@/api/shop/shopDealerApply";
import {addShopDealerRecord} from "@/api/shop/shopDealerRecord"; import {addShopDealerRecord} from "@/api/shop/shopDealerRecord";
import {useUser} from "@/hooks/useUser";
// 扩展User类型添加客户状态和保护天数 // 扩展User类型添加客户状态和保护天数
interface CustomerUser extends UserType { interface CustomerUser extends UserType {
@@ -32,6 +33,23 @@ const CustomerIndex = () => {
const [page, setPage] = useState(1) const [page, setPage] = useState(1)
const [hasMore, setHasMore] = useState(true) const [hasMore, setHasMore] = useState(true)
// 非分销商不允许查看客户列表
const {hasRole, loading: userLoading} = useUser()
const canView = hasRole('dealer')
const roleCheckFinished = !userLoading
const noPermissionShownRef = useRef(false)
useEffect(() => {
if (!roleCheckFinished || canView) return
if (noPermissionShownRef.current) return
noPermissionShownRef.current = true
Taro.showToast({
title: '没有查看权限',
icon: 'none',
duration: 1500
})
}, [roleCheckFinished, canView])
// Tab配置 // Tab配置
const tabList = getStatusOptions(); const tabList = getStatusOptions();
@@ -330,22 +348,24 @@ const CustomerIndex = () => {
}) })
} }
// 初始化数据 // 初始化统计数据
useEffect(() => { useEffect(() => {
fetchCustomerData(activeTab, true).then(); if (!roleCheckFinished || !canView) return;
fetchStatusCounts().then(); fetchStatusCounts().then();
}, []); }, [roleCheckFinished, canView]);
// 当activeTab变化时重新获取数据 // 当activeTab变化时重新获取数据
useEffect(() => { useEffect(() => {
if (!roleCheckFinished || !canView) return;
setList([]); // 清空列表 setList([]); // 清空列表
setPage(1); // 重置页码 setPage(1); // 重置页码
setHasMore(true); // 重置加载状态 setHasMore(true); // 重置加载状态
fetchCustomerData(activeTab, true); fetchCustomerData(activeTab, true);
}, [activeTab]); }, [activeTab, roleCheckFinished, canView]);
// 监听页面显示,当从其他页面返回时刷新数据 // 监听页面显示,当从其他页面返回时刷新数据
useDidShow(() => { useDidShow(() => {
if (!roleCheckFinished || !canView) return;
// 刷新当前tab的数据和统计信息 // 刷新当前tab的数据和统计信息
setList([]); setList([]);
setPage(1); setPage(1);
@@ -543,6 +563,30 @@ const CustomerIndex = () => {
); );
}; };
if (!roleCheckFinished) {
return (
<View className="bg-white flex items-center justify-center">
<Loading/>
<Text className="text-gray-500 ml-2">...</Text>
</View>
);
}
if (!canView) {
return (
<View className="bg-white flex flex-col items-center justify-center p-4">
<Empty description="没有查看权限"/>
<Button
size="small"
style={{marginTop: '12px'}}
onClick={() => Taro.navigateBack()}
>
</Button>
</View>
);
}
return ( return (
<View className="min-h-screen bg-gray-50"> <View className="min-h-screen bg-gray-50">
{/* 搜索栏 */} {/* 搜索栏 */}

View File

@@ -10,6 +10,7 @@ export const useUser = () => {
const [user, setUser] = useState<User | null>(null); const [user, setUser] = useState<User | null>(null);
const [isLoggedIn, setIsLoggedIn] = useState(false); const [isLoggedIn, setIsLoggedIn] = useState(false);
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
const [userInfo] = useState<User>()
// 自动登录通过OpenID // 自动登录通过OpenID
const autoLoginByOpenId = async () => { const autoLoginByOpenId = async () => {
@@ -256,23 +257,10 @@ export const useUser = () => {
return user?.nickname || user?.realName || user?.username || '未登录'; return user?.nickname || user?.realName || user?.username || '未登录';
}; };
// 获取用户显示的角色(同步版本) // 角色名称:优先取用户 roles 数组的第一个角色名称
const getRoleName = () => { const getRoleName = () => {
if(hasRole('superAdmin')){ return userInfo?.roles?.[0]?.roleName || userInfo?.roleName || '业务员'
return '超级管理员';
}
if(hasRole('admin')){
return '管理员';
}
if(hasRole('staff')){
return '员工';
}
if(hasRole('vip')){
return 'VIP会员';
}
return '注册用户';
} }
// 检查用户是否已实名认证 // 检查用户是否已实名认证
const isCertified = () => { const isCertified = () => {
return user?.certification === true; return user?.certification === true;

View File

@@ -1,6 +1,6 @@
import {Button} from '@nutui/nutui-react-taro' import {Button} from '@nutui/nutui-react-taro'
import {Avatar, Tag} from '@nutui/nutui-react-taro' import {Avatar} from '@nutui/nutui-react-taro'
import {View, Text} from '@tarojs/components' 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 {getWxOpenId} from '@/api/layout';
import Taro from '@tarojs/taro'; import Taro from '@tarojs/taro';
@@ -8,7 +8,6 @@ import {useEffect} from "react";
import navTo from "@/utils/common"; import navTo from "@/utils/common";
import {TenantId} from "@/config/app"; import {TenantId} from "@/config/app";
import {useUser} from "@/hooks/useUser"; import {useUser} from "@/hooks/useUser";
import {useUserData} from "@/hooks/useUserData";
function UserCard() { function UserCard() {
const { const {
@@ -17,10 +16,8 @@ function UserCard() {
isLoggedIn, isLoggedIn,
loginUser, loginUser,
fetchUserInfo, fetchUserInfo,
getDisplayName, getDisplayName
getRoleName
} = useUser(); } = useUser();
const {data} = useUserData();
useEffect(() => { useEffect(() => {
// Taro.getSetting获取用户的当前设置。返回值中只会出现小程序已经向用户请求过的权限。 // Taro.getSetting获取用户的当前设置。返回值中只会出现小程序已经向用户请求过的权限。
@@ -180,12 +177,10 @@ function UserCard() {
<View className={'user-info flex flex-col px-2'}> <View className={'user-info flex flex-col px-2'}>
<View className={'py-1 text-black font-bold max-w-28'}>{getDisplayName()}</View> <View className={'py-1 text-black font-bold max-w-28'}>{getDisplayName()}</View>
{isLoggedIn ? ( {isLoggedIn ? (
<View className={'grade text-xs py-1'}> <View className={'grade text-xs py-0'}>
<Tag type="success" round> {/*<Text className={'p-1'}>*/}
<Text className={'p-1'}> {/* {getRoleName()}*/}
{getRoleName()} {/*</Text>*/}
</Text>
</Tag>
</View> </View>
) : ''} ) : ''}
</View> </View>
@@ -198,27 +193,6 @@ function UserCard() {
</View> </View>
</View> </View>
</View> </View>
{/*<View className={'flex justify-around mt-1'}>*/}
{/* <View className={'item flex justify-center flex-col items-center'}*/}
{/* onClick={() => navTo('/user/wallet/wallet', true)}>*/}
{/* <Text className={'text-sm text-gray-500'}>余额</Text>*/}
{/* <Text className={'text-xl'}>{data?.balance || '0.00'}</Text>*/}
{/* </View>*/}
{/* <View className={'item flex justify-center flex-col items-center'}>*/}
{/* <Text className={'text-sm text-gray-500'}>积分</Text>*/}
{/* <Text className={'text-xl'}>{data?.points || 0}</Text>*/}
{/* </View>*/}
{/* <View className={'item flex justify-center flex-col items-center'}*/}
{/* onClick={() => navTo('/user/coupon/index', true)}>*/}
{/* <Text className={'text-sm text-gray-500'}>优惠券</Text>*/}
{/* <Text className={'text-xl'}>{data?.coupons || 0}</Text>*/}
{/* </View>*/}
{/* <View className={'item flex justify-center flex-col items-center'}*/}
{/* onClick={() => navTo('/user/gift/index', true)}>*/}
{/* <Text className={'text-sm text-gray-500'}>礼品卡</Text>*/}
{/* <Text className={'text-xl'}>{data?.giftCards || 0}</Text>*/}
{/* </View>*/}
{/*</View>*/}
</View> </View>
</View> </View>
</View> </View>