db = $db; } public function index() { $this->checkLogin(); $this->checkAdmin(); $employees = $this->db->select('employees', '*', ['ORDER' => ['id' => 'DESC']]); $this->render('Admin/employees.php', compact('employees')); } public function update() { $this->checkLogin(); $this->checkAdmin(); $data = json_decode(file_get_contents('php://input'), true); $id = (int)($data['id'] ?? 0); $fields = [ 'emp_code' => trim($data['emp_code'] ?? ''), 'username' => trim($data['username'] ?? ''), 'real_name' => trim($data['real_name'] ?? ''), 'shift' => $data['shift'] ?? 'all', 'permissions' => json_encode($data['permissions'] ?? ['deposit','withdraw']), 'status' => (int)($data['status'] ?? 1), ]; if ($id > 0) { if (!empty($data['password'])) $fields['password'] = password_hash($data['password'], PASSWORD_DEFAULT); $this->db->update('employees', $fields, ['id' => $id]); } else { if (empty($data['password'])) { $this->json(['status'=>'error','message'=>'Password required']); return; } $fields['password'] = password_hash($data['password'], PASSWORD_DEFAULT); $this->db->insert('employees', $fields); } $this->json(['status' => 'success']); } public function delete($id) { $this->checkLogin(); $this->checkAdmin(); $this->db->delete('employees', ['id' => (int)$id]); $this->json(['status' => 'success']); } // 员工登录(独立入口) public function loginPage() { include ROOT_PATH . 'App/Views/Admin/employee_login.php'; } public function loginSubmit() { header('Content-Type: application/json'); $data = json_decode(file_get_contents('php://input'), true); $db = new Database(); $emp = $db->get('employees', '*', ['username' => trim($data['username'] ?? '')]); if (!$emp || !password_verify($data['password'] ?? '', $emp['password'])) { echo json_encode(['success' => false, 'message' => 'Invalid credentials']); return; } if (!$emp['status']) { echo json_encode(['success' => false, 'message' => 'Account disabled']); return; } // 班次检查 $hour = (int)date('H'); if ($emp['shift'] === 'day' && ($hour < 8 || $hour >= 20)) { echo json_encode(['success' => false, 'message' => 'Not your shift']); return; } if ($emp['shift'] === 'night' && ($hour >= 8 && $hour < 20)) { echo json_encode(['success' => false, 'message' => 'Not your shift']); return; } if (session_status() === PHP_SESSION_NONE) session_start(); $_SESSION['emp_id'] = $emp['id']; $_SESSION['emp_code'] = $emp['emp_code']; $_SESSION['emp_permissions'] = json_decode($emp['permissions'], true) ?: []; $_SESSION['emp_last_activity'] = time(); $db->update('employees', ['last_login' => date('Y-m-d H:i:s')], ['id' => $emp['id']]); echo json_encode(['success' => true, 'redirect' => '/employee/dashboard']); } // 员工操作面板(仅上下分) public function dashboard() { $this->checkEmployee(); $users = $this->db->select('users', ['id','username','balance','is_virtual'], [ 'is_virtual' => 0, 'ORDER' => ['username' => 'ASC'] ]); $logs = $this->db->select('employee_logs', '*', [ 'emp_id' => $_SESSION['emp_id'], 'ORDER' => ['id' => 'DESC'], 'LIMIT' => 50 ]); include ROOT_PATH . 'App/Views/Admin/employee_dashboard.php'; } public function adjustBalance() { $this->checkEmployee(); header('Content-Type: application/json'); $data = json_decode(file_get_contents('php://input'), true); $userId = (int)($data['user_id'] ?? 0); $action = $data['action'] ?? ''; // deposit / withdraw $amount = abs(floatval($data['amount'] ?? 0)); $remark = trim($data['remark'] ?? ''); $perms = $_SESSION['emp_permissions'] ?? []; if (!in_array($action, ['deposit','withdraw']) || !in_array($action, $perms)) { echo json_encode(['success' => false, 'message' => 'No permission']); return; } if ($amount <= 0 || $userId <= 0) { echo json_encode(['success' => false, 'message' => 'Invalid input']); return; } try { $this->db->medoo->pdo->beginTransaction(); $stmt = $this->db->medoo->pdo->prepare("SELECT balance FROM users WHERE id = :id FOR UPDATE"); $stmt->execute([':id' => $userId]); $user = $stmt->fetch(\PDO::FETCH_ASSOC); if (!$user) { $this->db->medoo->pdo->rollBack(); echo json_encode(['success'=>false,'message'=>'User not found']); return; } $old = (float)$user['balance']; $new = $action === 'deposit' ? $old + $amount : $old - $amount; if ($new < 0) { $this->db->medoo->pdo->rollBack(); echo json_encode(['success'=>false,'message'=>'Insufficient balance']); return; } $this->db->update('users', ['balance' => $new], ['id' => $userId]); $this->db->insert('transactions', [ 'user_id' => $userId, 'type' => 'manual_' . $action, 'amount' => $action === 'deposit' ? $amount : -$amount, 'balance_before' => $old, 'balance_after' => $new, 'description' => "Employee {$_SESSION['emp_code']}: $remark", 'operator_id' => $_SESSION['emp_id'], 'operator_type' => 'employee', 'created_at' => date('Y-m-d H:i:s'), ]); $this->db->insert('employee_logs', [ 'emp_id' => $_SESSION['emp_id'], 'action' => $action, 'target_user_id' => $userId, 'amount' => $amount, 'remark' => $remark, 'created_at' => date('Y-m-d H:i:s'), ]); $this->db->medoo->pdo->commit(); echo json_encode(['success' => true, 'new_balance' => $new]); } catch (\Throwable $e) { if ($this->db->medoo->pdo->inTransaction()) $this->db->medoo->pdo->rollBack(); echo json_encode(['success' => false, 'message' => 'Error']); } } private function checkEmployee() { if (session_status() === PHP_SESSION_NONE) session_start(); if (empty($_SESSION['emp_id'])) { header('Location: /employee/login'); exit; } if (time() - ($_SESSION['emp_last_activity'] ?? 0) > 7200) { unset($_SESSION['emp_id']); header('Location: /employee/login'); exit; } $_SESSION['emp_last_activity'] = time(); } private function json($data) { header('Content-Type: application/json'); echo json_encode($data); } }