wo
This commit is contained in:
@@ -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('网络错误,请稍后重试')
|
||||
|
@@ -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>
|
||||
)}
|
||||
|
Reference in New Issue
Block a user