541 lines
22 KiB
PHP
541 lines
22 KiB
PHP
<?php
|
|
namespace app\controllers;
|
|
|
|
use core\base\Controller;
|
|
use app\models\HrEmployee;
|
|
use app\models\Asset;
|
|
use app\models\Document;
|
|
|
|
/**
|
|
* 综合管理控制器
|
|
* 访问权限:超级管理员 或 综合管理类目管理员
|
|
*/
|
|
class GeneralController extends Controller
|
|
{
|
|
private function checkCategoryAccess()
|
|
{
|
|
$this->checkLogin();
|
|
$user = $this->getCurrentUser();
|
|
|
|
if ($user['role'] === self::ROLE_SUPER_ADMIN) {
|
|
return $user;
|
|
}
|
|
if ($user['role'] === self::ROLE_ADMIN && ($user['category'] ?? '') === self::CATEGORY_GENERAL) {
|
|
return $user;
|
|
}
|
|
header('Location: ' . BASE_URL . '/Front/index');
|
|
exit;
|
|
}
|
|
|
|
public function index()
|
|
{
|
|
$user = $this->checkCategoryAccess();
|
|
|
|
$hrEmployee = new HrEmployee();
|
|
$asset = new Asset();
|
|
$document = new Document();
|
|
|
|
$this->assign('title', '综合管理概览');
|
|
$this->assign('user', $user);
|
|
$this->assign('activeMenu', 'general_dashboard');
|
|
$this->assign('employeeCount', $hrEmployee->getCount());
|
|
$this->assign('assetStats', $asset->getCount());
|
|
$this->assign('documentCount', $document->getCount());
|
|
$this->render();
|
|
}
|
|
|
|
// ========== 人事管理 ==========
|
|
public function hr()
|
|
{
|
|
$user = $this->checkCategoryAccess();
|
|
$hrEmployee = new HrEmployee();
|
|
$employees = $hrEmployee->getAll();
|
|
|
|
$this->assign('title', '人事管理');
|
|
$this->assign('user', $user);
|
|
$this->assign('activeMenu', 'hr');
|
|
$this->assign('employees', $employees);
|
|
$this->render();
|
|
}
|
|
|
|
public function hrAdd()
|
|
{
|
|
$user = $this->checkCategoryAccess();
|
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|
$this->csrfVerify();
|
|
$data = [
|
|
'emp_no' => trim($_POST['emp_no'] ?? ''),
|
|
'name' => trim($_POST['name'] ?? ''),
|
|
'gender' => trim($_POST['gender'] ?? ''),
|
|
'department' => trim($_POST['department'] ?? ''),
|
|
'position' => trim($_POST['position'] ?? ''),
|
|
'phone' => trim($_POST['phone'] ?? ''),
|
|
'email' => trim($_POST['email'] ?? ''),
|
|
'id_card' => trim($_POST['id_card'] ?? ''),
|
|
'entry_date' => trim($_POST['entry_date'] ?? ''),
|
|
'status' => trim($_POST['status'] ?? 'active'),
|
|
'education' => trim($_POST['education'] ?? ''),
|
|
'emergency_contact' => trim($_POST['emergency_contact'] ?? ''),
|
|
'emergency_phone' => trim($_POST['emergency_phone'] ?? ''),
|
|
'address' => trim($_POST['address'] ?? ''),
|
|
'remark' => trim($_POST['remark'] ?? ''),
|
|
];
|
|
if (empty($data['name'])) {
|
|
$this->assign('error', '姓名不能为空');
|
|
$this->assign('title', '添加员工');
|
|
$this->assign('user', $user);
|
|
$this->assign('activeMenu', 'hr');
|
|
$this->assign('csrfToken', $this->csrfToken());
|
|
$this->render();
|
|
return;
|
|
}
|
|
try {
|
|
$hrEmployee = new HrEmployee();
|
|
$hrEmployee->add($data);
|
|
header('Location: ' . BASE_URL . '/General/hr');
|
|
exit;
|
|
} catch (\Throwable $e) {
|
|
error_log('[hrAdd] ' . $e->getMessage());
|
|
$this->assign('error', '添加失败:' . $e->getMessage());
|
|
$this->assign('title', '添加员工');
|
|
$this->assign('user', $user);
|
|
$this->assign('activeMenu', 'hr');
|
|
$this->assign('csrfToken', $this->csrfToken());
|
|
$this->render();
|
|
return;
|
|
}
|
|
}
|
|
|
|
$this->assign('title', '添加员工');
|
|
$this->assign('user', $user);
|
|
$this->assign('activeMenu', 'hr');
|
|
$this->assign('csrfToken', $this->csrfToken());
|
|
$this->render();
|
|
}
|
|
|
|
public function hrEdit()
|
|
{
|
|
$user = $this->checkCategoryAccess();
|
|
$id = (int)($_GET['id'] ?? 0);
|
|
$hrEmployee = new HrEmployee();
|
|
$record = $hrEmployee->getById($id);
|
|
if (!$record) exit('员工不存在');
|
|
|
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|
$this->csrfVerify();
|
|
$data = [
|
|
'emp_no' => trim($_POST['emp_no'] ?? ''),
|
|
'name' => trim($_POST['name'] ?? ''),
|
|
'gender' => trim($_POST['gender'] ?? ''),
|
|
'department' => trim($_POST['department'] ?? ''),
|
|
'position' => trim($_POST['position'] ?? ''),
|
|
'phone' => trim($_POST['phone'] ?? ''),
|
|
'email' => trim($_POST['email'] ?? ''),
|
|
'id_card' => trim($_POST['id_card'] ?? ''),
|
|
'entry_date' => trim($_POST['entry_date'] ?? ''),
|
|
'leave_date' => trim($_POST['leave_date'] ?? ''),
|
|
'status' => trim($_POST['status'] ?? 'active'),
|
|
'education' => trim($_POST['education'] ?? ''),
|
|
'emergency_contact' => trim($_POST['emergency_contact'] ?? ''),
|
|
'emergency_phone' => trim($_POST['emergency_phone'] ?? ''),
|
|
'address' => trim($_POST['address'] ?? ''),
|
|
'remark' => trim($_POST['remark'] ?? ''),
|
|
];
|
|
try {
|
|
$hrEmployee->where(['id = :id'], [':id' => $id])->update($data);
|
|
header('Location: ' . BASE_URL . '/General/hr');
|
|
exit;
|
|
} catch (\Throwable $e) {
|
|
error_log('[hrEdit] ' . $e->getMessage());
|
|
$this->assign('error', '更新失败:' . $e->getMessage());
|
|
$this->assign('title', '编辑员工');
|
|
$this->assign('user', $user);
|
|
$this->assign('activeMenu', 'hr');
|
|
$this->assign('record', $record);
|
|
$this->assign('csrfToken', $this->csrfToken());
|
|
$this->render();
|
|
return;
|
|
}
|
|
}
|
|
|
|
$this->assign('title', '编辑员工');
|
|
$this->assign('user', $user);
|
|
$this->assign('activeMenu', 'hr');
|
|
$this->assign('record', $record);
|
|
$this->assign('csrfToken', $this->csrfToken());
|
|
$this->render();
|
|
}
|
|
|
|
public function hrDelete()
|
|
{
|
|
$this->checkLogin();
|
|
$this->requireMethod('post');
|
|
$this->csrfVerify();
|
|
$id = (int)($_POST['id'] ?? 0);
|
|
$hrEmployee = new HrEmployee();
|
|
$hrEmployee->delete($id);
|
|
header('Location: ' . BASE_URL . '/General/hr');
|
|
exit;
|
|
}
|
|
|
|
// ========== 资产管理 ==========
|
|
public function asset()
|
|
{
|
|
$user = $this->checkCategoryAccess();
|
|
$asset = new Asset();
|
|
$assets = $asset->getAll();
|
|
|
|
$this->assign('title', '资产管理');
|
|
$this->assign('user', $user);
|
|
$this->assign('activeMenu', 'asset');
|
|
$this->assign('assets', $assets);
|
|
$this->render();
|
|
}
|
|
|
|
public function assetAdd()
|
|
{
|
|
$user = $this->checkCategoryAccess();
|
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|
$this->csrfVerify();
|
|
$data = [
|
|
'asset_no' => trim($_POST['asset_no'] ?? ''),
|
|
'name' => trim($_POST['name'] ?? ''),
|
|
'category' => trim($_POST['category'] ?? ''),
|
|
'model' => trim($_POST['model'] ?? ''),
|
|
'quantity' => (int)($_POST['quantity'] ?? 1),
|
|
'unit' => trim($_POST['unit'] ?? '台'),
|
|
'purchase_price' => (float)($_POST['purchase_price'] ?? 0),
|
|
'purchase_date' => trim($_POST['purchase_date'] ?? ''),
|
|
'supplier' => trim($_POST['supplier'] ?? ''),
|
|
'department' => trim($_POST['department'] ?? ''),
|
|
'user_name' => trim($_POST['user_name'] ?? ''),
|
|
'location' => trim($_POST['location'] ?? ''),
|
|
'status' => trim($_POST['status'] ?? 'normal'),
|
|
'warranty_expire' => trim($_POST['warranty_expire'] ?? ''),
|
|
'remark' => trim($_POST['remark'] ?? ''),
|
|
];
|
|
if (empty($data['name'])) {
|
|
$this->assign('error', '资产名称不能为空');
|
|
$this->assign('title', '添加资产');
|
|
$this->assign('user', $user);
|
|
$this->assign('activeMenu', 'asset');
|
|
$this->assign('csrfToken', $this->csrfToken());
|
|
$this->render();
|
|
return;
|
|
}
|
|
try {
|
|
$asset = new Asset();
|
|
$asset->add($data);
|
|
header('Location: ' . BASE_URL . '/General/asset');
|
|
exit;
|
|
} catch (\Throwable $e) {
|
|
error_log('[assetAdd] ' . $e->getMessage());
|
|
$this->assign('error', '添加失败:' . $e->getMessage());
|
|
$this->assign('title', '添加资产');
|
|
$this->assign('user', $user);
|
|
$this->assign('activeMenu', 'asset');
|
|
$this->assign('csrfToken', $this->csrfToken());
|
|
$this->render();
|
|
return;
|
|
}
|
|
}
|
|
|
|
$this->assign('title', '添加资产');
|
|
$this->assign('user', $user);
|
|
$this->assign('activeMenu', 'asset');
|
|
$this->assign('csrfToken', $this->csrfToken());
|
|
$this->render();
|
|
}
|
|
|
|
public function assetEdit()
|
|
{
|
|
$user = $this->checkCategoryAccess();
|
|
$id = (int)($_GET['id'] ?? 0);
|
|
$asset = new Asset();
|
|
$record = $asset->getById($id);
|
|
if (!$record) exit('资产不存在');
|
|
|
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|
$this->csrfVerify();
|
|
$data = [
|
|
'asset_no' => trim($_POST['asset_no'] ?? ''),
|
|
'name' => trim($_POST['name'] ?? ''),
|
|
'category' => trim($_POST['category'] ?? ''),
|
|
'model' => trim($_POST['model'] ?? ''),
|
|
'quantity' => (int)($_POST['quantity'] ?? 1),
|
|
'unit' => trim($_POST['unit'] ?? '台'),
|
|
'purchase_price' => (float)($_POST['purchase_price'] ?? 0),
|
|
'purchase_date' => trim($_POST['purchase_date'] ?? ''),
|
|
'supplier' => trim($_POST['supplier'] ?? ''),
|
|
'department' => trim($_POST['department'] ?? ''),
|
|
'user_name' => trim($_POST['user_name'] ?? ''),
|
|
'location' => trim($_POST['location'] ?? ''),
|
|
'status' => trim($_POST['status'] ?? 'normal'),
|
|
'warranty_expire' => trim($_POST['warranty_expire'] ?? ''),
|
|
'remark' => trim($_POST['remark'] ?? ''),
|
|
];
|
|
try {
|
|
$asset->where(['id = :id'], [':id' => $id])->update($data);
|
|
header('Location: ' . BASE_URL . '/General/asset');
|
|
exit;
|
|
} catch (\Throwable $e) {
|
|
error_log('[assetEdit] ' . $e->getMessage());
|
|
$this->assign('error', '更新失败:' . $e->getMessage());
|
|
$this->assign('title', '编辑资产');
|
|
$this->assign('user', $user);
|
|
$this->assign('activeMenu', 'asset');
|
|
$this->assign('record', $record);
|
|
$this->assign('csrfToken', $this->csrfToken());
|
|
$this->render();
|
|
return;
|
|
}
|
|
}
|
|
|
|
$this->assign('title', '编辑资产');
|
|
$this->assign('user', $user);
|
|
$this->assign('activeMenu', 'asset');
|
|
$this->assign('record', $record);
|
|
$this->assign('csrfToken', $this->csrfToken());
|
|
$this->render();
|
|
}
|
|
|
|
public function assetDelete()
|
|
{
|
|
$this->checkLogin();
|
|
$this->requireMethod('post');
|
|
$this->csrfVerify();
|
|
$id = (int)($_POST['id'] ?? 0);
|
|
$asset = new Asset();
|
|
$asset->delete($id);
|
|
header('Location: ' . BASE_URL . '/General/asset');
|
|
exit;
|
|
}
|
|
|
|
// ========== 文档管理 ==========
|
|
public function document()
|
|
{
|
|
$user = $this->checkCategoryAccess();
|
|
$document = new Document();
|
|
$documents = $document->getAll();
|
|
$categories = $document->getCategories();
|
|
|
|
$this->assign('title', '文档管理');
|
|
$this->assign('user', $user);
|
|
$this->assign('activeMenu', 'document');
|
|
$this->assign('documents', $documents);
|
|
$this->assign('categories', $categories);
|
|
$this->render();
|
|
}
|
|
|
|
public function documentAdd()
|
|
{
|
|
$user = $this->checkCategoryAccess();
|
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|
$this->csrfVerify();
|
|
$data = [
|
|
'title' => trim($_POST['title'] ?? ''),
|
|
'doc_no' => trim($_POST['doc_no'] ?? ''),
|
|
'category' => trim($_POST['category'] ?? ''),
|
|
'version' => trim($_POST['version'] ?? '1.0'),
|
|
'author' => trim($_POST['author'] ?? ''),
|
|
'department' => trim($_POST['department'] ?? ''),
|
|
'status' => trim($_POST['status'] ?? 'active'),
|
|
'keywords' => trim($_POST['keywords'] ?? ''),
|
|
'description' => trim($_POST['description'] ?? ''),
|
|
'operator' => $user['emp_name'],
|
|
];
|
|
|
|
// 文件上传 — 仅允许安全文档类型
|
|
if (isset($_FILES['doc_file']) && $_FILES['doc_file']['error'] === UPLOAD_ERR_OK) {
|
|
$allowedExtensions = ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt', 'csv', 'zip', 'rar', 'jpg', 'jpeg', 'png', 'gif'];
|
|
$allowedMimeTypes = [
|
|
'application/pdf',
|
|
'application/msword',
|
|
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
|
'application/vnd.ms-excel',
|
|
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
|
'application/vnd.ms-powerpoint',
|
|
'application/vnd.openxmlformats-officedocument.presentationml.presentation',
|
|
'text/plain',
|
|
'text/csv',
|
|
'application/zip',
|
|
'application/x-zip-compressed',
|
|
'application/x-rar-compressed',
|
|
'image/jpeg',
|
|
'image/png',
|
|
'image/gif',
|
|
];
|
|
$originalName = $_FILES['doc_file']['name'];
|
|
$ext = strtolower(pathinfo($originalName, PATHINFO_EXTENSION));
|
|
$tmpPath = $_FILES['doc_file']['tmp_name'];
|
|
$mime = finfo_file(finfo_open(FILEINFO_MIME_TYPE), $tmpPath);
|
|
|
|
if (!in_array($ext, $allowedExtensions, true) || !in_array($mime, $allowedMimeTypes, true)) {
|
|
error_log('[documentAdd] Upload rejected: ext=' . $ext . ' mime=' . $mime . ' file=' . $originalName);
|
|
$this->assign('error', '不支持的文件类型,仅允许常见文档、图片和压缩包格式');
|
|
$this->assign('title', '添加文档');
|
|
$this->assign('user', $user);
|
|
$this->assign('activeMenu', 'document');
|
|
$this->assign('csrfToken', $this->csrfToken());
|
|
$this->render();
|
|
return;
|
|
}
|
|
|
|
$uploadDir = APP_PATH . 'static/uploads/documents/';
|
|
if (!is_dir($uploadDir)) {
|
|
mkdir($uploadDir, 0755, true);
|
|
}
|
|
$saveName = date('YmdHis') . '_' . uniqid() . '.' . $ext;
|
|
$savePath = $uploadDir . $saveName;
|
|
if (move_uploaded_file($tmpPath, $savePath)) {
|
|
$data['file_name'] = $originalName;
|
|
$data['file_path'] = '/static/uploads/documents/' . $saveName;
|
|
$data['file_size'] = $_FILES['doc_file']['size'];
|
|
$data['file_type'] = $ext;
|
|
}
|
|
}
|
|
|
|
if (empty($data['title'])) {
|
|
$this->assign('error', '文档标题不能为空');
|
|
$this->assign('title', '添加文档');
|
|
$this->assign('user', $user);
|
|
$this->assign('activeMenu', 'document');
|
|
$this->assign('csrfToken', $this->csrfToken());
|
|
$this->render();
|
|
return;
|
|
}
|
|
try {
|
|
$document = new Document();
|
|
$document->add($data);
|
|
header('Location: ' . BASE_URL . '/General/document');
|
|
exit;
|
|
} catch (\Throwable $e) {
|
|
error_log('[documentAdd] ' . $e->getMessage());
|
|
$this->assign('error', '添加失败:' . $e->getMessage());
|
|
$this->assign('title', '添加文档');
|
|
$this->assign('user', $user);
|
|
$this->assign('activeMenu', 'document');
|
|
$this->assign('csrfToken', $this->csrfToken());
|
|
$this->render();
|
|
return;
|
|
}
|
|
}
|
|
|
|
$this->assign('title', '添加文档');
|
|
$this->assign('user', $user);
|
|
$this->assign('activeMenu', 'document');
|
|
$this->assign('csrfToken', $this->csrfToken());
|
|
$this->render();
|
|
}
|
|
|
|
public function documentEdit()
|
|
{
|
|
$user = $this->checkCategoryAccess();
|
|
$id = (int)($_GET['id'] ?? 0);
|
|
$document = new Document();
|
|
$record = $document->getById($id);
|
|
if (!$record) exit('文档不存在');
|
|
|
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|
$this->csrfVerify();
|
|
$data = [
|
|
'title' => trim($_POST['title'] ?? ''),
|
|
'doc_no' => trim($_POST['doc_no'] ?? ''),
|
|
'category' => trim($_POST['category'] ?? ''),
|
|
'version' => trim($_POST['version'] ?? '1.0'),
|
|
'author' => trim($_POST['author'] ?? ''),
|
|
'department' => trim($_POST['department'] ?? ''),
|
|
'status' => trim($_POST['status'] ?? 'active'),
|
|
'keywords' => trim($_POST['keywords'] ?? ''),
|
|
'description' => trim($_POST['description'] ?? ''),
|
|
];
|
|
|
|
// 文件上传 — 仅允许安全文档类型
|
|
if (isset($_FILES['doc_file']) && $_FILES['doc_file']['error'] === UPLOAD_ERR_OK) {
|
|
$allowedExtensions = ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt', 'csv', 'zip', 'rar', 'jpg', 'jpeg', 'png', 'gif'];
|
|
$allowedMimeTypes = [
|
|
'application/pdf',
|
|
'application/msword',
|
|
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
|
'application/vnd.ms-excel',
|
|
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
|
'application/vnd.ms-powerpoint',
|
|
'application/vnd.openxmlformats-officedocument.presentationml.presentation',
|
|
'text/plain',
|
|
'text/csv',
|
|
'application/zip',
|
|
'application/x-zip-compressed',
|
|
'application/x-rar-compressed',
|
|
'image/jpeg',
|
|
'image/png',
|
|
'image/gif',
|
|
];
|
|
$originalName = $_FILES['doc_file']['name'];
|
|
$ext = strtolower(pathinfo($originalName, PATHINFO_EXTENSION));
|
|
$tmpPath = $_FILES['doc_file']['tmp_name'];
|
|
$mime = finfo_file(finfo_open(FILEINFO_MIME_TYPE), $tmpPath);
|
|
|
|
if (!in_array($ext, $allowedExtensions, true) || !in_array($mime, $allowedMimeTypes, true)) {
|
|
error_log('[documentEdit] Upload rejected: ext=' . $ext . ' mime=' . $mime . ' file=' . $originalName);
|
|
$this->assign('error', '不支持的文件类型,仅允许常见文档、图片和压缩包格式');
|
|
$this->assign('title', '编辑文档');
|
|
$this->assign('user', $user);
|
|
$this->assign('activeMenu', 'document');
|
|
$this->assign('record', $record);
|
|
$this->assign('csrfToken', $this->csrfToken());
|
|
$this->render();
|
|
return;
|
|
}
|
|
|
|
$uploadDir = APP_PATH . 'static/uploads/documents/';
|
|
if (!is_dir($uploadDir)) {
|
|
mkdir($uploadDir, 0755, true);
|
|
}
|
|
$saveName = date('YmdHis') . '_' . uniqid() . '.' . $ext;
|
|
$savePath = $uploadDir . $saveName;
|
|
if (move_uploaded_file($tmpPath, $savePath)) {
|
|
$data['file_name'] = $originalName;
|
|
$data['file_path'] = '/static/uploads/documents/' . $saveName;
|
|
$data['file_size'] = $_FILES['doc_file']['size'];
|
|
$data['file_type'] = $ext;
|
|
}
|
|
}
|
|
|
|
try {
|
|
$document->where(['id = :id'], [':id' => $id])->update($data);
|
|
header('Location: ' . BASE_URL . '/General/document');
|
|
exit;
|
|
} catch (\Throwable $e) {
|
|
error_log('[documentEdit] ' . $e->getMessage());
|
|
$this->assign('error', '更新失败:' . $e->getMessage());
|
|
$this->assign('title', '编辑文档');
|
|
$this->assign('user', $user);
|
|
$this->assign('activeMenu', 'document');
|
|
$this->assign('record', $record);
|
|
$this->assign('csrfToken', $this->csrfToken());
|
|
$this->render();
|
|
return;
|
|
}
|
|
}
|
|
|
|
$this->assign('title', '编辑文档');
|
|
$this->assign('user', $user);
|
|
$this->assign('activeMenu', 'document');
|
|
$this->assign('record', $record);
|
|
$this->assign('csrfToken', $this->csrfToken());
|
|
$this->render();
|
|
}
|
|
|
|
public function documentDelete()
|
|
{
|
|
$this->checkLogin();
|
|
$this->requireMethod('post');
|
|
$this->csrfVerify();
|
|
$id = (int)($_POST['id'] ?? 0);
|
|
$document = new Document();
|
|
$document->delete($id);
|
|
header('Location: ' . BASE_URL . '/General/document');
|
|
exit;
|
|
}
|
|
}
|