超管登录
This commit is contained in:
5
Server/application/superadmin/config/route.php
Normal file
5
Server/application/superadmin/config/route.php
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<?php
|
||||||
|
use think\facade\Route;
|
||||||
|
|
||||||
|
// 超级管理员认证相关路由
|
||||||
|
Route::post('auth/login', 'app\\superadmin\\controller\\Auth@login');
|
||||||
63
Server/application/superadmin/controller/Auth.php
Normal file
63
Server/application/superadmin/controller/Auth.php
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
<?php
|
||||||
|
namespace app\superadmin\controller;
|
||||||
|
|
||||||
|
use think\Controller;
|
||||||
|
use app\superadmin\model\Administrator;
|
||||||
|
|
||||||
|
class Auth extends Controller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 管理员登录
|
||||||
|
* @return \think\response\Json
|
||||||
|
*/
|
||||||
|
public function login()
|
||||||
|
{
|
||||||
|
if (!$this->request->isPost()) {
|
||||||
|
return json(['code' => 405, 'msg' => '请求方法不允许']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$account = $this->request->post('account');
|
||||||
|
$password = $this->request->post('password');
|
||||||
|
|
||||||
|
if (empty($account) || empty($password)) {
|
||||||
|
return json(['code' => 400, 'msg' => '账号和密码不能为空']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$admin = Administrator::login($account, $password);
|
||||||
|
|
||||||
|
if (!$admin) {
|
||||||
|
return json(['code' => 401, 'msg' => '账号或密码错误']);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新登录信息
|
||||||
|
$admin->lastLoginTime = time();
|
||||||
|
$admin->lastLoginIp = $this->request->ip();
|
||||||
|
$admin->save();
|
||||||
|
|
||||||
|
// 设置登录Cookie,有效期24小时
|
||||||
|
cookie('admin_id', $admin->id, 86400);
|
||||||
|
cookie('admin_token', $this->createToken($admin), 86400);
|
||||||
|
|
||||||
|
return json([
|
||||||
|
'code' => 200,
|
||||||
|
'msg' => '登录成功',
|
||||||
|
'data' => [
|
||||||
|
'id' => $admin->id,
|
||||||
|
'name' => $admin->name,
|
||||||
|
'account' => $admin->account,
|
||||||
|
'token' => cookie('admin_token')
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建登录令牌
|
||||||
|
* @param Administrator $admin
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private function createToken($admin)
|
||||||
|
{
|
||||||
|
$data = $admin->id . '|' . $admin->account . '|' . time();
|
||||||
|
return md5($data . 'cunkebao_admin_secret');
|
||||||
|
}
|
||||||
|
}
|
||||||
2
Server/application/superadmin/data/administrator.sql
Normal file
2
Server/application/superadmin/data/administrator.sql
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
INSERT INTO `tk_administrators` (`name`, `account`, `password`, `status`, `createTime`, `updateTime`)
|
||||||
|
VALUES ('超级管理员', 'admin', MD5('123456'), 1, UNIX_TIMESTAMP(), UNIX_TIMESTAMP());
|
||||||
48
Server/application/superadmin/model/Administrator.php
Normal file
48
Server/application/superadmin/model/Administrator.php
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
<?php
|
||||||
|
namespace app\superadmin\model;
|
||||||
|
|
||||||
|
use think\Model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 超级管理员模型类
|
||||||
|
*/
|
||||||
|
class Administrator extends Model
|
||||||
|
{
|
||||||
|
// 设置数据表名
|
||||||
|
protected $name = 'administrators';
|
||||||
|
|
||||||
|
// 设置数据表前缀
|
||||||
|
protected $prefix = 'tk_';
|
||||||
|
|
||||||
|
// 设置主键
|
||||||
|
protected $pk = 'id';
|
||||||
|
|
||||||
|
// 自动写入时间戳
|
||||||
|
protected $autoWriteTimestamp = true;
|
||||||
|
|
||||||
|
// 定义时间戳字段名
|
||||||
|
protected $createTime = 'createTime';
|
||||||
|
protected $updateTime = 'updateTime';
|
||||||
|
protected $deleteTime = 'deleteTime';
|
||||||
|
|
||||||
|
// 隐藏字段
|
||||||
|
protected $hidden = [
|
||||||
|
'password'
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证管理员登录
|
||||||
|
* @param string $account 账号
|
||||||
|
* @param string $password 密码(已MD5加密)
|
||||||
|
* @return array|null
|
||||||
|
*/
|
||||||
|
public static function login($account, $password)
|
||||||
|
{
|
||||||
|
return self::where([
|
||||||
|
['account', '=', $account],
|
||||||
|
['password', '=', $password],
|
||||||
|
['status', '=', 1],
|
||||||
|
['deleteTime', '=', 0]
|
||||||
|
])->find();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -24,12 +24,14 @@ include __DIR__ . '/../application/api/config/route.php';
|
|||||||
// 加载Common模块路由配置
|
// 加载Common模块路由配置
|
||||||
include __DIR__ . '/../application/common/config/route.php';
|
include __DIR__ . '/../application/common/config/route.php';
|
||||||
|
|
||||||
// 加载Devices模块路由配置
|
// 加载Cunkebao模块路由配置
|
||||||
include __DIR__ . '/../application/cunkebao/config/route.php';
|
include __DIR__ . '/../application/cunkebao/config/route.php';
|
||||||
|
|
||||||
// 加载Store模块路由配置
|
// 加载Store模块路由配置
|
||||||
include __DIR__ . '/../application/store/config/route.php';
|
include __DIR__ . '/../application/store/config/route.php';
|
||||||
|
|
||||||
|
// 加载Superadmin模块路由配置
|
||||||
|
include __DIR__ . '/../application/superadmin/config/route.php';
|
||||||
|
|
||||||
// 加载CozeAI模块路由配置
|
// 加载CozeAI模块路由配置
|
||||||
include __DIR__ . '/../application/cozeai/config/route.php';
|
include __DIR__ . '/../application/cozeai/config/route.php';
|
||||||
|
|||||||
@@ -1,11 +1,52 @@
|
|||||||
|
"use client"
|
||||||
|
|
||||||
|
import { useEffect, useState } from "react"
|
||||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
|
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
|
||||||
import { Users, FolderKanban, UserCog } from "lucide-react"
|
import { Users, FolderKanban, UserCog } from "lucide-react"
|
||||||
|
import useAuthCheck from "@/hooks/useAuthCheck"
|
||||||
|
|
||||||
export default function DashboardPage() {
|
export default function DashboardPage() {
|
||||||
|
const [greeting, setGreeting] = useState("")
|
||||||
|
const [userName, setUserName] = useState("")
|
||||||
|
|
||||||
|
// 验证用户是否已登录
|
||||||
|
useAuthCheck()
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// 获取用户信息
|
||||||
|
const adminInfo = localStorage.getItem("admin_info")
|
||||||
|
if (adminInfo) {
|
||||||
|
try {
|
||||||
|
const { name } = JSON.parse(adminInfo)
|
||||||
|
setUserName(name || "管理员")
|
||||||
|
} catch (err) {
|
||||||
|
console.error("解析用户信息失败:", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取当前时间
|
||||||
|
const hour = new Date().getHours()
|
||||||
|
let timeGreeting = ""
|
||||||
|
|
||||||
|
if (hour >= 5 && hour < 12) {
|
||||||
|
timeGreeting = "上午好"
|
||||||
|
} else if (hour >= 12 && hour < 14) {
|
||||||
|
timeGreeting = "中午好"
|
||||||
|
} else if (hour >= 14 && hour < 18) {
|
||||||
|
timeGreeting = "下午好"
|
||||||
|
} else {
|
||||||
|
timeGreeting = "晚上好"
|
||||||
|
}
|
||||||
|
|
||||||
|
setGreeting(timeGreeting)
|
||||||
|
}, [])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
<h1 className="text-3xl font-bold">欢迎使用超级管理员后台</h1>
|
<h1 className="text-3xl font-bold">欢迎使用超级管理员后台</h1>
|
||||||
<p className="text-muted-foreground">通过此平台,您可以管理项目、客户和管理员权限。</p>
|
<p className="text-muted-foreground">
|
||||||
|
{greeting},{userName}!通过此平台,您可以管理项目、客户和管理员权限。
|
||||||
|
</p>
|
||||||
|
|
||||||
<div className="grid gap-6 md:grid-cols-2 lg:grid-cols-3">
|
<div className="grid gap-6 md:grid-cols-2 lg:grid-cols-3">
|
||||||
<Card>
|
<Card>
|
||||||
|
|||||||
@@ -8,22 +8,55 @@ import { Button } from "@/components/ui/button"
|
|||||||
import { Input } from "@/components/ui/input"
|
import { Input } from "@/components/ui/input"
|
||||||
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card"
|
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card"
|
||||||
import { Label } from "@/components/ui/label"
|
import { Label } from "@/components/ui/label"
|
||||||
|
import { md5 } from "@/lib/utils"
|
||||||
|
|
||||||
export default function LoginPage() {
|
export default function LoginPage() {
|
||||||
const [username, setUsername] = useState("")
|
const [username, setUsername] = useState("")
|
||||||
const [password, setPassword] = useState("")
|
const [password, setPassword] = useState("")
|
||||||
const [isLoading, setIsLoading] = useState(false)
|
const [isLoading, setIsLoading] = useState(false)
|
||||||
|
const [error, setError] = useState("")
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
|
||||||
const handleLogin = async (e: React.FormEvent) => {
|
const handleLogin = async (e: React.FormEvent) => {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
setIsLoading(true)
|
setIsLoading(true)
|
||||||
|
setError("")
|
||||||
|
|
||||||
// Simulate login API call
|
try {
|
||||||
setTimeout(() => {
|
// 对密码进行MD5加密
|
||||||
|
const encryptedPassword = md5(password)
|
||||||
|
|
||||||
|
// 调用登录接口
|
||||||
|
const response = await fetch(`${process.env.NEXT_PUBLIC_API_BASE_URL}/auth/login`, {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
account: username,
|
||||||
|
password: encryptedPassword
|
||||||
|
}),
|
||||||
|
credentials: "include"
|
||||||
|
})
|
||||||
|
|
||||||
|
const result = await response.json()
|
||||||
|
|
||||||
|
if (result.code === 200) {
|
||||||
|
// 保存用户信息到本地存储
|
||||||
|
localStorage.setItem("admin_info", JSON.stringify(result.data))
|
||||||
|
localStorage.setItem("admin_token", result.data.token)
|
||||||
|
|
||||||
|
// 跳转到仪表盘
|
||||||
|
router.push("/dashboard")
|
||||||
|
} else {
|
||||||
|
setError(result.msg || "登录失败")
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error("登录失败:", err)
|
||||||
|
setError("网络错误,请稍后再试")
|
||||||
|
} finally {
|
||||||
setIsLoading(false)
|
setIsLoading(false)
|
||||||
router.push("/dashboard")
|
}
|
||||||
}, 1500)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -32,6 +65,7 @@ export default function LoginPage() {
|
|||||||
<CardHeader className="space-y-1">
|
<CardHeader className="space-y-1">
|
||||||
<CardTitle className="text-2xl text-center">超级管理员后台</CardTitle>
|
<CardTitle className="text-2xl text-center">超级管理员后台</CardTitle>
|
||||||
<CardDescription className="text-center">请输入您的账号和密码登录系统</CardDescription>
|
<CardDescription className="text-center">请输入您的账号和密码登录系统</CardDescription>
|
||||||
|
{error && <p className="text-sm text-red-500 text-center">{error}</p>}
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<form onSubmit={handleLogin}>
|
<form onSubmit={handleLogin}>
|
||||||
<CardContent className="space-y-4">
|
<CardContent className="space-y-4">
|
||||||
|
|||||||
19
SuperAdmin/hooks/useAuthCheck.ts
Normal file
19
SuperAdmin/hooks/useAuthCheck.ts
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import { useEffect } from 'react';
|
||||||
|
import { useRouter } from 'next/navigation';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查用户是否已登录的钩子
|
||||||
|
* @param redirectTo 如果未登录,重定向到的路径
|
||||||
|
*/
|
||||||
|
export default function useAuthCheck(redirectTo: string = '/login') {
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// 检查本地存储中是否有token
|
||||||
|
const token = localStorage.getItem('admin_token');
|
||||||
|
|
||||||
|
if (!token) {
|
||||||
|
router.push(redirectTo);
|
||||||
|
}
|
||||||
|
}, [redirectTo, router]);
|
||||||
|
}
|
||||||
@@ -1,6 +1,14 @@
|
|||||||
import { clsx, type ClassValue } from "clsx"
|
import { clsx, type ClassValue } from "clsx"
|
||||||
import { twMerge } from "tailwind-merge"
|
import { twMerge } from "tailwind-merge"
|
||||||
|
import crypto from "crypto"
|
||||||
|
|
||||||
export function cn(...inputs: ClassValue[]) {
|
export function cn(...inputs: ClassValue[]) {
|
||||||
return twMerge(clsx(inputs))
|
return twMerge(clsx(inputs))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MD5加密函数
|
||||||
|
*/
|
||||||
|
export function md5(text: string): string {
|
||||||
|
return crypto.createHash("md5").update(text).digest("hex")
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user