24 changed files with 5069 additions and 323 deletions
@ -0,0 +1,98 @@ |
|||||
|
<?php |
||||
|
// +---------------------------------------------------------------------- |
||||
|
// | Niucloud-admin 企业快速开发的多应用管理平台 |
||||
|
// +---------------------------------------------------------------------- |
||||
|
// | 官方网址:https://www.niucloud.com |
||||
|
// +---------------------------------------------------------------------- |
||||
|
// | niucloud团队 版权所有 开源版本可自由商用 |
||||
|
// +---------------------------------------------------------------------- |
||||
|
// | Author: Niucloud Team |
||||
|
// +---------------------------------------------------------------------- |
||||
|
|
||||
|
namespace app\api\controller\apiController; |
||||
|
|
||||
|
use app\Request; |
||||
|
use app\service\api\apiService\StudentService; |
||||
|
use core\base\BaseApiService; |
||||
|
|
||||
|
/** |
||||
|
* 学员管理相关接口 |
||||
|
* Class StudentManager |
||||
|
* @package app\api\controller\apiController |
||||
|
*/ |
||||
|
class StudentManager extends BaseApiService |
||||
|
{ |
||||
|
/** |
||||
|
* 添加学员 |
||||
|
* @param Request $request |
||||
|
* @return \think\Response |
||||
|
*/ |
||||
|
public function add(Request $request) |
||||
|
{ |
||||
|
try { |
||||
|
$data = $this->request->params([ |
||||
|
["name", ""], |
||||
|
["gender", 0], |
||||
|
["age", 0.00], |
||||
|
["birthday", ""], |
||||
|
["user_id", 0], |
||||
|
["campus_id", 0], |
||||
|
["class_id", 0], |
||||
|
["note", ""], |
||||
|
["status", 1], |
||||
|
["emergency_contact", ""], |
||||
|
["contact_phone", ""], |
||||
|
["member_label", ""], |
||||
|
["consultant_id", ""], |
||||
|
["coach_id", ""], |
||||
|
["trial_class_count", 2] |
||||
|
]); |
||||
|
|
||||
|
// 表单验证 |
||||
|
if (empty($data['name'])) { |
||||
|
return fail('学员姓名不能为空'); |
||||
|
} |
||||
|
if ($data['gender'] == 0) { |
||||
|
return fail('请选择学员性别'); |
||||
|
} |
||||
|
if (empty($data['birthday'])) { |
||||
|
return fail('请选择学员出生日期'); |
||||
|
} |
||||
|
|
||||
|
$result = (new StudentService())->add($data); |
||||
|
if ($result['code'] === 1) { |
||||
|
return success('添加成功', $result['data']); |
||||
|
} else { |
||||
|
return fail($result['msg']); |
||||
|
} |
||||
|
} catch (\Exception $e) { |
||||
|
return fail('添加学员失败:' . $e->getMessage()); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取学员列表 |
||||
|
* @param Request $request |
||||
|
* @return \think\Response |
||||
|
*/ |
||||
|
public function list(Request $request) |
||||
|
{ |
||||
|
try { |
||||
|
$data = $this->request->params([ |
||||
|
["parent_resource_id", 0], |
||||
|
["user_id", 0], |
||||
|
["campus_id", 0], |
||||
|
["status", 0] |
||||
|
]); |
||||
|
|
||||
|
$result = (new StudentService())->getList($data); |
||||
|
if ($result['code'] === 1) { |
||||
|
return success('获取成功', $result['data']); |
||||
|
} else { |
||||
|
return fail($result['msg']); |
||||
|
} |
||||
|
} catch (\Exception $e) { |
||||
|
return fail('获取学员列表失败:' . $e->getMessage()); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,162 @@ |
|||||
|
<?php |
||||
|
// +---------------------------------------------------------------------- |
||||
|
// | Niucloud-admin 企业快速开发的多应用管理平台 |
||||
|
// +---------------------------------------------------------------------- |
||||
|
// | 官方网址:https://www.niucloud.com |
||||
|
// +---------------------------------------------------------------------- |
||||
|
// | niucloud团队 版权所有 开源版本可自由商用 |
||||
|
// +---------------------------------------------------------------------- |
||||
|
// | Author: Niucloud Team |
||||
|
// +---------------------------------------------------------------------- |
||||
|
|
||||
|
namespace app\api\controller\login; |
||||
|
|
||||
|
use app\service\api\login\LoginService; |
||||
|
use app\service\api\login\UnifiedLoginService; |
||||
|
use core\base\BaseController; |
||||
|
use think\Response; |
||||
|
|
||||
|
/** |
||||
|
* 统一登录控制器 |
||||
|
* 支持员工端和会员端两种登录方式 |
||||
|
*/ |
||||
|
class UnifiedLogin extends BaseController |
||||
|
{ |
||||
|
/** |
||||
|
* 统一登录接口 |
||||
|
* @return Response |
||||
|
*/ |
||||
|
public function login() |
||||
|
{ |
||||
|
$data = $this->request->params([ |
||||
|
['username', ''], // 用户名/手机号 |
||||
|
['password', ''], // 密码 |
||||
|
['login_type', ''], // 登录类型: staff=员工端, member=会员端 |
||||
|
]); |
||||
|
|
||||
|
// 参数验证 |
||||
|
$this->validate($data, [ |
||||
|
'username' => 'require', |
||||
|
'password' => 'require', |
||||
|
'login_type' => 'require|in:staff,member' |
||||
|
]); |
||||
|
|
||||
|
try { |
||||
|
$service = new UnifiedLoginService(); |
||||
|
$result = $service->unifiedLogin($data); |
||||
|
|
||||
|
if (!$result) { |
||||
|
return fail('登录失败,请检查用户名和密码'); |
||||
|
} |
||||
|
|
||||
|
return success($result, '登录成功'); |
||||
|
|
||||
|
} catch (\Exception $e) { |
||||
|
return fail($e->getMessage()); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 员工端登录(兼容旧接口) |
||||
|
* @return Response |
||||
|
*/ |
||||
|
public function staffLogin() |
||||
|
{ |
||||
|
$data = $this->request->params([ |
||||
|
['phone', ''], |
||||
|
['password', ''], |
||||
|
['user_type', ''], // 1=市场, 2=教练, 3=销售 |
||||
|
]); |
||||
|
|
||||
|
// 参数验证 |
||||
|
$this->validate($data, [ |
||||
|
'phone' => 'require|mobile', |
||||
|
'password' => 'require', |
||||
|
'user_type' => 'require|in:1,2,3' |
||||
|
]); |
||||
|
|
||||
|
try { |
||||
|
$service = new UnifiedLoginService(); |
||||
|
$result = $service->staffLogin($data); |
||||
|
|
||||
|
return success($result, '员工登录成功'); |
||||
|
|
||||
|
} catch (\Exception $e) { |
||||
|
return fail($e->getMessage()); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 会员端登录(兼容旧接口) |
||||
|
* @return Response |
||||
|
*/ |
||||
|
public function memberLogin() |
||||
|
{ |
||||
|
$data = $this->request->params([ |
||||
|
['username', ''], |
||||
|
['password', ''], |
||||
|
['mobile', ''], |
||||
|
]); |
||||
|
|
||||
|
try { |
||||
|
$service = new UnifiedLoginService(); |
||||
|
$result = $service->memberLogin($data); |
||||
|
|
||||
|
return success($result, '会员登录成功'); |
||||
|
|
||||
|
} catch (\Exception $e) { |
||||
|
return fail($e->getMessage()); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 登出 |
||||
|
* @return Response |
||||
|
*/ |
||||
|
public function logout() |
||||
|
{ |
||||
|
try { |
||||
|
$service = new UnifiedLoginService(); |
||||
|
$service->logout(); |
||||
|
|
||||
|
return success([], '登出成功'); |
||||
|
|
||||
|
} catch (\Exception $e) { |
||||
|
return fail($e->getMessage()); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取用户信息 |
||||
|
* @return Response |
||||
|
*/ |
||||
|
public function getUserInfo() |
||||
|
{ |
||||
|
try { |
||||
|
$service = new UnifiedLoginService(); |
||||
|
$result = $service->getUserInfo(); |
||||
|
|
||||
|
return success($result, '获取用户信息成功'); |
||||
|
|
||||
|
} catch (\Exception $e) { |
||||
|
return fail($e->getMessage()); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 刷新Token |
||||
|
* @return Response |
||||
|
*/ |
||||
|
public function refreshToken() |
||||
|
{ |
||||
|
try { |
||||
|
$service = new UnifiedLoginService(); |
||||
|
$result = $service->refreshToken(); |
||||
|
|
||||
|
return success($result, 'Token刷新成功'); |
||||
|
|
||||
|
} catch (\Exception $e) { |
||||
|
return fail($e->getMessage()); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,163 @@ |
|||||
|
<?php |
||||
|
// +---------------------------------------------------------------------- |
||||
|
// | Niucloud-admin 企业快速开发的多应用管理平台 |
||||
|
// +---------------------------------------------------------------------- |
||||
|
// | 官方网址:https://www.niucloud.com |
||||
|
// +---------------------------------------------------------------------- |
||||
|
// | niucloud团队 版权所有 开源版本可自由商用 |
||||
|
// +---------------------------------------------------------------------- |
||||
|
// | Author: Niucloud Team |
||||
|
// +---------------------------------------------------------------------- |
||||
|
|
||||
|
namespace app\service\api\apiService; |
||||
|
|
||||
|
use core\base\BaseApiService; |
||||
|
use think\facade\Db; |
||||
|
|
||||
|
/** |
||||
|
* 学员服务层 |
||||
|
* Class StudentService |
||||
|
* @package app\service\api\apiService |
||||
|
*/ |
||||
|
class StudentService extends BaseApiService |
||||
|
{ |
||||
|
public function __construct() |
||||
|
{ |
||||
|
parent::__construct(); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 添加学员 |
||||
|
* @param array $data |
||||
|
* @return array |
||||
|
*/ |
||||
|
public function add(array $data) |
||||
|
{ |
||||
|
$res = [ |
||||
|
'code' => 0, |
||||
|
'msg' => '操作失败', |
||||
|
'data' => [] |
||||
|
]; |
||||
|
|
||||
|
try { |
||||
|
// 准备插入数据 |
||||
|
$insertData = [ |
||||
|
'name' => $data['name'], |
||||
|
'gender' => $data['gender'], |
||||
|
'age' => $data['age'], |
||||
|
'birthday' => $data['birthday'], |
||||
|
'user_id' => $data['user_id'], |
||||
|
'campus_id' => $data['campus_id'], |
||||
|
'class_id' => $data['class_id'], |
||||
|
'note' => $data['note'], |
||||
|
'status' => $data['status'], |
||||
|
'emergency_contact' => $data['emergency_contact'], |
||||
|
'contact_phone' => $data['contact_phone'], |
||||
|
'member_label' => $data['member_label'], |
||||
|
'consultant_id' => $data['consultant_id'], |
||||
|
'coach_id' => $data['coach_id'], |
||||
|
'trial_class_count' => $data['trial_class_count'], |
||||
|
'created_at' => date('Y-m-d H:i:s'), |
||||
|
'updated_at' => date('Y-m-d H:i:s'), |
||||
|
'deleted_at' => 0 |
||||
|
]; |
||||
|
|
||||
|
// 插入数据库 |
||||
|
$id = Db::table('school_student')->insertGetId($insertData); |
||||
|
|
||||
|
if ($id) { |
||||
|
$res['code'] = 1; |
||||
|
$res['msg'] = '添加成功'; |
||||
|
$res['data'] = ['id' => $id]; |
||||
|
} else { |
||||
|
$res['msg'] = '添加失败'; |
||||
|
} |
||||
|
} catch (\Exception $e) { |
||||
|
$res['msg'] = '添加失败:' . $e->getMessage(); |
||||
|
} |
||||
|
|
||||
|
return $res; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取学员列表 |
||||
|
* @param array $data |
||||
|
* @return array |
||||
|
*/ |
||||
|
public function getList(array $data) |
||||
|
{ |
||||
|
$res = [ |
||||
|
'code' => 0, |
||||
|
'msg' => '操作失败', |
||||
|
'data' => [] |
||||
|
]; |
||||
|
|
||||
|
try { |
||||
|
$where = []; |
||||
|
$where[] = ['deleted_at', '=', 0]; |
||||
|
|
||||
|
if (!empty($data['user_id'])) { |
||||
|
$where[] = ['user_id', '=', $data['user_id']]; |
||||
|
} |
||||
|
|
||||
|
if (!empty($data['parent_resource_id'])) { |
||||
|
$where[] = ['user_id', '=', $data['parent_resource_id']]; |
||||
|
} |
||||
|
|
||||
|
if (!empty($data['campus_id'])) { |
||||
|
$where[] = ['campus_id', '=', $data['campus_id']]; |
||||
|
} |
||||
|
|
||||
|
if (!empty($data['status'])) { |
||||
|
$where[] = ['status', '=', $data['status']]; |
||||
|
} |
||||
|
|
||||
|
$list = Db::table('school_student') |
||||
|
->where($where) |
||||
|
->order('created_at', 'desc') |
||||
|
->select() |
||||
|
->toArray(); |
||||
|
|
||||
|
// 为每个学员添加到访情况信息 |
||||
|
foreach ($list as &$student) { |
||||
|
// 查询该学员的课程安排记录,按日期排序获取一访和二访信息 |
||||
|
$visitRecords = Db::table('school_person_course_schedule') |
||||
|
->where([ |
||||
|
['person_id', '=', $student['id']], |
||||
|
['person_type', '=', 'student'] |
||||
|
]) |
||||
|
->order('course_date', 'asc') |
||||
|
->select() |
||||
|
->toArray(); |
||||
|
|
||||
|
// 初始化到访信息 |
||||
|
$student['first_visit_time'] = ''; |
||||
|
$student['second_visit_time'] = ''; |
||||
|
$student['first_visit_status'] = '未到访'; |
||||
|
$student['second_visit_status'] = '未到访'; |
||||
|
|
||||
|
// 设置一访和二访信息 |
||||
|
if (!empty($visitRecords)) { |
||||
|
if (isset($visitRecords[0])) { |
||||
|
$student['first_visit_time'] = $visitRecords[0]['course_date']; |
||||
|
$student['first_visit_status'] = '已到访'; |
||||
|
} |
||||
|
if (isset($visitRecords[1])) { |
||||
|
$student['second_visit_time'] = $visitRecords[1]['course_date']; |
||||
|
$student['second_visit_status'] = '已到访'; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 保留原始访问记录数据供前端使用 |
||||
|
$student['visit_records'] = $visitRecords; |
||||
|
} |
||||
|
|
||||
|
$res['code'] = 1; |
||||
|
$res['data'] = $list; |
||||
|
} catch (\Exception $e) { |
||||
|
$res['msg'] = '获取失败:' . $e->getMessage(); |
||||
|
} |
||||
|
|
||||
|
return $res; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,420 @@ |
|||||
|
<?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; // 默认为教师 |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,73 @@ |
|||||
|
<script> |
||||
|
export default { |
||||
|
name: 'CustomTopPopup', |
||||
|
props: { |
||||
|
modelValue: { |
||||
|
type: Boolean, |
||||
|
default: false |
||||
|
} |
||||
|
}, |
||||
|
computed: { |
||||
|
show() { |
||||
|
return this.modelValue |
||||
|
} |
||||
|
}, |
||||
|
methods: { |
||||
|
closePopup() { |
||||
|
console.log('关闭弹窗') |
||||
|
this.$emit('update:modelValue', false) |
||||
|
}, |
||||
|
handleMaskClick() { |
||||
|
console.log('点击遮罩') |
||||
|
this.closePopup() |
||||
|
} |
||||
|
}, |
||||
|
mounted() { |
||||
|
console.log('CustomTopPopup mounted, modelValue:', this.modelValue) |
||||
|
}, |
||||
|
watch: { |
||||
|
modelValue(newVal) { |
||||
|
console.log('CustomTopPopup modelValue changed:', newVal) |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<template> |
||||
|
<view v-if="show" class="top-popup-mask" @tap="handleMaskClick"> |
||||
|
<view class="top-popup-content" @tap.stop> |
||||
|
<slot /> |
||||
|
</view> |
||||
|
</view> |
||||
|
</template> |
||||
|
|
||||
|
<style lang="scss"> |
||||
|
.top-popup-mask { |
||||
|
position: fixed; |
||||
|
top: 0; |
||||
|
left: 0; |
||||
|
right: 0; |
||||
|
bottom: 0; |
||||
|
background: rgba(0, 0, 0, 0.6); |
||||
|
z-index: 1001; |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
} |
||||
|
|
||||
|
.top-popup-content { |
||||
|
background: #fff; |
||||
|
border-bottom-left-radius: 24rpx; |
||||
|
border-bottom-right-radius: 24rpx; |
||||
|
animation: slideDown 0.3s ease-out; |
||||
|
width: 100%; |
||||
|
} |
||||
|
|
||||
|
@keyframes slideDown { |
||||
|
from { |
||||
|
transform: translateY(-100%); |
||||
|
} |
||||
|
to { |
||||
|
transform: translateY(0); |
||||
|
} |
||||
|
} |
||||
|
</style> |
||||
@ -0,0 +1,230 @@ |
|||||
|
<template> |
||||
|
<view class="home-container"> |
||||
|
<!-- 自定义导航栏 --> |
||||
|
<uni-nav-bar |
||||
|
:statusBar="true" |
||||
|
backgroundColor="#181A20" |
||||
|
color="#fff" |
||||
|
title="首页" |
||||
|
/> |
||||
|
|
||||
|
<!-- 用户信息区域 --> |
||||
|
<view class="user-info-section"> |
||||
|
<view class="user-avatar"> |
||||
|
<image :src="userInfo.avatar || '/static/icon-img/tou.png'" mode="aspectFill"></image> |
||||
|
</view> |
||||
|
<view class="user-details"> |
||||
|
<text class="user-name">{{ userInfo.name || '员工姓名' }}</text> |
||||
|
<text class="user-role">{{ (userInfo.role_info && userInfo.role_info.role_name) || '员工角色' }}</text> |
||||
|
<text class="user-number">工号:{{ userInfo.employee_number || '未设置' }}</text> |
||||
|
</view> |
||||
|
</view> |
||||
|
|
||||
|
<!-- 九宫格操作区域 --> |
||||
|
<view class="grid-container"> |
||||
|
<view class="grid-title">员工操作</view> |
||||
|
<view class="grid-content"> |
||||
|
<view |
||||
|
class="grid-item" |
||||
|
v-for="(item, index) in gridItems" |
||||
|
:key="index" |
||||
|
@click="handleGridClick(item)" |
||||
|
> |
||||
|
<view class="grid-icon"> |
||||
|
<uni-icons :type="item.icon" size="32" color="#29d3b4"></uni-icons> |
||||
|
</view> |
||||
|
<text class="grid-text">{{ item.title }}</text> |
||||
|
</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
</template> |
||||
|
|
||||
|
<script> |
||||
|
export default { |
||||
|
data() { |
||||
|
return { |
||||
|
userInfo: {}, |
||||
|
gridItems: [ |
||||
|
{ |
||||
|
title: '客户资源', |
||||
|
icon: 'person-filled', |
||||
|
path: '/pages/market/clue/index' |
||||
|
}, |
||||
|
{ |
||||
|
title: '课程安排', |
||||
|
icon: 'calendar-filled', |
||||
|
path: '/pages/market/clue/class_arrangement' |
||||
|
}, |
||||
|
{ |
||||
|
title: '课程查询', |
||||
|
icon: 'search', |
||||
|
path: '/pages/coach/schedule/schedule_table' |
||||
|
}, |
||||
|
{ |
||||
|
title: '学员管理', |
||||
|
icon: 'contact-filled', |
||||
|
path: '/pages/coach/student/student_list' |
||||
|
}, |
||||
|
{ |
||||
|
title: '我的数据', |
||||
|
icon: 'bars', |
||||
|
path: '/pages/market/my/my_data' |
||||
|
}, |
||||
|
{ |
||||
|
title: '部门数据', |
||||
|
icon: 'staff', |
||||
|
path: '/pages/market/my/dept_data' |
||||
|
}, |
||||
|
{ |
||||
|
title: '校区数据', |
||||
|
icon: 'location-filled', |
||||
|
path: '/pages/market/my/campus_data' |
||||
|
}, |
||||
|
{ |
||||
|
title: '考勤管理', |
||||
|
icon: 'checkmarkempty', |
||||
|
path: '/pages/common/my_attendance' |
||||
|
}, |
||||
|
{ |
||||
|
title: '我的消息', |
||||
|
icon: 'chat-filled', |
||||
|
path: '/pages/common/my_message' |
||||
|
}, |
||||
|
{ |
||||
|
title: '报销管理', |
||||
|
icon: 'wallet-filled', |
||||
|
path: '/pages/market/reimbursement/list' |
||||
|
}, |
||||
|
{ |
||||
|
title: '资料库', |
||||
|
icon: 'folder-add-filled', |
||||
|
path: '/pages/coach/my/teaching_management' |
||||
|
} |
||||
|
] |
||||
|
} |
||||
|
}, |
||||
|
onLoad() { |
||||
|
this.loadUserInfo(); |
||||
|
}, |
||||
|
methods: { |
||||
|
loadUserInfo() { |
||||
|
// 从本地存储获取用户信息 |
||||
|
const userInfo = uni.getStorageSync('userInfo'); |
||||
|
if (userInfo) { |
||||
|
this.userInfo = userInfo; |
||||
|
} |
||||
|
}, |
||||
|
handleGridClick(item) { |
||||
|
uni.navigateTo({ |
||||
|
url: item.path, |
||||
|
fail: (err) => { |
||||
|
console.error('页面跳转失败:', err); |
||||
|
uni.showToast({ |
||||
|
title: '页面暂未开放', |
||||
|
icon: 'none' |
||||
|
}); |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<style scoped> |
||||
|
.home-container { |
||||
|
background-color: #181A20; |
||||
|
min-height: 100vh; |
||||
|
color: #fff; |
||||
|
} |
||||
|
|
||||
|
.user-info-section { |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
padding: 20px; |
||||
|
background: linear-gradient(135deg, #29d3b4 0%, #1a9b7c 100%); |
||||
|
margin: 20px; |
||||
|
border-radius: 12px; |
||||
|
} |
||||
|
|
||||
|
.user-avatar { |
||||
|
width: 60px; |
||||
|
height: 60px; |
||||
|
margin-right: 15px; |
||||
|
} |
||||
|
|
||||
|
.user-avatar image { |
||||
|
width: 100%; |
||||
|
height: 100%; |
||||
|
border-radius: 50%; |
||||
|
} |
||||
|
|
||||
|
.user-details { |
||||
|
flex: 1; |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
} |
||||
|
|
||||
|
.user-name { |
||||
|
font-size: 18px; |
||||
|
font-weight: bold; |
||||
|
margin-bottom: 5px; |
||||
|
color: #fff; |
||||
|
} |
||||
|
|
||||
|
.user-role { |
||||
|
font-size: 14px; |
||||
|
color: rgba(255, 255, 255, 0.8); |
||||
|
margin-bottom: 3px; |
||||
|
} |
||||
|
|
||||
|
.user-number { |
||||
|
font-size: 12px; |
||||
|
color: rgba(255, 255, 255, 0.6); |
||||
|
} |
||||
|
|
||||
|
.grid-container { |
||||
|
margin: 20px; |
||||
|
} |
||||
|
|
||||
|
.grid-title { |
||||
|
font-size: 16px; |
||||
|
font-weight: bold; |
||||
|
margin-bottom: 15px; |
||||
|
color: #fff; |
||||
|
} |
||||
|
|
||||
|
.grid-content { |
||||
|
display: grid; |
||||
|
grid-template-columns: repeat(3, 1fr); |
||||
|
gap: 15px; |
||||
|
} |
||||
|
|
||||
|
.grid-item { |
||||
|
background-color: #292929; |
||||
|
border-radius: 8px; |
||||
|
padding: 20px 10px; |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
align-items: center; |
||||
|
justify-content: center; |
||||
|
min-height: 80px; |
||||
|
transition: all 0.3s ease; |
||||
|
} |
||||
|
|
||||
|
.grid-item:active { |
||||
|
background-color: #3a3a3a; |
||||
|
transform: scale(0.95); |
||||
|
} |
||||
|
|
||||
|
.grid-icon { |
||||
|
margin-bottom: 8px; |
||||
|
} |
||||
|
|
||||
|
.grid-text { |
||||
|
font-size: 12px; |
||||
|
color: #fff; |
||||
|
text-align: center; |
||||
|
line-height: 1.2; |
||||
|
} |
||||
|
</style> |
||||
@ -0,0 +1,245 @@ |
|||||
|
<template> |
||||
|
<view class="profile-container"> |
||||
|
<!-- 自定义导航栏 --> |
||||
|
<uni-nav-bar |
||||
|
:statusBar="true" |
||||
|
backgroundColor="#181A20" |
||||
|
color="#fff" |
||||
|
title="我的" |
||||
|
/> |
||||
|
|
||||
|
<!-- 用户头像和基本信息 --> |
||||
|
<view class="profile-header"> |
||||
|
<view class="avatar-section"> |
||||
|
<image :src="userInfo.avatar || '/static/icon-img/tou.png'" mode="aspectFill"></image> |
||||
|
</view> |
||||
|
<view class="user-info"> |
||||
|
<text class="user-name">{{ userInfo.name || '员工姓名' }}</text> |
||||
|
<text class="user-role">{{ (userInfo.role_info && userInfo.role_info.role_name) || '员工角色' }}</text> |
||||
|
<text class="user-phone">{{ userInfo.phone || '手机号码' }}</text> |
||||
|
</view> |
||||
|
</view> |
||||
|
|
||||
|
<!-- 我的功能九宫格 --> |
||||
|
<view class="grid-container"> |
||||
|
<view class="grid-title">个人中心</view> |
||||
|
<view class="grid-content"> |
||||
|
<view |
||||
|
class="grid-item" |
||||
|
v-for="(item, index) in profileItems" |
||||
|
:key="index" |
||||
|
@click="handleProfileClick(item)" |
||||
|
> |
||||
|
<view class="grid-icon"> |
||||
|
<uni-icons :type="item.icon" size="32" color="#29d3b4"></uni-icons> |
||||
|
</view> |
||||
|
<text class="grid-text">{{ item.title }}</text> |
||||
|
<text class="grid-desc" v-if="item.desc">{{ item.desc }}</text> |
||||
|
</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
</template> |
||||
|
|
||||
|
<script> |
||||
|
export default { |
||||
|
data() { |
||||
|
return { |
||||
|
userInfo: {}, |
||||
|
profileItems: [ |
||||
|
{ |
||||
|
title: '我的资料', |
||||
|
icon: 'contact', |
||||
|
desc: '查看编辑个人信息', |
||||
|
action: 'viewProfile' |
||||
|
}, |
||||
|
{ |
||||
|
title: '我的合同', |
||||
|
icon: 'compose', |
||||
|
path: '/pages/parent/contracts/index' |
||||
|
}, |
||||
|
{ |
||||
|
title: '我的工资', |
||||
|
icon: 'wallet', |
||||
|
desc: '查看工资明细', |
||||
|
action: 'viewSalary' |
||||
|
}, |
||||
|
{ |
||||
|
title: '我的考勤', |
||||
|
icon: 'calendar', |
||||
|
path: '/pages/common/my_attendance' |
||||
|
}, |
||||
|
{ |
||||
|
title: '系统设置', |
||||
|
icon: 'settings', |
||||
|
path: '/pages/market/my/set_up' |
||||
|
} |
||||
|
] |
||||
|
} |
||||
|
}, |
||||
|
onLoad() { |
||||
|
this.loadUserInfo(); |
||||
|
}, |
||||
|
onShow() { |
||||
|
this.loadUserInfo(); |
||||
|
}, |
||||
|
methods: { |
||||
|
loadUserInfo() { |
||||
|
// 从本地存储获取用户信息 |
||||
|
const userInfo = uni.getStorageSync('userInfo'); |
||||
|
if (userInfo) { |
||||
|
this.userInfo = userInfo; |
||||
|
} |
||||
|
}, |
||||
|
handleProfileClick(item) { |
||||
|
if (item.action) { |
||||
|
// 处理特殊操作 |
||||
|
switch (item.action) { |
||||
|
case 'viewProfile': |
||||
|
this.viewPersonalProfile(); |
||||
|
break; |
||||
|
case 'viewSalary': |
||||
|
this.viewSalaryInfo(); |
||||
|
break; |
||||
|
} |
||||
|
} else if (item.path) { |
||||
|
// 页面跳转 |
||||
|
uni.navigateTo({ |
||||
|
url: item.path, |
||||
|
fail: (err) => { |
||||
|
console.error('页面跳转失败:', err); |
||||
|
uni.showToast({ |
||||
|
title: '页面暂未开放', |
||||
|
icon: 'none' |
||||
|
}); |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
}, |
||||
|
viewPersonalProfile() { |
||||
|
// 显示个人资料弹窗或跳转到编辑页面 |
||||
|
uni.showModal({ |
||||
|
title: '个人资料', |
||||
|
content: '个人资料页面开发中,将包含employee_number、name、phone、email、address等字段的查看和编辑功能', |
||||
|
showCancel: false |
||||
|
}); |
||||
|
}, |
||||
|
viewSalaryInfo() { |
||||
|
// 显示工资信息弹窗或跳转到工资页面 |
||||
|
uni.showModal({ |
||||
|
title: '工资明细', |
||||
|
content: '工资明细页面开发中,将显示base_salary、performance_bonus、deductions、net_salary等字段,只能查看不能修改', |
||||
|
showCancel: false |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<style scoped> |
||||
|
.profile-container { |
||||
|
background-color: #181A20; |
||||
|
min-height: 100vh; |
||||
|
color: #fff; |
||||
|
} |
||||
|
|
||||
|
.profile-header { |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
padding: 30px 20px; |
||||
|
background: linear-gradient(135deg, #29d3b4 0%, #1a9b7c 100%); |
||||
|
margin: 20px; |
||||
|
border-radius: 12px; |
||||
|
} |
||||
|
|
||||
|
.avatar-section { |
||||
|
width: 80px; |
||||
|
height: 80px; |
||||
|
margin-right: 20px; |
||||
|
} |
||||
|
|
||||
|
.avatar-section image { |
||||
|
width: 100%; |
||||
|
height: 100%; |
||||
|
border-radius: 50%; |
||||
|
border: 3px solid rgba(255, 255, 255, 0.3); |
||||
|
} |
||||
|
|
||||
|
.user-info { |
||||
|
flex: 1; |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
} |
||||
|
|
||||
|
.user-name { |
||||
|
font-size: 20px; |
||||
|
font-weight: bold; |
||||
|
margin-bottom: 8px; |
||||
|
color: #fff; |
||||
|
} |
||||
|
|
||||
|
.user-role { |
||||
|
font-size: 14px; |
||||
|
color: rgba(255, 255, 255, 0.8); |
||||
|
margin-bottom: 5px; |
||||
|
} |
||||
|
|
||||
|
.user-phone { |
||||
|
font-size: 12px; |
||||
|
color: rgba(255, 255, 255, 0.6); |
||||
|
} |
||||
|
|
||||
|
.grid-container { |
||||
|
margin: 20px; |
||||
|
} |
||||
|
|
||||
|
.grid-title { |
||||
|
font-size: 16px; |
||||
|
font-weight: bold; |
||||
|
margin-bottom: 15px; |
||||
|
color: #fff; |
||||
|
} |
||||
|
|
||||
|
.grid-content { |
||||
|
display: grid; |
||||
|
grid-template-columns: repeat(3, 1fr); |
||||
|
gap: 15px; |
||||
|
} |
||||
|
|
||||
|
.grid-item { |
||||
|
background-color: #292929; |
||||
|
border-radius: 8px; |
||||
|
padding: 20px 10px; |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
align-items: center; |
||||
|
justify-content: center; |
||||
|
min-height: 90px; |
||||
|
transition: all 0.3s ease; |
||||
|
} |
||||
|
|
||||
|
.grid-item:active { |
||||
|
background-color: #3a3a3a; |
||||
|
transform: scale(0.95); |
||||
|
} |
||||
|
|
||||
|
.grid-icon { |
||||
|
margin-bottom: 8px; |
||||
|
} |
||||
|
|
||||
|
.grid-text { |
||||
|
font-size: 12px; |
||||
|
color: #fff; |
||||
|
text-align: center; |
||||
|
line-height: 1.2; |
||||
|
margin-bottom: 3px; |
||||
|
font-weight: bold; |
||||
|
} |
||||
|
|
||||
|
.grid-desc { |
||||
|
font-size: 10px; |
||||
|
color: rgba(255, 255, 255, 0.6); |
||||
|
text-align: center; |
||||
|
line-height: 1.1; |
||||
|
} |
||||
|
</style> |
||||
File diff suppressed because it is too large
|
After Width: | Height: | Size: 36 KiB |
|
After Width: | Height: | Size: 36 KiB |
|
After Width: | Height: | Size: 36 KiB |
|
After Width: | Height: | Size: 36 KiB |
Loading…
Reference in new issue