智慧教务系统
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

420 lines
15 KiB

<?php
// +----------------------------------------------------------------------
// | Niucloud-admin 企业快速开发的多应用管理平台
// +----------------------------------------------------------------------
// | 官方网址:https://www.niucloud.com
// +----------------------------------------------------------------------
// | niucloud团队 版权所有 开源版本可自由商用
// +----------------------------------------------------------------------
// | Author: Niucloud Team
// +----------------------------------------------------------------------
namespace app\service\api\login;
use app\dict\sys\AppTypeDict;
use app\model\member\Member;
use app\model\personnel\Personnel;
use app\model\site\Site;
use app\service\core\menu\CoreMenuService;
use core\util\TokenAuth;
use core\base\BaseService;
use core\exception\CommonException;
use think\facade\Cache;
/**
* 统一登录服务类
*/
class UnifiedLoginService extends BaseService
{
/**
* 用户类型常量
*/
const USER_TYPE_STAFF = 'staff'; // 员工端
const USER_TYPE_MEMBER = 'member'; // 会员端
/**
* 员工角色类型
*/
const STAFF_ROLE_MARKET = 1; // 市场人员
const STAFF_ROLE_COACH = 2; // 教练
const STAFF_ROLE_SALES = 3; // 销售
const STAFF_ROLE_TEACHER = 4; // 教师
/**
* 统一登录方法
* @param array $data
* @return array
* @throws \Exception
*/
public function unifiedLogin(array $data)
{
$username = trim($data['username']);
$password = trim($data['password']);
$loginType = trim($data['login_type']);
if (empty($username) || empty($password)) {
throw new CommonException('用户名和密码不能为空');
}
switch ($loginType) {
case self::USER_TYPE_STAFF:
return $this->handleStaffLogin($username, $password);
case self::USER_TYPE_MEMBER:
return $this->handleMemberLogin($username, $password);
default:
throw new CommonException('不支持的登录类型');
}
}
/**
* 员工端登录处理
* @param string $username
* @param string $password
* @return array
* @throws \Exception
*/
private function handleStaffLogin(string $username, string $password)
{
// 查找员工信息及关联的系统用户信息
$personnel = new Personnel();
$staffInfo = $personnel->alias('p')
->leftJoin('school_sys_user u', 'p.sys_user_id = u.uid')
->where('p.phone', $username)
->where('p.status', 2) // 2=已审核(正常状态)
->where('u.status', 1)
->field('p.*, u.username, u.password, u.real_name')
->find();
if (!$staffInfo) {
throw new CommonException('员工账号不存在或已禁用');
}
// 验证密码
if (!password_verify($password, $staffInfo['password'])) {
throw new CommonException('密码错误');
}
// 根据account_type确定角色类型
$roleType = $this->getAccountTypeCode($staffInfo['account_type']);
// 生成Token
$tokenData = [
'user_id' => $staffInfo['id'],
'user_type' => self::USER_TYPE_STAFF,
'role_type' => $roleType,
'site_id' => 0, // 默认站点ID
];
$tokenResult = TokenAuth::createToken($staffInfo['id'], AppTypeDict::PERSONNEL, $tokenData, 86400);
$token = $tokenResult['token'];
// 获取角色信息和菜单权限
$roleInfo = $this->getStaffRoleInfo($roleType);
$menuList = $this->getStaffMenuList($roleType);
return [
'token' => $token,
'user_info' => [
'id' => $staffInfo['id'],
'name' => $staffInfo['name'],
'phone' => $staffInfo['phone'],
'avatar' => $staffInfo['head_img'] ?? '',
'real_name' => $staffInfo['real_name'] ?? $staffInfo['name'],
'account_type' => $staffInfo['account_type'],
'employee_number' => $staffInfo['employee_number'],
'user_type' => self::USER_TYPE_STAFF,
'role_type' => $roleType,
],
'role_info' => $roleInfo,
'menu_list' => $menuList,
];
}
/**
* 会员端登录处理
* @param string $username
* @param string $password
* @return array
* @throws \Exception
*/
private function handleMemberLogin(string $username, string $password)
{
// 查找会员信息
$member = new Member();
$memberInfo = $member->where(function($query) use ($username) {
$query->where('username', $username)
->whereOr('mobile', $username);
})
->where('status', 1)
->find();
if (!$memberInfo) {
throw new CommonException('会员账号不存在或已禁用');
}
// 验证密码
if (!password_verify($password, $memberInfo['password'])) {
throw new CommonException('密码错误');
}
// 生成Token
$tokenData = [
'user_id' => $memberInfo['member_id'],
'user_type' => self::USER_TYPE_MEMBER,
'site_id' => $memberInfo['site_id'] ?? 0,
];
$tokenResult = TokenAuth::createToken($memberInfo['member_id'], AppTypeDict::API, $tokenData, 86400);
$token = $tokenResult['token'];
// 获取会员菜单权限
$menuList = $this->getMemberMenuList();
return [
'token' => $token,
'user_info' => [
'id' => $memberInfo['member_id'],
'username' => $memberInfo['username'],
'nickname' => $memberInfo['nickname'],
'mobile' => $memberInfo['mobile'],
'avatar' => $memberInfo['headimg'] ?? '',
'user_type' => self::USER_TYPE_MEMBER,
],
'role_info' => [
'role_name' => '会员',
'role_type' => 'member',
],
'menu_list' => $menuList,
];
}
/**
* 员工端登录(兼容旧接口)
* @param array $data
* @return array
*/
public function staffLogin(array $data)
{
$staffData = [
'username' => $data['phone'],
'password' => $data['password'],
'login_type' => self::USER_TYPE_STAFF,
];
$result = $this->unifiedLogin($staffData);
// 添加user_type到用户信息中用于前端判断
$result['user_info']['user_type_code'] = $data['user_type'];
return $result;
}
/**
* 会员端登录(兼容旧接口)
* @param array $data
* @return array
*/
public function memberLogin(array $data)
{
$memberData = [
'username' => $data['username'] ?: $data['mobile'],
'password' => $data['password'],
'login_type' => self::USER_TYPE_MEMBER,
];
return $this->unifiedLogin($memberData);
}
/**
* 获取员工角色信息
* @param int $roleType
* @return array
*/
private function getStaffRoleInfo(int $roleType)
{
$roles = [
self::STAFF_ROLE_MARKET => ['role_name' => '市场人员', 'role_code' => 'market'],
self::STAFF_ROLE_COACH => ['role_name' => '教练', 'role_code' => 'coach'],
self::STAFF_ROLE_SALES => ['role_name' => '销售人员', 'role_code' => 'sales'],
self::STAFF_ROLE_TEACHER => ['role_name' => '教师', 'role_code' => 'teacher'],
];
return $roles[$roleType] ?? ['role_name' => '教师', 'role_code' => 'teacher'];
}
/**
* 获取员工菜单列表
* @param int $roleType
* @return array
*/
private function getStaffMenuList(int $roleType)
{
// 根据角色类型返回对应的菜单权限
switch ($roleType) {
case self::STAFF_ROLE_MARKET:
return [
['path' => '/pages/market/home/index', 'name' => '首页', 'icon' => 'home'],
['path' => '/pages/market/clue/index', 'name' => '线索管理', 'icon' => 'clue'],
['path' => '/pages/market/clue/add_clues', 'name' => '添加客户', 'icon' => 'add'],
['path' => '/pages/market/data/statistics', 'name' => '数据统计', 'icon' => 'data'],
['path' => '/pages/market/my/index', 'name' => '个人中心', 'icon' => 'user'],
];
case self::STAFF_ROLE_COACH:
case self::STAFF_ROLE_TEACHER:
return [
['path' => '/pages/coach/home/index', 'name' => '首页', 'icon' => 'home'],
['path' => '/pages/coach/course/list', 'name' => '课表管理', 'icon' => 'course'],
['path' => '/pages/coach/student/student_list', 'name' => '我的学员', 'icon' => 'student'],
['path' => '/pages/coach/job/list', 'name' => '作业管理', 'icon' => 'job'],
['path' => '/pages/coach/my/index', 'name' => '个人中心', 'icon' => 'user'],
];
case self::STAFF_ROLE_SALES:
return [
['path' => '/pages/market/index/index', 'name' => '首页', 'icon' => 'home'],
['path' => '/pages/market/clue/index', 'name' => '线索管理', 'icon' => 'clue'],
['path' => '/pages/market/clue/add_clues', 'name' => '添加客户', 'icon' => 'add'],
['path' => '/pages/market/clue/clue_table', 'name' => '数据统计', 'icon' => 'data'],
['path' => '/pages/market/my/index', 'name' => '个人中心', 'icon' => 'user'],
];
default:
return [
['path' => '/pages/coach/home/index', 'name' => '首页', 'icon' => 'home'],
['path' => '/pages/coach/my/index', 'name' => '个人中心', 'icon' => 'user'],
];
}
}
/**
* 获取会员菜单列表
* @return array
*/
private function getMemberMenuList()
{
return [
['path' => '/pages/student/index/index', 'name' => '首页', 'icon' => 'home'],
['path' => '/pages/student/timetable/index', 'name' => '课表', 'icon' => 'timetable'],
['path' => '/pages/student/my/my', 'name' => '个人中心', 'icon' => 'user'],
// 家长端菜单
['path' => '/pages/parent/user-info/index', 'name' => '用户信息', 'icon' => 'user-info'],
['path' => '/pages/parent/courses/index', 'name' => '课程管理', 'icon' => 'course'],
['path' => '/pages/parent/materials/index', 'name' => '教学资料', 'icon' => 'material'],
['path' => '/pages/parent/services/index', 'name' => '服务管理', 'icon' => 'service'],
['path' => '/pages/parent/orders/index', 'name' => '订单管理', 'icon' => 'order'],
['path' => '/pages/parent/messages/index', 'name' => '消息管理', 'icon' => 'message'],
['path' => '/pages/parent/contracts/index', 'name' => '合同管理', 'icon' => 'contract'],
];
}
/**
* 登出
* @throws \Exception
*/
public function logout()
{
$token = request()->header('token');
if ($token) {
(new CoreTokenService())->delete($token);
}
}
/**
* 获取用户信息
* @return array
* @throws \Exception
*/
public function getUserInfo()
{
$token = request()->header('token');
if (!$token) {
throw new CommonException('未登录');
}
$tokenData = (new CoreTokenService())->verify($token);
if (!$tokenData) {
throw new CommonException('Token无效');
}
$userType = $tokenData['user_type'];
$userId = $tokenData['user_id'];
if ($userType === self::USER_TYPE_STAFF) {
$personnel = new Personnel();
$userInfo = $personnel->alias('p')
->leftJoin('school_sys_user u', 'p.sys_user_id = u.uid')
->where('p.id', $userId)
->field('p.*, u.real_name')
->find();
if (!$userInfo) {
throw new CommonException('员工信息不存在');
}
$roleType = $this->getAccountTypeCode($userInfo['account_type']);
return [
'id' => $userInfo['id'],
'name' => $userInfo['name'],
'phone' => $userInfo['phone'],
'avatar' => $userInfo['head_img'] ?? '',
'real_name' => $userInfo['real_name'] ?? $userInfo['name'],
'account_type' => $userInfo['account_type'],
'user_type' => self::USER_TYPE_STAFF,
'role_type' => $roleType,
];
} else {
$member = new Member();
$userInfo = $member->where('member_id', $userId)->find();
if (!$userInfo) {
throw new CommonException('会员信息不存在');
}
return [
'id' => $userInfo['member_id'],
'username' => $userInfo['username'],
'nickname' => $userInfo['nickname'],
'mobile' => $userInfo['mobile'],
'avatar' => $userInfo['headimg'] ?? '',
'user_type' => self::USER_TYPE_MEMBER,
];
}
}
/**
* 刷新Token
* @return array
* @throws \Exception
*/
public function refreshToken()
{
$token = request()->header('token');
if (!$token) {
throw new CommonException('未登录');
}
$newToken = (new CoreTokenService())->refresh($token);
if (!$newToken) {
throw new CommonException('Token刷新失败');
}
return ['token' => $newToken];
}
/**
* 根据账户类型获取角色编码
* @param string $accountType
* @return int
*/
private function getAccountTypeCode(string $accountType)
{
switch ($accountType) {
case 'teacher':
return self::STAFF_ROLE_TEACHER;
case 'market':
return self::STAFF_ROLE_MARKET;
default:
return self::STAFF_ROLE_TEACHER; // 默认为教师
}
}
}