This commit is contained in:
menxipeng
2025-10-20 08:09:08 +08:00
parent 36cd20eada
commit ff2b80d639
2 changed files with 174 additions and 32 deletions

View File

@@ -85,14 +85,87 @@ export default function LoginPage() {
console.log("Login attempt:", loginData)
// 使用统一的 API 客户端发送登录请求
// 先调用登录接口
const result = await apiPost('/login', loginData)
if (result.code === 200) {
if (result.code !== 200) {
// 登录失败,显示错误信息
alert(result.msg || '登录失败,请检查用户名和密码')
return
}
console.log("登录成功,开始验证路由数据")
// 临时保存 token以便后续的 API 请求可以使用
const tempUserData = {
username: formData.username,
role: formData.role,
token: result.token,
}
setStorageItem("user", JSON.stringify(tempUserData))
// 登录成功后,验证该角色的路由数据是否有效
const routeValidationResult = await apiGet(`/getRoutersByRoleId?roleId=${formData.role}`)
if (routeValidationResult.code !== 200) {
alert(`路由验证失败: ${routeValidationResult.msg || '未知错误'},请联系管理员`)
// 清除临时保存的用户信息
setStorageItem("user", "")
return
}
// 检查路由数据是否存在
if (!routeValidationResult.data) {
alert('路由数据不存在,请联系管理员配置角色权限')
// 清除临时保存的用户信息
setStorageItem("user", "")
return
}
// 验证路由数据格式
const routeData = routeValidationResult.data
console.log("获取到的路由数据:", routeData)
if (!Array.isArray(routeData) || routeData.length === 0) {
alert('路由数据格式错误或为空,请联系管理员')
// 清除临时保存的用户信息
setStorageItem("user", "")
return
}
// 验证路由数据的基本字段(放宽验证条件)
const hasInvalidRoute = routeData.some((route: any) => {
console.log("验证路由项:", route)
// 必须有 path 字段
if (!route.path || typeof route.path !== 'string') {
console.error('无效的路由数据,缺少或错误的 path 字段:', route)
return true
}
// name 字段不是必需的(某些布局路由可能没有 name
// 只验证如果有 name 字段,它必须是字符串类型
if (route.name !== undefined && typeof route.name !== 'string') {
console.error('无效的路由数据name 字段类型错误:', route)
return true
}
return false
})
if (hasInvalidRoute) {
alert('路由数据包含错误信息,请联系管理员检查配置')
// 清除临时保存的用户信息
setStorageItem("user", "")
return
}
console.log("路由数据验证通过,保存用户信息并跳转")
// 获取选择的角色信息
const selectedRole = roles.find(role => role.roleId === formData.role)
// 登录成功,保存用户信息(包含 token 和角色信息)
// 登录成功且路由验证通过,保存用户信息(包含 token 和角色信息)
const userData = {
username: formData.username,
role: formData.role,
@@ -111,10 +184,6 @@ export default function LoginPage() {
// 跳转到管理后台
navigate("/admin")
} else {
// 登录失败,显示错误信息
alert(result.msg || '登录失败,请检查用户名和密码')
}
} catch (error) {
console.error('登录请求失败:', error)
alert('网络错误,请稍后重试')

View File

@@ -95,6 +95,8 @@ export default function MallsPage() {
const [mallUsers, setMallUsers] = useState<MallUser[]>([])
const [loading, setLoading] = useState(false)
const [userRole, setUserRole] = useState<string>("")
const [mallMerchants, setMallMerchants] = useState<{[key: string]: any[]}>({})
const [loadingMallMerchants, setLoadingMallMerchants] = useState<{[key: string]: boolean}>({})
const [newMall, setNewMall] = useState({
name: "",
address: "",
@@ -171,6 +173,27 @@ export default function MallsPage() {
}
}
// 获取商场下的商户列表
const fetchMallMerchants = async (mallId: string) => {
if (!mallId) return []
setLoadingMallMerchants(prev => ({ ...prev, [mallId]: true }))
try {
const response = await apiGet(`/back/merchants/list?mallId=${mallId}`)
if (response.code === 200) {
const merchants = response.rows || []
setMallMerchants(prev => ({ ...prev, [mallId]: merchants }))
return merchants
}
return []
} catch (error) {
console.error(`获取商场${mallId}商户列表失败:`, error)
return []
} finally {
setLoadingMallMerchants(prev => ({ ...prev, [mallId]: false }))
}
}
// 页面加载时获取数据
useEffect(() => {
fetchUserRole()
@@ -234,8 +257,19 @@ export default function MallsPage() {
}
}
const toggleMallExpansion = (mallId: string) => {
setExpandedMalls((prev) => (prev.includes(mallId) ? prev.filter((id) => id !== mallId) : [...prev, mallId]))
const toggleMallExpansion = (mall: Mall) => {
const isExpanding = !expandedMalls.includes(mall.id)
setExpandedMalls((prev) =>
prev.includes(mall.id)
? prev.filter((id) => id !== mall.id)
: [...prev, mall.id]
)
// 如果是展开操作,获取该商场的商户列表
if (isExpanding && mall.mallId) {
fetchMallMerchants(mall.mallId)
}
}
const getStatusBadge = (status: string) => {
@@ -442,7 +476,7 @@ export default function MallsPage() {
<div key={mall.id} className="border rounded-lg">
<div
className="w-full p-4 flex items-center justify-between hover:bg-gray-50 transition-colors cursor-pointer"
onClick={() => toggleMallExpansion(mall.id)}
onClick={() => toggleMallExpansion(mall)}
>
<div className="flex items-center space-x-4">
{expandedMalls.includes(mall.id) ? (
@@ -495,10 +529,49 @@ export default function MallsPage() {
<div className="px-4 pb-4 border-t bg-gray-50">
<div className="py-4">
<h4 className="font-medium mb-3"></h4>
{loadingMallMerchants[mall.mallId || ''] ? (
<div className="text-center py-8 text-gray-500">
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-gray-900 mx-auto"></div>
<p className="mt-2">...</p>
</div>
) : (mallMerchants[mall.mallId || ''] || []).length > 0 ? (
<div className="space-y-3">
{(mallMerchants[mall.mallId || ''] || []).map((merchant: any) => (
<div key={merchant.id} className="bg-white p-4 rounded-lg border hover:shadow-sm transition-shadow">
<div className="flex items-start justify-between">
<div className="flex-1">
<div className="flex items-center space-x-2 mb-2">
<Store className="h-4 w-4 text-blue-600" />
<span className="font-medium">{merchant.merchantName}</span>
<Badge className={merchant.status === "1" ? "bg-green-100 text-green-800" : "bg-red-100 text-red-800"}>
{merchant.status === "1" ? "正常" : "停用"}
</Badge>
</div>
<div className="grid grid-cols-2 gap-2 text-sm text-gray-600">
<div>
<span className="font-medium"></span>
{merchant.contactPerson || '无'}
</div>
<div>
<span className="font-medium"></span>
{merchant.contactPhone || '无'}
</div>
<div className="col-span-2 flex items-start">
<MapPin className="h-3 w-3 mr-1 mt-0.5 flex-shrink-0" />
<span>{merchant.fullAddress || merchant.detailedAddress || '无'}</span>
</div>
</div>
</div>
</div>
</div>
))}
</div>
) : (
<div className="text-center py-8 text-gray-500">
<Store className="h-8 w-8 mx-auto mb-2 opacity-50" />
<p></p>
</div>
)}
</div>
</div>
)}